From 6107a2d2d5850afbe94173b57cb0cc5bd75d0a3e Mon Sep 17 00:00:00 2001
From: medariox <dariovizz@hotmail.it>
Date: Tue, 12 Jan 2016 15:03:48 +0100
Subject: [PATCH] Added guessit2, rebulk, regex

---
 lib/guessit2/__init__.py                      |     8 +
 lib/guessit2/__main__.py                      |   158 +
 lib/guessit2/__version__.py                   |     7 +
 lib/guessit2/api.py                           |    89 +
 lib/guessit2/backports.py                     |    27 +
 lib/guessit2/jsonutils.py                     |    32 +
 lib/guessit2/options.py                       |    97 +
 lib/guessit2/rules/__init__.py                |    76 +
 lib/guessit2/rules/common/__init__.py         |    13 +
 lib/guessit2/rules/common/comparators.py      |    70 +
 lib/guessit2/rules/common/date.py             |    78 +
 lib/guessit2/rules/common/formatters.py       |    75 +
 lib/guessit2/rules/common/numeral.py          |   167 +
 lib/guessit2/rules/common/validators.py       |    30 +
 lib/guessit2/rules/common/words.py            |    61 +
 lib/guessit2/rules/markers/__init__.py        |     5 +
 lib/guessit2/rules/markers/groups.py          |    51 +
 lib/guessit2/rules/markers/path.py            |    45 +
 lib/guessit2/rules/processors.py              |   199 +
 lib/guessit2/rules/properties/__init__.py     |     5 +
 lib/guessit2/rules/properties/audio_codec.py  |   148 +
 lib/guessit2/rules/properties/bonus.py        |    52 +
 lib/guessit2/rules/properties/cds.py          |    35 +
 lib/guessit2/rules/properties/container.py    |    53 +
 lib/guessit2/rules/properties/country.py      |   108 +
 lib/guessit2/rules/properties/crc.py          |    87 +
 lib/guessit2/rules/properties/date.py         |    74 +
 lib/guessit2/rules/properties/edition.py      |    33 +
 .../rules/properties/episode_title.py         |   198 +
 lib/guessit2/rules/properties/episodes.py     |   366 +
 lib/guessit2/rules/properties/film.py         |    44 +
 lib/guessit2/rules/properties/format.py       |    68 +
 lib/guessit2/rules/properties/language.py     |   249 +
 lib/guessit2/rules/properties/mimetype.py     |    43 +
 lib/guessit2/rules/properties/other.py        |   159 +
 lib/guessit2/rules/properties/part.py         |    29 +
 .../rules/properties/release_group.py         |   166 +
 lib/guessit2/rules/properties/screen_size.py  |    79 +
 lib/guessit2/rules/properties/title.py        |   340 +
 lib/guessit2/rules/properties/type.py         |    77 +
 lib/guessit2/rules/properties/video_codec.py  |    67 +
 lib/guessit2/rules/properties/website.py      |    39 +
 lib/guessit2/test/__init__.py                 |     3 +
 lib/guessit2/test/episodes.yml                |  1708 ++
 lib/guessit2/test/movies.yml                  |   788 +
 lib/guessit2/test/rules/__init__.py           |     3 +
 lib/guessit2/test/rules/audio_codec.yml       |    77 +
 lib/guessit2/test/rules/bonus.yml             |     9 +
 lib/guessit2/test/rules/cds.yml               |     5 +
 lib/guessit2/test/rules/country.yml           |    10 +
 lib/guessit2/test/rules/date.yml              |    50 +
 lib/guessit2/test/rules/edition.yml           |    25 +
 lib/guessit2/test/rules/episodes.yml          |   119 +
 lib/guessit2/test/rules/film.yml              |     9 +
 lib/guessit2/test/rules/format.yml            |   112 +
 lib/guessit2/test/rules/language.yml          |    26 +
 lib/guessit2/test/rules/other.yml             |   137 +
 lib/guessit2/test/rules/part.yml              |    18 +
 lib/guessit2/test/rules/processors.yml        |     8 +
 lib/guessit2/test/rules/release_group.yml     |    33 +
 lib/guessit2/test/rules/screen_size.yml       |    65 +
 lib/guessit2/test/rules/title.yml             |    32 +
 lib/guessit2/test/rules/video_codec.yml       |    54 +
 lib/guessit2/test/rules/website.yml           |    15 +
 lib/guessit2/test/test-input-file.txt         |     2 +
 lib/guessit2/test/test_api.py                 |    31 +
 lib/guessit2/test/test_benchmark.py           |    53 +
 lib/guessit2/test/test_main.py                |    72 +
 lib/guessit2/test/test_yml.py                 |   274 +
 lib/guessit2/test/various.yml                 |   545 +
 lib/guessit2/tlds-alpha-by-domain.txt         |   341 +
 lib/guessit2/yamlutils.py                     |    71 +
 lib/rebulk/__init__.py                        |    10 +
 lib/rebulk/__version__.py                     |     7 +
 lib/rebulk/debug.py                           |    56 +
 lib/rebulk/formatters.py                      |    23 +
 lib/rebulk/introspector.py                    |   126 +
 lib/rebulk/loose.py                           |   194 +
 lib/rebulk/match.py                           |   781 +
 lib/rebulk/pattern.py                         |   415 +
 lib/rebulk/processors.py                      |    92 +
 lib/rebulk/rebulk.py                          |   281 +
 lib/rebulk/rules.py                           |   378 +
 lib/rebulk/test/__init__.py                   |     3 +
 lib/rebulk/test/default_rules_module.py       |    80 +
 lib/rebulk/test/rebulk_rules_module.py        |    38 +
 lib/rebulk/test/rules_module.py               |    54 +
 lib/rebulk/test/test_debug.py                 |    83 +
 lib/rebulk/test/test_introspector.py          |   138 +
 lib/rebulk/test/test_loose.py                 |    83 +
 lib/rebulk/test/test_match.py                 |   571 +
 lib/rebulk/test/test_pattern.py               |   757 +
 lib/rebulk/test/test_processors.py            |   215 +
 lib/rebulk/test/test_rebulk.py                |   408 +
 lib/rebulk/test/test_rules.py                 |   197 +
 lib/rebulk/test/test_toposort.py              |   111 +
 lib/rebulk/test/test_validators.py            |    68 +
 lib/rebulk/toposort.py                        |    84 +
 lib/rebulk/utils.py                           |   133 +
 lib/rebulk/validators.py                      |    70 +
 lib/regex/__init__.py                         |   703 +
 lib/regex/_regex.c                            | 24497 ++++++++++++++++
 lib/regex/_regex.h                            |   243 +
 lib/regex/_regex.so                           |   Bin 0 -> 1189938 bytes
 lib/regex/_regex_core.py                      |  4317 +++
 lib/regex/_regex_unicode.c                    | 14258 +++++++++
 lib/regex/_regex_unicode.h                    |   226 +
 lib/regex/test_regex.py                       |  3585 +++
 108 files changed, 61787 insertions(+)
 create mode 100644 lib/guessit2/__init__.py
 create mode 100644 lib/guessit2/__main__.py
 create mode 100644 lib/guessit2/__version__.py
 create mode 100644 lib/guessit2/api.py
 create mode 100644 lib/guessit2/backports.py
 create mode 100644 lib/guessit2/jsonutils.py
 create mode 100644 lib/guessit2/options.py
 create mode 100644 lib/guessit2/rules/__init__.py
 create mode 100644 lib/guessit2/rules/common/__init__.py
 create mode 100644 lib/guessit2/rules/common/comparators.py
 create mode 100644 lib/guessit2/rules/common/date.py
 create mode 100644 lib/guessit2/rules/common/formatters.py
 create mode 100644 lib/guessit2/rules/common/numeral.py
 create mode 100644 lib/guessit2/rules/common/validators.py
 create mode 100644 lib/guessit2/rules/common/words.py
 create mode 100644 lib/guessit2/rules/markers/__init__.py
 create mode 100644 lib/guessit2/rules/markers/groups.py
 create mode 100644 lib/guessit2/rules/markers/path.py
 create mode 100644 lib/guessit2/rules/processors.py
 create mode 100644 lib/guessit2/rules/properties/__init__.py
 create mode 100644 lib/guessit2/rules/properties/audio_codec.py
 create mode 100644 lib/guessit2/rules/properties/bonus.py
 create mode 100644 lib/guessit2/rules/properties/cds.py
 create mode 100644 lib/guessit2/rules/properties/container.py
 create mode 100644 lib/guessit2/rules/properties/country.py
 create mode 100644 lib/guessit2/rules/properties/crc.py
 create mode 100644 lib/guessit2/rules/properties/date.py
 create mode 100644 lib/guessit2/rules/properties/edition.py
 create mode 100644 lib/guessit2/rules/properties/episode_title.py
 create mode 100644 lib/guessit2/rules/properties/episodes.py
 create mode 100644 lib/guessit2/rules/properties/film.py
 create mode 100644 lib/guessit2/rules/properties/format.py
 create mode 100644 lib/guessit2/rules/properties/language.py
 create mode 100644 lib/guessit2/rules/properties/mimetype.py
 create mode 100644 lib/guessit2/rules/properties/other.py
 create mode 100644 lib/guessit2/rules/properties/part.py
 create mode 100644 lib/guessit2/rules/properties/release_group.py
 create mode 100644 lib/guessit2/rules/properties/screen_size.py
 create mode 100644 lib/guessit2/rules/properties/title.py
 create mode 100644 lib/guessit2/rules/properties/type.py
 create mode 100644 lib/guessit2/rules/properties/video_codec.py
 create mode 100644 lib/guessit2/rules/properties/website.py
 create mode 100644 lib/guessit2/test/__init__.py
 create mode 100644 lib/guessit2/test/episodes.yml
 create mode 100644 lib/guessit2/test/movies.yml
 create mode 100644 lib/guessit2/test/rules/__init__.py
 create mode 100644 lib/guessit2/test/rules/audio_codec.yml
 create mode 100644 lib/guessit2/test/rules/bonus.yml
 create mode 100644 lib/guessit2/test/rules/cds.yml
 create mode 100644 lib/guessit2/test/rules/country.yml
 create mode 100644 lib/guessit2/test/rules/date.yml
 create mode 100644 lib/guessit2/test/rules/edition.yml
 create mode 100644 lib/guessit2/test/rules/episodes.yml
 create mode 100644 lib/guessit2/test/rules/film.yml
 create mode 100644 lib/guessit2/test/rules/format.yml
 create mode 100644 lib/guessit2/test/rules/language.yml
 create mode 100644 lib/guessit2/test/rules/other.yml
 create mode 100644 lib/guessit2/test/rules/part.yml
 create mode 100644 lib/guessit2/test/rules/processors.yml
 create mode 100644 lib/guessit2/test/rules/release_group.yml
 create mode 100644 lib/guessit2/test/rules/screen_size.yml
 create mode 100644 lib/guessit2/test/rules/title.yml
 create mode 100644 lib/guessit2/test/rules/video_codec.yml
 create mode 100644 lib/guessit2/test/rules/website.yml
 create mode 100644 lib/guessit2/test/test-input-file.txt
 create mode 100644 lib/guessit2/test/test_api.py
 create mode 100644 lib/guessit2/test/test_benchmark.py
 create mode 100644 lib/guessit2/test/test_main.py
 create mode 100644 lib/guessit2/test/test_yml.py
 create mode 100644 lib/guessit2/test/various.yml
 create mode 100644 lib/guessit2/tlds-alpha-by-domain.txt
 create mode 100644 lib/guessit2/yamlutils.py
 create mode 100644 lib/rebulk/__init__.py
 create mode 100644 lib/rebulk/__version__.py
 create mode 100644 lib/rebulk/debug.py
 create mode 100644 lib/rebulk/formatters.py
 create mode 100644 lib/rebulk/introspector.py
 create mode 100644 lib/rebulk/loose.py
 create mode 100644 lib/rebulk/match.py
 create mode 100644 lib/rebulk/pattern.py
 create mode 100644 lib/rebulk/processors.py
 create mode 100644 lib/rebulk/rebulk.py
 create mode 100644 lib/rebulk/rules.py
 create mode 100644 lib/rebulk/test/__init__.py
 create mode 100644 lib/rebulk/test/default_rules_module.py
 create mode 100644 lib/rebulk/test/rebulk_rules_module.py
 create mode 100644 lib/rebulk/test/rules_module.py
 create mode 100644 lib/rebulk/test/test_debug.py
 create mode 100644 lib/rebulk/test/test_introspector.py
 create mode 100644 lib/rebulk/test/test_loose.py
 create mode 100644 lib/rebulk/test/test_match.py
 create mode 100644 lib/rebulk/test/test_pattern.py
 create mode 100644 lib/rebulk/test/test_processors.py
 create mode 100644 lib/rebulk/test/test_rebulk.py
 create mode 100644 lib/rebulk/test/test_rules.py
 create mode 100644 lib/rebulk/test/test_toposort.py
 create mode 100644 lib/rebulk/test/test_validators.py
 create mode 100644 lib/rebulk/toposort.py
 create mode 100644 lib/rebulk/utils.py
 create mode 100644 lib/rebulk/validators.py
 create mode 100644 lib/regex/__init__.py
 create mode 100644 lib/regex/_regex.c
 create mode 100644 lib/regex/_regex.h
 create mode 100644 lib/regex/_regex.so
 create mode 100644 lib/regex/_regex_core.py
 create mode 100644 lib/regex/_regex_unicode.c
 create mode 100644 lib/regex/_regex_unicode.h
 create mode 100644 lib/regex/test_regex.py

diff --git a/lib/guessit2/__init__.py b/lib/guessit2/__init__.py
new file mode 100644
index 000000000..8b5c841b8
--- /dev/null
+++ b/lib/guessit2/__init__.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Extracts as much information as possible from a video file.
+"""
+from .api import guessit, GuessItApi
+
+from .__version__ import __version__
diff --git a/lib/guessit2/__main__.py b/lib/guessit2/__main__.py
new file mode 100644
index 000000000..0ba11b422
--- /dev/null
+++ b/lib/guessit2/__main__.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Entry point module
+"""
+# pragma: no cover
+from __future__ import print_function, unicode_literals
+
+import os
+import logging
+import json
+import sys
+from io import open  #pylint:disable=redefined-builtin
+
+import six
+from guessit.jsonutils import GuessitEncoder
+
+from guessit.__version__ import __version__
+from guessit.options import argument_parser
+from guessit import api
+
+
+def guess_filename(filename, options):
+    """
+    Guess a single filename using given options
+    """
+    if not options.yaml and not options.json and not options.show_property:
+        print('For:', filename)
+
+    cmd_options = vars(options)
+    cmd_options['implicit'] = True  # Force implicit option in CLI
+
+    guess = api.guessit(filename, vars(options))
+
+    if options.show_property:
+        print(guess.get(options.show_property, ''))
+        return
+
+    if options.json:
+        print(json.dumps(guess, cls=GuessitEncoder, ensure_ascii=False))
+    elif options.yaml:
+        import yaml
+        from guessit import yamlutils
+
+        ystr = yaml.dump({filename: dict(guess)}, Dumper=yamlutils.CustomDumper, default_flow_style=False,
+                         allow_unicode=True)
+        i = 0
+        for yline in ystr.splitlines():
+            if i == 0:
+                print("? " + yline[:-1])
+            elif i == 1:
+                print(":" + yline[1:])
+            else:
+                print(yline)
+            i += 1
+    else:
+        print('GuessIt found:', json.dumps(guess, cls=GuessitEncoder, indent=4, ensure_ascii=False))
+
+
+def display_properties(options):
+    """
+    Display properties
+    """
+    properties = api.properties(options)
+
+    if options.json:
+        if options.values:
+            print(json.dumps(properties, cls=GuessitEncoder, ensure_ascii=False))
+        else:
+            print(json.dumps(list(properties.keys()), cls=GuessitEncoder, ensure_ascii=False))
+    elif options.yaml:
+        import yaml
+        from guessit import yamlutils
+        if options.values:
+            print(yaml.dump(properties, Dumper=yamlutils.CustomDumper, default_flow_style=False, allow_unicode=True))
+        else:
+            print(yaml.dump(list(properties.keys()), Dumper=yamlutils.CustomDumper, default_flow_style=False,
+                            allow_unicode=True))
+    else:
+        print('GuessIt properties:')
+
+        properties_list = list(sorted(properties.keys()))
+        for property_name in properties_list:
+            property_values = properties.get(property_name)
+            print(2 * ' ' + '[+] %s' % (property_name,))
+            if property_values and options.values:
+                for property_value in property_values:
+                    print(4 * ' ' + '[!] %s' % (property_value,))
+
+
+def main(args=None):  # pylint:disable=too-many-branches
+    """
+    Main function for entry point
+    """
+    if six.PY2 and os.name == 'nt':  # pragma: no cover
+        # see http://bugs.python.org/issue2128
+        import locale
+
+        for i, j in enumerate(sys.argv):
+            sys.argv[i] = j.decode(locale.getpreferredencoding())
+
+    if args is None:  # pragma: no cover
+        options = argument_parser.parse_args()
+    else:
+        options = argument_parser.parse_args(args)
+    if options.verbose:
+        logging.basicConfig(stream=sys.stdout, format='%(message)s')
+        logging.getLogger().setLevel(logging.DEBUG)
+
+    help_required = True
+
+    if options.version:
+        print('+-------------------------------------------------------+')
+        print('+                   GuessIt ' + __version__ + (28 - len(__version__)) * ' ' + '+')
+        print('+-------------------------------------------------------+')
+        print('|      Please report any bug or feature request at      |')
+        print('|       https://github.com/wackou/guessit/issues.       |')
+        print('+-------------------------------------------------------+')
+        help_required = False
+
+    if options.yaml:
+        try:
+            import yaml  # pylint:disable=unused-variable
+        except ImportError:  # pragma: no cover
+            options.yaml = False
+            print('PyYAML is not installed. \'--yaml\' option will be ignored ...', file=sys.stderr)
+
+    if options.properties or options.values:
+        display_properties(options)
+        help_required = False
+
+    filenames = []
+    if options.filename:
+        for filename in options.filename:
+            if not isinstance(filename, six.text_type):  # pragma: no cover
+                encoding = sys.getfilesystemencoding()
+                filename = filename.decode(encoding)
+            filenames.append(filename)
+    if options.input_file:
+        input_file = open(options.input_file, 'r', encoding='utf-8')
+        try:
+            filenames.extend([line.strip() for line in input_file.readlines()])
+        finally:
+            input_file.close()
+
+    filenames = list(filter(lambda f: f, filenames))
+
+    if filenames:
+        for filename in filenames:
+            help_required = False
+            guess_filename(filename, options)
+
+    if help_required:  # pragma: no cover
+        argument_parser.print_help()
+
+
+if __name__ == '__main__':  # pragma: no cover
+    main()
diff --git a/lib/guessit2/__version__.py b/lib/guessit2/__version__.py
new file mode 100644
index 000000000..c6db86db2
--- /dev/null
+++ b/lib/guessit2/__version__.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Version module
+"""
+# pragma: no cover
+__version__ = '2.0rc5.dev0'
diff --git a/lib/guessit2/api.py b/lib/guessit2/api.py
new file mode 100644
index 000000000..3a4959ad1
--- /dev/null
+++ b/lib/guessit2/api.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+API functions that can be used by external software
+"""
+from __future__ import unicode_literals
+try:
+    from collections import OrderedDict
+except ImportError:  # pragma: no-cover
+    from ordereddict import OrderedDict  # pylint:disable=import-error
+
+import six
+
+from rebulk.introspector import introspect
+
+from .rules import rebulk_builder
+from .options import parse_options
+
+
+def guessit(string, options=None):
+    """
+    Retrieves all matches from string as a dict
+    :param string: the filename or release name
+    :type string: str
+    :param options: the filename or release name
+    :type options: str|dict
+    :return:
+    :rtype:
+    """
+    return default_api.guessit(string, options)
+
+
+def properties(options=None):
+    """
+    Retrieves all properties with possible values that can be guessed
+    :param options:
+    :type options:
+    :return:
+    :rtype:
+    """
+    return default_api.properties(options)
+
+
+class GuessItApi(object):
+    """
+    An api class that can be configured with custom Rebulk configuration.
+    """
+
+    def __init__(self, rebulk):
+        """
+        :param rebulk: Rebulk instance to use.
+        :type rebulk: Rebulk
+        :return:
+        :rtype:
+        """
+        self.rebulk = rebulk
+
+    def guessit(self, string, options=None):
+        """
+        Retrieves all matches from string as a dict
+        :param string: the filename or release name
+        :type string: str
+        :param options: the filename or release name
+        :type options: str|dict
+        :return:
+        :rtype:
+        """
+        if not isinstance(string, six.text_type):
+            raise TypeError("guessit input must be %s." % six.text_type.__name__)
+        options = parse_options(options)
+        return self.rebulk.matches(string, options).to_dict(options.get('advanced', False),
+                                                            options.get('implicit', False))
+
+    def properties(self, options=None):
+        """
+        Grab properties and values that can be generated.
+        :param options:
+        :type options:
+        :return:
+        :rtype:
+        """
+        unordered = introspect(self.rebulk, options).properties
+        ordered = OrderedDict()
+        for k in sorted(unordered.keys(), key=six.text_type):
+            ordered[k] = list(sorted(unordered[k], key=six.text_type))
+        return ordered
+
+
+default_api = GuessItApi(rebulk_builder())
diff --git a/lib/guessit2/backports.py b/lib/guessit2/backports.py
new file mode 100644
index 000000000..3e94e27ad
--- /dev/null
+++ b/lib/guessit2/backports.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Backports
+"""
+# pragma: no-cover
+# pylint: disabled
+
+def cmp_to_key(mycmp):
+    """functools.cmp_to_key backport"""
+    class KeyClass(object):
+        """Key class"""
+        def __init__(self, obj, *args):  # pylint: disable=unused-argument
+            self.obj = obj
+        def __lt__(self, other):
+            return mycmp(self.obj, other.obj) < 0
+        def __gt__(self, other):
+            return mycmp(self.obj, other.obj) > 0
+        def __eq__(self, other):
+            return mycmp(self.obj, other.obj) == 0
+        def __le__(self, other):
+            return mycmp(self.obj, other.obj) <= 0
+        def __ge__(self, other):
+            return mycmp(self.obj, other.obj) >= 0
+        def __ne__(self, other):
+            return mycmp(self.obj, other.obj) != 0
+    return KeyClass
diff --git a/lib/guessit2/jsonutils.py b/lib/guessit2/jsonutils.py
new file mode 100644
index 000000000..54bf79431
--- /dev/null
+++ b/lib/guessit2/jsonutils.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+JSON Utils
+"""
+import json
+try:
+    from collections import OrderedDict
+except ImportError:  # pragma: no-cover
+    from ordereddict import OrderedDict  # pylint:disable=import-error
+
+from rebulk.match import Match
+
+
+class GuessitEncoder(json.JSONEncoder):
+    """
+    JSON Encoder for guessit response
+    """
+
+    def default(self, o):  # pylint:disable=method-hidden
+        if isinstance(o, Match):
+            ret = OrderedDict()
+            ret['value'] = o.value
+            if o.raw:
+                ret['raw'] = o.raw
+            ret['start'] = o.start
+            ret['end'] = o.end
+            return ret
+        elif hasattr(o, 'name'):  # Babelfish languages/countries long name
+            return o.name
+        else:  # pragma: no cover
+            return str(o)
diff --git a/lib/guessit2/options.py b/lib/guessit2/options.py
new file mode 100644
index 000000000..2cdc02cea
--- /dev/null
+++ b/lib/guessit2/options.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Options
+"""
+from __future__ import unicode_literals
+
+import sys
+from argparse import ArgumentParser
+import shlex
+
+import six
+
+
+if six.PY2:
+    StrOptType = lambda s: unicode(s, sys.stdin.encoding)  # pylint:disable=undefined-variable
+else:
+    StrOptType = str  # pylint:disable=redefined-variable-type
+
+
+def build_argument_parser():
+    """
+    Builds the argument parser
+    :return: the argument parser
+    :rtype: ArgumentParser
+    """
+    opts = ArgumentParser()
+    opts.add_argument(dest='filename', help='Filename or release name to guess', nargs='*')
+
+    naming_opts = opts.add_argument_group("Naming")
+    naming_opts.add_argument('-t', '--type', dest='type', default=None,
+                             help='The suggested file type: movie, episode. If undefined, type will be guessed.')
+    naming_opts.add_argument('-n', '--name-only', dest='name_only', action='store_true', default=False,
+                             help='Parse files as name only, considering "/" and "\\" like other separators.')
+    naming_opts.add_argument('-Y', '--date-year-first', action='store_true', dest='date_year_first', default=None,
+                             help='If short date is found, consider the first digits as the year.')
+    naming_opts.add_argument('-D', '--date-day-first', action='store_true', dest='date_day_first', default=None,
+                             help='If short date is found, consider the second digits as the day.')
+    naming_opts.add_argument('-L', '--allowed-languages', action='append', dest='allowed_languages',
+                             help='Allowed language (can be used multiple times)')
+    naming_opts.add_argument('-C', '--allowed-countries', action='append', dest='allowed_countries',
+                             help='Allowed country (can be used multiple times)')
+    naming_opts.add_argument('-E', '--episode-prefer-number', action='store_true', dest='episode_prefer_number',
+                             default=False,
+                             help='Guess "serie.213.avi" as the episode 213. Without this option, '
+                                  'it will be guessed as season 2, episode 13')
+    naming_opts.add_argument('-T', '--expected-title', action='append', dest='expected_title', type=StrOptType,
+                             help='Expected title to parse (can be used multiple times)')
+    naming_opts.add_argument('-G', '--expected-group', action='append', dest='expected_group', type=StrOptType,
+                             help='Expected release group (can be used multiple times)')
+
+    input_opts = opts.add_argument_group("Input")
+    input_opts.add_argument('-f', '--input-file', dest='input_file', default=False,
+                            help='Read filenames from an input text file. File should use UTF-8 charset.')
+
+    output_opts = opts.add_argument_group("Output")
+    output_opts.add_argument('-v', '--verbose', action='store_true', dest='verbose', default=False,
+                             help='Display debug output')
+    output_opts.add_argument('-P', '--show-property', dest='show_property', default=None,
+                             help='Display the value of a single property (title, series, video_codec, year, ...)')
+    output_opts.add_argument('-a', '--advanced', dest='advanced', action='store_true', default=False,
+                             help='Display advanced information for filename guesses, as json output')
+    output_opts.add_argument('-j', '--json', dest='json', action='store_true', default=False,
+                             help='Display information for filename guesses as json output')
+    output_opts.add_argument('-y', '--yaml', dest='yaml', action='store_true', default=False,
+                             help='Display information for filename guesses as yaml output')
+
+
+
+    information_opts = opts.add_argument_group("Information")
+    information_opts.add_argument('-p', '--properties', dest='properties', action='store_true', default=False,
+                                  help='Display properties that can be guessed.')
+    information_opts.add_argument('-V', '--values', dest='values', action='store_true', default=False,
+                                  help='Display property values that can be guessed.')
+    information_opts.add_argument('--version', dest='version', action='store_true', default=False,
+                                  help='Display the guessit version.')
+
+    return opts
+
+
+def parse_options(options):
+    """
+    Parse given option string
+    :param options:
+    :type options:
+    :return:
+    :rtype:
+    """
+    if isinstance(options, six.string_types):
+        args = shlex.split(options)
+        options = vars(argument_parser.parse_args(args))
+    if options is None:
+        options = {}
+    return options
+
+
+argument_parser = build_argument_parser()
diff --git a/lib/guessit2/rules/__init__.py b/lib/guessit2/rules/__init__.py
new file mode 100644
index 000000000..8e2716cc0
--- /dev/null
+++ b/lib/guessit2/rules/__init__.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Rebulk object default builder
+"""
+from __future__ import unicode_literals
+
+from rebulk import Rebulk
+
+from .markers.path import path
+from .markers.groups import groups
+
+from .properties.episodes import episodes
+from .properties.container import container
+from .properties.format import format_
+from .properties.video_codec import video_codec
+from .properties.audio_codec import audio_codec
+from .properties.screen_size import screen_size
+from .properties.website import website
+from .properties.date import date
+from .properties.title import title
+from .properties.episode_title import episode_title
+from .properties.language import language
+from .properties.country import country
+from .properties.release_group import release_group
+from .properties.other import other
+from .properties.edition import edition
+from .properties.cds import cds
+from .properties.bonus import bonus
+from .properties.film import film
+from .properties.part import part
+from .properties.crc import crc
+from .properties.mimetype import mimetype
+from .properties.type import type_
+
+from .processors import processors
+
+
+def rebulk_builder():
+    """
+    Default builder for main Rebulk object used by api.
+    :return: Main Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk()
+
+    rebulk.rebulk(path())
+    rebulk.rebulk(groups())
+
+    rebulk.rebulk(episodes())
+    rebulk.rebulk(container())
+    rebulk.rebulk(format_())
+    rebulk.rebulk(video_codec())
+    rebulk.rebulk(audio_codec())
+    rebulk.rebulk(screen_size())
+    rebulk.rebulk(website())
+    rebulk.rebulk(date())
+    rebulk.rebulk(title())
+    rebulk.rebulk(episode_title())
+    rebulk.rebulk(language())
+    rebulk.rebulk(country())
+    rebulk.rebulk(release_group())
+    rebulk.rebulk(other())
+    rebulk.rebulk(edition())
+    rebulk.rebulk(cds())
+    rebulk.rebulk(bonus())
+    rebulk.rebulk(film())
+    rebulk.rebulk(part())
+    rebulk.rebulk(crc())
+
+    rebulk.rebulk(processors())
+
+    rebulk.rebulk(mimetype())
+    rebulk.rebulk(type_())
+
+    return rebulk
diff --git a/lib/guessit2/rules/common/__init__.py b/lib/guessit2/rules/common/__init__.py
new file mode 100644
index 000000000..a30f08798
--- /dev/null
+++ b/lib/guessit2/rules/common/__init__.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Common module
+"""
+from __future__ import unicode_literals
+
+seps = r' [](){}+*|=§-_~#/\.,;:'  # list of tags/words separators
+
+title_seps = r'-+/\|'  # separators for title
+
+dash = (r'-', r'[\W_]')  # abbreviation used by many rebulk objects.
+alt_dash = (r'@', r'[\W_]')  # abbreviation used by many rebulk objects.
diff --git a/lib/guessit2/rules/common/comparators.py b/lib/guessit2/rules/common/comparators.py
new file mode 100644
index 000000000..f27a407fe
--- /dev/null
+++ b/lib/guessit2/rules/common/comparators.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Comparators
+"""
+from __future__ import unicode_literals
+
+try:
+    from functools import cmp_to_key
+except ImportError:
+    from ...backports import cmp_to_key
+
+
+def marker_comparator_predicate(match):
+    """
+    Match predicate used in comparator
+    """
+    return not match.private and \
+           match.name not in ['proper_count', 'title', 'episode_title', 'alternativeTitle'] and \
+           not (match.name == 'container' and 'extension' in match.tags)
+
+
+def marker_weight(matches, marker):
+    """
+    Compute the comparator weight of a marker
+    :param matches:
+    :param marker:
+    :return:
+    """
+    return len(set(match.name for match in matches.range(*marker.span, predicate=marker_comparator_predicate)))
+
+
+def marker_comparator(matches, markers):
+    """
+    Builds a comparator that returns markers sorted from the most valuable to the less.
+
+    Take the parts where matches count is higher, then when length is higher, then when position is at left.
+
+    :param matches:
+    :type matches:
+    :return:
+    :rtype:
+    """
+    def comparator(marker1, marker2):
+        """
+        The actual comparator function.
+        """
+        matches_count = marker_weight(matches, marker2) - marker_weight(matches, marker1)
+        if matches_count:
+            return matches_count
+        len_diff = len(marker2) - len(marker1)
+        if len_diff:
+            return len_diff
+        return markers.index(marker2) - markers.index(marker1)
+
+    return comparator
+
+
+def marker_sorted(markers, matches):
+    """
+    Sort markers from matches, from the most valuable to the less.
+
+    :param fileparts:
+    :type fileparts:
+    :param matches:
+    :type matches:
+    :return:
+    :rtype:
+    """
+    return sorted(markers, key=cmp_to_key(marker_comparator(matches, markers)))
diff --git a/lib/guessit2/rules/common/date.py b/lib/guessit2/rules/common/date.py
new file mode 100644
index 000000000..56b0987f9
--- /dev/null
+++ b/lib/guessit2/rules/common/date.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Date
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from dateutil import parser
+
+_dsep = r'[-/ \.]'
+_dsep_bis = r'[-/ \.x]'
+
+date_regexps = [
+    re.compile(r'%s((\d{8}))%s' % (_dsep, _dsep), re.IGNORECASE),
+    re.compile(r'%s((\d{6}))%s' % (_dsep, _dsep), re.IGNORECASE),
+    re.compile(r'(?:^|[^\d])((\d{2})%s(\d{1,2})%s(\d{1,2}))(?:$|[^\d])' % (_dsep, _dsep), re.IGNORECASE),
+    re.compile(r'(?:^|[^\d])((\d{1,2})%s(\d{1,2})%s(\d{2}))(?:$|[^\d])' % (_dsep, _dsep), re.IGNORECASE),
+    re.compile(r'(?:^|[^\d])((\d{4})%s(\d{1,2})%s(\d{1,2}))(?:$|[^\d])' % (_dsep_bis, _dsep), re.IGNORECASE),
+    re.compile(r'(?:^|[^\d])((\d{1,2})%s(\d{1,2})%s(\d{4}))(?:$|[^\d])' % (_dsep, _dsep_bis), re.IGNORECASE),
+    re.compile(r'(?:^|[^\d])((\d{1,2}(?:st|nd|rd|th)?%s(?:[a-z]{3,10})%s\d{4}))(?:$|[^\d])' % (_dsep, _dsep),
+               re.IGNORECASE)]
+
+
+def valid_year(year):
+    """Check if number is a valid year"""
+    return 1920 <= year < 2030
+
+
+def search_date(string, year_first=None, day_first=True):
+    """Looks for date patterns, and if found return the date and group span.
+
+    Assumes there are sentinels at the beginning and end of the string that
+    always allow matching a non-digit delimiting the date.
+
+    Year can be defined on two digit only. It will return the nearest possible
+    date from today.
+
+    >>> search_date(' This happened on 2002-04-22. ')
+    (18, 28, datetime.date(2002, 4, 22))
+
+    >>> search_date(' And this on 17-06-1998. ')
+    (13, 23, datetime.date(1998, 6, 17))
+
+    >>> search_date(' no date in here ')
+    """
+    start, end = None, None
+    match = None
+    for date_re in date_regexps:
+        search_match = date_re.search(string)
+        if search_match and (match is None or search_match.end() - search_match.start() > len(match)):
+            start, end = search_match.start(1), search_match.end(1)
+            match = '-'.join(search_match.groups()[1:])
+
+    if match is None:
+        return
+
+    # If day_first/year_first is undefined, parse is made using both possible values.
+    yearfirst_opts = [False, True]
+    if year_first is not None:
+        yearfirst_opts = [year_first]
+
+    dayfirst_opts = [True, False]
+    if day_first is not None:
+        dayfirst_opts = [day_first]
+
+    kwargs_list = ({'dayfirst': d, 'yearfirst': y} for d in dayfirst_opts for y in yearfirst_opts)
+    for kwargs in kwargs_list:
+        try:
+            date = parser.parse(match, **kwargs)
+        except (ValueError, TypeError):  # pragma: no cover
+            # see https://bugs.launchpad.net/dateutil/+bug/1247643
+            date = None
+
+        # check date plausibility
+        if date and valid_year(date.year):  # pylint:disable=no-member
+            return start, end, date.date()  # pylint:disable=no-member
diff --git a/lib/guessit2/rules/common/formatters.py b/lib/guessit2/rules/common/formatters.py
new file mode 100644
index 000000000..ca70811f8
--- /dev/null
+++ b/lib/guessit2/rules/common/formatters.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Formatters
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk.formatters import formatters
+
+from . import seps
+
+
+_excluded_clean_chars = ',:;-/\\'
+clean_chars = ""
+for sep in seps:
+    if sep not in _excluded_clean_chars:
+        clean_chars += sep
+
+
+def cleanup(input_string):
+    """
+    Removes and strip separators from input_string (but keep ',;' characters)
+    :param input_string:
+    :type input_string:
+    :return:
+    :rtype:
+    """
+    for char in clean_chars:
+        input_string = input_string.replace(char, ' ')
+    return re.sub(' +', ' ', strip(input_string))
+
+
+def strip(input_string):
+    """
+    Strip separators from input_string
+    :param input_string:
+    :type input_string:
+    :return:
+    :rtype:
+    """
+    return input_string.strip(seps)
+
+
+def raw_cleanup(raw):
+    """
+    Cleanup a raw value to perform raw comparison
+    :param raw:
+    :type raw:
+    :return:
+    :rtype:
+    """
+    return formatters(cleanup, strip)(raw.lower())
+
+
+def reorder_title(title, articles=('the',), separators=(',', ', ')):
+    """
+    Reorder the title
+    :param title:
+    :type title:
+    :param articles:
+    :type articles:
+    :param separators:
+    :type separators:
+    :return:
+    :rtype:
+    """
+    ltitle = title.lower()
+    for article in articles:
+        for separator in separators:
+            suffix = separator + article
+            if ltitle[-len(suffix):] == suffix:
+                return title[-len(suffix) + len(separator):] + ' ' + title[:-len(suffix)]
+    return title
diff --git a/lib/guessit2/rules/common/numeral.py b/lib/guessit2/rules/common/numeral.py
new file mode 100644
index 000000000..8b868ea66
--- /dev/null
+++ b/lib/guessit2/rules/common/numeral.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+parse numeral from various formats
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+digital_numeral = r'\d{1,4}'
+
+roman_numeral = r'(?=[MCDLXVI]+)M{0,4}(?:CM|CD|D?C{0,3})(?:XC|XL|L?X{0,3})(?:IX|IV|V?I{0,3})'
+
+english_word_numeral_list = [
+    'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten',
+    'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty'
+]
+
+french_word_numeral_list = [
+    'zéro', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf', 'dix',
+    'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf', 'vingt'
+]
+
+french_alt_word_numeral_list = [
+    'zero', 'une', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf', 'dix',
+    'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize', 'dixsept', 'dixhuit', 'dixneuf', 'vingt'
+]
+
+
+def __build_word_numeral(*args):
+    """
+    Build word numeral regexp from list.
+
+    :param args:
+    :type args:
+    :param kwargs:
+    :type kwargs:
+    :return:
+    :rtype:
+    """
+    re_ = None
+    for word_list in args:
+        for word in word_list:
+            if not re_:
+                re_ = r'(?:(?=\w+)'
+            else:
+                re_ += '|'
+            re_ += word
+    re_ += ')'
+    return re_
+
+
+word_numeral = __build_word_numeral(english_word_numeral_list, french_word_numeral_list, french_alt_word_numeral_list)
+
+numeral = '(?:' + digital_numeral + '|' + roman_numeral + '|' + word_numeral + ')'
+
+__romanNumeralMap = (
+    ('M', 1000),
+    ('CM', 900),
+    ('D', 500),
+    ('CD', 400),
+    ('C', 100),
+    ('XC', 90),
+    ('L', 50),
+    ('XL', 40),
+    ('X', 10),
+    ('IX', 9),
+    ('V', 5),
+    ('IV', 4),
+    ('I', 1)
+)
+
+__romanNumeralPattern = re.compile('^' + roman_numeral + '$')
+
+
+def __parse_roman(value):
+    """
+    convert Roman numeral to integer
+
+    :param value: Value to parse
+    :type value: string
+    :return:
+    :rtype:
+    """
+    if not __romanNumeralPattern.search(value):
+        raise ValueError('Invalid Roman numeral: %s' % value)
+
+    result = 0
+    index = 0
+    for num, integer in __romanNumeralMap:
+        while value[index:index + len(num)] == num:
+            result += integer
+            index += len(num)
+    return result
+
+
+def __parse_word(value):
+    """
+    Convert Word numeral to integer
+
+    :param value: Value to parse
+    :type value: string
+    :return:
+    :rtype:
+    """
+    for word_list in [english_word_numeral_list, french_word_numeral_list, french_alt_word_numeral_list]:
+        try:
+            return word_list.index(value.lower())
+        except ValueError:
+            pass
+    raise ValueError  # pragma: no cover
+
+
+_clean_re = re.compile(r'[^\d]*(\d+)[^\d]*')
+
+
+def parse_numeral(value, int_enabled=True, roman_enabled=True, word_enabled=True, clean=True):
+    """
+    Parse a numeric value into integer.
+
+    :param value: Value to parse. Can be an integer, roman numeral or word.
+    :type value: string
+    :param int_enabled:
+    :type int_enabled:
+    :param roman_enabled:
+    :type roman_enabled:
+    :param word_enabled:
+    :type word_enabled:
+    :param clean:
+    :type clean:
+    :return: Numeric value, or None if value can't be parsed
+    :rtype: int
+    """
+    # pylint: disable=too-many-branches
+    if int_enabled:
+        try:
+            if clean:
+                match = _clean_re.match(value)
+                if match:
+                    clean_value = match.group(1)
+                    return int(clean_value)
+            return int(value)
+        except ValueError:
+            pass
+    if roman_enabled:
+        try:
+            if clean:
+                for word in value.split():
+                    try:
+                        return __parse_roman(word.upper())
+                    except ValueError:
+                        pass
+            return __parse_roman(value)
+        except ValueError:
+            pass
+    if word_enabled:
+        try:
+            if clean:
+                for word in value.split():
+                    try:
+                        return __parse_word(word)
+                    except ValueError:  # pragma: no cover
+                        pass
+            return __parse_word(value)  # pragma: no cover
+        except ValueError:  # pragma: no cover
+            pass
+    raise ValueError('Invalid numeral: ' + value)   # pragma: no cover
diff --git a/lib/guessit2/rules/common/validators.py b/lib/guessit2/rules/common/validators.py
new file mode 100644
index 000000000..f25dd0008
--- /dev/null
+++ b/lib/guessit2/rules/common/validators.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Validators
+"""
+from __future__ import unicode_literals
+
+from functools import partial
+
+from rebulk.validators import chars_before, chars_after, chars_surround
+from . import seps
+
+seps_before = partial(chars_before, seps)
+seps_after = partial(chars_after, seps)
+seps_surround = partial(chars_surround, seps)
+
+
+def int_coercable(string):
+    """
+    Check if string can be coerced to int
+    :param string:
+    :type string:
+    :return:
+    :rtype:
+    """
+    try:
+        int(string)
+        return True
+    except ValueError:
+        return False
diff --git a/lib/guessit2/rules/common/words.py b/lib/guessit2/rules/common/words.py
new file mode 100644
index 000000000..1a56117ee
--- /dev/null
+++ b/lib/guessit2/rules/common/words.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Words utils
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+_words_rexp = re.compile(r'\w+', re.UNICODE)
+
+
+def iter_words(string):
+    """
+    Iterate on all words in a string
+    :param string:
+    :type string:
+    :return:
+    :rtype: iterable[str]
+    """
+    return _words_rexp.finditer(string.replace('_', ' '))
+
+# list of common words which could be interpreted as properties, but which
+# are far too common to be able to say they represent a property in the
+# middle of a string (where they most likely carry their commmon meaning)
+COMMON_WORDS = frozenset([
+    # english words
+    'is', 'it', 'am', 'mad', 'men', 'man', 'run', 'sin', 'st', 'to',
+    'no', 'non', 'war', 'min', 'new', 'car', 'day', 'bad', 'bat', 'fan',
+    'fry', 'cop', 'zen', 'gay', 'fat', 'one', 'cherokee', 'got', 'an', 'as',
+    'cat', 'her', 'be', 'hat', 'sun', 'may', 'my', 'mr', 'rum', 'pi', 'bb',
+    'bt', 'tv', 'aw', 'by', 'md', 'mp', 'cd', 'lt', 'gt', 'in', 'ad', 'ice',
+    'ay', 'at', 'star', 'so', 'he',
+    # french words
+    'bas', 'de', 'le', 'son', 'ne', 'ca', 'ce', 'et', 'que',
+    'mal', 'est', 'vol', 'or', 'mon', 'se', 'je', 'tu', 'me',
+    'ne', 'ma', 'va', 'au',
+    # japanese words,
+    'wa', 'ga', 'ao',
+    # spanish words
+    'la', 'el', 'del', 'por', 'mar', 'al',
+    # other
+    'ind', 'arw', 'ts', 'ii', 'bin', 'chan', 'ss', 'san', 'oss', 'iii',
+    'vi', 'ben', 'da', 'lt', 'ch', 'sr', 'ps', 'cx', 'vo',
+    # new from babelfish
+    'mkv', 'avi', 'dmd', 'the', 'dis', 'cut', 'stv', 'des', 'dia', 'and',
+    'cab', 'sub', 'mia', 'rim', 'las', 'une', 'par', 'srt', 'ano', 'toy',
+    'job', 'gag', 'reel', 'www', 'for', 'ayu', 'csi', 'ren', 'moi', 'sur',
+    'fer', 'fun', 'two', 'big', 'psy', 'air',
+    # movie title
+    'brazil',
+    # release groups
+    'bs',  # Bosnian
+    'kz',
+    # countries
+    'gt', 'lt', 'im',
+    # part/pt
+    'pt',
+    # screener
+    'scr'
+])
diff --git a/lib/guessit2/rules/markers/__init__.py b/lib/guessit2/rules/markers/__init__.py
new file mode 100644
index 000000000..6a48a13b3
--- /dev/null
+++ b/lib/guessit2/rules/markers/__init__.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Markers
+"""
diff --git a/lib/guessit2/rules/markers/groups.py b/lib/guessit2/rules/markers/groups.py
new file mode 100644
index 000000000..15104b869
--- /dev/null
+++ b/lib/guessit2/rules/markers/groups.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Groups markers (...), [...] and {...}
+"""
+from __future__ import unicode_literals
+
+from rebulk import Rebulk
+
+
+def groups():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk()
+    rebulk.defaults(name="group", marker=True)
+
+    starting = '([{'
+    ending = ')]}'
+
+    def mark_groups(input_string):
+        """
+        Functional pattern to mark groups (...), [...] and {...}.
+
+        :param input_string:
+        :return:
+        """
+        openings = ([], [], [])
+        i = 0
+
+        ret = []
+        for char in input_string:
+            start_type = starting.find(char)
+            if start_type > -1:
+                openings[start_type].append(i)
+
+            i += 1
+
+            end_type = ending.find(char)
+            if end_type > -1:
+                try:
+                    start_index = openings[end_type].pop()
+                    ret.append((start_index, i))
+                except IndexError:
+                    pass
+        return ret
+
+    rebulk.functional(mark_groups)
+    return rebulk
diff --git a/lib/guessit2/rules/markers/path.py b/lib/guessit2/rules/markers/path.py
new file mode 100644
index 000000000..841419634
--- /dev/null
+++ b/lib/guessit2/rules/markers/path.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Path markers
+"""
+from __future__ import unicode_literals
+
+from rebulk import Rebulk
+
+from rebulk.utils import find_all
+
+
+def path():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk()
+    rebulk.defaults(name="path", marker=True)
+
+    def mark_path(input_string, context):
+        """
+        Functional pattern to mark path elements.
+
+        :param input_string:
+        :return:
+        """
+        ret = []
+        if context.get('name_only', False):
+            ret.append((0, len(input_string)))
+        else:
+            indices = list(find_all(input_string, '/'))
+            indices += list(find_all(input_string, r'\\'))
+            indices += [-1, len(input_string)]
+
+            indices.sort()
+
+            for i in range(0, len(indices) - 1):
+                ret.append((indices[i] + 1, indices[i + 1]))
+
+        return ret
+
+    rebulk.functional(mark_path)
+    return rebulk
diff --git a/lib/guessit2/rules/processors.py b/lib/guessit2/rules/processors.py
new file mode 100644
index 000000000..cce451ba1
--- /dev/null
+++ b/lib/guessit2/rules/processors.py
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Processors
+"""
+from __future__ import unicode_literals
+
+from collections import defaultdict
+import copy
+
+import six
+
+from rebulk import Rebulk, Rule, CustomRule, POST_PROCESS, PRE_PROCESS, AppendMatch, RemoveMatch
+from guessit2.rules.common.words import iter_words
+from .common.formatters import cleanup
+from .common.comparators import marker_sorted
+from .common.date import valid_year
+
+
+class EnlargeGroupMatches(CustomRule):
+    """
+    Enlarge matches that are starting and/or ending group to include brackets in their span.
+    :param matches:
+    :type matches:
+    :return:
+    :rtype:
+    """
+    priority = PRE_PROCESS
+
+    def when(self, matches, context):
+        starting = []
+        ending = []
+
+        for group in matches.markers.named('group'):
+            for match in matches.starting(group.start + 1):
+                starting.append(match)
+
+            for match in matches.ending(group.end - 1):
+                ending.append(match)
+
+        if starting or ending:
+            return starting, ending
+
+    def then(self, matches, when_response, context):
+        starting, ending = when_response
+        for match in starting:
+            matches.remove(match)
+            match.start -= 1
+            match.raw_start += 1
+            matches.append(match)
+
+        for match in ending:
+            matches.remove(match)
+            match.end += 1
+            match.raw_end -= 1
+            matches.append(match)
+
+
+class EquivalentHoles(Rule):
+    """
+    Creates equivalent matches for holes that have same values than existing (case insensitive)
+    """
+    priority = POST_PROCESS
+    consequence = AppendMatch
+
+    def when(self, matches, context):
+        new_matches = []
+
+        for filepath in marker_sorted(matches.markers.named('path'), matches):
+            holes = matches.holes(start=filepath.start, end=filepath.end, formatter=cleanup)
+            for name in matches.names:
+                for hole in list(holes):
+                    for current_match in matches.named(name):
+                        if isinstance(current_match.value, six.string_types) and \
+                                        hole.value.lower() == current_match.value.lower():
+                            if 'equivalent-ignore' in current_match.tags:
+                                continue
+                            new_value = _preferred_string(hole.value, current_match.value)
+                            if hole.value != new_value:
+                                hole.value = new_value
+                            if current_match.value != new_value:
+                                current_match.value = new_value
+                            hole.name = name
+                            hole.tags = ['equivalent']
+                            new_matches.append(hole)
+                            if hole in holes:
+                                holes.remove(hole)
+
+        return new_matches
+
+
+class RemoveAmbiguous(Rule):
+    """
+    If multiple match are found with same name and different values, keep the one in the most valuable filepart.
+    Also keep others match with same name and values than those kept ones.
+    """
+    priority = POST_PROCESS
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        fileparts = marker_sorted(matches.markers.named('path'), matches)
+
+        previous_fileparts_names = set()
+        values = defaultdict(list)
+
+        to_remove = []
+        for filepart in fileparts:
+            filepart_matches = matches.range(filepart.start, filepart.end)
+
+            filepart_names = set()
+            for match in filepart_matches:
+                filepart_names.add(match.name)
+                if match.name in previous_fileparts_names:
+                    if match.value not in values[match.name]:
+                        to_remove.append(match)
+                else:
+                    if match.value not in values[match.name]:
+                        values[match.name].append(match.value)
+
+            previous_fileparts_names.update(filepart_names)
+
+        return to_remove
+
+
+def _preferred_string(value1, value2):  # pylint:disable=too-many-return-statements
+    """
+    Retrieves preferred title from both values.
+    :param value1:
+    :type value1: str
+    :param value2:
+    :type value2: str
+    :return: The preferred title
+    :rtype: str
+    """
+    if value1 == value2:
+        return value1
+    if value1.istitle() and not value2.istitle():
+        return value1
+    if not value1.isupper() and value2.isupper():
+        return value1
+    if not value1.isupper() and value1[0].isupper() and not value2[0].isupper():
+        return value1
+    if _count_title_words(value1) > _count_title_words(value2):
+        return value1
+    return value2
+
+
+def _count_title_words(value):
+    """
+    Count only many words are titles in value.
+    :param value:
+    :type value:
+    :return:
+    :rtype:
+    """
+    ret = 0
+    for word in iter_words(value):
+        if word.group(0).istitle():
+            ret += 1
+    return ret
+
+class SeasonYear(Rule):
+    """
+    If a season is a valid year and no year was found, create an match with year.
+    """
+    priority = POST_PROCESS
+    consequence = AppendMatch
+
+    def when(self, matches, context):
+        ret = []
+        if not matches.named('year'):
+            for season in matches.named('season'):
+                if valid_year(season.value):
+                    year = copy.copy(season)
+                    year.name = 'year'
+                    ret.append(year)
+        return ret
+
+
+class Processors(CustomRule):
+    """
+    Empty rule for ordering post_processing properly.
+    """
+    priority = POST_PROCESS
+
+    def when(self, matches, context):
+        pass
+
+    def then(self, matches, when_response, context):  # pragma: no cover
+        pass
+
+
+def processors():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    return Rebulk().rules(EnlargeGroupMatches, EquivalentHoles, RemoveAmbiguous, SeasonYear, Processors)
diff --git a/lib/guessit2/rules/properties/__init__.py b/lib/guessit2/rules/properties/__init__.py
new file mode 100644
index 000000000..e0a24eaf0
--- /dev/null
+++ b/lib/guessit2/rules/properties/__init__.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Properties
+"""
diff --git a/lib/guessit2/rules/properties/audio_codec.py b/lib/guessit2/rules/properties/audio_codec.py
new file mode 100644
index 000000000..85ebff3e8
--- /dev/null
+++ b/lib/guessit2/rules/properties/audio_codec.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+audio_codec, audio_profile and audio_channels property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk, Rule, RemoveMatch
+from ..common import dash
+from ..common.validators import seps_before, seps_after
+
+audio_properties = ['audio_codec', 'audio_profile', 'audio_channels']
+
+
+def audio_codec():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE, abbreviations=[dash]).string_defaults(ignore_case=True)
+    rebulk.defaults(name="audio_codec")
+
+    rebulk.regex("MP3", "LAME", r"LAME(?:\d)+-?(?:\d)+", value="MP3")
+    rebulk.regex("DolbyDigital", "DD", value="DolbyDigital")
+    rebulk.regex("AAC", value="AAC")
+    rebulk.regex("AC3", value="AC3")
+    rebulk.regex("Flac", value="FLAC")
+    rebulk.regex("DTS", value="DTS")
+    rebulk.regex("True-?HD", value="TrueHD")
+
+    rebulk.defaults(name="audio_profile")
+    rebulk.string("HD", value="HD", tags="DTS")
+    rebulk.regex("HD-?MA", value="HDMA", tags="DTS")
+    rebulk.string("HE", value="HE", tags="AAC")
+    rebulk.string("LC", value="LC", tags="AAC")
+    rebulk.string("HQ", value="HQ", tags="AC3")
+
+    rebulk.defaults(name="audio_channels")
+    rebulk.regex(r'(7[\W_]1)(?:[^\d]|$)', value='7.1', children=True)
+    rebulk.regex(r'(5[\W_]1)(?:[^\d]|$)', value='5.1', children=True)
+    rebulk.regex(r'(2[\W_]0)(?:[^\d]|$)', value='2.0', children=True)
+    rebulk.string('7ch', '8ch', value='7.1')
+    rebulk.string('5ch', '6ch', value='5.1')
+    rebulk.string('2ch', 'stereo', value='2.0')
+    rebulk.string('1ch', 'mono', value='1.0')
+
+    rebulk.rules(DtsRule, AacRule, Ac3Rule, AudioValidatorRule, HqConflictRule)
+
+    return rebulk
+
+
+class AudioValidatorRule(Rule):
+    """
+    Remove audio properties if not surrounded by separators and not next each others
+    """
+    priority = 64
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+
+        audio_list = matches.range(predicate=lambda match: match.name in audio_properties)
+        for audio in audio_list:
+            if not seps_before(audio):
+                valid_before = matches.range(audio.start - 1, audio.start,
+                                             lambda match: match.name in audio_properties)
+                if not valid_before:
+                    ret.append(audio)
+                    continue
+            if not seps_after(audio):
+                valid_after = matches.range(audio.end, audio.end + 1,
+                                            lambda match: match.name in audio_properties)
+                if not valid_after:
+                    ret.append(audio)
+                    continue
+
+        return ret
+
+
+class AudioProfileRule(Rule):
+    """
+    Abstract rule to validate audio profiles
+    """
+    priority = 64
+    dependency = AudioValidatorRule
+    consequence = RemoveMatch
+
+    def __init__(self, codec):
+        super(AudioProfileRule, self).__init__()
+        self.codec = codec
+
+    def when(self, matches, context):
+        profile_list = matches.named('audio_profile', lambda match: self.codec in match.tags)
+        ret = []
+        for profile in profile_list:
+            codec = matches.previous(profile, lambda match: match.name == 'audio_codec' and match.value == self.codec)
+            if not codec:
+                codec = matches.next(profile, lambda match: match.name == 'audio_codec' and match.value == self.codec)
+            if not codec:
+                ret.append(profile)
+        return ret
+
+
+class DtsRule(AudioProfileRule):
+    """
+    Rule to validate DTS profile
+    """
+
+    def __init__(self):
+        super(DtsRule, self).__init__("DTS")
+
+
+class AacRule(AudioProfileRule):
+    """
+    Rule to validate AAC profile
+    """
+
+    def __init__(self):
+        super(AacRule, self).__init__("AAC")
+
+
+class Ac3Rule(AudioProfileRule):
+    """
+    Rule to validate AC3 profile
+    """
+
+    def __init__(self):
+        super(Ac3Rule, self).__init__("AC3")
+
+
+class HqConflictRule(Rule):
+    """
+    Solve conflict between HQ from other property and from audio_profile.
+    """
+
+    dependency = [DtsRule, AacRule, Ac3Rule]
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        hq_audio = matches.named('audio_profile', lambda match: match.value == 'HQ')
+        hq_audio_spans = [match.span for match in hq_audio]
+        hq_other = matches.named('other', lambda match: match.span in hq_audio_spans)
+
+        if hq_other:
+            return hq_other
diff --git a/lib/guessit2/rules/properties/bonus.py b/lib/guessit2/rules/properties/bonus.py
new file mode 100644
index 000000000..416de2b2c
--- /dev/null
+++ b/lib/guessit2/rules/properties/bonus.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+bonus property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk, AppendMatch, Rule
+
+from .title import TitleFromPosition
+from ..common.formatters import cleanup
+from ..common.validators import seps_surround
+
+
+def bonus():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE)
+
+    rebulk.regex(r'x(\d+)', name='bonus', private_parent=True, children=True, formatter=int,
+                 validator={'__parent__': lambda match: seps_surround},
+                 conflict_solver=lambda match, conflicting: match
+                 if conflicting.name in ['video_codec', 'episode'] and 'bonus-conflict' not in conflicting.tags
+                 else '__default__')
+
+    rebulk.rules(BonusTitleRule)
+
+    return rebulk
+
+
+class BonusTitleRule(Rule):
+    """
+    Find bonus title after bonus.
+    """
+    dependency = TitleFromPosition
+    consequence = AppendMatch
+
+    properties = {'bonus_title': [None]}
+
+    def when(self, matches, context):
+        bonus_number = matches.named('bonus', lambda match: not match.private, index=0)
+        if bonus_number:
+            filepath = matches.markers.at_match(bonus_number, lambda marker: marker.name == 'path', 0)
+            hole = matches.holes(bonus_number.end, filepath.end + 1, formatter=cleanup, index=0)
+            if hole and hole.value:
+                hole.name = 'bonus_title'
+                return hole
diff --git a/lib/guessit2/rules/properties/cds.py b/lib/guessit2/rules/properties/cds.py
new file mode 100644
index 000000000..e2d39b3ff
--- /dev/null
+++ b/lib/guessit2/rules/properties/cds.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+cd and cd_count properties
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk
+from ..common import dash
+
+
+def cds():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE, abbreviations=[dash])
+
+    rebulk.regex(r'cd-?(?P<cd>\d+)(?:-?of-?(?P<cd_count>\d+))?',
+                 validator={'cd': lambda match: match.value > 0, 'cd_count': lambda match: match.value > 0},
+                 formatter={'cd': int, 'cd_count': int},
+                 children=True,
+                 private_parent=True,
+                 properties={'cd': [None], 'cd_count': [None]})
+    rebulk.regex(r'(?P<cd_count>\d+)-?cds?',
+                 validator={'cd': lambda match: match.value > 0, 'cd_count': lambda match: match.value > 0},
+                 formatter={'cd_count': int},
+                 children=True,
+                 private_parent=True,
+                 properties={'cd': [None], 'cd_count': [None]})
+
+    return rebulk
diff --git a/lib/guessit2/rules/properties/container.py b/lib/guessit2/rules/properties/container.py
new file mode 100644
index 000000000..564b32f99
--- /dev/null
+++ b/lib/guessit2/rules/properties/container.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+container property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk
+from ..common.validators import seps_surround
+
+
+def container():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE).string_defaults(ignore_case=True)
+    rebulk.defaults(name='container',
+                    formatter=lambda value: value[1:],
+                    tags=['extension'],
+                    conflict_solver=lambda match, other: other
+                    if other.name in ['format', 'video_codec'] or
+                    other.name == 'container' and 'extension' not in other.tags
+                    else '__default__')
+
+    subtitles = ['srt', 'idx', 'sub', 'ssa', 'ass']
+    info = ['nfo']
+    videos = ['3g2', '3gp', '3gp2', 'asf', 'avi', 'divx', 'flv', 'm4v', 'mk2',
+              'mka', 'mkv', 'mov', 'mp4', 'mp4a', 'mpeg', 'mpg', 'ogg', 'ogm',
+              'ogv', 'qt', 'ra', 'ram', 'rm', 'ts', 'wav', 'webm', 'wma', 'wmv',
+              'iso', 'vob']
+    torrent = ['torrent']
+
+    rebulk.regex(r'\.\L<exts>$', exts=subtitles, tags=['extension', 'subtitle'])
+    rebulk.regex(r'\.\L<exts>$', exts=info, tags=['extension', 'info'])
+    rebulk.regex(r'\.\L<exts>$', exts=videos, tags=['extension', 'video'])
+    rebulk.regex(r'\.\L<exts>$', exts=torrent, tags=['extension', 'torrent'])
+
+    rebulk.defaults(name='container',
+                    validator=seps_surround,
+                    conflict_solver=lambda match, other: match
+                    if other.name in ['format',
+                                      'video_codec'] or other.name == 'container' and 'extension' in other.tags
+                    else '__default__')
+
+    rebulk.string(*[sub for sub in subtitles if sub not in ['sub']], tags=['subtitle'])
+    rebulk.string(*videos, tags=['video'])
+    rebulk.string(*torrent, tags=['torrent'])
+
+    return rebulk
diff --git a/lib/guessit2/rules/properties/country.py b/lib/guessit2/rules/properties/country.py
new file mode 100644
index 000000000..4cda291ea
--- /dev/null
+++ b/lib/guessit2/rules/properties/country.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+country property
+"""
+# pylint: disable=no-member
+from __future__ import unicode_literals
+
+import babelfish
+
+from rebulk import Rebulk
+from ..common.words import COMMON_WORDS, iter_words
+
+
+def country():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().defaults(name='country')
+
+    rebulk.functional(find_countries,
+                      #  Prefer language and any other property over country if not US or GB.
+                      conflict_solver=lambda match, other: match
+                      if other.name != 'language' or match.value not in [babelfish.Country('US'),
+                                                                         babelfish.Country('GB')]
+                      else other,
+                      properties={'country': [None]})
+
+    return rebulk
+
+
+COUNTRIES_SYN = {'ES': ['españa'],
+                 'GB': ['UK'],
+                 'BR': ['brazilian', 'bra'],
+                 # FIXME: this one is a bit of a stretch, not sure how to do it properly, though...
+                 'MX': ['Latinoamérica', 'latin america']}
+
+
+class GuessitCountryConverter(babelfish.CountryReverseConverter):  # pylint: disable=missing-docstring
+    def __init__(self):
+        self.guessit_exceptions = {}
+
+        for alpha2, synlist in COUNTRIES_SYN.items():
+            for syn in synlist:
+                self.guessit_exceptions[syn.lower()] = alpha2
+
+    @property
+    def codes(self):  # pylint: disable=missing-docstring
+        return (babelfish.country_converters['name'].codes |
+                frozenset(babelfish.COUNTRIES.values()) |
+                frozenset(self.guessit_exceptions.keys()))
+
+    def convert(self, alpha2):
+        if alpha2 == 'GB':
+            return 'UK'
+        return str(babelfish.Country(alpha2))
+
+    def reverse(self, name):
+        # exceptions come first, as they need to override a potential match
+        # with any of the other guessers
+        try:
+            return self.guessit_exceptions[name.lower()]
+        except KeyError:
+            pass
+
+        try:
+            return babelfish.Country(name.upper()).alpha2
+        except ValueError:
+            pass
+
+        for conv in [babelfish.Country.fromname]:
+            try:
+                return conv(name).alpha2
+            except babelfish.CountryReverseError:
+                pass
+
+        raise babelfish.CountryReverseError(name)
+
+
+babelfish.country_converters['guessit'] = GuessitCountryConverter()
+
+
+def is_valid_country(country_object, context=None):
+    """
+    Check if country is valid.
+    """
+    if context and context.get('allowed_countries'):
+        allowed_countries = context.get('allowed_countries')
+        return country_object.name.lower() in allowed_countries or country_object.alpha2.lower() in allowed_countries
+    else:
+        return country_object.name.lower() not in COMMON_WORDS and country_object.alpha2.lower() not in COMMON_WORDS
+
+
+def find_countries(string, context=None):
+    """
+    Find countries in given string.
+    """
+    ret = []
+    for word_match in iter_words(string.strip().lower()):
+        try:
+            country_object = babelfish.Country.fromguessit(word_match.group())
+            if is_valid_country(country_object, context):
+                ret.append((word_match.start(), word_match.end(), {'value': country_object}))
+        except babelfish.Error:
+            continue
+    return ret
diff --git a/lib/guessit2/rules/properties/crc.py b/lib/guessit2/rules/properties/crc.py
new file mode 100644
index 000000000..62275ca32
--- /dev/null
+++ b/lib/guessit2/rules/properties/crc.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+crc and uuid properties
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk
+from ..common.validators import seps_surround
+
+
+def crc():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE)
+    rebulk.defaults(validator=seps_surround)
+
+    rebulk.regex('(?:[a-fA-F]|[0-9]){8}', name='crc32',
+                 conflict_solver=lambda match, other: match
+                 if other.name in ['episode', 'season']
+                 else '__default__')
+
+    rebulk.functional(guess_idnumber, name='uuid',
+                      conflict_solver=lambda match, other: match
+                      if other.name in ['episode', 'season']
+                      else '__default__')
+    return rebulk
+
+
+_DIGIT = 0
+_LETTER = 1
+_OTHER = 2
+
+_idnum = re.compile(r'(?P<uuid>[a-zA-Z0-9-]{20,})')  # 1.0, (0, 0))
+
+
+def guess_idnumber(string):
+    """
+    Guess id number function
+    :param string:
+    :type string:
+    :return:
+    :rtype:
+    """
+    # pylint:disable=invalid-name
+    ret = []
+
+    matches = list(_idnum.finditer(string))
+    for match in matches:
+        result = match.groupdict()
+        switch_count = 0
+        switch_letter_count = 0
+        letter_count = 0
+        last_letter = None
+
+        last = _LETTER
+        for c in result['uuid']:
+            if c in '0123456789':
+                ci = _DIGIT
+            elif c in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
+                ci = _LETTER
+                if c != last_letter:
+                    switch_letter_count += 1
+                last_letter = c
+                letter_count += 1
+            else:
+                ci = _OTHER
+
+            if ci != last:
+                switch_count += 1
+
+            last = ci
+
+        # only return the result as probable if we alternate often between
+        # char type (more likely for hash values than for common words)
+        switch_ratio = float(switch_count) / len(result['uuid'])
+        letters_ratio = (float(switch_letter_count) / letter_count) if letter_count > 0 else 1
+
+        if switch_ratio > 0.4 and letters_ratio > 0.4:
+            ret.append(match.span())
+
+    return ret
diff --git a/lib/guessit2/rules/properties/date.py b/lib/guessit2/rules/properties/date.py
new file mode 100644
index 000000000..ff9c24851
--- /dev/null
+++ b/lib/guessit2/rules/properties/date.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+date and year properties
+"""
+from __future__ import unicode_literals
+
+from rebulk import Rebulk, RemoveMatch, Rule
+
+from ..common.date import search_date, valid_year
+from ..common.validators import seps_surround
+
+
+def date():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().defaults(validator=seps_surround)
+
+    rebulk.regex(r"\d{4}", name="year", formatter=int,
+                 validator=lambda match: seps_surround(match) and valid_year(match.value))
+
+    def date_functional(string, context):
+        """
+        Search for date in the string and retrieves match
+
+        :param string:
+        :return:
+        """
+
+        ret = search_date(string, context.get('date_year_first'), context.get('date_day_first'))
+        if ret:
+            return ret[0], ret[1], {'value': ret[2]}
+
+    rebulk.functional(date_functional, name="date", properties={'date': [None]},
+                      conflict_solver=lambda match, other: other
+                      if other.name in ['episode', 'season']
+                      else '__default__')
+
+    rebulk.rules(KeepMarkedYearInFilepart)
+
+    return rebulk
+
+
+class KeepMarkedYearInFilepart(Rule):
+    """
+    Keep first years marked with [](){} in filepart, or if no year is marked, ensure it won't override titles.
+    """
+    priority = 64
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        if len(matches.named('year')) > 1:
+            for filepart in matches.markers.named('path'):
+                years = matches.range(filepart.start, filepart.end, lambda match: match.name == 'year')
+                if len(years) > 1:
+                    group_years = []
+                    ungroup_years = []
+                    for year in years:
+                        if matches.markers.at_match(year, lambda marker: marker.name == 'group'):
+                            group_years.append(year)
+                        else:
+                            ungroup_years.append(year)
+                    if group_years and ungroup_years:
+                        ret.extend(ungroup_years)
+                        ret.extend(group_years[1:])  # Keep the first year in marker.
+                    elif not group_years:
+                        ret.append(ungroup_years[0])  # Keep first year for title.
+                        if len(ungroup_years) > 2:
+                            ret.extend(ungroup_years[2:])
+        return ret
diff --git a/lib/guessit2/rules/properties/edition.py b/lib/guessit2/rules/properties/edition.py
new file mode 100644
index 000000000..93021a5f8
--- /dev/null
+++ b/lib/guessit2/rules/properties/edition.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+edition property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk
+from ..common import dash
+from ..common.validators import seps_surround
+
+
+def edition():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE, abbreviations=[dash]).string_defaults(ignore_case=True)
+    rebulk.defaults(name='edition', validator=seps_surround)
+
+    rebulk.regex('collector', 'collector-edition', 'edition-collector', value='Collector Edition')
+    rebulk.regex('special-edition', 'edition-special', value='Special Edition',
+                 conflict_solver=lambda match, other: other
+                 if other.name == 'episode_details' and other.value == 'Special'
+                 else '__default__')
+    rebulk.regex('criterion-edition', 'edition-criterion', value='Criterion Edition')
+    rebulk.regex('deluxe', 'deluxe-edition', 'edition-deluxe', value='Deluxe Edition')
+    rebulk.regex('director\'?s?-cut', 'director\'?s?-cut-edition', 'edition-director\'?s?-cut', value='Director\'s cut')
+
+    return rebulk
diff --git a/lib/guessit2/rules/properties/episode_title.py b/lib/guessit2/rules/properties/episode_title.py
new file mode 100644
index 000000000..fc92d7b97
--- /dev/null
+++ b/lib/guessit2/rules/properties/episode_title.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Episode title
+"""
+from __future__ import unicode_literals
+
+from collections import defaultdict
+
+from rebulk import Rebulk, Rule, AppendMatch, RenameMatch
+from ..common import seps, title_seps
+from ..properties.title import TitleFromPosition, TitleBaseRule
+from ..common.formatters import cleanup
+
+
+def episode_title():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().rules(EpisodeTitleFromPosition,
+                            AlternativeTitleReplace,
+                            TitleToEpisodeTitle,
+                            Filepart3EpisodeTitle,
+                            Filepart2EpisodeTitle)
+    return rebulk
+
+
+class TitleToEpisodeTitle(Rule):
+    """
+    If multiple different title are found, convert the one following episode number to episode_title.
+    """
+    dependency = TitleFromPosition
+
+    def when(self, matches, context):
+        titles = matches.named('title')
+
+        if len(titles) < 2:
+            return
+
+        title_groups = defaultdict(list)
+        for title in titles:
+            title_groups[title.value].append(title)
+
+        episode_titles = []
+        main_titles = []
+        for title in titles:
+            if matches.previous(title, lambda match: match.name == 'episode'):
+                episode_titles.append(title)
+            else:
+                main_titles.append(title)
+
+        if episode_titles:
+            return episode_titles
+
+    def then(self, matches, when_response, context):
+        for title in when_response:
+            matches.remove(title)
+            title.name = 'episode_title'
+            matches.append(title)
+
+
+class EpisodeTitleFromPosition(TitleBaseRule):
+    """
+    Add episode title match in existing matches
+    Must run after TitleFromPosition rule.
+    """
+    dependency = TitleToEpisodeTitle
+
+    def hole_filter(self, hole, matches):
+        episode = matches.previous(hole,
+                                   lambda previous: any(name in previous.names
+                                                        for name in ['episode', 'episode_details',
+                                                                     'episode_count', 'season', 'season_count',
+                                                                     'date', 'title', 'year']),
+                                   0)
+
+        crc32 = matches.named('crc32')
+
+        return episode or crc32
+
+    def filepart_filter(self, filepart, matches):
+        # Filepart where title was found.
+        if matches.range(filepart.start, filepart.end, lambda match: match.name == 'title'):
+            return True
+        return False
+
+    def should_remove(self, match, matches, filepart, hole, context):
+        if match.name == 'episode_details':
+            return False
+        return super(EpisodeTitleFromPosition, self).should_remove(match, matches, filepart, hole, context)
+
+    def __init__(self):
+        super(EpisodeTitleFromPosition, self).__init__('episode_title', ['title'])
+
+    def when(self, matches, context):
+        if matches.named('episode_title'):
+            return
+        return super(EpisodeTitleFromPosition, self).when(matches, context)
+
+
+class AlternativeTitleReplace(Rule):
+    """
+    If alternateTitle was found and title is next to episode, season or date, replace it with episode_title.
+    """
+    dependency = EpisodeTitleFromPosition
+    consequence = RenameMatch
+
+    def when(self, matches, context):
+        if matches.named('episode_title'):
+            return
+
+        alternative_title = matches.range(predicate=lambda match: match.name == 'alternativeTitle', index=0)
+        if alternative_title:
+            main_title = matches.chain_before(alternative_title.start, seps=seps,
+                                              predicate=lambda match: 'title' in match.tags, index=0)
+            if main_title:
+                episode = matches.previous(main_title,
+                                           lambda previous: any(name in previous.names
+                                                                for name in ['episode', 'episode_details',
+                                                                             'episode_count', 'season',
+                                                                             'season_count',
+                                                                             'date', 'title', 'year']),
+                                           0)
+
+                crc32 = matches.named('crc32')
+
+                if episode or crc32:
+                    return alternative_title
+
+    def then(self, matches, when_response, context):
+        matches.remove(when_response)
+        when_response.name = 'episode_title'
+        matches.append(when_response)
+
+
+class Filepart3EpisodeTitle(Rule):
+    """
+    If we have at least 3 filepart structured like this:
+
+    Serie name/SO1/E01-episode_title.mkv
+    AAAAAAAAAA/BBB/CCCCCCCCCCCCCCCCCCCC
+
+    If CCCC contains episode and BBB contains seasonNumber
+    Then title is to be found in AAAA.
+    """
+    consequence = AppendMatch('title')
+
+    def when(self, matches, context):
+        fileparts = matches.markers.named('path')
+        if len(fileparts) < 3:
+            return
+
+        filename = fileparts[-1]
+        directory = fileparts[-2]
+        subdirectory = fileparts[-3]
+
+        episode_number = matches.range(filename.start, filename.end, lambda match: match.name == 'episode', 0)
+        if episode_number:
+            season = matches.range(directory.start, directory.end, lambda match: match.name == 'season', 0)
+
+            if season:
+                hole = matches.holes(subdirectory.start, subdirectory.end,
+                                     formatter=cleanup, seps=title_seps, predicate=lambda match: match.value,
+                                     index=0)
+                if hole:
+                    return hole
+
+
+class Filepart2EpisodeTitle(Rule):
+    """
+    If we have at least 2 filepart structured like this:
+
+    Serie name SO1/E01-episode_title.mkv
+    AAAAAAAAAAAAA/BBBBBBBBBBBBBBBBBBBBB
+
+    If BBBB contains episode and AAA contains a hole followed by seasonNumber
+    Then title is to be found in AAAA.
+    """
+    consequence = AppendMatch('title')
+
+    def when(self, matches, context):
+        fileparts = matches.markers.named('path')
+        if len(fileparts) < 2:
+            return
+
+        filename = fileparts[-1]
+        directory = fileparts[-2]
+
+        episode_number = matches.range(filename.start, filename.end, lambda match: match.name == 'episode', 0)
+        if episode_number:
+            season = matches.range(directory.start, directory.end, lambda match: match.name == 'season', 0)
+            if season:
+                hole = matches.holes(directory.start, directory.end, formatter=cleanup, seps=title_seps,
+                                     predicate=lambda match: match.value, index=0)
+                if hole:
+                    return hole
diff --git a/lib/guessit2/rules/properties/episodes.py b/lib/guessit2/rules/properties/episodes.py
new file mode 100644
index 000000000..87995f0de
--- /dev/null
+++ b/lib/guessit2/rules/properties/episodes.py
@@ -0,0 +1,366 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+episode, season, episode_count, season_count and episode_details properties
+"""
+from __future__ import unicode_literals
+
+from collections import defaultdict
+import copy
+
+import regex as re
+
+from rebulk import Rebulk, RemoveMatch, Rule, AppendMatch, RenameMatch
+from .title import TitleFromPosition
+from ..common.validators import seps_surround
+from ..common import dash, alt_dash
+from ..common.numeral import numeral, parse_numeral
+
+
+def episodes():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk()
+    rebulk.regex_defaults(flags=re.IGNORECASE).string_defaults(ignore_case=True)
+    rebulk.defaults(private_names=['episodeSeparator', 'seasonSeparator'])
+
+    # 01x02, 01x02x03x04
+    rebulk.regex(r'(?P<season>\d+)@?x@?(?P<episode>\d+)' +
+                 r'(?:(?P<episodeSeparator>x|-|\+|&)(?P<episode>\d+))*',
+                 # S01E02, S01x02, S01E02E03, S01Ex02, S01xE02, SO1Ex02Ex03
+                 r'S(?P<season>\d+)@?(?:xE|Ex|E|x)@?(?P<episode>\d+)' +
+                 r'(?:(?P<episodeSeparator>xE|Ex|E|x|-|\+|&)(?P<episode>\d+))*',
+                 # S01
+                 r'S(?P<season>\d+)' +
+                 r'(?:(?P<seasonSeparator>S|-|\+|&)(?P<season>\d+))*',
+                 formatter={'season': int, 'episode': int},
+                 tags=['SxxExx'],
+                 abbreviations=[alt_dash],
+                 children=True,
+                 private_parent=True,
+                 conflict_solver=lambda match, other: match
+                 if match.name in ['season', 'episode'] and other.name in
+                 ['screen_size', 'video_codec', 'audio_codec', 'audio_channels', 'container', 'date']
+                 else '__default__')
+
+    # episode_details property
+    for episode_detail in ('Special', 'Bonus', 'Omake', 'Ova', 'Oav', 'Pilot', 'Unaired'):
+        rebulk.string(episode_detail, value=episode_detail, name='episode_details')
+    rebulk.regex(r'Extras?', name='episode_details', value='Extras')
+
+    rebulk.defaults(private_names=['episodeSeparator', 'seasonSeparator'],
+                    validate_all=True, validator={'__parent__': seps_surround}, children=True, private_parent=True)
+
+    season_words = ['season', 'saison', 'serie', 'seasons', 'saisons', 'series']
+    episode_words = ['episode', 'episodes', 'ep']
+    of_words = ['of', 'sur']
+    all_words = ['All']
+
+    rebulk.regex(r'\L<season_words>@?(?P<season>' + numeral + ')' +
+                 r'(?:@?\L<of_words>@?(?P<count>' + numeral + '))?' +
+                 r'(?:@?(?P<seasonSeparator>-)@?(?P<season>\d+))*' +
+                 r'(?:@?(?P<seasonSeparator>\+|&)@?(?P<season>\d+))*',
+                 of_words=of_words,
+                 season_words=season_words,  # Season 1, # Season one
+                 abbreviations=[alt_dash], formatter={'season': parse_numeral, 'count': parse_numeral})
+
+    rebulk.regex(r'\L<episode_words>-?(?P<episode>\d+)' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:-?\L<of_words>?-?(?P<count>\d+))?',
+                 of_words=of_words,
+                 episode_words=episode_words,  # Episode 4
+                 abbreviations=[dash], formatter=int,
+                 disabled=lambda context: context.get('type') == 'episode')
+
+    rebulk.regex(r'\L<episode_words>-?(?P<episode>' + numeral + ')' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:-?\L<of_words>?-?(?P<count>\d+))?',
+                 of_words=of_words,
+                 episode_words=episode_words,  # Episode 4
+                 abbreviations=[dash], formatter={'episode': parse_numeral, 'version': int, 'count': int},
+                 disabled=lambda context: context.get('type') != 'episode')
+
+    rebulk.regex(r'S?(?P<season>\d+)-?(?:xE|Ex|E|x)-?(?P<other>\L<all_words>)',
+                 tags=['SxxExx'],
+                 all_words=all_words,
+                 abbreviations=[dash],
+                 validator=None,
+                 formatter={'season': int, 'other': lambda match: 'Complete'})
+
+    rebulk.defaults(private_names=['episodeSeparator', 'seasonSeparator'], validate_all=True,
+                    validator={'__parent__': seps_surround}, children=True, private_parent=True)
+
+    # 12, 13
+    rebulk.regex(r'(?P<episode>\d{2})' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:(?P<episodeSeparator>[x-])(?P<episode>\d{2}))*',
+                 tags=['bonus-conflict', 'weak-movie'], formatter={'episode': int, 'version': int})
+
+    # 012, 013
+    rebulk.regex(r'0(?P<episode>\d{1,2})' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:(?P<episodeSeparator>[x-])0(?P<episode>\d{1,2}))*',
+                 tags=['bonus-conflict', 'weak-movie'], formatter={'episode': int, 'version': int})
+
+    # 112, 113
+    rebulk.regex(r'(?P<episode>\d{3,4})' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:(?P<episodeSeparator>[x-])(?P<episode>\d{3,4}))*',
+                 tags=['bonus-conflict', 'weak-movie'], formatter={'episode': int, 'version': int},
+                 disabled=lambda context: not context.get('episode_prefer_number', False))
+
+    # 1, 2, 3
+    rebulk.regex(r'(?P<episode>\d)' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:(?P<episodeSeparator>[x-])(?P<episode>\d{1,2}))*',
+                 tags=['bonus-conflict', 'weak-movie'], formatter={'episode': int, 'version': int},
+                 disabled=lambda context: context.get('type') != 'episode')
+
+    # e112, e113
+    rebulk.regex(r'e(?P<episode>\d{1,4})' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:(?P<episodeSeparator>e|x|-)(?P<episode>\d{1,4}))*',
+                 formatter={'episode': int, 'version': int})
+
+    # ep 112, ep113, ep112, ep113
+    rebulk.regex(r'ep-?(?P<episode>\d{1,4})' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:(?P<episodeSeparator>ep|e|x|-)(?P<episode>\d{1,4}))*',
+                 abbreviations=[dash],
+                 formatter={'episode': int, 'version': int})
+
+    # 102, 0102
+    rebulk.regex(r'(?P<season>\d{1,2})(?P<episode>\d{2})' +
+                 r'(?:v(?P<version>\d+))?' +
+                 r'(?:(?P<episodeSeparator>x|-)(?P<episode>\d{2}))*',
+                 tags=['bonus-conflict', 'weak-movie', 'weak-duplicate'],
+                 formatter={'season': int, 'episode': int, 'version': int},
+                 conflict_solver=lambda match, other: match if other.name == 'year' else '__default__',
+                 disabled=lambda context: context.get('episode_prefer_number', False))
+
+    rebulk.regex(r'v(?P<version>\d+)', children=True, private_parent=True, formatter=int)
+
+    rebulk.defaults(private_names=['episodeSeparator', 'seasonSeparator'])
+
+    # detached of X count (season/episode)
+    rebulk.regex(r'(?P<episode>\d+)?-?\L<of_words>-?(?P<count>\d+)-?\L<episode_words>?', of_words=of_words,
+                 episode_words=episode_words, abbreviations=[dash], children=True, private_parent=True, formatter=int)
+
+    rebulk.regex(r'Minisodes?', name='episode_format', value="Minisode")
+
+    # Harcoded movie to disable weak season/episodes
+    rebulk.regex('OSS-?117',
+                 abbreviations=[dash], name="hardcoded-movies", marker=True,
+                 conflict_solver=lambda match, other: None)
+
+    rebulk.rules(EpisodeNumberSeparatorRange, SeasonSeparatorRange, RemoveWeakIfMovie, RemoveWeakIfSxxExx,
+                 RemoveWeakDuplicate, EpisodeDetailValidator, RemoveDetachedEpisodeNumber, VersionValidator,
+                 CountValidator, EpisodeSingleDigitValidator)
+
+    return rebulk
+
+
+class CountValidator(Rule):
+    """
+    Validate count property and rename it
+    """
+    priority = 64
+    consequence = [RemoveMatch, RenameMatch('episode_count'), RenameMatch('season_count')]
+
+    properties = {'episode_count': [None], 'season_count': [None]}
+
+    def when(self, matches, context):
+        to_remove = []
+        episode_count = []
+        season_count = []
+
+        for count in matches.named('count'):
+            previous = matches.previous(count, lambda match: match.name in ['episode', 'season'], 0)
+            if previous:
+                if previous.name == 'episode':
+                    episode_count.append(count)
+                elif previous.name == 'season':
+                    season_count.append(count)
+            else:
+                to_remove.append(count)
+        return to_remove, episode_count, season_count
+
+
+class EpisodeNumberSeparatorRange(Rule):
+    """
+    Remove separator matches and create matches for episoderNumber range.
+    """
+    priority = 128
+    consequence = [RemoveMatch, AppendMatch]
+
+    def when(self, matches, context):
+        to_remove = []
+        to_append = []
+        for separator in matches.named('episodeSeparator'):
+            previous_match = matches.previous(separator, lambda match: match.name == 'episode', 0)
+            next_match = matches.next(separator, lambda match: match.name == 'episode', 0)
+
+            if previous_match and next_match and separator.value == '-':
+                for episode_number in range(previous_match.value + 1, next_match.value):
+                    match = copy.copy(separator)
+                    match.private = False
+                    match.name = 'episode'
+                    match.value = episode_number
+                    to_append.append(match)
+            to_remove.append(separator)
+        return to_remove, to_append
+
+
+class SeasonSeparatorRange(Rule):
+    """
+    Remove separator matches and create matches for season range.
+    """
+    priority = 128
+    consequence = [RemoveMatch, AppendMatch]
+
+    def when(self, matches, context):
+        to_remove = []
+        to_append = []
+        for separator in matches.named('seasonSeparator'):
+            previous_match = matches.previous(separator, lambda match: match.name == 'season', 0)
+            next_match = matches.next(separator, lambda match: match.name == 'season', 0)
+
+            if previous_match and next_match and separator.value == '-':
+                for episode_number in range(previous_match.value + 1, next_match.value):
+                    match = copy.copy(separator)
+                    match.private = False
+                    match.name = 'season'
+                    match.value = episode_number
+                    to_append.append(match)
+            to_remove.append(separator)
+        return to_remove, to_append
+
+
+class RemoveWeakIfMovie(Rule):
+    """
+    Remove weak-movie tagged matches if it seems to be a movie.
+    """
+    priority = 64
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        if matches.named('year') or matches.markers.named('hardcoded-movies'):
+            return matches.tagged('weak-movie')
+
+
+class RemoveWeakIfSxxExx(Rule):
+    """
+    Remove weak-movie tagged matches if SxxExx pattern is matched.
+    """
+    priority = 64
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        if matches.tagged('SxxExx', lambda match: not match.private):
+            return matches.tagged('weak-movie')
+
+
+class RemoveWeakDuplicate(Rule):
+    """
+    Remove weak-duplicate tagged matches if duplicate patterns, for example The 100.109
+    """
+    priority = 64
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        to_remove = []
+        for filepart in matches.markers.named('path'):
+            patterns = defaultdict(list)
+            for match in reversed(matches.range(filepart.start, filepart.end,
+                                                predicate=lambda match: 'weak-duplicate' in match.tags)):
+                if match.pattern in patterns[match.name]:
+                    to_remove.append(match)
+                else:
+                    patterns[match.name].append(match.pattern)
+        return to_remove
+
+
+class EpisodeDetailValidator(Rule):
+    """
+    Validate episode_details if they are detached or next to season or episode.
+    """
+    priority = 64
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        for detail in matches.named('episode_details'):
+            if not seps_surround(detail) \
+                    and not matches.previous(detail, lambda match: match.name in ['season', 'episode']) \
+                    and not matches.next(detail, lambda match: match.name in ['season', 'episode']):
+                ret.append(detail)
+        return ret
+
+
+class RemoveDetachedEpisodeNumber(Rule):
+    """
+    If multiple episode are found, remove those that are not detached from a range and less than 10.
+
+    Fairy Tail 2 - 16-20, 2 should be removed.
+    """
+    priority = 64
+    consequence = RemoveMatch
+    dependency = [RemoveWeakIfSxxExx, RemoveWeakDuplicate]
+
+    def when(self, matches, context):
+        ret = []
+
+        episode_numbers = []
+        episode_values = set()
+        for match in matches.named('episode', lambda match: not match.private and 'weak-movie' in match.tags):
+            if match.value not in episode_values:
+                episode_numbers.append(match)
+                episode_values.add(match.value)
+
+        episode_numbers = list(sorted(episode_numbers, key=lambda match: match.value))
+        if len(episode_numbers) > 1 and \
+                        episode_numbers[0].value < 10 and \
+                                episode_numbers[1].value - episode_numbers[0].value != 1:
+            parent = episode_numbers[0]
+            while parent:  # TODO: Add a feature in rebulk to avoid this ...
+                ret.append(parent)
+                parent = parent.parent
+        return ret
+
+
+class VersionValidator(Rule):
+    """
+    Validate version if previous match is episode or if surrounded by separators.
+    """
+    priority = 64
+    dependency = [RemoveWeakIfMovie, RemoveWeakIfSxxExx]
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        for version in matches.named('version'):
+            episode_number = matches.previous(version, lambda match: match.name == 'episode', 0)
+            if not episode_number and not seps_surround(version.initiator):
+                ret.append(version)
+        return ret
+
+
+class EpisodeSingleDigitValidator(Rule):
+    """
+    Remove single digit episode when inside a group that doesn't own title.
+    """
+    dependency = [TitleFromPosition]
+
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        for episode in matches.named('episode', lambda match: len(match.initiator) == 1):
+            group = matches.markers.at_match(episode, lambda marker: marker.name == 'group', index=0)
+            if group:
+                if not matches.range(*group.span, predicate=lambda match: match.name == 'title'):
+                    ret.append(episode)
+        return ret
diff --git a/lib/guessit2/rules/properties/film.py b/lib/guessit2/rules/properties/film.py
new file mode 100644
index 000000000..5c6e3ab5b
--- /dev/null
+++ b/lib/guessit2/rules/properties/film.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+film property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk, AppendMatch, Rule
+from ..common.formatters import cleanup
+
+
+def film():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE)
+
+    rebulk.regex(r'f(\d+)', name='film', private_parent=True, children=True, formatter=int)
+
+    rebulk.rules(FilmTitleRule)
+
+    return rebulk
+
+
+class FilmTitleRule(Rule):
+    """
+    Rule to find out film_title (hole after film property
+    """
+    consequence = AppendMatch
+
+    properties = {'film_title': [None]}
+
+    def when(self, matches, context):
+        bonus_number = matches.named('film', lambda match: not match.private, index=0)
+        if bonus_number:
+            filepath = matches.markers.at_match(bonus_number, lambda marker: marker.name == 'path', 0)
+            hole = matches.holes(filepath.start, bonus_number.start + 1, formatter=cleanup, index=0)
+            if hole and hole.value:
+                hole.name = 'film_title'
+                return hole
diff --git a/lib/guessit2/rules/properties/format.py b/lib/guessit2/rules/properties/format.py
new file mode 100644
index 000000000..d250a8b88
--- /dev/null
+++ b/lib/guessit2/rules/properties/format.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+format property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk, RemoveMatch, Rule
+from ..common import dash
+from ..common.validators import seps_before, seps_after
+
+
+def format_():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE, abbreviations=[dash])
+    rebulk.defaults(name="format")
+
+    rebulk.regex("VHS", "VHS-?Rip", value="VHS")
+    rebulk.regex("CAM", "CAM-?Rip", "HD-?CAM", value="Cam")
+    rebulk.regex("TELESYNC", "TS", "HD-?TS", value="Telesync")
+    rebulk.regex("WORKPRINT", "WP", value="Workprint")
+    rebulk.regex("TELECINE", "TC", value="Telecine")
+    rebulk.regex("PPV", "PPV-?Rip", value="PPV")  # Pay Per View
+    rebulk.regex("SD-?TV", "SD-?TV-?Rip", "Rip-?SD-?TV", "TV-?Rip",
+                 "Rip-?TV", value="TV")  # TV is too common to allow matching
+    rebulk.regex("DVB-?Rip", "DVB", "PD-?TV", value="DVB")
+    rebulk.regex("DVD", "DVD-?Rip", "VIDEO-?TS", "DVD-?R(?:$|(?!E))",  # "DVD-?R(?:$|^E)" => DVD-Real ...
+                 "DVD-?9", "DVD-?5", value="DVD")
+
+    rebulk.regex("HD-?TV", "TV-?RIP-?HD", "HD-?TV-?RIP", "HD-?RIP", value="HDTV")
+    rebulk.regex("VOD", "VOD-?Rip", value="VOD")
+    rebulk.regex("WEB-?Rip", value="WEBRip")
+    rebulk.regex("WEB-?DL", "WEB-?HD", "WEB", value="WEB-DL")
+    rebulk.regex("HD-?DVD-?Rip", "HD-?DVD", value="HD-DVD")
+    rebulk.regex("Blu-?ray(?:-?Rip)?", "B[DR]", "B[DR]-?Rip", "BD[59]", "BD25", "BD50", value="BluRay")
+
+    rebulk.rules(ValidateFormat)
+
+    return rebulk
+
+
+class ValidateFormat(Rule):
+    """
+    Validate format with screener property or separated.
+    """
+    priority = 64
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        for format_match in matches.named('format'):
+            if not seps_before(format_match) and \
+                    not matches.range(format_match.start - 1, format_match.start - 2,
+                                      lambda match: match.name == 'other' and match.value == 'Screener'):
+                ret.append(format_match)
+                continue
+            if not seps_after(format_match) and \
+                    not matches.range(format_match.end, format_match.end + 1,
+                                      lambda match: match.name == 'other' and match.value == 'Screener'):
+                ret.append(format_match)
+                continue
+        return ret
diff --git a/lib/guessit2/rules/properties/language.py b/lib/guessit2/rules/properties/language.py
new file mode 100644
index 000000000..c42b2e116
--- /dev/null
+++ b/lib/guessit2/rules/properties/language.py
@@ -0,0 +1,249 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+language and subtitle_language properties
+"""
+# pylint: disable=no-member
+from __future__ import unicode_literals
+
+import copy
+
+import regex as re
+import babelfish
+
+from rebulk import Rebulk, Rule, RemoveMatch, RenameMatch
+from ..common.words import iter_words, COMMON_WORDS
+from ..common.validators import seps_surround
+
+
+def language():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk()
+
+    rebulk.string(*subtitle_prefixes, name="subtitle_language.prefix", ignore_case=True, private=True,
+                  validator=seps_surround)
+    rebulk.string(*subtitle_suffixes, name="subtitle_language.suffix", ignore_case=True, private=True,
+                  validator=seps_surround)
+    rebulk.functional(find_languages, properties={'language': [None]})
+    rebulk.rules(SubtitlePrefixLanguageRule, SubtitleSuffixLanguageRule, SubtitleExtensionRule)
+
+    return rebulk
+
+
+COMMON_WORDS_STRICT = frozenset(['brazil'])
+
+UNDETERMINED = babelfish.Language('und')
+
+SYN = {('und', None): ['unknown', 'inconnu', 'unk', 'un'],
+       ('ell', None): ['gr', 'greek'],
+       ('spa', None): ['esp', 'español'],
+       ('fra', None): ['français', 'vf', 'vff', 'vfi', 'vfq'],
+       ('swe', None): ['se'],
+       ('por', 'BR'): ['po', 'pb', 'pob', 'br', 'brazilian'],
+       ('cat', None): ['català'],
+       ('ces', None): ['cz'],
+       ('ukr', None): ['ua'],
+       ('zho', None): ['cn'],
+       ('jpn', None): ['jp'],
+       ('hrv', None): ['scr'],
+       ('mul', None): ['multi', 'dl']}  # http://scenelingo.wordpress.com/2009/03/24/what-does-dl-mean/
+
+
+class GuessitConverter(babelfish.LanguageReverseConverter):  # pylint: disable=missing-docstring
+    _with_country_regexp = re.compile(r'(.*)\((.*)\)')
+    _with_country_regexp2 = re.compile(r'(.*)-(.*)')
+
+    def __init__(self):
+        self.guessit_exceptions = {}
+        for (alpha3, country), synlist in SYN.items():
+            for syn in synlist:
+                self.guessit_exceptions[syn.lower()] = (alpha3, country, None)
+
+    @property
+    def codes(self):  # pylint: disable=missing-docstring
+        return (babelfish.language_converters['alpha3b'].codes |
+                babelfish.language_converters['alpha2'].codes |
+                babelfish.language_converters['name'].codes |
+                babelfish.language_converters['opensubtitles'].codes |
+                babelfish.country_converters['name'].codes |
+                frozenset(self.guessit_exceptions.keys()))
+
+    def convert(self, alpha3, country=None, script=None):
+        return str(babelfish.Language(alpha3, country, script))
+
+    def reverse(self, name):
+        with_country = (GuessitConverter._with_country_regexp.match(name) or
+                        GuessitConverter._with_country_regexp2.match(name))
+
+        name = name.lower()
+        if with_country:
+            lang = babelfish.Language.fromguessit(with_country.group(1).strip())
+            lang.country = babelfish.Country.fromguessit(with_country.group(2).strip())
+            return lang.alpha3, lang.country.alpha2 if lang.country else None, lang.script or None
+
+        # exceptions come first, as they need to override a potential match
+        # with any of the other guessers
+        try:
+            return self.guessit_exceptions[name]
+        except KeyError:
+            pass
+
+        for conv in [babelfish.Language,
+                     babelfish.Language.fromalpha3b,
+                     babelfish.Language.fromalpha2,
+                     babelfish.Language.fromname,
+                     babelfish.Language.fromopensubtitles]:
+            try:
+                reverse = conv(name)
+                return reverse.alpha3, reverse.country, reverse.script
+            except (ValueError, babelfish.LanguageReverseError):
+                pass
+
+        raise babelfish.LanguageReverseError(name)
+
+
+babelfish.language_converters['guessit'] = GuessitConverter()
+
+subtitle_prefixes = ['sub', 'subs', 'st', 'vost', 'subforced', 'fansub', 'hardsub']
+subtitle_suffixes = ['subforced', 'fansub', 'hardsub', 'sub', 'subs']
+lang_prefixes = ['true']
+
+all_lang_prefixes_suffixes = subtitle_prefixes + subtitle_suffixes + lang_prefixes
+
+
+def find_languages(string, context=None):
+    """Find languages in the string
+
+    :return: list of tuple (property, Language, lang_word, word)
+    """
+    allowed_languages = context.get('allowed_languages')
+    common_words = COMMON_WORDS_STRICT if allowed_languages else COMMON_WORDS
+
+    matches = []
+    for word_match in iter_words(string):
+        word = word_match.group()
+        start, end = word_match.span()
+
+        lang_word = word.lower()
+        key = 'language'
+        for prefix in subtitle_prefixes:
+            if lang_word.startswith(prefix):
+                lang_word = lang_word[len(prefix):]
+                key = 'subtitle_language'
+        for suffix in subtitle_suffixes:
+            if lang_word.endswith(suffix):
+                lang_word = lang_word[:len(suffix) - 1]
+                key = 'subtitle_language'
+        for prefix in lang_prefixes:
+            if lang_word.startswith(prefix):
+                lang_word = lang_word[len(prefix):]
+        if lang_word not in common_words and word.lower() not in common_words:
+            try:
+                lang = babelfish.Language.fromguessit(lang_word)
+                match = (start, end, {'name': key, 'value': lang})
+                if allowed_languages:
+                    if lang.name.lower() in allowed_languages \
+                            or lang.alpha2.lower() in allowed_languages \
+                            or lang.alpha3.lower() in allowed_languages:
+                        matches.append(match)
+                # Keep language with alpha2 equivalent. Others are probably
+                # uncommon languages.
+                elif lang == 'mul' or hasattr(lang, 'alpha2'):
+                    matches.append(match)
+            except babelfish.Error:
+                pass
+    return matches
+
+
+class SubtitlePrefixLanguageRule(Rule):
+    """
+    Convert language guess as subtitle_language if previous match is a subtitle language prefix
+    """
+    consequence = RemoveMatch
+
+    properties = {'subtitle_language': [None]}
+
+    def when(self, matches, context):
+        to_rename = []
+        to_remove = matches.named('subtitle_language.prefix')
+        for lang in matches.named('language'):
+            prefix = matches.previous(lang, lambda match: match.name == 'subtitle_language.prefix', 0)
+            if not prefix:
+                group_marker = matches.markers.at_match(lang, lambda marker: marker.name == 'group', 0)
+                if group_marker:
+                    # Find prefix if placed just before the group
+                    prefix = matches.previous(group_marker, lambda match: match.name == 'subtitle_language.prefix',
+                                              0)
+                    if not prefix:
+                        # Find prefix if placed before in the group
+                        prefix = matches.range(group_marker.start, lang.start,
+                                               lambda match: match.name == 'subtitle_language.prefix', 0)
+            if prefix:
+                to_rename.append((prefix, lang))
+                if prefix in to_remove:
+                    to_remove.remove(prefix)
+        return to_rename, to_remove
+
+    def then(self, matches, when_response, context):
+        to_rename, to_remove = when_response
+        super(SubtitlePrefixLanguageRule, self).then(matches, to_remove, context)
+        for prefix, match in to_rename:
+            # Remove suffix equivalent of  prefix.
+            suffix = copy.copy(prefix)
+            suffix.name = 'subtitle_language.suffix'
+            if suffix in matches:
+                matches.remove(suffix)
+            matches.remove(match)
+            match.name = 'subtitle_language'
+            matches.append(match)
+
+
+class SubtitleSuffixLanguageRule(Rule):
+    """
+    Convert language guess as subtitle_language if next match is a subtitle language suffix
+    """
+    dependency = SubtitlePrefixLanguageRule
+    consequence = RemoveMatch
+
+    properties = {'subtitle_language': [None]}
+
+    def when(self, matches, context):
+        to_append = []
+        to_remove = matches.named('subtitle_language.suffix')
+        for lang in matches.named('language'):
+            suffix = matches.next(lang, lambda match: match.name == 'subtitle_language.suffix', 0)
+            if suffix:
+                to_append.append(lang)
+                if suffix in to_remove:
+                    to_remove.remove(suffix)
+        return to_append, to_remove
+
+    def then(self, matches, when_response, context):
+        to_rename, to_remove = when_response
+        super(SubtitleSuffixLanguageRule, self).then(matches, to_remove, context)
+        for match in to_rename:
+            matches.remove(match)
+            match.name = 'subtitle_language'
+            matches.append(match)
+
+
+class SubtitleExtensionRule(Rule):
+    """
+    Convert language guess as subtitle_language if next match is a subtitle extension
+    """
+    consequence = RenameMatch('subtitle_language')
+
+    properties = {'subtitle_language': [None]}
+
+    def when(self, matches, context):
+        subtitle_extension = matches.named('container',
+                                           lambda match: 'extension' in match.tags and 'subtitle' in match.tags,
+                                           0)
+        if subtitle_extension:
+            subtitle_lang = matches.previous(subtitle_extension, lambda match: match.name == 'language', 0)
+            if subtitle_lang:
+                return subtitle_lang
diff --git a/lib/guessit2/rules/properties/mimetype.py b/lib/guessit2/rules/properties/mimetype.py
new file mode 100644
index 000000000..8e21ca32e
--- /dev/null
+++ b/lib/guessit2/rules/properties/mimetype.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+mimetype property
+"""
+from __future__ import unicode_literals
+
+import mimetypes
+
+from rebulk import Rebulk, CustomRule, POST_PROCESS
+from rebulk.match import Match
+
+from ...rules.processors import Processors
+
+
+def mimetype():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    return Rebulk().rules(Mimetype)
+
+
+class Mimetype(CustomRule):
+    """
+    Mimetype post processor
+    :param matches:
+    :type matches:
+    :return:
+    :rtype:
+    """
+    priority = POST_PROCESS
+
+    dependency = Processors
+
+    def when(self, matches, context):
+        mime, _ = mimetypes.guess_type(matches.input_string, strict=False)
+        return mime
+
+    def then(self, matches, when_response, context):
+        mime = when_response
+        matches.append(Match(len(matches.input_string), len(matches.input_string), name='mimetype', value=mime))
diff --git a/lib/guessit2/rules/properties/other.py b/lib/guessit2/rules/properties/other.py
new file mode 100644
index 000000000..38e69f767
--- /dev/null
+++ b/lib/guessit2/rules/properties/other.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+other property
+"""
+from __future__ import unicode_literals
+
+import copy
+
+import regex as re
+
+from rebulk import Rebulk, Rule, RemoveMatch, POST_PROCESS, AppendMatch
+from ..common import dash
+from ..common import seps
+from ..common.validators import seps_surround
+from guessit2.rules.common.formatters import raw_cleanup
+
+
+def other():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE, abbreviations=[dash]).string_defaults(ignore_case=True)
+    rebulk.defaults(name="other", validator=seps_surround)
+
+    rebulk.regex('Audio-?Fix', 'Audio-?Fixed', value='AudioFix')
+    rebulk.regex('Sync-?Fix', 'Sync-?Fixed', value='SyncFix')
+    rebulk.regex('Dual-?Audio', value='DualAudio')
+    rebulk.regex('ws', 'wide-?screen', value='WideScreen')
+    rebulk.string('Netflix', 'NF', value='Netflix')
+
+    rebulk.string('Real', 'Fix', value='Proper', tags=['has-neighbor-before', 'has-neighbor-after'])
+    rebulk.string('Proper', 'Repack', 'Rerip', value='Proper')
+    rebulk.string('Fansub', value='Fansub', tags='has-neighbor')
+    rebulk.string('Fastsub', value='Fastsub', tags='has-neighbor')
+
+    rebulk.regex('(?:Seasons?-)?Complete', value='Complete', tags=['release-group-prefix'],
+                 validator=lambda match: seps_surround(match) and match.raw.lower().strip(seps) != "complete")
+    rebulk.string('R5', 'RC', value='R5')
+    rebulk.regex('Pre-?Air', value='Preair')
+
+    for value in (
+            'Screener', 'Remux', '3D', 'HD', 'mHD', 'HDLight', 'HQ', 'DDC', 'HR', 'PAL', 'SECAM', 'NTSC', 'CC', 'LD',
+            'MD'):
+        rebulk.string(value, value=value)
+
+    for value in ('Limited', 'Complete', 'Classic', 'Unrated', 'LiNE', 'Bonus', 'Trailer', 'FINAL'):
+        rebulk.string(value, value=value, tags=['has-neighbor', 'release-group-prefix'])
+
+    rebulk.string('VO', 'OV', value='OV', tags='has-neighbor')
+
+    rebulk.regex('Scr(?:eener)?', value='Screener', validator=None, tags='other.validate.screener')
+
+    rebulk.rules(ValidateHasNeighbor, ValidateHasNeighborAfter, ValidateHasNeighborBefore, ValidateScreenerRule,
+                 ProperCountRule)
+
+    return rebulk
+
+
+class ProperCountRule(Rule):
+    """
+    Add proper_count property
+    """
+    priority = POST_PROCESS
+
+    consequence = AppendMatch
+
+    properties = {'proper_count': [None]}
+
+    def when(self, matches, context):
+        propers = matches.named('other', lambda match: match.value == 'Proper')
+        if propers:
+            raws = {}  # Count distinct raw values
+            for proper in propers:
+                raws[raw_cleanup(proper.raw)] = proper
+            proper_count_match = copy.copy(propers[-1])
+            proper_count_match.name = 'proper_count'
+            proper_count_match.value = len(raws)
+            return proper_count_match
+
+
+class ValidateHasNeighbor(Rule):
+    """
+    Validate tag has-neighbor
+    """
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        for to_check in matches.range(predicate=lambda match: 'has-neighbor' in match.tags):
+            previous_match = matches.previous(to_check, index=0)
+            previous_group = matches.markers.previous(to_check, lambda marker: marker.name == 'group', 0)
+            if previous_group and (not previous_match or previous_group.end > previous_match.end):
+                previous_match = previous_group
+            if previous_match and not matches.input_string[previous_match.end:to_check.start].strip(seps):
+                break
+            next_match = matches.next(to_check, index=0)
+            next_group = matches.markers.next(to_check, lambda marker: marker.name == 'group', 0)
+            if next_group and (not next_match or next_group.start < next_match.start):
+                next_match = next_group
+            if next_match and not matches.input_string[to_check.end:next_match.start].strip(seps):
+                break
+            ret.append(to_check)
+        return ret
+
+
+class ValidateHasNeighborBefore(Rule):
+    """
+    Validate tag has-neighbor-before that previous match exists.
+    """
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        for to_check in matches.range(predicate=lambda match: 'has-neighbor-before' in match.tags):
+            next_match = matches.next(to_check, index=0)
+            next_group = matches.markers.next(to_check, lambda marker: marker.name == 'group', 0)
+            if next_group and (not next_match or next_group.start < next_match.start):
+                next_match = next_group
+            if next_match and not matches.input_string[to_check.end:next_match.start].strip(seps):
+                break
+            ret.append(to_check)
+        return ret
+
+
+class ValidateHasNeighborAfter(Rule):
+    """
+    Validate tag has-neighbor-after that next match exists.
+    """
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        for to_check in matches.range(predicate=lambda match: 'has-neighbor-after' in match.tags):
+            previous_match = matches.previous(to_check, index=0)
+            previous_group = matches.markers.previous(to_check, lambda marker: marker.name == 'group', 0)
+            if previous_group and (not previous_match or previous_group.end > previous_match.end):
+                previous_match = previous_group
+            if previous_match and not matches.input_string[previous_match.end:to_check.start].strip(seps):
+                break
+            ret.append(to_check)
+        return ret
+
+
+class ValidateScreenerRule(Rule):
+    """
+    Validate tag other.validate.screener
+    """
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        ret = []
+        for screener in matches.named('other', lambda match: 'other.validate.screener' in match.tags):
+            format_match = matches.previous(screener, lambda match: match.name == 'format', 0)
+            if not format_match or matches.input_string[format_match.end:screener.start].strip(seps):
+                ret.append(screener)
+        return ret
diff --git a/lib/guessit2/rules/properties/part.py b/lib/guessit2/rules/properties/part.py
new file mode 100644
index 000000000..483b86edb
--- /dev/null
+++ b/lib/guessit2/rules/properties/part.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+part property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk
+from ..common import dash
+from ..common.validators import seps_surround
+from ..common.numeral import numeral, parse_numeral
+
+
+def part():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE, abbreviations=[dash], validator={'__parent__': seps_surround})
+
+    prefixes = ['pt', 'part']
+
+    rebulk.regex(r'\L<prefixes>-?(' + numeral + r')', prefixes=prefixes,
+                 name='part', validate_all=True, private_parent=True, children=True, formatter=parse_numeral)
+
+    return rebulk
diff --git a/lib/guessit2/rules/properties/release_group.py b/lib/guessit2/rules/properties/release_group.py
new file mode 100644
index 000000000..0802f490a
--- /dev/null
+++ b/lib/guessit2/rules/properties/release_group.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+release_group property
+"""
+from __future__ import unicode_literals
+
+import copy
+
+import regex as re
+
+from rebulk import Rebulk, Rule, AppendMatch
+from ..common.validators import int_coercable
+from ..properties.title import TitleFromPosition
+from ..common.formatters import cleanup
+from ..common import seps, dash
+from ..common.comparators import marker_sorted
+
+
+def release_group():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    return Rebulk().rules(SceneReleaseGroup, AnimeReleaseGroup, ExpectedReleaseGroup)
+
+
+forbidden_groupnames = ['rip', 'by', 'for', 'par', 'pour', 'bonus']
+
+groupname_seps = ''.join([c for c in seps if c not in '[]{}()'])
+
+
+def clean_groupname(string):
+    """
+    Removes and strip separators from input_string
+    :param input_string:
+    :type input_string:
+    :return:
+    :rtype:
+    """
+    string = string.strip(groupname_seps)
+    for forbidden in forbidden_groupnames:
+        if string.lower().startswith(forbidden):
+            string = string[len(forbidden):]
+            string = string.strip(groupname_seps)
+        if string.lower().endswith(forbidden):
+            string = string[:len(forbidden)]
+            string = string.strip(groupname_seps)
+    return string
+
+
+_scene_previous_names = ['video_codec', 'format', 'video_api', 'audio_codec', 'audio_profile', 'video_profile',
+                         'audio_channels', 'screen_size']
+
+_scene_previous_tags = ['release-group-prefix']
+
+
+class ExpectedReleaseGroup(Rule):
+    """
+    Add release_group match from expected_group option
+    """
+    consequence = AppendMatch
+
+    properties = {'release_group': [None]}
+
+    def enabled(self, context):
+        return context.get('expected_group')
+
+    def when(self, matches, context):
+        expected_rebulk = Rebulk().defaults(name='release_group')
+
+        for expected_group in context.get('expected_group'):
+            if expected_group.startswith('re:'):
+                expected_group = expected_group[3:]
+                expected_group = expected_group.replace(' ', '-')
+                expected_rebulk.regex(expected_group, abbreviations=[dash], flags=re.IGNORECASE)
+            else:
+                expected_rebulk.string(expected_group, ignore_case=True)
+
+        matches = expected_rebulk.matches(matches.input_string, context)
+        return matches
+
+
+class SceneReleaseGroup(Rule):
+    """
+    Add release_group match in existing matches (scene format).
+
+    Something.XViD-ReleaseGroup.mkv
+    """
+    dependency = [TitleFromPosition, ExpectedReleaseGroup]
+    consequence = AppendMatch
+
+    properties = {'release_group': [None]}
+
+    def when(self, matches, context):
+        # If a release_group is found before, ignore this kind of release_group rule.
+        if matches.named('release_group'):
+            return
+
+        ret = []
+
+        for filepart in marker_sorted(matches.markers.named('path'), matches):
+            start, end = filepart.span
+
+            last_hole = matches.holes(start, end + 1, formatter=clean_groupname,
+                                      predicate=lambda hole: cleanup(hole.value), index=-1)
+
+            if last_hole:
+                previous_match = matches.previous(last_hole, lambda match: not match.private, index=0)
+                if previous_match and (previous_match.name in _scene_previous_names or
+                                       any(tag in previous_match.tags for tag in _scene_previous_tags)) and \
+                        not matches.input_string[previous_match.end:last_hole.start].strip(seps) \
+                        and not int_coercable(last_hole.value.strip(seps)):
+
+                    last_hole.name = 'release_group'
+                    last_hole.tags = ['scene']
+
+                    # if hole is insed a group marker with same value, remove [](){} ...
+                    group = matches.markers.at_match(last_hole, lambda marker: marker.name == 'group', 0)
+                    if group:
+                        group.formatter = clean_groupname
+                        if group.value == last_hole.value:
+                            last_hole.start = group.start + 1
+                            last_hole.end = group.end - 1
+                            last_hole.tags = ['anime']
+
+                    ret.append(last_hole)
+        return ret
+
+
+class AnimeReleaseGroup(Rule):
+    """
+    Add release_group match in existing matches (anime format)
+    ...[ReleaseGroup] Something.mkv
+    """
+    dependency = [SceneReleaseGroup, TitleFromPosition]
+    consequence = AppendMatch
+
+    properties = {'release_group': [None]}
+
+    def when(self, matches, context):
+        ret = []
+
+        # If a release_group is found before, ignore this kind of release_group rule.
+        if matches.named('release_group'):
+            return ret
+
+        for filepart in marker_sorted(matches.markers.named('path'), matches):
+
+            # pylint:disable=bad-continuation
+            empty_group_marker = matches.markers \
+                .range(filepart.start, filepart.end, lambda marker: marker.name == 'group'
+                                                                    and not matches.range(marker.start, marker.end)
+                                                                    and not int_coercable(marker.value.strip(seps)),
+                       0)
+
+            if empty_group_marker:
+                group = copy.copy(empty_group_marker)
+                group.marker = False
+                group.raw_start += 1
+                group.raw_end -= 1
+                group.tags = ['anime']
+                group.name = 'release_group'
+                ret.append(group)
+        return ret
diff --git a/lib/guessit2/rules/properties/screen_size.py b/lib/guessit2/rules/properties/screen_size.py
new file mode 100644
index 000000000..1ccc6572e
--- /dev/null
+++ b/lib/guessit2/rules/properties/screen_size.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+screen_size property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk, Rule, RemoveMatch
+from ..common.validators import seps_surround
+from guessit2.rules.common import dash
+
+
+def screen_size():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    def conflict_solver(match, other):
+        """
+        Conflict solver for most screen_size.
+        """
+        if other.name == 'screen_size':
+            if 'resolution' in other.tags:
+                # The chtouile to solve conflict in "720 x 432" string matching both 720p pattern
+                int_value = _digits_re.findall(match.raw)[-1]
+                if other.value.startswith(int_value):
+                    return match
+            return other
+        return '__default__'
+
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE)
+    rebulk.defaults(name="screen_size", validator=seps_surround, conflict_solver=conflict_solver)
+
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?360(?:i|p?x?)", value="360p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?368(?:i|p?x?)", value="368p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?480(?:i|p?x?)", value="480p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?576(?:i|p?x?)", value="576p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?720(?:i|p?(?:50|60)?x?)", value="720p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?720(?:p(?:50|60)?x?)", value="720p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?720hd", value="720p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?900(?:i|p?x?)", value="900p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?1080i", value="1080i")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?1080p?x?", value="1080p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?1080(?:p(?:50|60)?x?)", value="1080p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?1080hd", value="1080p")
+    rebulk.regex(r"(?:\d{3,}(?:x|\*))?2160(?:i|p?x?)", value="4K")
+
+    _digits_re = re.compile(r'\d+')
+
+    rebulk.defaults(name="screen_size", validator=seps_surround)
+    rebulk.regex(r'\d{3,}-?(?:x|\*)-?\d{3,}',
+                 formatter=lambda value: 'x'.join(_digits_re.findall(value)),
+                 abbreviations=[dash],
+                 tags=['resolution'],
+                 conflict_solver=lambda match, other: '__default__' if other.name == 'screen_size' else other)
+
+    rebulk.rules(ScreenSizeOnlyOne)
+
+    return rebulk
+
+
+class ScreenSizeOnlyOne(Rule):
+    """
+    Keep a single screen_size pet filepath part.
+    """
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        to_remove = []
+        for filepart in matches.markers.named('path'):
+            screensize = list(reversed(matches.range(filepart.start, filepart.end,
+                                                     lambda match: match.name == 'screen_size')))
+            if len(screensize) > 1:
+                to_remove.extend(screensize[1:])
+
+        return to_remove
diff --git a/lib/guessit2/rules/properties/title.py b/lib/guessit2/rules/properties/title.py
new file mode 100644
index 000000000..25efea85c
--- /dev/null
+++ b/lib/guessit2/rules/properties/title.py
@@ -0,0 +1,340 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+title property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk, Rule, AppendMatch, RemoveMatch, AppendTags
+from rebulk.formatters import formatters
+from rebulk.pattern import RePattern
+from rebulk.utils import find_all
+
+from .film import FilmTitleRule
+from .language import SubtitlePrefixLanguageRule, SubtitleSuffixLanguageRule, SubtitleExtensionRule
+from ..common.formatters import cleanup, reorder_title
+from ..common.comparators import marker_sorted
+from ..common import seps, title_seps, dash
+
+
+def title():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().rules(TitleFromPosition, PreferTitleWithYear)
+
+    def expected_title(input_string, context):
+        """
+        Expected title functional pattern.
+        :param input_string:
+        :type input_string:
+        :param context:
+        :type context:
+        :return:
+        :rtype:
+        """
+        ret = []
+        for search in context.get('expected_title'):
+            if search.startswith('re:'):
+                search = search[3:]
+                search = search.replace(' ', '-')
+                matches = RePattern(search, abbreviations=[dash], flags=re.IGNORECASE).matches(input_string, context)
+                for match in matches:
+                    ret.append(match.span)
+            else:
+                for start in find_all(input_string, search, ignore_case=True):
+                    ret.append((start, start+len(search)))
+        return ret
+
+    rebulk.functional(expected_title, name='title', tags=['expected'],
+                      conflict_solver=lambda match, other: other,
+                      disabled=lambda context: not context.get('expected_title'))
+
+    return rebulk
+
+
+class TitleBaseRule(Rule):
+    """
+    Add title match in existing matches
+    """
+    # pylint:disable=no-self-use,unused-argument
+    consequence = [AppendMatch, RemoveMatch]
+
+    def __init__(self, match_name, match_tags=None, alternative_match_name=None):
+        super(TitleBaseRule, self).__init__()
+        self.match_name = match_name
+        self.match_tags = match_tags
+        self.alternative_match_name = alternative_match_name
+
+    def hole_filter(self, hole, matches):
+        """
+        Filter holes for titles.
+        :param hole:
+        :type hole:
+        :param matches:
+        :type matches:
+        :return:
+        :rtype:
+        """
+        return True
+
+    def filepart_filter(self, filepart, matches):
+        """
+        Filter filepart for titles.
+        :param filepart:
+        :type filepart:
+        :param matches:
+        :type matches:
+        :return:
+        :rtype:
+        """
+        return True
+
+    def holes_process(self, holes, matches):
+        """
+        process holes
+        :param holes:
+        :type holes:
+        :param matches:
+        :type matches:
+        :return:
+        :rtype:
+        """
+        cropped_holes = []
+        for hole in holes:
+            group_markers = matches.markers.named('group')
+            cropped_holes.extend(hole.crop(group_markers))
+        return cropped_holes
+
+    def is_ignored(self, match):
+        """
+        Ignore matches when scanning for title (hole)
+        """
+        return match.name in ['language', 'country', 'episode_details']
+
+    def should_keep(self, match, to_keep, matches, filepart, hole, starting):
+        """
+        Check if this match should be accepted when ending or starting a hole.
+        :param match:
+        :type match:
+        :param to_keep:
+        :type to_keep: list[Match]
+        :param matches:
+        :type matches: Matches
+        :param hole: the filepart match
+        :type hole: Match
+        :param hole: the hole match
+        :type hole: Match
+        :param starting: true if match is starting the hole
+        :type starting: bool
+        :return:
+        :rtype:
+        """
+        # Keep language if other languages exists in the filepart.
+        if match.name in ['language', 'country']:
+            outside_matches = filepart.crop(hole)
+            other_languages = []
+            for outside in outside_matches:
+                other_languages.extend(matches.range(outside.start, outside.end,
+                                                     lambda c_match: c_match.name == match.name and
+                                                     c_match not in to_keep))
+
+            if not other_languages:
+                return True
+
+        return False
+
+    def should_remove(self, match, matches, filepart, hole, context):
+        """
+        Check if this match should be removed after beeing ignored.
+        :param match:
+        :param matches:
+        :param filepart:
+        :param hole:
+        :return:
+        """
+        if context.get('type') == 'episode' and match.name == 'episode_details':
+            return False
+        return True
+
+    def check_titles_in_filepart(self, filepart, matches, context):
+        """
+        Find title in filepart (ignoring language)
+        """
+        # pylint:disable=too-many-locals,too-many-branches,too-many-statements
+        start, end = filepart.span
+
+        holes = matches.holes(start, end + 1, formatter=formatters(cleanup, reorder_title),
+                              ignore=self.is_ignored,
+                              predicate=lambda hole: hole.value)
+
+        holes = self.holes_process(holes, matches)
+
+        for hole in holes:
+            # pylint:disable=cell-var-from-loop
+            if not hole or (self.hole_filter and not self.hole_filter(hole, matches)):
+                continue
+
+            to_remove = []
+            to_keep = []
+
+            ignored_matches = matches.range(hole.start, hole.end, self.is_ignored)
+
+            if ignored_matches:
+                for ignored_match in reversed(ignored_matches):
+                    # pylint:disable=undefined-loop-variable
+                    trailing = matches.chain_before(hole.end, seps, predicate=lambda match: match == ignored_match)
+                    if trailing:
+                        should_keep = self.should_keep(ignored_match, to_keep, matches, filepart, hole, False)
+                        if should_keep:
+                            # pylint:disable=unpacking-non-sequence
+                            try:
+                                append, crop = should_keep
+                            except TypeError:
+                                append, crop = should_keep, should_keep
+                            if append:
+                                to_keep.append(ignored_match)
+                            if crop:
+                                hole.end = ignored_match.start
+
+                for ignored_match in ignored_matches:
+                    if ignored_match not in to_keep:
+                        starting = matches.chain_after(hole.start, seps,
+                                                       predicate=lambda match: match == ignored_match)
+                        if starting:
+                            should_keep = self.should_keep(ignored_match, to_keep, matches, filepart, hole, True)
+                            if should_keep:
+                                # pylint:disable=unpacking-non-sequence
+                                try:
+                                    append, crop = should_keep
+                                except TypeError:
+                                    append, crop = should_keep, should_keep
+                                if append:
+                                    to_keep.append(ignored_match)
+                                if crop:
+                                    hole.start = ignored_match.end
+
+            for match in ignored_matches:
+                if self.should_remove(match, matches, filepart, hole, context):
+                    to_remove.append(match)
+            for keep_match in to_keep:
+                to_remove.remove(keep_match)
+
+            if hole and hole.value:
+                hole.name = self.match_name
+                hole.tags = self.match_tags
+                if self.alternative_match_name:
+                    # Split and keep values that can be a title
+                    titles = hole.split(title_seps, lambda match: match.value)
+                    for title_match in list(titles[1:]):
+                        previous_title = titles[titles.index(title_match) - 1]
+                        separator = matches.input_string[previous_title.end:title_match.start]
+                        if len(separator) == 1 and separator == '-' \
+                                and previous_title.raw[-1] not in seps \
+                                and title_match.raw[0] not in seps:
+                            titles[titles.index(title_match) - 1].end = title_match.end
+                            titles.remove(title_match)
+                        else:
+                            title_match.name = self.alternative_match_name
+
+                else:
+                    titles = [hole]
+                return titles, to_remove
+
+    def when(self, matches, context):
+        if matches.named(self.match_name, lambda match: 'expected' in match.tags):
+            return
+
+        fileparts = [filepart for filepart in list(marker_sorted(matches.markers.named('path'), matches))
+                     if not self.filepart_filter or self.filepart_filter(filepart, matches)]
+
+        to_remove = []
+
+        # Priorize fileparts containing the year
+        years_fileparts = []
+        for filepart in fileparts:
+            year_match = matches.range(filepart.start, filepart.end, lambda match: match.name == 'year', 0)
+            if year_match:
+                years_fileparts.append(filepart)
+
+        ret = []
+        for filepart in fileparts:
+            try:
+                years_fileparts.remove(filepart)
+            except ValueError:
+                pass
+            titles = self.check_titles_in_filepart(filepart, matches, context)
+            if titles:
+                titles, to_remove_c = titles
+                ret.extend(titles)
+                to_remove.extend(to_remove_c)
+                break
+
+        # Add title match in all fileparts containing the year.
+        for filepart in years_fileparts:
+            titles = self.check_titles_in_filepart(filepart, matches, context)
+            if titles:
+                # pylint:disable=unbalanced-tuple-unpacking
+                titles, to_remove_c = titles
+                ret.extend(titles)
+                to_remove.extend(to_remove_c)
+
+        return ret, to_remove
+
+
+class TitleFromPosition(TitleBaseRule):
+    """
+    Add title match in existing matches
+    """
+    dependency = [FilmTitleRule, SubtitlePrefixLanguageRule, SubtitleSuffixLanguageRule, SubtitleExtensionRule]
+
+    properties = {'title': [None]}
+
+    def __init__(self):
+        super(TitleFromPosition, self).__init__('title', ['title'], 'alternativeTitle')
+
+
+class PreferTitleWithYear(Rule):
+    """
+    Prefer title where filepart contains year.
+    """
+    dependency = TitleFromPosition
+    consequence = [RemoveMatch, AppendTags(['equivalent-ignore'])]
+
+    properties = {'title': [None]}
+
+    def when(self, matches, context):
+        with_year_in_group = []
+        with_year = []
+        titles = matches.named('title')
+
+        for title_match in titles:
+            filepart = matches.markers.at_match(title_match, lambda marker: marker.name == 'path', 0)
+            if filepart:
+                year_match = matches.range(filepart.start, filepart.end, lambda match: match.name == 'year', 0)
+                if year_match:
+                    group = matches.markers.at_match(year_match, lambda group: group.name == 'group')
+                    if group:
+                        with_year_in_group.append(title_match)
+                    else:
+                        with_year.append(title_match)
+
+        to_tag = []
+        if with_year_in_group:
+            title_values = set([title_match.value for title_match in with_year_in_group])
+            to_tag.extend(with_year_in_group)
+        elif with_year:
+            title_values = set([title_match.value for title_match in with_year])
+            to_tag.extend(with_year)
+        else:
+            title_values = set([title_match.value for title_match in titles])
+
+        to_remove = []
+        for title_match in titles:
+            if title_match.value not in title_values:
+                to_remove.append(title_match)
+        return to_remove, to_tag
diff --git a/lib/guessit2/rules/properties/type.py b/lib/guessit2/rules/properties/type.py
new file mode 100644
index 000000000..70043e091
--- /dev/null
+++ b/lib/guessit2/rules/properties/type.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+type property
+"""
+from __future__ import unicode_literals
+
+from rebulk import CustomRule, Rebulk, POST_PROCESS
+from rebulk.match import Match
+
+from ...rules.processors import Processors
+
+
+def _type(matches, value):
+    """
+    Define type match with given value.
+    :param matches:
+    :param value:
+    :return:
+    """
+    matches.append(Match(len(matches.input_string), len(matches.input_string), name='type', value=value))
+
+
+def type_():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    return Rebulk().rules(TypeProcessor)
+
+
+class TypeProcessor(CustomRule):
+    """
+    Post processor to find file type based on all others found matches.
+    """
+    priority = POST_PROCESS
+
+    dependency = Processors
+
+    properties = {'type': ['episode', 'movie']}
+
+    def when(self, matches, context):  # pylint:disable=too-many-return-statements
+        option_type = context.get('type', None)
+        if option_type:
+            return option_type
+
+        episode = matches.named('episode')
+        season = matches.named('season')
+        episode_details = matches.named('episode_details')
+
+        if episode or season or episode_details:
+            return 'episode'
+
+        film = matches.named('film')
+        if film:
+            return 'movie'
+
+        year = matches.named('year')
+        date = matches.named('date')
+
+        if date and not year:
+            return 'episode'
+
+        bonus = matches.named('bonus')
+        if bonus and not year:
+            return 'episode'
+
+        crc32 = matches.named('crc32')
+        anime_release_group = matches.named('release_group', lambda match: 'anime' in match.tags)
+        if crc32 and anime_release_group:
+            return 'episode'
+
+        return 'movie'
+
+    def then(self, matches, when_response, context):
+        _type(matches, when_response)
diff --git a/lib/guessit2/rules/properties/video_codec.py b/lib/guessit2/rules/properties/video_codec.py
new file mode 100644
index 000000000..41ad1cf5e
--- /dev/null
+++ b/lib/guessit2/rules/properties/video_codec.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+video_codec and video_profile property
+"""
+from __future__ import unicode_literals
+
+import regex as re
+
+from rebulk import Rebulk, Rule, RemoveMatch
+from ..common import dash
+from ..common.validators import seps_surround
+
+
+def video_codec():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE, abbreviations=[dash]).string_defaults(ignore_case=True)
+    rebulk.defaults(name="video_codec", validator=seps_surround)
+
+    rebulk.regex(r"Rv\d{2}", value="Real")
+    rebulk.regex("Mpeg2", value="Mpeg2")
+    rebulk.regex("DVDivX", "DivX", value="DivX")
+    rebulk.regex("XviD", value="XviD")
+    rebulk.regex("[hx]-?264(?:-?AVC)?", "MPEG-?4(?:-?AVC)", value="h264")
+    rebulk.regex("[hx]-?265(?:-?HEVC)?", "HEVC", value="h265")
+
+    # http://blog.mediacoderhq.com/h264-profiles-and-levels/
+    # http://fr.wikipedia.org/wiki/H.264
+    rebulk.defaults(name="video_profile", validator=seps_surround)
+
+    rebulk.regex('10.?bit', 'Hi10P', value='10bit')
+    rebulk.regex('8.?bit', value='8bit')
+
+    rebulk.string('BP', value='BP', tags='video_profile.rule')
+    rebulk.string('XP', 'EP', value='XP', tags='video_profile.rule')
+    rebulk.string('MP', value='MP', tags='video_profile.rule')
+    rebulk.string('HP', 'HiP', value='HP', tags='video_profile.rule')
+    rebulk.regex('Hi422P', value='Hi422P', tags='video_profile.rule')
+    rebulk.regex('Hi444PP', value='Hi444PP', tags='video_profile.rule')
+
+    rebulk.string('DXVA', value='DXVA', name='video_api')
+
+    rebulk.rules(VideoProfileRule)
+
+    return rebulk
+
+
+class VideoProfileRule(Rule):
+    """
+    Rule to validate video_profile
+    """
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        profile_list = matches.named('video_profile', lambda match: 'video_profile.rule' in match.tags)
+        ret = []
+        for profile in profile_list:
+            codec = matches.previous(profile, lambda match: match.name == 'video_codec')
+            if not codec:
+                codec = matches.next(profile, lambda match: match.name == 'video_codec')
+            if not codec:
+                ret.append(profile)
+        return ret
diff --git a/lib/guessit2/rules/properties/website.py b/lib/guessit2/rules/properties/website.py
new file mode 100644
index 000000000..8040ad73d
--- /dev/null
+++ b/lib/guessit2/rules/properties/website.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Website property.
+"""
+from __future__ import unicode_literals
+
+from pkg_resources import resource_stream  # @UnresolvedImport
+import regex as re
+
+from rebulk import Rebulk
+
+
+def website():
+    """
+    Builder for rebulk object.
+    :return: Created Rebulk object
+    :rtype: Rebulk
+    """
+    rebulk = Rebulk().regex_defaults(flags=re.IGNORECASE)
+    rebulk.defaults(name="website")
+
+    tlds = [l.strip().decode('utf-8')
+            for l in resource_stream('guessit', 'tlds-alpha-by-domain.txt').readlines()
+            if b'--' not in l][1:]  # All registered domain extension
+
+    safe_tlds = ['com', 'org', 'net']  # For sure a website extension
+    safe_subdomains = ['www']  # For sure a website subdomain
+    safe_prefix = ['co', 'com', 'org', 'net']  # Those words before a tlds are sure
+
+    rebulk.regex(r'(?:[^a-z0-9]|^)((?:\L<safe_subdomains>\.)+(?:[a-z-]+\.)+(?:\L<tlds>))(?:[^a-z0-9]|$)',
+                 safe_subdomains=safe_subdomains, tlds=tlds, children=True)
+    rebulk.regex(r'(?:[^a-z0-9]|^)((?:\L<safe_subdomains>\.)*[a-z-]+\.(?:\L<safe_tlds>))(?:[^a-z0-9]|$)',
+                 safe_subdomains=safe_subdomains, safe_tlds=safe_tlds, children=True)
+    rebulk.regex(
+        r'(?:[^a-z0-9]|^)((?:\L<safe_subdomains>\.)*[a-z-]+\.(?:\L<safe_prefix>\.)+(?:\L<tlds>))(?:[^a-z0-9]|$)',
+        safe_subdomains=safe_subdomains, safe_prefix=safe_prefix, tlds=tlds, children=True)
+
+    return rebulk
diff --git a/lib/guessit2/test/__init__.py b/lib/guessit2/test/__init__.py
new file mode 100644
index 000000000..e5be370e4
--- /dev/null
+++ b/lib/guessit2/test/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
diff --git a/lib/guessit2/test/episodes.yml b/lib/guessit2/test/episodes.yml
new file mode 100644
index 000000000..2173a258d
--- /dev/null
+++ b/lib/guessit2/test/episodes.yml
@@ -0,0 +1,1708 @@
+? __default__
+: type: episode
+
+? Series/Californication/Season 2/Californication.2x05.Vaginatown.HDTV.XviD-0TV.avi
+: title: Californication
+  season: 2
+  episode: 5
+  episode_title: Vaginatown
+  format: HDTV
+  video_codec: XviD
+  release_group: 0TV
+  container: avi
+
+? Series/dexter/Dexter.5x02.Hello,.Bandit.ENG.-.sub.FR.HDTV.XviD-AlFleNi-TeaM.[tvu.org.ru].avi
+: title: Dexter
+  season: 5
+  episode: 2
+  episode_title: Hello, Bandit
+  language: English
+  subtitle_language: French
+  format: HDTV
+  video_codec: XviD
+  release_group: AlFleNi-TeaM
+  website: tvu.org.ru
+  container: avi
+
+? Series/Treme/Treme.1x03.Right.Place,.Wrong.Time.HDTV.XviD-NoTV.avi
+: title: Treme
+  season: 1
+  episode: 3
+  episode_title: Right Place, Wrong Time
+  format: HDTV
+  video_codec: XviD
+  release_group: NoTV
+
+? Series/Duckman/Duckman - S1E13 Joking The Chicken (unedited).avi
+: title: Duckman
+  season: 1
+  episode: 13
+  episode_title: Joking The Chicken
+
+? Series/Simpsons/Saison 12 Français/Simpsons,.The.12x08.A.Bas.Le.Sergent.Skinner.FR.avi
+: title: The Simpsons
+  season: 12
+  episode: 8
+  episode_title: A Bas Le Sergent Skinner
+  language: French
+
+? Series/Duckman/Duckman - 101 (01) - 20021107 - I, Duckman.avi
+: title: Duckman
+  season: 1
+  episode: 1
+  episode_title: I, Duckman
+  date: 2002-11-07
+
+? Series/Simpsons/Saison 12 Français/Simpsons,.The.12x08.A.Bas.Le.Sergent.Skinner.FR.avi
+: title: The Simpsons
+  season: 12
+  episode: 8
+  episode_title: A Bas Le Sergent Skinner
+  language: French
+
+? Series/Futurama/Season 3 (mkv)/[™] Futurama - S03E22 - Le chef de fer à 30% ( 30 Percent Iron Chef ).mkv
+: title: Futurama
+  season: 3
+  episode: 22
+  episode_title: Le chef de fer à 30%
+
+? Series/The Office/Season 6/The Office - S06xE01.avi
+: title: The Office
+  season: 6
+  episode: 1
+
+? series/The Office/Season 4/The Office [401] Fun Run.avi
+: title: The Office
+  season: 4
+  episode: 1
+  episode_title: Fun Run
+
+? Series/Mad Men Season 1 Complete/Mad.Men.S01E01.avi
+: title: Mad Men
+  season: 1
+  episode: 1
+  other: Complete
+
+? series/Psych/Psych S02 Season 2 Complete English DVD/Psych.S02E02.65.Million.Years.Off.avi
+: title: Psych
+  season: 2
+  episode: 2
+  episode_title: 65 Million Years Off
+  language: english
+  format: DVD
+  other: Complete
+
+? series/Psych/Psych S02 Season 2 Complete English DVD/Psych.S02E03.Psy.Vs.Psy.Français.srt
+: title: Psych
+  season: 2
+  episode: 3
+  episode_title: Psy Vs Psy
+  format: DVD
+  language: English
+  subtitle_language: French
+  other: Complete
+
+? Series/Pure Laine/Pure.Laine.1x01.Toutes.Couleurs.Unies.FR.(Québec).DVB-Kceb.[tvu.org.ru].avi
+: title: Pure Laine
+  season: 1
+  episode: 1
+  episode_title: Toutes Couleurs Unies
+  format: DVB
+  release_group: Kceb
+  language: french
+  website: tvu.org.ru
+
+? Series/Pure Laine/2x05 - Pure Laine - Je Me Souviens.avi
+: title: Pure Laine
+  season: 2
+  episode: 5
+  episode_title: Je Me Souviens
+
+? Series/Tout sur moi/Tout sur moi - S02E02 - Ménage à trois (14-01-2008) [Rip by Ampli].avi
+: title: Tout sur moi
+  season: 2
+  episode: 2
+  episode_title: Ménage à trois
+  date: 2008-01-14
+
+? The.Mentalist.2x21.18-5-4.ENG.-.sub.FR.HDTV.XviD-AlFleNi-TeaM.[tvu.org.ru].avi
+: title: The Mentalist
+  season: 2
+  episode: 21
+  episode_title: 18-5-4
+  language: english
+  subtitle_language: french
+  format: HDTV
+  video_codec: XviD
+  release_group: AlFleNi-TeaM
+  website: tvu.org.ru
+
+? series/__ Incomplete __/Dr Slump (Catalan)/Dr._Slump_-_003_DVB-Rip_Catalan_by_kelf.avi
+: title: Dr Slump
+  episode: 3
+  format: DVB
+  language: catalan
+
+# Disabling this test because it just doesn't looks like a serie ...
+#? series/Ren and Stimpy - Black_hole_[DivX].avi
+#: title: Ren and Stimpy
+#  episode_title: Black hole
+#  video_codec: DivX
+
+# Disabling this test because it just doesn't looks like a serie ...
+# ? Series/Walt Disney/Donald.Duck.-.Good.Scouts.[www.bigernie.jump.to].avi
+#: title: Donald Duck
+#  episode_title: Good Scouts
+#  website: www.bigernie.jump.to
+
+? Series/Neverwhere/Neverwhere.05.Down.Street.[tvu.org.ru].avi
+: title: Neverwhere
+  episode: 5
+  episode_title: Down Street
+  website: tvu.org.ru
+
+? Series/South Park/Season 4/South.Park.4x07.Cherokee.Hair.Tampons.DVDRip.[tvu.org.ru].avi
+: title: South Park
+  season: 4
+  episode: 7
+  episode_title: Cherokee Hair Tampons
+  format: DVD
+  website: tvu.org.ru
+
+? Series/Kaamelott/Kaamelott - Livre V - Ep 23 - Le Forfait.avi
+: title: Kaamelott
+  alternativeTitle: Livre V
+  episode: 23
+  episode_title: Le Forfait
+
+? Series/Duckman/Duckman - 110 (10) - 20021218 - Cellar Beware.avi
+: title: Duckman
+  season: 1
+  episode: 10
+  date: 2002-12-18
+  episode_title: Cellar Beware
+
+# Removing this test because it doesn't look like a series
+# ? Series/Ren & Stimpy/Ren And Stimpy - Onward & Upward-Adult Party Cartoon.avi
+# : title: Ren And Stimpy
+#   episode_title: Onward & Upward-Adult Party Cartoon
+
+? Series/Breaking Bad/Minisodes/Breaking.Bad.(Minisodes).01.Good.Cop.Bad.Cop.WEBRip.XviD.avi
+: title: Breaking Bad
+  episode_format: Minisode
+  episode: 1
+  episode_title: Good Cop Bad Cop
+  format: WEBRip
+  video_codec: XviD
+
+? Series/My Name Is Earl/My.Name.Is.Earl.S01Extras.-.Bad.Karma.DVDRip.XviD.avi
+: title: My Name Is Earl
+  season: 1
+  episode_title: Extras - Bad Karma
+  format: DVD
+  episode_details: Extras
+  video_codec: XviD
+
+? series/Freaks And Geeks/Season 1/Episode 4 - Kim Kelly Is My Friend-eng(1).srt
+: title: Freaks And Geeks
+  season: 1
+  episode: 4
+  episode_title: Kim Kelly Is My Friend
+  subtitle_language: English  # This is really a subtitle_language, despite guessit 1.x assert for language.
+
+? /mnt/series/The Big Bang Theory/S01/The.Big.Bang.Theory.S01E01.mkv
+: title: The Big Bang Theory
+  season: 1
+  episode: 1
+
+? /media/Parks_and_Recreation-s03-e01.mkv
+: title: Parks and Recreation
+  season: 3
+  episode: 1
+
+? /media/Parks_and_Recreation-s03-e02-Flu_Season.mkv
+: title: Parks and Recreation
+  season: 3
+  episode_title: Flu Season
+  episode: 2
+
+? /media/Parks_and_Recreation-s03-x01.mkv
+: title: Parks and Recreation
+  season: 3
+  episode: 1
+
+? /media/Parks_and_Recreation-s03-x02-Gag_Reel.mkv
+: title: Parks and Recreation
+  season: 3
+  episode: 2
+  episode_title: Gag Reel
+
+? /media/Band_of_Brothers-e01-Currahee.mkv
+: title: Band of Brothers
+  episode: 1
+  episode_title: Currahee
+
+? /media/Band_of_Brothers-x02-We_Stand_Alone_Together.mkv
+: title: Band of Brothers
+  bonus: 2
+  bonus_title: We Stand Alone Together
+
+? /TV Shows/Mad.M-5x9.mkv
+: title: Mad M
+  season: 5
+  episode: 9
+
+? /TV Shows/new.girl.117.hdtv-lol.mp4
+: title: new girl
+  season: 1
+  episode: 17
+  format: HDTV
+  release_group: lol
+
+? Kaamelott - 5x44x45x46x47x48x49x50.avi
+: title: Kaamelott
+  season: 5
+  episode: [44, 45, 46, 47, 48, 49, 50]
+
+? Example S01E01-02.avi
+? Example S01E01E02.avi
+: title: Example
+  season: 1
+  episode: [1, 2]
+
+? Series/Baccano!/Baccano!_-_T1_-_Trailer_-_[Ayu](dae8173e).mkv
+: title: Baccano!
+  other: Trailer
+  release_group: Ayu
+  episode_title: T1
+  crc32: dae8173e
+
+? Series/Doctor Who (2005)/Season 06/Doctor Who (2005) - S06E01 - The Impossible Astronaut (1).avi
+: title: Doctor Who
+  year: 2005
+  season: 6
+  episode: 1
+  episode_title: The Impossible Astronaut
+
+? The Sopranos - [05x07] - In Camelot.mp4
+: title: The Sopranos
+  season: 5
+  episode: 7
+  episode_title: In Camelot
+
+? The.Office.(US).1x03.Health.Care.HDTV.XviD-LOL.avi
+: title: The Office
+  country: US
+  season: 1
+  episode: 3
+  episode_title: Health Care
+  format: HDTV
+  video_codec: XviD
+  release_group: LOL
+
+? /Volumes/data-1/Series/Futurama/Season 3/Futurama_-_S03_DVD_Bonus_-_Deleted_Scenes_Part_3.ogm
+: title: Futurama
+  season: 3
+  part: 3
+  other: Bonus
+  episode_title: Deleted Scenes
+  format: DVD
+
+? Ben.and.Kate.S01E02.720p.HDTV.X264-DIMENSION.mkv
+: title: Ben and Kate
+  season: 1
+  episode: 2
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: DIMENSION
+
+? /volume1/TV Series/Drawn Together/Season 1/Drawn Together 1x04 Requiem for a Reality Show.avi
+: title: Drawn Together
+  season: 1
+  episode: 4
+  episode_title: Requiem for a Reality Show
+
+? Sons.of.Anarchy.S05E06.720p.WEB.DL.DD5.1.H.264-CtrlHD.mkv
+: title: Sons of Anarchy
+  season: 5
+  episode: 6
+  screen_size: 720p
+  format: WEB-DL
+  audio_channels: "5.1"
+  audio_codec: DolbyDigital
+  video_codec: h264
+  release_group: CtrlHD
+
+? /media/bdc64bfe-e36f-4af8-b550-e6fd2dfaa507/TV_Shows/Doctor Who (2005)/Saison 6/Doctor Who (2005) - S06E13 - The Wedding of River Song.mkv
+: title: Doctor Who
+  season: 6
+  episode: 13
+  year: 2005
+  episode_title: The Wedding of River Song
+  uuid: bdc64bfe-e36f-4af8-b550-e6fd2dfaa507
+
+? /mnt/videos/tvshows/Doctor Who/Season 06/E13 - The Wedding of River Song.mkv
+: title: Doctor Who
+  season: 6
+  episode: 13
+  episode_title: The Wedding of River Song
+
+? The.Simpsons.S24E03.Adventures.in.Baby-Getting.720p.WEB-DL.DD5.1.H.264-CtrlHD.mkv
+: title: The Simpsons
+  season: 24
+  episode: 3
+  episode_title: Adventures in Baby-Getting
+  screen_size: 720p
+  format: WEB-DL
+  audio_channels: "5.1"
+  audio_codec: DolbyDigital
+  video_codec: h264
+  release_group: CtrlHD
+
+? /home/disaster/Videos/TV/Merlin/merlin_2008.5x02.arthurs_bane_part_two.repack.720p_hdtv_x264-fov.mkv
+: title: merlin
+  season: 5
+  episode: 2
+  part: 2
+  episode_title: arthurs bane
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: fov
+  year: 2008
+  other: Proper
+  proper_count: 1
+
+? "Da Vinci's Demons - 1x04 - The Magician.mkv"
+: title: "Da Vinci's Demons"
+  season: 1
+  episode: 4
+  episode_title: The Magician
+
+? CSI.S013E18.Sheltered.720p.WEB-DL.DD5.1.H.264.mkv
+: title: CSI
+  season: 13
+  episode: 18
+  episode_title: Sheltered
+  screen_size: 720p
+  format: WEB-DL
+  audio_channels: "5.1"
+  audio_codec: DolbyDigital
+  video_codec: h264
+
+? Game of Thrones S03E06 1080i HDTV DD5.1 MPEG2-TrollHD.ts
+: title: Game of Thrones
+  season: 3
+  episode: 6
+  screen_size: 1080i
+  format: HDTV
+  audio_channels: "5.1"
+  audio_codec: DolbyDigital
+  video_codec: Mpeg2
+  release_group: TrollHD
+
+? gossip.girl.s01e18.hdtv.xvid-2hd.eng.srt
+: title: gossip girl
+  season: 1
+  episode: 18
+  format: HDTV
+  video_codec: XviD
+  release_group: 2hd
+  subtitle_language: english
+
+? Wheels.S03E01E02.720p.HDTV.x264-IMMERSE.mkv
+: title: Wheels
+  season: 3
+  episode: [1, 2]
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: IMMERSE
+
+? Wheels.S03E01-02.720p.HDTV.x264-IMMERSE.mkv
+: title: Wheels
+  season: 3
+  episode: [1, 2]
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: IMMERSE
+
+? Wheels.S03E01-E02.720p.HDTV.x264-IMMERSE.mkv
+: title: Wheels
+  season: 3
+  episode: [1, 2]
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: IMMERSE
+
+? Wheels.S03E01-04.720p.HDTV.x264-IMMERSE.mkv
+: title: Wheels
+  season: 3
+  episode: [1, 2, 3, 4]
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: IMMERSE
+
+? Marvels.Agents.of.S.H.I.E.L.D.S01E06.720p.HDTV.X264-DIMENSION.mkv
+: title: Marvels Agents of S H I E L D
+  season: 1
+  episode: 6
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: DIMENSION
+
+? Marvels.Agents.of.S.H.I.E.L.D..S01E06.720p.HDTV.X264-DIMENSION.mkv
+: title: Marvels Agents of S H I E L D
+  season: 1
+  episode: 6
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: DIMENSION
+
+? Series/Friday Night Lights/Season 1/Friday Night Lights S01E19 - Ch-Ch-Ch-Ch-Changes.avi
+: title: Friday Night Lights
+  season: 1
+  episode: 19
+  episode_title: Ch-Ch-Ch-Ch-Changes
+
+? Dexter Saison VII FRENCH.BDRip.XviD-MiND.nfo
+: title: Dexter
+  season: 7
+  video_codec: XviD
+  language: French
+  format: BluRay
+  release_group: MiND
+
+? Dexter Saison sept FRENCH.BDRip.XviD-MiND.nfo
+: title: Dexter
+  season: 7
+  video_codec: XviD
+  language: French
+  format: BluRay
+  release_group: MiND
+
+? "Pokémon S16 - E29 - 1280*720 HDTV VF.mkv"
+: title: Pokémon
+  format: HDTV
+  language: French
+  season: 16
+  episode: 29
+  screen_size: 720p
+
+? One.Piece.E576.VOSTFR.720p.HDTV.x264-MARINE-FORD.mkv
+: episode: 576
+  video_codec: h264
+  format: HDTV
+  title: One Piece
+  release_group: MARINE-FORD
+  subtitle_language: French
+  screen_size: 720p
+
+? Dexter.S08E12.FINAL.MULTi.1080p.BluRay.x264-MiND.mkv
+: video_codec: h264
+  episode: 12
+  season: 8
+  format: BluRay
+  title: Dexter
+  other: FINAL
+  language: Multiple languages
+  release_group: MiND
+  screen_size: 1080p
+
+? One Piece - E623 VOSTFR HD [www.manga-ddl-free.com].mkv
+: website: www.manga-ddl-free.com
+  episode: 623
+  subtitle_language: French
+  title: One Piece
+  other: HD
+
+? Falling Skies Saison 1.HDLight.720p.x264.VFF.mkv
+: language: French
+  screen_size: 720p
+  season: 1
+  title: Falling Skies
+  video_codec: h264
+  other: HDLight
+
+? Sleepy.Hollow.S01E09.720p.WEB-DL.DD5.1.H.264-BP.mkv
+: episode: 9
+  video_codec: h264
+  format: WEB-DL
+  title: Sleepy Hollow
+  audio_channels: "5.1"
+  screen_size: 720p
+  season: 1
+  video_profile: BP
+  audio_codec: DolbyDigital
+
+? Sleepy.Hollow.S01E09.720p.WEB-DL.DD5.1.H.264-BS.mkv
+: episode: 9
+  video_codec: h264
+  format: WEB-DL
+  title: Sleepy Hollow
+  audio_channels: "5.1"
+  screen_size: 720p
+  season: 1
+  release_group: BS
+  audio_codec: DolbyDigital
+
+? Battlestar.Galactica.S00.Pilot.FRENCH.DVDRip.XviD-NOTAG.avi
+: title: Battlestar Galactica
+  season: 0
+  episode_details: Pilot
+  episode_title: Pilot
+  language: French
+  format: DVD
+  video_codec: XviD
+  release_group: NOTAG
+
+? The Big Bang Theory S00E00 Unaired Pilot VOSTFR TVRip XviD-VioCs
+: title: The Big Bang Theory
+  season: 0
+  episode: 0
+  subtitle_language: French
+  format: TV
+  video_codec: XviD
+  release_group: VioCs
+  episode_details: [Unaired, Pilot]
+
+? The Big Bang Theory S01E00 PROPER Unaired Pilot TVRip XviD-GIGGITY
+: title: The Big Bang Theory
+  season: 1
+  episode: 0
+  format: TV
+  video_codec: XviD
+  release_group: GIGGITY
+  other: Proper
+  proper_count: 1
+  episode_details: [Unaired, Pilot]
+
+? Pawn.Stars.S2014E18.720p.HDTV.x264-KILLERS
+: title: Pawn Stars
+  season: 2014
+  year: 2014
+  episode: 18
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: KILLERS
+
+? 2.Broke.Girls.S03E10.480p.HDTV.x264-mSD.mkv
+: title: 2 Broke Girls
+  season: 3
+  episode: 10
+  screen_size: 480p
+  format: HDTV
+  video_codec: h264
+  release_group: mSD
+
+? House.of.Cards.2013.S02E03.1080p.NF.WEBRip.DD5.1.x264-NTb.mkv
+: title: House of Cards
+  year: 2013
+  season: 2
+  episode: 3
+  screen_size: 1080p
+  other: Netflix
+  format: WEBRip
+  audio_channels: "5.1"
+  audio_codec: DolbyDigital
+  video_codec: h264
+  release_group: NTb
+
+? the.100.109.hdtv-lol.mp4
+: title: the 100
+  season: 1
+  episode: 9
+  format: HDTV
+  release_group: lol
+
+? Criminal.Minds.5x03.Reckoner.ENG.-.sub.FR.HDTV.XviD-STi.[tvu.org.ru].avi
+: title: Criminal Minds
+  language: English
+  subtitle_language: French
+  season: 5
+  episode: 3
+  video_codec: XviD
+  format: HDTV
+  website: tvu.org.ru
+  release_group: STi
+  episode_title: Reckoner
+
+? 03-Criminal.Minds.avi
+: title: Criminal Minds
+  episode: 3
+
+? '[Evil-Saizen]_Laughing_Salesman_14_[DVD][1C98686A].mkv'
+: crc32: 1C98686A
+  episode: 14
+  format: DVD
+  release_group: Evil-Saizen
+  title: Laughing Salesman
+
+? '[Kaylith] Zankyou no Terror - 04 [480p][B4D4514E].mp4'
+: crc32: B4D4514E
+  episode: 4
+  release_group: Kaylith
+  screen_size: 480p
+  title: Zankyou no Terror
+
+? '[PuyaSubs!] Seirei Tsukai no Blade Dance - 05 [720p][32DD560E].mkv'
+: crc32: 32DD560E
+  episode: 5
+  release_group: PuyaSubs!
+  screen_size: 720p
+  title: Seirei Tsukai no Blade Dance
+
+? '[Doremi].Happiness.Charge.Precure.27.[1280x720].[DC91581A].mkv'
+: crc32: DC91581A
+  episode: 27
+  release_group: Doremi
+  screen_size: 720p
+  title: Happiness Charge Precure
+
+? "[Daisei] Free!:Iwatobi Swim Club - 01 ~ (BD 720p 10-bit AAC) [99E8E009].mkv"
+: audio_codec: AAC
+  crc32: 99E8E009
+  episode: 1
+  format: BluRay
+  release_group: Daisei
+  screen_size: 720p
+  title: Free!:Iwatobi Swim Club
+  video_profile: 10bit
+
+? '[Tsundere] Boku wa Tomodachi ga Sukunai - 03 [BDRip h264 1920x1080 10bit FLAC][AF0C22CC].mkv'
+: audio_codec: FLAC
+  crc32: AF0C22CC
+  episode: 3
+  format: BluRay
+  release_group: Tsundere
+  screen_size: 1080p
+  title: Boku wa Tomodachi ga Sukunai
+  video_codec: h264
+  video_profile: 10bit
+
+? '[t.3.3.d]_Mikakunin_de_Shinkoukei_-_12_[720p][5DDC1352].mkv'
+: crc32: 5DDC1352
+  episode: 12
+  screen_size: 720p
+  title: Mikakunin de Shinkoukei
+  release_group: t.3.3.d
+
+? '[Anime-Koi] Sabagebu! - 06 [h264-720p][ABB3728A].mkv'
+: crc32: ABB3728A
+  episode: 6
+  release_group: Anime-Koi
+  screen_size: 720p
+  title: Sabagebu!
+  video_codec: h264
+
+? '[aprm-Diogo4D] [BD][1080p] Nagi no Asukara 08 [4D102B7C].mkv'
+: crc32: 4D102B7C
+  episode: 8
+  format: BluRay
+  release_group: aprm-Diogo4D
+  screen_size: 1080p
+  title: Nagi no Asukara
+
+? '[Akindo-SSK] Zankyou no Terror - 05 [720P][Sub_ITA][F5CCE87C].mkv'
+: crc32: F5CCE87C
+  episode: 5
+  release_group: Akindo-SSK
+  screen_size: 720p
+  title: Zankyou no Terror
+  subtitle_language: it
+
+? Naruto Shippuden Episode 366 VOSTFR.avi
+: episode: 366
+  title: Naruto Shippuden
+  subtitle_language: fr
+
+? Naruto Shippuden Episode 366v2 VOSTFR.avi
+: episode: 366
+  version: 2
+  title: Naruto Shippuden
+  subtitle_language: fr
+
+? '[HorribleSubs] Ao Haru Ride - 06 [480p].mkv'
+: episode: 6
+  release_group: HorribleSubs
+  screen_size: 480p
+  title: Ao Haru Ride
+
+? '[DeadFish] Tari Tari - 01 [BD][720p][AAC].mp4'
+: audio_codec: AAC
+  episode: 1
+  format: BluRay
+  release_group: DeadFish
+  screen_size: 720p
+  title: Tari Tari
+
+? '[NoobSubs] Sword Art Online II 06 (720p 8bit AAC).mp4'
+: audio_codec: AAC
+  episode: 6
+  release_group: NoobSubs
+  screen_size: 720p
+  title: Sword Art Online II
+  video_profile: 8bit
+
+? '[DeadFish] 01 - Tari Tari [BD][720p][AAC].mp4'
+: audio_codec: AAC
+  episode: 1
+  format: BluRay
+  release_group: DeadFish
+  screen_size: 720p
+  title: Tari Tari
+
+? '[NoobSubs] 06 Sword Art Online II (720p 8bit AAC).mp4'
+: audio_codec: AAC
+  episode: 6
+  release_group: NoobSubs
+  screen_size: 720p
+  title: Sword Art Online II
+  video_profile: 8bit
+
+? '[DeadFish] 12 - Tari Tari [BD][720p][AAC].mp4'
+: audio_codec: AAC
+  episode: 12
+  format: BluRay
+  release_group: DeadFish
+  screen_size: 720p
+  title: Tari Tari
+
+? Something.Season.2.1of4.Ep.Title.HDTV.torrent
+: episode_count: 4
+  episode: 1
+  format: HDTV
+  season: 2
+  title: Something
+  episode_title: Title
+  container: torrent
+
+? Something.Season.2of5.3of9.Ep.Title.HDTV.torrent
+: episode_count: 9
+  episode: 3
+  format: HDTV
+  season: 2
+  season_count: 5
+  title: Something
+  episode_title: Title
+  container: torrent
+
+? Something.Other.Season.3of5.Complete.HDTV.torrent
+: format: HDTV
+  other: Complete
+  season: 3
+  season_count: 5
+  title: Something Other
+  container: torrent
+
+? Something.Other.Season.1-3.avi
+: season: [1, 2, 3]
+  title: Something Other
+
+? Something.Other.Season.1&3.avi
+: season: [1, 3]
+  title: Something Other
+
+? Something.Other.Season.1&3-1to12ep.avi
+: season: [1, 3]
+  title: Something Other
+
+? W2Test.123.HDTV.XViD-FlexGet
+: episode: 23
+  season: 1
+  format: HDTV
+  release_group: FlexGet
+  title: W2Test
+  video_codec: XviD
+
+? W2Test.123.HDTV.XViD-FlexGet
+: options: --episode-prefer-number
+  episode: 123
+  format: HDTV
+  release_group: FlexGet
+  title: W2Test
+  video_codec: XviD
+
+? FooBar.0307.PDTV-FlexGet
+: episode: 7
+  format: DVB
+  release_group: FlexGet
+  season: 3
+  title: FooBar
+
+? FooBar.0307.PDTV-FlexGet
+? FooBar.307.PDTV-FlexGet
+: options: --episode-prefer-number
+  episode: 307
+  format: DVB
+  release_group: FlexGet
+  title: FooBar
+
+? FooBar.07.PDTV-FlexGet
+: options: --episode-prefer-number
+  episode: 7
+  format: DVB
+  release_group: FlexGet
+  title: FooBar
+
+? FooBar.7.PDTV-FlexGet
+: options: --episode-prefer-number
+  episode: 7
+  format: DVB
+  release_group: FlexGet
+  title: FooBar
+
+? FooBar.0307.PDTV-FlexGet
+: episode: 7
+  format: DVB
+  release_group: FlexGet
+  season: 3
+  title: FooBar
+
+? FooBar.307.PDTV-FlexGet
+: episode: 7
+  format: DVB
+  release_group: FlexGet
+  season: 3
+  title: FooBar
+
+? FooBar.07.PDTV-FlexGet
+: episode: 7
+  format: DVB
+  release_group: FlexGet
+  title: FooBar
+
+? FooBar.07v4.PDTV-FlexGet
+: episode: 7
+  version: 4
+  format: DVB
+  release_group: FlexGet
+  title: FooBar
+
+? FooBar.7.PDTV-FlexGet
+: format: DVB
+  release_group: FlexGet
+  title: FooBar 7
+  type: movie
+
+? FooBar.7.PDTV-FlexGet
+: options: -t episode
+  episode: 7
+  format: DVB
+  release_group: FlexGet
+  title: FooBar
+
+? FooBar.7v3.PDTV-FlexGet
+: options: -t episode
+  episode: 7
+  version: 3
+  format: DVB
+  release_group: FlexGet
+  title: FooBar
+
+? Test.S02E01.hdtv.real.proper
+: episode: 1
+  format: HDTV
+  other: Proper
+  proper_count: 2
+  season: 2
+  title: Test
+
+? Real.Test.S02E01.hdtv.proper
+: episode: 1
+  format: HDTV
+  other: Proper
+  proper_count: 1
+  season: 2
+  title: Real Test
+
+? Test.Real.S02E01.hdtv.proper
+: episode: 1
+  format: HDTV
+  other: Proper
+  proper_count: 1
+  season: 2
+  title: Test Real
+
+? Test.S02E01.hdtv.proper
+: episode: 1
+  format: HDTV
+  other: Proper
+  proper_count: 1
+  season: 2
+  title: Test
+
+? Test.S02E01.hdtv.real.repack.proper
+: episode: 1
+  format: HDTV
+  other: Proper
+  proper_count: 3
+  season: 2
+  title: Test
+
+? Date.Show.03-29-2012.HDTV.XViD-FlexGet
+: date: 2012-03-29
+  format: HDTV
+  release_group: FlexGet
+  title: Date Show
+  video_codec: XviD
+
+? Something.1x5.Season.Complete-FlexGet
+: episode: 5
+  other: Complete
+  season: 1
+  title: Something
+  release_group: FlexGet
+
+? Something Seasons 1 & 2 - Complete
+: other: Complete
+  season:
+  - 1
+  - 2
+  title: Something
+
+? Something Seasons 4 Complete
+: other: Complete
+  season: 4
+  title: Something
+
+? Something.1xAll.Season.Complete-FlexGet
+: other: Complete
+  season: 1
+  title: Something
+  release_group: FlexGet
+
+? Something.1xAll-FlexGet
+: other: Complete
+  season: 1
+  title: Something
+  episode_title: FlexGet  # 1.x guess this as release_group, but it's better to guess it as episode_title
+
+? FlexGet.US.S2013E14.Title.Here.720p.HDTV.AAC5.1.x264-NOGRP
+: audio_channels: '5.1'
+  audio_codec: AAC
+  country: US
+  episode: 14
+  format: HDTV
+  release_group: NOGRP
+  screen_size: 720p
+  season: 2013
+  title: FlexGet
+  episode_title: Title Here
+  video_codec: h264
+  year: 2013
+
+? FlexGet.14.of.21.Title.Here.720p.HDTV.AAC5.1.x264-NOGRP
+: audio_channels: '5.1'
+  audio_codec: AAC
+  episode_count: 21
+  episode: 14
+  format: HDTV
+  release_group: NOGRP
+  screen_size: 720p
+  title: FlexGet
+  episode_title: Title Here
+  video_codec: h264
+
+? FlexGet.Series.2013.14.of.21.Title.Here.720p.HDTV.AAC5.1.x264-NOGRP
+: audio_channels: '5.1'
+  audio_codec: AAC
+  episode_count: 21
+  episode: 14
+  format: HDTV
+  release_group: NOGRP
+  screen_size: 720p
+  season: 2013
+  title: FlexGet
+  episode_title: Title Here
+  video_codec: h264
+  year: 2013
+
+? Something.S04E05E09
+: episode: # 1.x guessit this as a range from 5 to 9. But not sure if it should ...
+  - 5
+  - 9
+  season: 4
+  title: Something
+
+? FooBar 360 1080i
+: options: --episode-prefer-number
+  episode: 360
+  screen_size: 1080i
+  title: FooBar
+
+? FooBar 360 1080i
+: episode: 60
+  season: 3
+  screen_size: 1080i
+  title: FooBar
+
+? FooBar 360
+: screen_size: 360p
+  title: FooBar
+
+? BarFood christmas special HDTV
+: options: --expected-title BarFood
+  format: HDTV
+  title: BarFood
+  episode_title: christmas special
+  episode_details: Special
+
+? Something.2008x12.13-FlexGet
+: title: Something
+  date: 2008-12-13
+  episode_title: FlexGet
+
+? '[Ignored] Test 12'
+: episode: 12
+  release_group: Ignored
+  title: Test
+
+? '[FlexGet] Test 12'
+: episode: 12
+  release_group: FlexGet
+  title: Test
+
+? Test.13.HDTV-Ignored
+: episode: 13
+  format: HDTV
+  release_group: Ignored
+  title: Test
+
+? Test.13.HDTV-Ignored
+: options: --expected-series test
+  episode: 13
+  format: HDTV
+  release_group: Ignored
+  title: Test
+
+? Test.13.HDTV-Ignored
+: title: Test
+  episode: 13
+  format: HDTV
+  release_group: Ignored
+
+? Test.13.HDTV-Ignored
+: episode: 13
+  format: HDTV
+  release_group: Ignored
+  title: Test
+
+? Test.13.HDTV-FlexGet
+: episode: 13
+  format: HDTV
+  release_group: FlexGet
+  title: Test
+
+? Test.14.HDTV-Name
+: episode: 14
+  format: HDTV
+  release_group: Name
+  title: Test
+
+? Real.Time.With.Bill.Maher.2014.10.31.HDTV.XviD-AFG.avi
+: date: 2014-10-31
+  format: HDTV
+  release_group: AFG
+  title: Real Time With Bill Maher
+  video_codec: XviD
+
+? Arrow.S03E21.Al.Sah-Him.1080p.WEB-DL.DD5.1.H.264-BS.mkv
+: title: Arrow
+  season: 3
+  episode: 21
+  episode_title: Al Sah-Him
+  screen_size: 1080p
+  audio_codec: DolbyDigital
+  audio_channels: "5.1"
+  video_codec: h264
+  release_group: BS
+  format: WEB-DL
+
+? How to Make It in America - S02E06 - I'm Sorry, Who's Yosi?.mkv
+: title: How to Make It in America
+  season: 2
+  episode: 6
+  episode_title: I'm Sorry, Who's Yosi?
+
+? 24.S05E07.FRENCH.DVDRip.XviD-FiXi0N.avi
+: episode: 7
+  format: DVD
+  language: fr
+  season: 5
+  title: '24'
+  video_codec: XviD
+  release_group: FiXi0N
+
+? 12.Monkeys.S01E12.FRENCH.BDRip.x264-VENUE.mkv
+: episode: 12
+  format: BluRay
+  language: fr
+  release_group: VENUE
+  season: 1
+  title: 12 Monkeys
+  video_codec: h264
+
+? The.Daily.Show.2015.07.01.Kirsten.Gillibrand.Extended.720p.CC.WEBRip.AAC2.0.x264-BTW.mkv
+: audio_channels: '2.0'
+  audio_codec: AAC
+  date: 2015-07-01
+  format: WEBRip
+  other: CC
+  release_group: BTW
+  screen_size: 720p
+  title: The Daily Show
+  episode_title: Kirsten Gillibrand Extended
+  video_codec: h264
+
+? The.Daily.Show.2015.07.02.Sarah.Vowell.CC.WEBRip.AAC2.0.x264-BTW.mkv
+: audio_channels: '2.0'
+  audio_codec: AAC
+  date: 2015-07-02
+  format: WEBRip
+  other: CC
+  release_group: BTW
+  title: The Daily Show
+  episode_title: Sarah Vowell
+  video_codec: h264
+
+? 90.Day.Fiance.S02E07.I.Have.To.Tell.You.Something.720p.HDTV.x264-W4F
+: episode: 7
+  format: HDTV
+  screen_size: 720p
+  season: 2
+  title: 90 Day Fiance
+  episode_title: I Have To Tell You Something
+  release_group: W4F
+
+? Doctor.Who.2005.S04E06.FRENCH.LD.DVDRip.XviD-TRACKS.avi
+: episode: 6
+  format: DVD
+  language: fr
+  release_group: TRACKS
+  season: 4
+  title: Doctor Who
+  other: LD
+  video_codec: XviD
+  year: 2005
+
+? Astro.Le.Petit.Robot.S01E01+02.FRENCH.DVDRiP.X264.INT-BOOLZ.mkv
+: episode: [1, 2]
+  format: DVD
+  language: fr
+  release_group: INT-BOOLZ
+  season: 1
+  title: Astro Le Petit Robot
+  video_codec: h264
+
+? Annika.Bengtzon.2012.E01.Le.Testament.De.Nobel.FRENCH.DVDRiP.XViD-STVFRV.avi
+: episode: 1
+  format: DVD
+  language: fr
+  release_group: STVFRV
+  title: Annika Bengtzon
+  episode_title: Le Testament De Nobel
+  video_codec: XviD
+  year: 2012
+
+? Dead.Set.02.FRENCH.LD.DVDRip.XviD-EPZ.avi
+: episode: 2
+  format: DVD
+  language: fr
+  other: LD
+  release_group: EPZ
+  title: Dead Set
+  video_codec: XviD
+
+? Phineas and Ferb S01E00 & S01E01 & S01E02
+: episode: [0, 1, 2]
+  season: 1
+  title: Phineas and Ferb
+
+? Show.Name.S01E02.S01E03.HDTV.XViD.Etc-Group
+: episode: [2, 3]
+  format: HDTV
+  release_group: Etc-Group
+  season: 1
+  title: Show Name
+  video_codec: XviD
+
+? Show Name - S01E02 - S01E03 - S01E04 - Ep Name
+: episode: [2, 3, 4]
+  season: 1
+  title: Show Name
+  episode_title: Ep Name
+
+? Show.Name.1x02.1x03.HDTV.XViD.Etc-Group
+: episode: [2, 3]
+  format: HDTV
+  release_group: Etc-Group
+  season: 1
+  title: Show Name
+  video_codec: XviD
+
+? Show Name - 1x02 - 1x03 - 1x04 - Ep Name
+: episode: [2, 3, 4]
+  season: 1
+  title: Show Name
+  episode_title: Ep Name
+
+? Show.Name.S01E02.HDTV.XViD.Etc-Group
+: episode: 2
+  format: HDTV
+  release_group: Etc-Group
+  season: 1
+  title: Show Name
+  video_codec: XviD
+
+? Show Name - S01E02 - My Ep Name
+: episode: 2
+  season: 1
+  title: Show Name
+  episode_title: My Ep Name
+
+? Show Name - S01.E03 - My Ep Name
+: episode: 3
+  season: 1
+  title: Show Name
+  episode_title: My Ep Name
+
+? Show.Name.S01E02E03.HDTV.XViD.Etc-Group
+: episode: [2, 3]
+  format: HDTV
+  release_group: Etc-Group
+  season: 1
+  title: Show Name
+  video_codec: XviD
+
+? Show Name - S01E02-03 - My Ep Name
+: episode: [2, 3]
+  season: 1
+  title: Show Name
+  episode_title: My Ep Name
+
+? Show.Name.S01.E02.E03
+: episode: [2, 3]
+  season: 1
+  title: Show Name
+
+? Show_Name.1x02.HDTV_XViD_Etc-Group
+: episode: 2
+  format: HDTV
+  release_group: Etc-Group
+  season: 1
+  title: Show Name
+  video_codec: XviD
+
+? Show Name - 1x02 - My Ep Name
+: episode: 2
+  season: 1
+  title: Show Name
+  episode_title: My Ep Name
+
+? Show_Name.1x02x03x04.HDTV_XViD_Etc-Group
+: episode: [2, 3, 4]
+  format: HDTV
+  release_group: Etc-Group
+  season: 1
+  title: Show Name
+  video_codec: XviD
+
+? Show Name - 1x02-03-04 - My Ep Name
+: episode: [2, 3, 4]
+  season: 1
+  title: Show Name
+  episode_title: My Ep Name
+
+# 1x guess this as episode 100 but 101 as episode 1 season 1.
+? Show.Name.100.Event.2010.11.23.HDTV.XViD.Etc-Group
+: date: 2010-11-23
+  season: 1
+  episode: 0
+  format: HDTV
+  release_group: Etc-Group
+  title: Show Name
+  episode_title: Event
+  video_codec: XviD
+
+? Show.Name.101.Event.2010.11.23.HDTV.XViD.Etc-Group
+: date: 2010-11-23
+  season: 1
+  episode: 1
+  format: HDTV
+  release_group: Etc-Group
+  title: Show Name
+  episode_title: Event
+  video_codec: XviD
+
+? Show.Name.2010.11.23.HDTV.XViD.Etc-Group
+: date: 2010-11-23
+  format: HDTV
+  release_group: Etc-Group
+  title: Show Name
+
+? Show Name - 2010-11-23 - Ep Name
+: date: 2010-11-23
+  title: Show Name
+  episode_title: Ep Name
+
+? Show Name Season 1 Episode 2 Ep Name
+: episode: 2
+  season: 1
+  title: Show Name
+  episode_title: Ep Name
+
+? Show.Name.S01.HDTV.XViD.Etc-Group
+: format: HDTV
+  release_group: Etc-Group
+  season: 1
+  title: Show Name
+  video_codec: XviD
+
+? Show.Name.E02-03
+: episode: [2, 3]
+  title: Show Name
+
+? Show.Name.E02.2010
+: episode: 2
+  year: 2010
+  title: Show Name
+
+? Show.Name.E23.Test
+: episode: 23
+  title: Show Name
+  episode_title: Test
+
+? Show.Name.Part.3.HDTV.XViD.Etc-Group
+: part: 3
+  title: Show Name
+  format: HDTV
+  video_codec: XviD
+  release_group: Etc-Group
+  type: movie
+  # Fallback to movie type because we can't tell it's a series ...
+
+? Show.Name.Part.1.and.Part.2.Blah-Group
+: part: [1, 2]
+  title: Show Name
+  type: movie
+  # Fallback to movie type because we can't tell it's a series ...
+
+? Show Name - 01 - Ep Name
+: episode: 1
+  title: Show Name
+  episode_title: Ep Name
+
+? 01 - Ep Name
+: episode: 1
+  title: Ep Name
+
+? Show.Name.102.HDTV.XViD.Etc-Group
+: episode: 2
+  format: HDTV
+  release_group: Etc-Group
+  season: 1
+  title: Show Name
+  video_codec: XviD
+
+? '[HorribleSubs] Maria the Virgin Witch - 01 [720p].mkv'
+: episode: 1
+  release_group: HorribleSubs
+  screen_size: 720p
+  title: Maria the Virgin Witch
+
+? '[ISLAND]One_Piece_679_[VOSTFR]_[V1]_[8bit]_[720p]_[EB7838FC].mp4'
+: options: -E
+  crc32: EB7838FC
+  episode: 679
+  release_group: ISLAND
+  screen_size: 720p
+  title: One Piece
+  subtitle_language: fr
+  video_profile: 8bit
+  version: 1
+
+? '[ISLAND]One_Piece_679_[VOSTFR]_[8bit]_[720p]_[EB7838FC].mp4'
+: options: -E
+  crc32: EB7838FC
+  episode: 679
+  release_group: ISLAND
+  screen_size: 720p
+  title: One Piece
+  subtitle_language: fr
+  video_profile: 8bit
+
+? '[Kaerizaki-Fansub]_One_Piece_679_[VOSTFR][HD_1280x720].mp4'
+: options: -E
+  episode: 679
+  other: HD
+  release_group: Kaerizaki-Fansub
+  screen_size: 720p
+  title: One Piece
+  subtitle_language: fr
+
+? '[Kaerizaki-Fansub]_One_Piece_679_[VOSTFR][FANSUB][HD_1280x720].mp4'
+: options: -E
+  episode: 679
+  other:
+  - Fansub
+  - HD
+  release_group: Kaerizaki-Fansub
+  screen_size: 720p
+  title: One Piece
+  subtitle_language: fr
+
+? '[Kaerizaki-Fansub]_One_Piece_681_[VOSTFR][HD_1280x720]_V2.mp4'
+: options: -E
+  episode: 681
+  other: HD
+  release_group: Kaerizaki-Fansub
+  screen_size: 720p
+  title: One Piece
+  subtitle_language: fr
+  version: 2
+
+? '[Kaerizaki-Fansub] High School DxD New 04 VOSTFR HD (1280x720) V2.mp4'
+: options: -E
+  episode: 4
+  other: HD
+  release_group: Kaerizaki-Fansub
+  screen_size: 720p
+  title: High School DxD New
+  subtitle_language: fr
+  version: 2
+
+? '[Kaerizaki-Fansub] One Piece 603 VOSTFR PS VITA (960x544) V2.mp4'
+: options: -E
+  episode: 603
+  release_group: Kaerizaki-Fansub
+  screen_size: 960x544
+  title: One Piece
+  subtitle_language: fr
+  version: 2
+
+? '[Group Name] Show Name.13'
+: episode: 13
+  release_group: Group Name
+  title: Show Name
+
+? '[Group Name] Show Name - 13'
+: episode: 13
+  release_group: Group Name
+  title: Show Name
+
+? '[Group Name] Show Name 13'
+: episode: 13
+  release_group: Group Name
+  title: Show Name
+
+# [Group Name] Show Name.13-14
+# [Group Name] Show Name - 13-14
+# Show Name 13-14
+
+? '[Stratos-Subs]_Infinite_Stratos_-_12_(1280x720_H.264_AAC)_[379759DB]'
+: audio_codec: AAC
+  crc32: 379759DB
+  episode: 12
+  release_group: Stratos-Subs
+  screen_size: 720p
+  title: Infinite Stratos
+  video_codec: h264
+
+# [ShinBunBu-Subs] Bleach - 02-03 (CX 1280x720 x264 AAC)
+
+? '[SGKK] Bleach 312v1 [720p/MKV]'
+: options: -E  # guessit 1.x for episode only when version is guessed, but it's doesn't make it consistent.
+  episode: 312
+  release_group: SGKK
+  screen_size: 720p
+  title: Bleach
+  version: 1
+
+? '[Ayako]_Infinite_Stratos_-_IS_-_07_[H264][720p][EB7838FC]'
+: crc32: EB7838FC
+  episode: 7
+  release_group: Ayako
+  screen_size: 720p
+  title: Infinite Stratos
+  video_codec: h264
+
+? '[Ayako] Infinite Stratos - IS - 07v2 [H264][720p][44419534]'
+: crc32: '44419534'
+  episode: 7
+  release_group: Ayako
+  screen_size: 720p
+  title: Infinite Stratos
+  video_codec: h264
+  version: 2
+
+? '[Ayako-Shikkaku] Oniichan no Koto Nanka Zenzen Suki Janain Dakara ne - 10 [LQ][h264][720p] [8853B21C]'
+: crc32: 8853B21C
+  episode: 10
+  release_group: Ayako-Shikkaku
+  screen_size: 720p
+  title: Oniichan no Koto Nanka Zenzen Suki Janain Dakara ne
+  video_codec: h264
+
+# TODO: Add support for absolute episodes
+? Bleach - s16e03-04 - 313-314
+? Bleach.s16e03-04.313-314
+? Bleach.s16e03-04.313-314
+? Bleach - s16e03-04 - 313-314
+? Bleach.s16e03-04.313-314
+? Bleach s16e03e04 313-314
+: episode: [3, 4]
+  season: 16
+  title: Bleach
+
+? Bleach - 313-314
+: options: -E
+  episode: [313, 314]
+  title: Bleach
+
+? '[ShinBunBu-Subs] Bleach - 02-03 (CX 1280x720 x264 AAC)'
+: audio_codec: AAC
+  episode: [2, 3]
+  release_group: ShinBunBu-Subs
+  screen_size: 720p
+  title: Bleach
+  video_codec: h264
+
+? 003. Show Name - Ep Name.avi
+: episode: 3
+  title: Show Name
+  episode_title: Ep Name
+
+? 003-004. Show Name - Ep Name.avi
+: episode: [3, 4]
+  title: Show Name
+  episode_title: Ep Name
+
+? One Piece - 102
+: episode: 2
+  season: 1
+  title: One Piece
+
+? "[ACX]_Wolf's_Spirit_001.mkv"
+: episode: 1
+  release_group: ACX
+  title: "Wolf's Spirit"
+
+? Project.Runway.S14E00.and.S14E01.(Eng.Subs).SDTV.x264-[2Maverick].mp4
+: episode: [0, 1]
+  format: TV
+  release_group: 2Maverick
+  season: 14
+  title: Project Runway
+  subtitle_language: en
+  video_codec: h264
+
+? '[Hatsuyuki-Kaitou]_Fairy_Tail_2_-_16-20_[720p][10bit].torrent'
+: episode: [16, 17, 18, 19, 20]
+  release_group: Hatsuyuki-Kaitou
+  screen_size: 720p
+  title: Fairy Tail 2
+  video_profile: 10bit
+
+? '[Hatsuyuki-Kaitou]_Fairy_Tail_2_-_16-20_(191-195)_[720p][10bit].torrent'
+: options: -E
+  episode: [16, 17, 18, 19, 20, 191, 192, 193, 194, 195]
+  release_group: Hatsuyuki-Kaitou
+  screen_size: 720p
+  title: Fairy Tail 2
+
+? "Looney Tunes 1940x01 Porky's Last Stand.mkv"
+: episode: 1
+  season: 1940
+  title: Looney Tunes
+  episode_title: Porky's Last Stand
+  year: 1940
+
+? The.Good.Wife.S06E01.E10.720p.WEB-DL.DD5.1.H.264-CtrlHD/The.Good.Wife.S06E09.Trust.Issues.720p.WEB-DL.DD5.1.H.264-CtrlHD.mkv
+: audio_channels: '5.1'
+  audio_codec: DolbyDigital
+  episode: 9
+  format: WEB-DL
+  release_group: CtrlHD
+  screen_size: 720p
+  season: 6
+  title: The Good Wife
+  episode_title: Trust Issues
+  video_codec: h264
+
+? Fear the Walking Dead - 01x02 - So Close, Yet So Far.REPACK-KILLERS.French.C.updated.Addic7ed.com.mkv
+: episode: 2
+  language: fr
+  other: Proper
+  proper_count: 1
+  season: 1
+  title: Fear the Walking Dead
+  episode_title: So Close, Yet So Far
+
+? Fear the Walking Dead - 01x02 - En Close, Yet En Far.REPACK-KILLERS.French.C.updated.Addic7ed.com.mkv
+: episode: 2
+  language: fr
+  other: Proper
+  proper_count: 1
+  season: 1
+  title: Fear the Walking Dead
+  episode_title: En Close, Yet En Far
+
+? /av/unsorted/The.Daily.Show.2015.07.22.Jake.Gyllenhaal.720p.HDTV.x264-BATV.mkv
+: date: 2015-07-22
+  format: HDTV
+  release_group: BATV
+  screen_size: 720p
+  title: The Daily Show
+  episode_title: Jake Gyllenhaal
+  video_codec: h264
+
+? "[7.1.7.8.5] Foo Bar - 11 (H.264) [5235532D].mkv"
+: options: -E
+  episode: 11
+
+? my 720p show S01E02
+: options: -T "my 720p show"
+  title: my 720p show
+  season: 1
+  episode: 2
+
+? my 720p show S01E02 720p
+: options: -T "my 720p show"
+  title: my 720p show
+  season: 1
+  episode: 2
+  screen_size: 720p
+
+? -my 720p show S01E02
+: options: -T "re:my \d+p show"
+  screen_size: 720p
+
+? Show S01E02
+: options: -T "The Show"
+  title: Show
+  season: 1
+  episode: 2
+
+? Foo's &amp; Bars (2009) S01E01 720p XviD-2HD[AOEU]
+: episode: 1
+  release_group: 2HD[AOEU]
+  screen_size: 720p
+  season: 1
+  title: Foo's &amp; Bars
+  type: episode
+  video_codec: XviD
+  year: 2009
+
+? Date.Series.10-11-2008.XViD
+: date: 2008-11-10
+  title: Date
+  type: episode
+  video_codec: XviD
diff --git a/lib/guessit2/test/movies.yml b/lib/guessit2/test/movies.yml
new file mode 100644
index 000000000..5167622c8
--- /dev/null
+++ b/lib/guessit2/test/movies.yml
@@ -0,0 +1,788 @@
+? __default__
+: type: movie
+
+? Movies/Fear and Loathing in Las Vegas (1998)/Fear.and.Loathing.in.Las.Vegas.720p.HDDVD.DTS.x264-ESiR.mkv
+: title: Fear and Loathing in Las Vegas
+  year: 1998
+  screen_size: 720p
+  format: HD-DVD
+  audio_codec: DTS
+  video_codec: h264
+  container: mkv
+  release_group: ESiR
+
+? Movies/El Dia de la Bestia (1995)/El.dia.de.la.bestia.DVDrip.Spanish.DivX.by.Artik[SEDG].avi
+: title: El Dia de la Bestia
+  year: 1995
+  format: DVD
+  language: spanish
+  video_codec: DivX
+  release_group: Artik[SEDG]
+  container: avi
+
+? Movies/Dark City (1998)/Dark.City.(1998).DC.BDRip.720p.DTS.X264-CHD.mkv
+: title: Dark City
+  year: 1998
+  format: BluRay
+  screen_size: 720p
+  audio_codec: DTS
+  video_codec: h264
+  release_group: CHD
+
+? Movies/Sin City (BluRay) (2005)/Sin.City.2005.BDRip.720p.x264.AC3-SEPTiC.mkv
+: title: Sin City
+  year: 2005
+  format: BluRay
+  screen_size: 720p
+  video_codec: h264
+  audio_codec: AC3
+  release_group: SEPTiC
+
+? Movies/Borat (2006)/Borat.(2006).R5.PROPER.REPACK.DVDRip.XviD-PUKKA.avi
+: title: Borat
+  year: 2006
+  proper_count: 2
+  format: DVD
+  other: [ R5, Proper ]
+  video_codec: XviD
+  release_group: PUKKA
+
+? "[XCT].Le.Prestige.(The.Prestige).DVDRip.[x264.HP.He-Aac.{Fr-Eng}.St{Fr-Eng}.Chaps].mkv"
+: title: Le Prestige
+  format: DVD
+  video_codec: h264
+  video_profile: HP
+  audio_codec: AAC
+  audio_profile: HE
+  language: [ french, english ]
+  subtitle_language: [ french, english ]
+  release_group: XCT
+
+? Battle Royale (2000)/Battle.Royale.(Batoru.Rowaiaru).(2000).(Special.Edition).CD1of2.DVDRiP.XviD-[ZeaL].avi
+: title: Battle Royale
+  year: 2000
+  edition: Special Edition
+  cd: 1
+  cd_count: 2
+  format: DVD
+  video_codec: XviD
+  release_group: ZeaL
+
+? Movies/Brazil (1985)/Brazil_Criterion_Edition_(1985).CD2.avi
+: title: Brazil
+  edition: Criterion Edition
+  year: 1985
+  cd: 2
+
+? Movies/Persepolis (2007)/[XCT] Persepolis [H264+Aac-128(Fr-Eng)+ST(Fr-Eng)+Ind].mkv
+: title: Persepolis
+  year: 2007
+  video_codec: h264
+  audio_codec: AAC
+  language: [ French, English ]
+  subtitle_language: [ French, English ]
+  release_group: XCT
+
+? Movies/Toy Story (1995)/Toy Story [HDTV 720p English-Spanish].mkv
+: title: Toy Story
+  year: 1995
+  format: HDTV
+  screen_size: 720p
+  language: [ english, spanish ]
+
+? Movies/Office Space (1999)/Office.Space.[Dual-DVDRip].[Spanish-English].[XviD-AC3-AC3].[by.Oswald].avi
+: title: Office Space
+  year: 1999
+  format: DVD
+  language: [ english, spanish ]
+  video_codec: XviD
+  audio_codec: AC3
+
+? Movies/Wild Zero (2000)/Wild.Zero.DVDivX-EPiC.avi
+: title: Wild Zero
+  year: 2000
+  video_codec: DivX
+  release_group: EPiC
+
+? movies/Baraka_Edition_Collector.avi
+: title: Baraka
+  edition: Collector Edition
+
+? Movies/Blade Runner (1982)/Blade.Runner.(1982).(Director's.Cut).CD1.DVDRip.XviD.AC3-WAF.avi
+: title: Blade Runner
+  year: 1982
+  edition: Director's cut
+  cd: 1
+  format: DVD
+  video_codec: XviD
+  audio_codec: AC3
+  release_group: WAF
+
+? movies/American.The.Bill.Hicks.Story.2009.DVDRip.XviD-EPiSODE.[UsaBit.com]/UsaBit.com_esd-americanbh.avi
+: title: American The Bill Hicks Story
+  year: 2009
+  format: DVD
+  video_codec: XviD
+  release_group: EPiSODE
+  website: UsaBit.com
+
+? movies/Charlie.And.Boots.DVDRip.XviD-TheWretched/wthd-cab.avi
+: title: Charlie And Boots
+  format: DVD
+  video_codec: XviD
+  release_group: TheWretched
+
+? movies/Steig Larsson Millenium Trilogy (2009) BRrip 720 AAC x264/(1)The Girl With The Dragon Tattoo (2009) BRrip 720 AAC x264.mkv
+: title: The Girl With The Dragon Tattoo
+  #film_title: Steig Larsson Millenium Trilogy
+  #film: 1
+  year: 2009
+  format: BluRay
+  audio_codec: AAC
+  video_codec: h264
+  screen_size: 720p
+
+? movies/Greenberg.REPACK.LiMiTED.DVDRip.XviD-ARROW/arw-repack-greenberg.dvdrip.xvid.avi
+: title: Greenberg
+  format: DVD
+  video_codec: XviD
+  release_group: ARROW
+  other: ['Proper', 'Limited']
+  proper_count: 1
+
+? Movies/Fr - Paris 2054, Renaissance (2005) - De Christian Volckman - (Film Divx Science Fiction Fantastique Thriller Policier N&B).avi
+: title: Paris 2054, Renaissance
+  year: 2005
+  language: french
+  video_codec: DivX
+
+? Movies/[阿维达].Avida.2006.FRENCH.DVDRiP.XViD-PROD.avi
+: title: Avida
+  year: 2006
+  language: french
+  format: DVD
+  video_codec: XviD
+  release_group: PROD
+
+? Movies/Alice in Wonderland DVDRip.XviD-DiAMOND/dmd-aw.avi
+: title: Alice in Wonderland
+  format: DVD
+  video_codec: XviD
+  release_group: DiAMOND
+
+? Movies/Ne.Le.Dis.A.Personne.Fr 2 cd/personnea_mp.avi
+: title: Ne Le Dis A Personne
+  language: french
+  cd_count: 2
+
+? Movies/Bunker Palace Hôtel (Enki Bilal) (1989)/Enki Bilal - Bunker Palace Hotel (Fr Vhs Rip).avi
+: title: Bunker Palace Hôtel
+  year: 1989
+  language: french
+  format: VHS
+
+? Movies/21 (2008)/21.(2008).DVDRip.x264.AC3-FtS.[sharethefiles.com].mkv
+: title: "21"
+  year: 2008
+  format: DVD
+  video_codec: h264
+  audio_codec: AC3
+  release_group: FtS
+  website: sharethefiles.com
+
+? Movies/9 (2009)/9.2009.Blu-ray.DTS.720p.x264.HDBRiSe.[sharethefiles.com].mkv
+: title: "9"
+  year: 2009
+  format: BluRay
+  audio_codec: DTS
+  screen_size: 720p
+  video_codec: h264
+  release_group: HDBRiSe
+  website: sharethefiles.com
+
+? Movies/Mamma.Mia.2008.DVDRip.AC3.XviD-CrazyTeam/Mamma.Mia.2008.DVDRip.AC3.XviD-CrazyTeam.avi
+: title: Mamma Mia
+  year: 2008
+  format: DVD
+  audio_codec: AC3
+  video_codec: XviD
+  release_group: CrazyTeam
+
+? Movies/M.A.S.H. (1970)/MASH.(1970).[Divx.5.02][Dual-Subtitulos][DVDRip].ogm
+: title: MASH
+  year: 1970
+  video_codec: DivX
+  format: DVD
+
+? Movies/The Doors (1991)/09.03.08.The.Doors.(1991).BDRip.720p.AC3.X264-HiS@SiLUHD-English.[sharethefiles.com].mkv
+: title: The Doors
+  year: 1991
+  date: 2008-03-09
+  format: BluRay
+  screen_size: 720p
+  audio_codec: AC3
+  video_codec: h264
+  release_group: HiS@SiLUHD
+  language: english
+  website: sharethefiles.com
+
+? Movies/The Doors (1991)/08.03.09.The.Doors.(1991).BDRip.720p.AC3.X264-HiS@SiLUHD-English.[sharethefiles.com].mkv
+: options: --date-year-first
+  title: The Doors
+  year: 1991
+  date: 2008-03-09
+  format: BluRay
+  screen_size: 720p
+  audio_codec: AC3
+  video_codec: h264
+  release_group: HiS@SiLUHD
+  language: english
+  website: sharethefiles.com
+
+? Movies/Ratatouille/video_ts-ratatouille.srt
+: title: Ratatouille
+  format: DVD
+
+# Removing this one because 001 is guessed as an episode number.
+# ? Movies/001 __ A classer/Fantomas se déchaine - Louis de Funès.avi
+# : title: Fantomas se déchaine
+
+? Movies/Comme une Image (2004)/Comme.Une.Image.FRENCH.DVDRiP.XViD-NTK.par-www.divx-overnet.com.avi
+: title: Comme une Image
+  year: 2004
+  language: french
+  format: DVD
+  video_codec: XviD
+  release_group: NTK
+  website: www.divx-overnet.com
+
+? Movies/Fantastic Mr Fox/Fantastic.Mr.Fox.2009.DVDRip.{x264+LC-AAC.5.1}{Fr-Eng}{Sub.Fr-Eng}-™.[sharethefiles.com].mkv
+: title: Fantastic Mr Fox
+  year: 2009
+  format: DVD
+  video_codec: h264
+  audio_codec: AAC
+  audio_profile: LC
+  audio_channels: "5.1"
+  language: [ french, english ]
+  subtitle_language: [ french, english ]
+  website: sharethefiles.com
+
+? Movies/Somewhere.2010.DVDRip.XviD-iLG/i-smwhr.avi
+: title: Somewhere
+  year: 2010
+  format: DVD
+  video_codec: XviD
+  release_group: iLG
+
+? Movies/Moon_(2009).mkv
+: title: Moon
+  year: 2009
+
+? Movies/Moon_(2009)-x02-Making_Of.mkv
+: title: Moon
+  year: 2009
+  bonus: 2
+  bonus_title: Making Of
+
+? movies/James_Bond-f17-Goldeneye.mkv
+: title: Goldeneye
+  film_title: James Bond
+  film: 17
+
+
+? /movies/James_Bond-f21-Casino_Royale.mkv
+: title: Casino Royale
+  film_title: James Bond
+  film: 21
+
+? /movies/James_Bond-f21-Casino_Royale-x01-Becoming_Bond.mkv
+: title: Casino Royale
+  film_title: James Bond
+  film: 21
+  bonus: 1
+  bonus_title: Becoming Bond
+
+? /movies/James_Bond-f21-Casino_Royale-x02-Stunts.mkv
+: title: Casino Royale
+  film_title: James Bond
+  film: 21
+  bonus: 2
+  bonus_title: Stunts
+
+? OSS_117--Cairo,_Nest_of_Spies.mkv
+: title: OSS 117
+# TODO: Implement subTitle for movies.
+
+? The Godfather Part 3.mkv
+? The Godfather Part III.mkv
+: title: The Godfather
+  part: 3
+
+? Foobar Part VI.mkv
+: title: Foobar
+  part: 6
+
+? The_Insider-(1999)-x02-60_Minutes_Interview-1996.mp4
+: title: The Insider
+  year: 1999
+  bonus: 2
+  bonus_title: 60 Minutes Interview-1996
+
+? Rush.._Beyond_The_Lighted_Stage-x09-Between_Sun_and_Moon-2002_Hartford.mkv
+: title: Rush Beyond The Lighted Stage
+  bonus: 9
+  bonus_title: Between Sun and Moon
+  year: 2002
+
+? /public/uTorrent/Downloads Finished/Movies/Indiana.Jones.and.the.Temple.of.Doom.1984.HDTV.720p.x264.AC3.5.1-REDµX/Indiana.Jones.and.the.Temple.of.Doom.1984.HDTV.720p.x264.AC3.5.1-REDµX.mkv
+: title: Indiana Jones and the Temple of Doom
+  year: 1984
+  format: HDTV
+  screen_size: 720p
+  video_codec: h264
+  audio_codec: AC3
+  audio_channels: "5.1"
+  release_group: REDµX
+
+? The.Director’s.Notebook.2006.Blu-Ray.x264.DXVA.720p.AC3-de[42].mkv
+: title: The Director’s Notebook
+  year: 2006
+  format: BluRay
+  video_codec: h264
+  video_api: DXVA
+  screen_size: 720p
+  audio_codec: AC3
+  release_group: de[42]
+
+
+? Movies/Cosmopolis.2012.LiMiTED.720p.BluRay.x264-AN0NYM0US[bb]/ano-cosmo.720p.mkv
+: title: Cosmopolis
+  year: 2012
+  screen_size: 720p
+  video_codec: h264
+  release_group: AN0NYM0US[bb]
+  format: BluRay
+  other: Limited
+
+? movies/La Science des Rêves (2006)/La.Science.Des.Reves.FRENCH.DVDRip.XviD-MP-AceBot.avi
+: title: La Science des Rêves
+  year: 2006
+  format: DVD
+  video_codec: XviD
+  video_profile: MP
+  release_group: AceBot
+  language: French
+
+? The_Italian_Job.mkv
+: title: The Italian Job
+
+? The.Rum.Diary.2011.1080p.BluRay.DTS.x264.D-Z0N3.mkv
+: title: The Rum Diary
+  year: 2011
+  screen_size: 1080p
+  format: BluRay
+  video_codec: h264
+  audio_codec: DTS
+  release_group: D-Z0N3
+
+? Life.Of.Pi.2012.1080p.BluRay.DTS.x264.D-Z0N3.mkv
+: title: Life Of Pi
+  year: 2012
+  screen_size: 1080p
+  format: BluRay
+  video_codec: h264
+  audio_codec: DTS
+  release_group: D-Z0N3
+
+? The.Kings.Speech.2010.1080p.BluRay.DTS.x264.D Z0N3.mkv
+: title: The Kings Speech
+  year: 2010
+  screen_size: 1080p
+  format: BluRay
+  audio_codec: DTS
+  video_codec: h264
+  release_group: D Z0N3
+
+? Street.Kings.2008.BluRay.1080p.DTS.x264.dxva EuReKA.mkv
+: title: Street Kings
+  year: 2008
+  format: BluRay
+  screen_size: 1080p
+  audio_codec: DTS
+  video_codec: h264
+  video_api: DXVA
+  release_group: EuReKA
+
+? 2001.A.Space.Odyssey.1968.HDDVD.1080p.DTS.x264.dxva EuReKA.mkv
+: title: 2001 A Space Odyssey
+  year: 1968
+  format: HD-DVD
+  screen_size: 1080p
+  audio_codec: DTS
+  video_codec: h264
+  video_api: DXVA
+  release_group: EuReKA
+
+? 2012.2009.720p.BluRay.x264.DTS WiKi.mkv
+: title: "2012"
+  year: 2009
+  screen_size: 720p
+  format: BluRay
+  video_codec: h264
+  audio_codec: DTS
+  release_group: WiKi
+
+? /share/Download/movie/Dead Man Down (2013) BRRiP XViD DD5_1 Custom NLSubs =-_lt Q_o_Q gt-=_/XD607ebb-BRc59935-5155473f-1c5f49/XD607ebb-BRc59935-5155473f-1c5f49.avi
+: title: Dead Man Down
+  year: 2013
+  format: BluRay
+  video_codec: XviD
+  audio_channels: "5.1"
+  audio_codec: DolbyDigital
+  uuid: XD607ebb-BRc59935-5155473f-1c5f49
+
+? Pacific.Rim.3D.2013.COMPLETE.BLURAY-PCH.avi
+: title: Pacific Rim
+  year: 2013
+  format: BluRay
+  other:
+   - Complete
+   - 3D
+  release_group: PCH
+
+? Immersion.French.2011.STV.READNFO.QC.FRENCH.ENGLISH.NTSC.DVDR.nfo
+: title: Immersion French
+  year: 2011
+  language:
+    - French
+    - English
+  format: DVD
+  other: NTSC
+
+? Immersion.French.2011.STV.READNFO.QC.FRENCH.NTSC.DVDR.nfo
+: title: Immersion French
+  year: 2011
+  language: French
+  format: DVD
+  other: NTSC
+
+? Immersion.French.2011.STV.READNFO.QC.NTSC.DVDR.nfo
+: title: Immersion
+  language: French
+  year: 2011
+  format: DVD
+  other: NTSC
+
+? French.Immersion.2011.STV.READNFO.QC.ENGLISH.NTSC.DVDR.nfo
+: title: French Immersion
+  year: 2011
+  language: ENGLISH
+  format: DVD
+  other: NTSC
+
+? Howl's_Moving_Castle_(2004)_[720p,HDTV,x264,DTS]-FlexGet.avi
+: video_codec: h264
+  format: HDTV
+  title: Howl's Moving Castle
+  screen_size: 720p
+  year: 2004
+  audio_codec: DTS
+  release_group: FlexGet
+
+? Pirates de langkasuka.2008.FRENCH.1920X1080.h264.AVC.AsiaRa.mkv
+: screen_size: 1080p
+  year: 2008
+  language: French
+  video_codec: h264
+  title: Pirates de langkasuka
+  release_group: AsiaRa
+
+? Masala (2013) Telugu Movie HD DVDScr XviD - Exclusive.avi
+: year: 2013
+  video_codec: XviD
+  title: Masala
+  format: HD-DVD
+  other: Screener
+  language: Telugu
+  release_group: Exclusive
+
+? Django Unchained 2012 DVDSCR X264 AAC-P2P.nfo
+: year: 2012
+  other: Screener
+  video_codec: h264
+  title: Django Unchained
+  audio_codec: AAC
+  format: DVD
+  release_group: P2P
+
+? Ejecutiva.En.Apuros(2009).BLURAY.SCR.Xvid.Spanish.LanzamientosD.nfo
+: year: 2009
+  other: Screener
+  format: BluRay
+  video_codec: XviD
+  language: Spanish
+  title: Ejecutiva En Apuros
+
+? Die.Schluempfe.2.German.DL.1080p.BluRay.x264-EXQUiSiTE.mkv
+: title: Die Schluempfe 2
+  format: BluRay
+  language:
+    - Multiple languages
+    - German
+  video_codec: h264
+  release_group: EXQUiSiTE
+  screen_size: 1080p
+
+? Rocky 1976 French SubForced BRRip x264 AC3-FUNKY.mkv
+: title: Rocky
+  year: 1976
+  subtitle_language: French
+  format: BluRay
+  video_codec: h264
+  audio_codec: AC3
+  release_group: FUNKY
+
+? REDLINE (BD 1080p H264 10bit FLAC) [3xR].mkv
+: title: REDLINE
+  format: BluRay
+  video_codec: h264
+  video_profile: 10bit
+  audio_codec: FLAC
+  screen_size: 1080p
+
+? The.Lizzie.McGuire.Movie.(2003).HR.DVDRiP.avi
+: title: The Lizzie McGuire Movie
+  year: 2003
+  format: DVD
+  other: HR
+
+? Hua.Mulan.BRRIP.MP4.x264.720p-HR.avi
+: title: Hua Mulan
+  video_codec: h264
+  format: BluRay
+  screen_size: 720p
+  other: HR
+
+? Dr.Seuss.The.Lorax.2012.DVDRip.LiNE.XviD.AC3.HQ.Hive-CM8.mp4
+: video_codec: XviD
+  title: Dr Seuss The Lorax
+  format: DVD
+  other: LiNE
+  year: 2012
+  audio_codec: AC3
+  audio_profile: HQ
+  release_group: Hive-CM8
+
+? "Star Wars: Episode IV - A New Hope (2004) Special Edition.MKV"
+: title: "Star Wars: Episode IV"
+  alternativeTitle: A New Hope
+  year: 2004
+  edition: Special Edition
+
+? Dr.LiNE.The.Lorax.2012.DVDRip.LiNE.XviD.AC3.HQ.Hive-CM8.mp4
+: video_codec: XviD
+  title: Dr LiNE The Lorax
+  format: DVD
+  other: LiNE
+  year: 2012
+  audio_codec: AC3
+  audio_profile: HQ
+  release_group: Hive-CM8
+
+? Dr.LiNE.The.Lorax.2012.DVDRip.XviD.AC3.HQ.Hive-CM8.mp4
+: video_codec: XviD
+  title: Dr LiNE The Lorax
+  format: DVD
+  year: 2012
+  audio_codec: AC3
+  audio_profile: HQ
+  release_group: Hive-CM8
+
+? Perfect Child-2007-TRUEFRENCH-TVRip.Xvid-h@mster.avi
+: release_group: h@mster
+  title: Perfect Child
+  video_codec: XviD
+  language: French
+  format: TV
+  year: 2007
+
+? entre.ciel.et.terre.(1994).dvdrip.h264.aac-psypeon.avi
+: audio_codec: AAC
+  format: DVD
+  release_group: psypeon
+  title: entre ciel et terre
+  video_codec: h264
+  year: 1994
+
+? Yves.Saint.Laurent.2013.FRENCH.DVDSCR.MD.XviD-ViVARiUM.avi
+: format: DVD
+  language: French
+  other:
+      - MD
+      - Screener
+  release_group: ViVARiUM
+  title: Yves Saint Laurent
+  video_codec: XviD
+  year: 2013
+
+? Echec et Mort - Hard to Kill - Steven Seagal Multi 1080p BluRay x264 CCATS.avi
+: format: BluRay
+  language: Multiple languages
+  release_group: CCATS
+  screen_size: 1080p
+  title: Echec et Mort
+  alternativeTitle:
+    - Hard to Kill
+    - Steven Seagal
+  video_codec: h264
+
+? Paparazzi - Timsit/Lindon (MKV 1080p tvripHD)
+: options: -n
+  title: Paparazzi
+  alternativeTitle:
+    - Timsit
+    - Lindon
+  screen_size: 1080p
+  format: HDTV
+
+? some.movie.720p.bluray.x264-mind
+: title: some movie
+  screen_size: 720p
+  video_codec: h264
+  release_group: mind
+  format: BluRay
+
+? Dr LiNE The Lorax 720p h264 BluRay
+: title: Dr LiNE The Lorax
+  screen_size: 720p
+  video_codec: h264
+  format: BluRay
+
+#TODO: Camelcase implementation
+#? BeatdownFrenchDVDRip.mkv
+#: options: -c
+#  title: Beatdown
+#  language: French
+#  format: DVD
+
+#? YvesSaintLaurent2013FrenchDVDScrXvid.avi
+#: options: -c
+#  format: DVD
+#  language: French
+#  other: Screener
+#  title: Yves saint laurent
+#  video_codec: XviD
+#  year: 2013
+
+
+? Elle.s.en.va.720p.mkv
+: screen_size: 720p
+  title: Elle s en va
+
+? FooBar.7.PDTV-FlexGet
+: format: DVB
+  release_group: FlexGet
+  title: FooBar 7
+
+? h265 - HEVC Riddick Unrated Director Cut French 1080p DTS.mkv
+: audio_codec: DTS
+  edition: Director's cut
+  language: fr
+  screen_size: 1080p
+  title: Riddick
+  other: Unrated
+  video_codec: h265
+
+? "[h265 - HEVC] Riddick Unrated Director Cut French [1080p DTS].mkv"
+: audio_codec: DTS
+  edition: Director's cut
+  language: fr
+  screen_size: 1080p
+  title: Riddick
+  other: Unrated
+  video_codec: h265
+
+? Barbecue-2014-French-mHD-1080p
+: language: fr
+  other: mHD
+  screen_size: 1080p
+  title: Barbecue
+  year: 2014
+
+? Underworld Quadrilogie VO+VFF+VFQ 1080p HDlight.x264~Tonyk~Monde Infernal
+: language: fr
+  other:
+    - HDLight
+    - OV
+  screen_size: 1080p
+  title: Underworld Quadrilogie
+  video_codec: h264
+
+? A Bout Portant (The Killers).PAL.Multi.DVD-R-KZ
+: format: DVD
+  language: mul
+  release_group: KZ
+  title: A Bout Portant
+
+? "Mise à Sac (Alain Cavalier, 1967) [Vhs.Rip.Vff]"
+: format: VHS
+  language: fr
+  title: "Mise à Sac"
+  year: 1967
+
+? A Bout Portant (The Killers).PAL.Multi.DVD-R-KZ
+: format: DVD
+  other: PAL
+  language: mul
+  release_group: KZ
+  title: A Bout Portant
+
+? Youth.In.Revolt.(Be.Bad).2009.MULTI.1080p.LAME3*92-MEDIOZZ
+: audio_codec: MP3
+  language: mul
+  release_group: MEDIOZZ
+  screen_size: 1080p
+  title: Youth In Revolt
+  year: 2009
+
+? La Defense Lincoln (The Lincoln Lawyer) 2011 [DVDRIP][Vostfr]
+: format: DVD
+  subtitle_language: fr
+  title: La Defense Lincoln
+  year: 2011
+
+? '[h265 - HEVC] Fight Club French 1080p DTS.'
+: audio_codec: DTS
+  language: fr
+  screen_size: 1080p
+  title: Fight Club
+  video_codec: h265
+
+? Love Gourou (Mike Myers) - FR
+: language: fr
+  title: Love Gourou
+
+? '[h265 - hevc] transformers 2 1080p french ac3 6ch.'
+: audio_channels: '5.1'
+  audio_codec: AC3
+  language: fr
+  screen_size: 1080p
+  title: transformers 2
+  video_codec: h265
+
+? 1.Angry.Man.1957.mkv
+: title: 1 Angry Man
+  year: 1957
+
+? 12.Angry.Men.1957.mkv
+: title: 12 Angry Men
+  year: 1957
+
+? 123.Angry.Men.1957.mkv
+: title: 123 Angry Men
+  year: 1957
+
+? "Looney Tunes 1444x866 Porky's Last Stand.mkv"
+: screen_size: 1444x866
+  title: Looney Tunes
diff --git a/lib/guessit2/test/rules/__init__.py b/lib/guessit2/test/rules/__init__.py
new file mode 100644
index 000000000..e5be370e4
--- /dev/null
+++ b/lib/guessit2/test/rules/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
diff --git a/lib/guessit2/test/rules/audio_codec.yml b/lib/guessit2/test/rules/audio_codec.yml
new file mode 100644
index 000000000..afbfae04b
--- /dev/null
+++ b/lib/guessit2/test/rules/audio_codec.yml
@@ -0,0 +1,77 @@
+# Multiple input strings having same expected results can be chained.
+# Use $ marker to check inputs that should not match results.
+
+
+? +MP3
+? +lame
+? +lame3.12
+? +lame3.100
+: audio_codec: MP3
+
+? +DolbyDigital
+? +DD
+? -Dolby Digital
+: audio_codec: DolbyDigital
+
+? +AAC
+: audio_codec: AAC
+
+? +AC3
+: audio_codec: AC3
+
+? +Flac
+: audio_codec: FLAC
+
+? +DTS
+: audio_codec: DTS
+
+? +True-HD
+? +trueHD
+: audio_codec: TrueHD
+
+? +DTS-HD
+: audio_codec: DTS
+  audio_profile: HD
+
+? +DTS-HDma
+: audio_codec: DTS
+  audio_profile: HDMA
+
+? +AC3-hq
+: audio_codec: AC3
+  audio_profile: HQ
+
+? +AAC-HE
+: audio_codec: AAC
+  audio_profile: HE
+
+? +AAC-LC
+: audio_codec: AAC
+  audio_profile: LC
+
+? +AAC2.0
+: audio_codec: AAC
+  audio_channels: '2.0'
+
+? +7.1
+? +7ch
+? +8ch
+: audio_channels: '7.1'
+
+? +5.1
+? +5ch
+? +6ch
+: audio_channels: '5.1'
+
+? +2ch
+? +2.0
+? +stereo
+: audio_channels: '2.0'
+
+? +1ch
+? +mono
+: audio_channels: '1.0'
+
+? DD5.1
+: audio_codec: DolbyDigital
+  audio_channels: '5.1'
diff --git a/lib/guessit2/test/rules/bonus.yml b/lib/guessit2/test/rules/bonus.yml
new file mode 100644
index 000000000..6ef6f5b25
--- /dev/null
+++ b/lib/guessit2/test/rules/bonus.yml
@@ -0,0 +1,9 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? Movie Title-x01-Other Title.mkv
+? Movie Title-x01-Other Title
+? directory/Movie Title-x01-Other Title/file.mkv
+: title: Movie Title
+  bonus_title: Other Title
+  bonus: 1
+
diff --git a/lib/guessit2/test/rules/cds.yml b/lib/guessit2/test/rules/cds.yml
new file mode 100644
index 000000000..8bb4e98c6
--- /dev/null
+++ b/lib/guessit2/test/rules/cds.yml
@@ -0,0 +1,5 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? cd 1of3
+: cd: 1
+  cd_count: 3
diff --git a/lib/guessit2/test/rules/country.yml b/lib/guessit2/test/rules/country.yml
new file mode 100644
index 000000000..f2da1b205
--- /dev/null
+++ b/lib/guessit2/test/rules/country.yml
@@ -0,0 +1,10 @@
+# Multiple input strings having same expected results can be chained.
+# Use $ marker to check inputs that should not match results.
+? Us.this.is.title
+? this.is.title.US
+: country: US
+  title: this is title
+
+? This.is.us.title
+: title: This is us title
+
diff --git a/lib/guessit2/test/rules/date.yml b/lib/guessit2/test/rules/date.yml
new file mode 100644
index 000000000..d7379f03c
--- /dev/null
+++ b/lib/guessit2/test/rules/date.yml
@@ -0,0 +1,50 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? +09.03.08
+? +09.03.2008
+? +2008.03.09
+: date: 2008-03-09
+
+? +31.01.15
+? +31.01.2015
+? +15.01.31
+? +2015.01.31
+: date: 2015-01-31
+
+? +01.02.03
+: date: 2003-02-01
+
+? +01.02.03
+: options: --date-year-first
+  date: 2001-02-03
+
+? +01.02.03
+: options: --date-day-first
+  date: 2003-02-01
+
+? 1919
+? 2030
+: !!map {}
+
+? 2029
+: year: 2029
+
+? (1920)
+: year: 1920
+
+? 2012
+: year: 2012
+
+? 2011 2013 (2012) (2015)  # first marked year is guessed.
+: title: "2011 2013"
+  year: 2012
+
+? 2012 2009 S01E02 2015  # If no year is marked, the second one is guessed.
+: title: "2012"
+  year: 2009
+  episode_title: "2015"
+
+? Something 2 mar 2013)
+: title: Something
+  date: 2013-03-02
+  type: episode
diff --git a/lib/guessit2/test/rules/edition.yml b/lib/guessit2/test/rules/edition.yml
new file mode 100644
index 000000000..bc35b85e6
--- /dev/null
+++ b/lib/guessit2/test/rules/edition.yml
@@ -0,0 +1,25 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? Director's cut
+? Edition Director's cut
+: edition: Director's cut
+
+? Collector
+? Collector Edition
+? Edition Collector
+: edition: Collector Edition
+
+? Special Edition
+? Edition Special
+? -Special
+: edition: Special Edition
+
+? Criterion Edition
+? Edition Criterion
+? -Criterion
+: edition: Criterion Edition
+
+? Deluxe
+? Deluxe Edition
+? Edition Deluxe
+: edition: Deluxe Edition
diff --git a/lib/guessit2/test/rules/episodes.yml b/lib/guessit2/test/rules/episodes.yml
new file mode 100644
index 000000000..61eea5766
--- /dev/null
+++ b/lib/guessit2/test/rules/episodes.yml
@@ -0,0 +1,119 @@
+# Multiple input strings having same expected results can be chained.
+# Use $ marker to check inputs that should not match results.
+? +2x5
+? +2X5
+? +02x05
+? +2X05
+? +02x5
+? S02E05
+? s02e05
+? s02e5
+? s2e05
+? -s03e05
+? -s02e06
+? -3x05
+? -2x06
+: season: 2
+  episode: 5
+
+? "+0102"
+? "+102"
+: season: 1
+  episode: 2
+
+? "0102 S03E04"
+? "S03E04 102"
+: season: 3
+  episode: 4
+
+? +serie Saison 2 other
+? +serie Season 2 other
+? +serie Saisons 2 other
+? +serie Seasons 2 other
+? +serie Serie 2 other
+? +serie Series 2 other
+? +serie Season Two other
+? +serie Season II other
+: season: 2
+
+? Some Series.S02E01.Episode.title.mkv
+? Some Series/Season 02/E01-Episode title.mkv
+? Some Series/Season 02/Some Series-E01-Episode title.mkv
+? Some Dummy Directory/Season 02/Some Series-E01-Episode title.mkv
+? -Some Dummy Directory/Season 02/E01-Episode title.mkv
+? Some Series/Unsafe Season 02/Some Series-E01-Episode title.mkv
+? -Some Series/Unsafe Season 02/E01-Episode title.mkv
+? Some Series/Season 02/E01-Episode title.mkv
+? Some Series/ Season 02/E01-Episode title.mkv
+? Some Dummy Directory/Some Series S02/E01-Episode title.mkv
+? Some Dummy Directory/S02 Some Series/E01-Episode title.mkv
+: title: Some Series
+  episode_title: Episode title
+  season: 2
+  episode: 1
+
+? Some Series.S02E01.mkv
+? Some Series/Season 02/E01.mkv
+? Some Series/Season 02/Some Series-E01.mkv
+? Some Dummy Directory/Season 02/Some Series-E01.mkv
+? -Some Dummy Directory/Season 02/E01.mkv
+? Some Series/Unsafe Season 02/Some Series-E01.mkv
+? -Some Series/Unsafe Season 02/E01.mkv
+? Some Series/Season 02/E01.mkv
+? Some Series/ Season 02/E01.mkv
+? Some Dummy Directory/Some Series S02/E01-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.mkv
+: title: Some Series
+  season: 2
+  episode: 1
+
+? Some Series S03E01E02
+: title: Some Series
+  season: 3
+  episode: [1, 2]
+
+? Some Series S01S02S03
+? Some Series S01-02-03
+? Some Series S01 S02 S03
+? -Some Series S01 02 03
+: title: Some Series
+  season: [1, 2, 3]
+
+? Some Series E01E02E03
+? Some Series E01-02-03
+? Some Series E01-03
+? Some Series E01 E02 E03
+? Some Series E01 02 03
+: title: Some Series
+  episode: [1, 2, 3]
+
+? Some Series E01E02E04
+? Some Series E01 E02 E04
+? Some Series E01 02 04
+: title: Some Series
+  episode: [1, 2, 4]
+
+? Some Series E01-02-04
+? Some Series E01-04
+? Some Series E01-04
+: title: Some Series
+  episode: [1, 2, 3, 4]
+
+? Some Series E01-02-E04
+: title: Some Series
+  episode: [1, 2, 4]
+
+? Episode 3
+? -Episode III
+: episode: 3
+
+? Episode 3
+? Episode III
+: options: -t episode
+  episode: 3
+
+? -A very special movie
+: episode_details: Special
+
+? A very special episode
+: options: -t episode
+  episode_details: Special
diff --git a/lib/guessit2/test/rules/film.yml b/lib/guessit2/test/rules/film.yml
new file mode 100644
index 000000000..1f7743318
--- /dev/null
+++ b/lib/guessit2/test/rules/film.yml
@@ -0,0 +1,9 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? Film Title-f01-Series Title.mkv
+? Film Title-f01-Series Title
+? directory/Film Title-f01-Series Title/file.mkv
+: title: Series Title
+  film_title: Film Title
+  film: 1
+
diff --git a/lib/guessit2/test/rules/format.yml b/lib/guessit2/test/rules/format.yml
new file mode 100644
index 000000000..cf3dea921
--- /dev/null
+++ b/lib/guessit2/test/rules/format.yml
@@ -0,0 +1,112 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? +VHS
+? +VHSRip
+? +VHS-Rip
+? +VhS_rip
+? +VHS.RIP
+? -VHSAnythingElse
+? -SomeVHS stuff
+? -VH
+? -VHx
+? -VHxRip
+: format: VHS
+
+? +Cam
+? +CamRip
+? +CaM Rip
+? +Cam_Rip
+? +cam.rip
+: format: Cam
+
+? +Telesync
+? +TS
+? +HD TS
+? -Hd.Ts # ts file extension
+? -HD.TS # ts file extension
+? +Hd-Ts
+: format: Telesync
+
+? +Workprint
+? +workPrint
+? +WorkPrint
+? +WP
+? -Work Print
+: format: Workprint
+
+? +Telecine
+? +teleCine
+? +TC
+? -Tele Cine
+: format: Telecine
+
+? +PPV
+? +ppv-rip
+: format: PPV
+
+? -TV
+? +SDTV
+? +SDTVRIP
+? +Rip sd tv
+? +TvRip
+? +Rip TV
+: format: TV
+
+? +DVB
+? +DVB-Rip
+? +DvBRiP
+? +pdTV
+? +Pd Tv
+: format: DVB
+
+? +DVD
+? +DVD-RIP
+? +video ts
+? +DVDR
+? +DVD 9
+? +dvd 5
+? -dvd ts
+: format: DVD
+  -format: ts
+
+? +HDTV
+? +tv rip hd
+? +HDtv Rip
+? +HdRip
+: format: HDTV
+
+? +VOD
+? +VodRip
+? +vod rip
+: format: VOD
+
+? +webrip
+? +Web Rip
+: format: WEBRip
+
+? +webdl
+? +Web DL
+? +webHD
+? +WEB hd
+? +web
+: format: WEB-DL
+
+? +HDDVD
+? +hd dvd
+? +hdDvdRip
+: format: HD-DVD
+
+? +BluRay
+? +BluRay rip
+? +BD
+? +BR
+? +BDRip
+? +BR rip
+? +BD5
+? +BD9
+? +BD25
+? +bd50
+: format: BluRay
+
+? XVID.NTSC.DVDR.nfo
+: format: DVD
diff --git a/lib/guessit2/test/rules/language.yml b/lib/guessit2/test/rules/language.yml
new file mode 100644
index 000000000..7871898b6
--- /dev/null
+++ b/lib/guessit2/test/rules/language.yml
@@ -0,0 +1,26 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? +English
+? .ENG.
+: language: English
+
+? +French
+: language: French
+
+? +SubFrench
+? +SubFr
+? +STFr
+? ST.FR
+: subtitle_language: French
+
+? +ENG.-.sub.FR
+? ENG.-.FR Sub
+? +ENG.-.SubFR
+? +ENG.-.FRSUB
+: language: English
+  subtitle_language: French
+
+? "{Fr-Eng}.St{Fr-Eng}"
+? "Le.Prestige[x264.{Fr-Eng}.St{Fr-Eng}.Chaps].mkv"
+: language: [French, English]
+  subtitle_language: [French, English]
\ No newline at end of file
diff --git a/lib/guessit2/test/rules/other.yml b/lib/guessit2/test/rules/other.yml
new file mode 100644
index 000000000..cce8cbd05
--- /dev/null
+++ b/lib/guessit2/test/rules/other.yml
@@ -0,0 +1,137 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? +DVDSCR
+? +DVDScreener
+? +DVD-SCR
+? +DVD Screener
+? +DVD AnythingElse Screener
+? -DVD AnythingElse SCR
+: other: Screener
+
+? +AudioFix
+? +AudioFixed
+? +Audio Fix
+? +Audio Fixed
+: other: AudioFix
+
+? +SyncFix
+? +SyncFixed
+? +Sync Fix
+? +Sync Fixed
+: other: SyncFix
+
+? +DualAudio
+? +Dual Audio
+: other: DualAudio
+
+? +ws
+? +WideScreen
+? +Wide Screen
+: other: WideScreen
+
+? +NF
+? +Netflix
+: other: Netflix
+
+# Fix and Real must be surround by others properties to be matched.
+? DVD.Real.XViD
+? DVD.fix.XViD
+? -DVD.Real
+? -DVD.Fix
+? -Real.XViD
+? -Fix.XViD
+: other: Proper
+  proper_count: 1
+
+? -DVD.BlablaBla.Fix.Blablabla.XVID
+? -DVD.BlablaBla.Fix.XVID
+? -DVD.Fix.Blablabla.XVID
+: other: Proper
+  proper_count: 1
+
+
+? DVD.Real.PROPER.REPACK
+: other: Proper
+  proper_count: 3
+
+
+? Proper
+? +Repack
+? +Rerip
+: other: Proper
+  proper_count: 1
+
+? XViD.Fansub
+: other: Fansub
+
+? XViD.Fastsub
+: other: Fastsub
+
+? +Season Complete
+? -Complete
+: other: Complete
+
+? R5
+? RC
+: other: R5
+
+? PreAir
+? Pre Air
+: other: Preair
+
+? Screener
+: other: Screener
+
+? Remux
+: other: Remux
+
+? 3D
+: other: 3D
+
+? HD
+: other: HD
+
+? mHD # ??
+: other: mHD
+
+? HDLight
+: other: HDLight
+
+? HQ
+: other: HQ
+
+? ddc
+: other: DDC
+
+? hr
+: other: HR
+
+? PAL
+: other: PAL
+
+? SECAM
+: other: SECAM
+
+? NTSC
+: other: NTSC
+
+? CC
+: other: CC
+
+? LD
+: other: LD
+
+? MD
+: other: MD
+
+? -The complete movie
+: other: Complete
+
+? +The complete movie
+: title: The complete movie
+
+? +AC3-HQ
+: audio_profile: HQ
+
+? Other-HQ
+: other: HQ
diff --git a/lib/guessit2/test/rules/part.yml b/lib/guessit2/test/rules/part.yml
new file mode 100644
index 000000000..72f3d98a8
--- /dev/null
+++ b/lib/guessit2/test/rules/part.yml
@@ -0,0 +1,18 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? Filename Part 3.mkv
+? Filename Part III.mkv
+? Filename Part Three.mkv
+? Filename Part Trois.mkv
+: title: Filename
+  part: 3
+
+? Part 3
+? Part III
+? Part Three
+? Part Trois
+? Part3
+: part: 3
+
+? -Something.Apt.1
+: part: 1
\ No newline at end of file
diff --git a/lib/guessit2/test/rules/processors.yml b/lib/guessit2/test/rules/processors.yml
new file mode 100644
index 000000000..ee906b2c3
--- /dev/null
+++ b/lib/guessit2/test/rules/processors.yml
@@ -0,0 +1,8 @@
+# Multiple input strings having same expected results can be chained.
+# Use $ marker to check inputs that should not match results.
+
+# Prefer information for last path.
+? Some movie (2000)/Some movie (2001).mkv
+? Some movie (2001)/Some movie.mkv
+: year: 2001
+  container: mkv
diff --git a/lib/guessit2/test/rules/release_group.yml b/lib/guessit2/test/rules/release_group.yml
new file mode 100644
index 000000000..8f1d9e931
--- /dev/null
+++ b/lib/guessit2/test/rules/release_group.yml
@@ -0,0 +1,33 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? Some.Title.XViD-ReleaseGroup
+? Some.Title.XViD-ReleaseGroup.mkv
+: release_group: ReleaseGroup
+
+? Some.Title.XViD-by.Artik[SEDG].avi
+: release_group: Artik[SEDG]
+
+? "[ABC] Some.Title.XViD.avi"
+? some/folder/[ABC]Some.Title.avi
+: release_group: ABC
+
+? Some.Title.XViD-S2E02.NoReleaseGroup.avi
+: release_group: !!null
+
+? Test.S01E01-FooBar-Group
+: options: -G group -G xxxx
+  episode: 1
+  episode_title: FooBar
+  release_group: Group
+  season: 1
+  title: Test
+  type: episode
+
+? Test.S01E01-FooBar-Group
+: options: -G re:gr.?up -G xxxx
+  episode: 1
+  episode_title: FooBar
+  release_group: Group
+  season: 1
+  title: Test
+  type: episode
diff --git a/lib/guessit2/test/rules/screen_size.yml b/lib/guessit2/test/rules/screen_size.yml
new file mode 100644
index 000000000..b7de201c3
--- /dev/null
+++ b/lib/guessit2/test/rules/screen_size.yml
@@ -0,0 +1,65 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? +360p
+? +360px
+? +360i
+? "+360"
+? +500x360
+: screen_size: 360p
+
+? +368p
+? +368px
+? +368i
+? "+368"
+? +500x368
+: screen_size: 368p
+
+? +480p
+? +480px
+? +480i
+? "+480"
+? +500x480
+: screen_size: 480p
+
+? +576p
+? +576px
+? +576i
+? "+576"
+? +500x576
+: screen_size: 576p
+
+? +720p
+? +720px
+? +720i
+? "+720"
+? +500x720
+: screen_size: 720p
+
+? +900p
+? +900px
+? +900i
+? "+900"
+? +500x900
+: screen_size: 900p
+
+? +1080p
+? +1080px
+? -1080i
+? "+1080"
+? +500x1080
+: screen_size: 1080p
+
+? +1080i
+? -1080p
+: screen_size: 1080i
+
+? +2160p
+? +2160px
+? +2160i
+? "+2160"
+? +4096x2160
+: screen_size: 4K
+
+? Test.File.720hd.bluray
+? Test.File.720p50
+: screen_size: 720p
diff --git a/lib/guessit2/test/rules/title.yml b/lib/guessit2/test/rules/title.yml
new file mode 100644
index 000000000..fffaf8a25
--- /dev/null
+++ b/lib/guessit2/test/rules/title.yml
@@ -0,0 +1,32 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? Title Only
+? -Title XViD 720p Only
+? sub/folder/Title Only
+? -sub/folder/Title XViD 720p Only
+? Title Only.mkv
+? Title Only.avi
+: title: Title Only
+
+? Title Only/title_only.mkv
+: title: Title Only
+
+? title_only.mkv
+: title: title only
+
+? Some Title/some.title.mkv
+? some.title/Some.Title.mkv
+: title: Some Title
+
+? SOME TITLE/Some.title.mkv
+? Some.title/SOME TITLE.mkv
+: title: Some title
+
+? some title/Some.title.mkv
+? Some.title/some title.mkv
+: title: Some title
+
+? Some other title/Some.Other.title.mkv
+? Some.Other title/Some other title.mkv
+: title: Some Other title
+
diff --git a/lib/guessit2/test/rules/video_codec.yml b/lib/guessit2/test/rules/video_codec.yml
new file mode 100644
index 000000000..d195eaafe
--- /dev/null
+++ b/lib/guessit2/test/rules/video_codec.yml
@@ -0,0 +1,54 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? rv10
+? rv13
+? RV20
+? Rv30
+? rv40
+? -xrv40
+: video_codec: Real
+
+? mpeg2
+? MPEG2
+? -mpeg
+? -mpeg 2  # Not sure if we should ignore this one ...
+? -xmpeg2
+? -mpeg2x
+: video_codec: Mpeg2
+
+? DivX
+? -div X
+? divx
+? dvdivx
+? DVDivX
+: video_codec: DivX
+
+? XviD
+? xvid
+? -x vid
+: video_codec: XviD
+
+? h264
+? x264
+? h.264
+? x.264
+? mpeg4-AVC
+? -MPEG-4
+? -mpeg4
+? -mpeg
+? -h 265
+? -x265
+: video_codec: h264
+
+? h265
+? x265
+? h.265
+? x.265
+? hevc
+? -h 264
+? -x264
+: video_codec: h265
+
+? h265-HP
+: video_codec: h265
+  video_profile: HP
\ No newline at end of file
diff --git a/lib/guessit2/test/rules/website.yml b/lib/guessit2/test/rules/website.yml
new file mode 100644
index 000000000..552386576
--- /dev/null
+++ b/lib/guessit2/test/rules/website.yml
@@ -0,0 +1,15 @@
+# Multiple input strings having same expected results can be chained.
+# Use - marker to check inputs that should not match results.
+? +tvu.org.ru
+? -tvu.unsafe.ru
+: website: tvu.org.ru
+
+? +www.nimp.na
+? -somewww.nimp.na
+? -www.nimp.nawouak
+? -nimp.na
+: website: www.nimp.na
+
+? +wawa.co.uk
+? -wawa.uk
+: website: wawa.co.uk
diff --git a/lib/guessit2/test/test-input-file.txt b/lib/guessit2/test/test-input-file.txt
new file mode 100644
index 000000000..656bc9317
--- /dev/null
+++ b/lib/guessit2/test/test-input-file.txt
@@ -0,0 +1,2 @@
+Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv
+SecondFile.avi
\ No newline at end of file
diff --git a/lib/guessit2/test/test_api.py b/lib/guessit2/test/test_api.py
new file mode 100644
index 000000000..05ed9a431
--- /dev/null
+++ b/lib/guessit2/test/test_api.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
+
+import os
+
+import pytest
+
+from ..api import guessit, properties
+
+__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
+
+
+def test_default():
+    ret = guessit(u'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv')
+    assert ret and 'title' in ret
+
+
+def test_unicode():
+    ret = guessit(u'[阿维达].Avida.2006.FRENCH.DVDRiP.XViD-PROD.avi')
+    assert ret and 'title' in ret
+
+
+def test_main_non_unicode():
+    with pytest.raises(TypeError):
+        guessit(b'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv')
+
+
+def test_properties():
+    props = properties()
+    assert 'video_codec' in props.keys()
diff --git a/lib/guessit2/test/test_benchmark.py b/lib/guessit2/test/test_benchmark.py
new file mode 100644
index 000000000..7638fe2d6
--- /dev/null
+++ b/lib/guessit2/test/test_benchmark.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use,pointless-statement,missing-docstring,invalid-name,line-too-long
+import time
+
+import pytest
+
+from ..api import guessit
+
+
+def case1():
+    return guessit(u'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv')
+
+
+def case2():
+    return guessit(u'Movies/Fantastic Mr Fox/Fantastic.Mr.Fox.2009.DVDRip.{x264+LC-AAC.5.1}{Fr-Eng}{Sub.Fr-Eng}-™.[sharethefiles.com].mkv')
+
+
+def case3():
+    return guessit(u'Series/dexter/Dexter.5x02.Hello,.Bandit.ENG.-.sub.FR.HDTV.XviD-AlFleNi-TeaM.[tvu.org.ru].avi')
+
+
+def case4():
+    return guessit(u'Movies/The Doors (1991)/09.03.08.The.Doors.(1991).BDRip.720p.AC3.X264-HiS@SiLUHD-English.[sharethefiles.com].mkv')
+
+
+@pytest.mark.benchmark(
+    group="Performance Tests",
+    min_time=1,
+    max_time=2,
+    min_rounds=5,
+    timer=time.time,
+    disable_gc=True,
+    warmup=False
+)
+@pytest.mark.skipif(True, reason="Disabled")
+class TestBenchmark(object):
+    def test_case1(self, benchmark):
+        ret = benchmark(case1)
+        assert ret
+
+    def test_case2(self, benchmark):
+        ret = benchmark(case2)
+        assert ret
+
+    def test_case3(self, benchmark):
+        ret = benchmark(case3)
+        assert ret
+
+    def test_case4(self, benchmark):
+        ret = benchmark(case4)
+        assert ret
+
diff --git a/lib/guessit2/test/test_main.py b/lib/guessit2/test/test_main.py
new file mode 100644
index 000000000..5c76064a6
--- /dev/null
+++ b/lib/guessit2/test/test_main.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
+
+import os
+
+import pytest
+
+from ..__main__ import main
+
+__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
+
+
+def test_main_no_args():
+    main([])
+
+
+def test_main():
+    main([u'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv'])
+
+
+def test_main_unicode():
+    main([u'[阿维达].Avida.2006.FRENCH.DVDRiP.XViD-PROD.avi'])
+
+
+def test_main_non_unicode():
+    main(['Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv'])
+
+
+def test_main_verbose():
+    main([u'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv', '--verbose'])
+
+
+def test_main_yaml():
+    main([u'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv', '--yaml'])
+
+
+def test_main_json():
+    main([u'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv', '--json'])
+
+
+def test_main_show_property():
+    main([u'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv', '-P', 'title'])
+
+
+def test_main_advanced():
+    main([u'Fear.and.Loathing.in.Las.Vegas.FRENCH.ENGLISH.720p.HDDVD.DTS.x264-ESiR.mkv', '-a'])
+
+
+def test_main_input():
+    main(['--input', os.path.join(__location__, 'test-input-file.txt')])
+
+
+def test_main_properties():
+    main(['-p'])
+    main(['-p', '--json'])
+    main(['-p', '--yaml'])
+
+
+def test_main_values():
+    main(['-V'])
+    main(['-V', '--json'])
+    main(['-V', '--yaml'])
+
+
+def test_main_help():
+    with pytest.raises(SystemExit):
+        main(['--help'])
+
+
+def test_main_version():
+    main(['--version'])
diff --git a/lib/guessit2/test/test_yml.py b/lib/guessit2/test/test_yml.py
new file mode 100644
index 000000000..ccd78e15d
--- /dev/null
+++ b/lib/guessit2/test/test_yml.py
@@ -0,0 +1,274 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
+import logging
+
+# io.open supports encoding= in python 2.7
+from io import open  # pylint: disable=redefined-builtin
+import os
+import yaml
+
+import six
+
+import regex as re
+
+import babelfish
+import pytest
+
+from rebulk.utils import is_iterable
+
+from guessit.options import parse_options
+from ..yamlutils import OrderedDictYAMLLoader
+from .. import guessit
+
+
+logger = logging.getLogger(__name__)
+
+__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
+
+filename_predicate = None
+string_predicate = None
+
+
+# filename_predicate = lambda filename: 'episode_title' in filename
+# string_predicate = lambda string: '-DVD.BlablaBla.Fix.Blablabla.XVID' in string
+
+
+
+class EntryResult(object):
+    def __init__(self, string, negates=False):
+        self.string = string
+        self.negates = negates
+        self.valid = []
+        self.missing = []
+        self.different = []
+        self.extra = []
+        self.others = []
+
+    @property
+    def ok(self):
+        if self.negates:
+            return self.missing or self.different
+        return not self.missing and not self.different and not self.extra and not self.others
+
+    @property
+    def warning(self):
+        if self.negates:
+            return False
+        return not self.missing and not self.different and self.extra
+
+    @property
+    def error(self):
+        if self.negates:
+            return not self.missing and not self.different and not self.others
+        return self.missing or self.different or self.others
+
+    def __repr__(self):
+        if self.ok:
+            return self.string + ': OK!'
+        elif self.warning:
+            return '%s%s: WARNING! (valid=%i, extra=%i)' % ('-' if self.negates else '', self.string, len(self.valid),
+                                                            len(self.extra))
+        elif self.error:
+            return '%s%s: ERROR! (valid=%i, missing=%i, different=%i, extra=%i, others=%i)' % \
+                   ('-' if self.negates else '', self.string, len(self.valid), len(self.missing), len(self.different),
+                    len(self.extra), len(self.others))
+        else:
+            return '%s%s: UNKOWN! (valid=%i, missing=%i, different=%i, extra=%i, others=%i)' % \
+                   ('-' if self.negates else '', self.string, len(self.valid), len(self.missing), len(self.different),
+                    len(self.extra), len(self.others))
+
+    @property
+    def details(self):
+        ret = []
+        if self.valid:
+            ret.append('valid=' + str(len(self.valid)))
+        for valid in self.valid:
+            ret.append(' ' * 4 + str(valid))
+        if self.missing:
+            ret.append('missing=' + str(len(self.missing)))
+        for missing in self.missing:
+            ret.append(' ' * 4 + str(missing))
+        if self.different:
+            ret.append('different=' + str(len(self.different)))
+        for different in self.different:
+            ret.append(' ' * 4 + str(different))
+        if self.extra:
+            ret.append('extra=' + str(len(self.extra)))
+        for extra in self.extra:
+            ret.append(' ' * 4 + str(extra))
+        if self.others:
+            ret.append('others=' + str(len(self.others)))
+        for other in self.others:
+            ret.append(' ' * 4 + str(other))
+        return ret
+
+
+class Results(list):
+    def assert_ok(self):
+        errors = [entry for entry in self if entry.error]
+        assert not errors
+
+
+def files_and_ids(predicate=None):
+    files = []
+    ids = []
+
+    for (dirpath, _, filenames) in os.walk(__location__):
+        if dirpath == __location__:
+            dirpath_rel = ''
+        else:
+            dirpath_rel = os.path.relpath(dirpath, __location__)
+        for filename in filenames:
+            name, ext = os.path.splitext(filename)
+            filepath = os.path.join(dirpath_rel, filename)
+            if ext == '.yml' and (not predicate or predicate(filepath)):
+                files.append(filepath)
+                ids.append(os.path.join(dirpath_rel, name))
+
+    return files, ids
+
+
+class TestYml(object):
+    """
+    Run tests from yaml files.
+    Multiple input strings having same expected results can be chained.
+    Use $ marker to check inputs that should not match results.
+    """
+
+    options_re = re.compile(r'^([ \+-]+)(.*)')
+
+    files, ids = files_and_ids(filename_predicate)
+
+    @staticmethod
+    def set_default(expected, default):
+        if default:
+            for k, v in default.items():
+                if k not in expected:
+                    expected[k] = v
+
+    @pytest.mark.parametrize('filename', files, ids=ids)
+    def test(self, filename, caplog):
+        caplog.setLevel(logging.INFO)
+        with open(os.path.join(__location__, filename), 'r', encoding='utf-8') as infile:
+            data = yaml.load(infile, OrderedDictYAMLLoader)
+        entries = Results()
+
+        last_expected = None
+        for string, expected in reversed(list(data.items())):
+            if expected is None:
+                data[string] = last_expected
+            else:
+                last_expected = expected
+
+        default = None
+        try:
+            default = data['__default__']
+            del data['__default__']
+        except KeyError:
+            pass
+
+        for string, expected in data.items():
+            TestYml.set_default(expected, default)
+            if not isinstance(string, six.text_type):
+                string = six.text_type(string)
+            if not string_predicate or string_predicate(string):  # pylint: disable=not-callable
+                entry = self.check(string, expected)
+                if entry.ok:
+                    logger.debug(u'[' + filename + '] ' + six.text_type(entry))
+                elif entry.warning:
+                    logger.warning(u'[' + filename + '] ' + six.text_type(entry))
+                elif entry.error:
+                    logger.error(u'[' + filename + '] ' + six.text_type(entry))
+                    for line in entry.details:
+                        logger.error(u'[' + filename + '] ' + ' ' * 4 + line)
+                entries.append(entry)
+        entries.assert_ok()
+
+    def check(self, string, expected):
+        negates, global_, string = self.parse_token_options(string)
+
+        options = expected.get('options')
+        if options is None:
+            options = {}
+        if not isinstance(options, dict):
+            options = parse_options(options)
+        if 'implicit' not in options:
+            options['implicit'] = True
+        try:
+            result = guessit(string, options)
+        except Exception as exc:
+            logger.error('[' + string + '] Exception: ' + str(exc))
+            raise exc
+
+        entry = EntryResult(string, negates)
+
+        if global_:
+            self.check_global(string, result, entry)
+
+        self.check_expected(result, expected, entry)
+
+        return entry
+
+    def parse_token_options(self, string):
+        matches = self.options_re.search(string)
+        negates = False
+        global_ = False
+        if matches:
+            string = matches.group(2)
+            for opt in matches.group(1):
+                if '-' in opt:
+                    negates = True
+                if '+' in opt:
+                    global_ = True
+        return negates, global_, string
+
+    def check_global(self, string, result, entry):
+        global_span = []
+        for result_matches in result.matches.values():
+            for result_match in result_matches:
+                if not global_span:
+                    global_span = list(result_match.span)
+                else:
+                    if global_span[0] > result_match.span[0]:
+                        global_span[0] = result_match.span[0]
+                    if global_span[1] < result_match.span[1]:
+                        global_span[1] = result_match.span[1]
+        if global_span and global_span[1] - global_span[0] < len(string):
+            entry.others.append("Match is not global")
+
+    def is_same(self, value, expected):
+        values = set(value) if is_iterable(value) else set((value,))
+        expecteds = set(expected) if is_iterable(expected) else set((expected,))
+        if len(values) != len(expecteds):
+            return False
+        if isinstance(next(iter(values)), babelfish.Language):
+            # pylint: disable=no-member
+            expecteds = set([babelfish.Language.fromguessit(expected) for expected in expecteds])
+        elif isinstance(next(iter(values)), babelfish.Country):
+            # pylint: disable=no-member
+            expecteds = set([babelfish.Country.fromguessit(expected) for expected in expecteds])
+        return values == expecteds
+
+    def check_expected(self, result, expected, entry):
+        if expected:
+            for expected_key, expected_value in expected.items():
+                if expected_key and expected_key != 'options' and expected_value is not None:
+                    negates_key, _, result_key = self.parse_token_options(expected_key)
+                    if result_key in result.keys():
+                        if not self.is_same(result[result_key], expected_value):
+                            if negates_key:
+                                entry.valid.append((expected_key, expected_value))
+                            else:
+                                entry.different.append((expected_key, expected_value, result[expected_key]))
+                        else:
+                            if negates_key:
+                                entry.different.append((expected_key, expected_value, result[expected_key]))
+                            else:
+                                entry.valid.append((expected_key, expected_value))
+                    elif not negates_key:
+                        entry.missing.append((expected_key, expected_value))
+
+        for result_key, result_value in result.items():
+            if result_key not in expected.keys():
+                entry.extra.append((result_key, result_value))
diff --git a/lib/guessit2/test/various.yml b/lib/guessit2/test/various.yml
new file mode 100644
index 000000000..1d22a4eb9
--- /dev/null
+++ b/lib/guessit2/test/various.yml
@@ -0,0 +1,545 @@
+? Movies/Fear and Loathing in Las Vegas (1998)/Fear.and.Loathing.in.Las.Vegas.720p.HDDVD.DTS.x264-ESiR.mkv
+: type: movie
+  title: Fear and Loathing in Las Vegas
+  year: 1998
+  screen_size: 720p
+  format: HD-DVD
+  audio_codec: DTS
+  video_codec: h264
+  release_group: ESiR
+
+? Series/Duckman/Duckman - 101 (01) - 20021107 - I, Duckman.avi
+: type: episode
+  title: Duckman
+  season: 1
+  episode: 1
+  episode_title: I, Duckman
+  date: 2002-11-07
+
+? Series/Neverwhere/Neverwhere.05.Down.Street.[tvu.org.ru].avi
+: type: episode
+  title: Neverwhere
+  episode: 5
+  episode_title: Down Street
+  website: tvu.org.ru
+
+? Neverwhere.05.Down.Street.[tvu.org.ru].avi
+: type: episode
+  title: Neverwhere
+  episode: 5
+  episode_title: Down Street
+  website: tvu.org.ru
+
+? Series/Breaking Bad/Minisodes/Breaking.Bad.(Minisodes).01.Good.Cop.Bad.Cop.WEBRip.XviD.avi
+: type: episode
+  title: Breaking Bad
+  episode_format: Minisode
+  episode: 1
+  episode_title: Good Cop Bad Cop
+  format: WEBRip
+  video_codec: XviD
+
+? Series/Kaamelott/Kaamelott - Livre V - Ep 23 - Le Forfait.avi
+: type: episode
+  title: Kaamelott
+  episode: 23
+  episode_title: Le Forfait
+
+? Movies/The Doors (1991)/09.03.08.The.Doors.(1991).BDRip.720p.AC3.X264-HiS@SiLUHD-English.[sharethefiles.com].mkv
+: type: movie
+  title: The Doors
+  year: 1991
+  date: 2008-03-09
+  format: BluRay
+  screen_size: 720p
+  audio_codec: AC3
+  video_codec: h264
+  release_group: HiS@SiLUHD
+  language: english
+  website: sharethefiles.com
+
+? Movies/M.A.S.H. (1970)/MASH.(1970).[Divx.5.02][Dual-Subtitulos][DVDRip].ogm
+: type: movie
+  title: MASH
+  year: 1970
+  video_codec: DivX
+  format: DVD
+
+? the.mentalist.501.hdtv-lol.mp4
+: type: episode
+  title: the mentalist
+  season: 5
+  episode: 1
+  format: HDTV
+  release_group: lol
+
+? the.simpsons.2401.hdtv-lol.mp4
+: type: episode
+  title: the simpsons
+  season: 24
+  episode: 1
+  format: HDTV
+  release_group: lol
+
+? Homeland.S02E01.HDTV.x264-EVOLVE.mp4
+: type: episode
+  title: Homeland
+  season: 2
+  episode: 1
+  format: HDTV
+  video_codec: h264
+  release_group: EVOLVE
+
+? /media/Band_of_Brothers-e01-Currahee.mkv
+: type: episode
+  title: Band of Brothers
+  episode: 1
+  episode_title: Currahee
+
+? /media/Band_of_Brothers-x02-We_Stand_Alone_Together.mkv
+: type: episode
+  title: Band of Brothers
+  bonus: 2
+  bonus_title: We Stand Alone Together
+
+? /movies/James_Bond-f21-Casino_Royale-x02-Stunts.mkv
+: type: movie
+  title: Casino Royale
+  film_title: James Bond
+  film: 21
+  bonus: 2
+  bonus_title: Stunts
+
+? /TV Shows/new.girl.117.hdtv-lol.mp4
+: type: episode
+  title: new girl
+  season: 1
+  episode: 17
+  format: HDTV
+  release_group: lol
+
+? The.Office.(US).1x03.Health.Care.HDTV.XviD-LOL.avi
+: type: episode
+  title: The Office
+  country: US
+  season: 1
+  episode: 3
+  episode_title: Health Care
+  format: HDTV
+  video_codec: XviD
+  release_group: LOL
+
+? The_Insider-(1999)-x02-60_Minutes_Interview-1996.mp4
+: type: movie
+  title: The Insider
+  year: 1999
+  bonus: 2
+  bonus_title: 60 Minutes Interview-1996
+
+? OSS_117--Cairo,_Nest_of_Spies.mkv
+: type: movie
+  title: OSS 117
+  alternativeTitle: Cairo, Nest of Spies
+
+? Rush.._Beyond_The_Lighted_Stage-x09-Between_Sun_and_Moon-2002_Hartford.mkv
+: type: movie
+  title: Rush Beyond The Lighted Stage
+  bonus: 9
+  bonus_title: Between Sun and Moon
+  year: 2002
+
+? House.Hunters.International.S56E06.720p.hdtv.x264.mp4
+: type: episode
+  title: House Hunters International
+  season: 56
+  episode: 6
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+
+? White.House.Down.2013.1080p.BluRay.DTS-HD.MA.5.1.x264-PublicHD.mkv
+: type: movie
+  title: White House Down
+  year: 2013
+  screen_size: 1080p
+  format: BluRay
+  audio_codec: DTS
+  audio_profile: HDMA
+  video_codec: h264
+  release_group: PublicHD
+  audio_channels: "5.1"
+
+? White.House.Down.2013.1080p.BluRay.DTSHD.MA.5.1.x264-PublicHD.mkv
+: type: movie
+  title: White House Down
+  year: 2013
+  screen_size: 1080p
+  format: BluRay
+  audio_codec: DTS
+  audio_profile: HDMA
+  video_codec: h264
+  release_group: PublicHD
+  audio_channels: "5.1"
+
+? Hostages.S01E01.Pilot.for.Air.720p.WEB-DL.DD5.1.H.264-NTb.nfo
+: type: episode
+  title: Hostages
+  episode_title: Pilot for Air
+  season: 1
+  episode: 1
+  screen_size: 720p
+  format: WEB-DL
+  audio_channels: "5.1"
+  video_codec: h264
+  audio_codec: DolbyDigital
+  release_group: NTb
+
+? Despicable.Me.2.2013.1080p.BluRay.x264-VeDeTT.nfo
+: type: movie
+  title: Despicable Me 2
+  year: 2013
+  screen_size: 1080p
+  format: BluRay
+  video_codec: h264
+  release_group: VeDeTT
+
+? Le Cinquieme Commando 1971 SUBFORCED FRENCH DVDRiP XViD AC3 Bandix.mkv
+: type: movie
+  audio_codec: AC3
+  format: DVD
+  release_group: Bandix
+  subtitle_language: French
+  title: Le Cinquieme Commando
+  video_codec: XviD
+  year: 1971
+
+? Le Seigneur des Anneaux - La Communauté de l'Anneau - Version Longue - BDRip.mkv
+: type: movie
+  format: BluRay
+  title: Le Seigneur des Anneaux
+
+? La petite bande (Michel Deville - 1983) VF PAL MP4 x264 AAC.mkv
+: type: movie
+  audio_codec: AAC
+  language: French
+  title: La petite bande
+  video_codec: h264
+  year: 1983
+  other: PAL
+
+? Retour de Flammes (Gregor Schnitzler 2003) FULL DVD.iso
+: type: movie
+  format: DVD
+  title: Retour de Flammes
+  type: movie
+  year: 2003
+
+? A.Common.Title.Special.2014.avi
+: type: movie
+  year: 2014
+  title: A Common Title Special
+
+? A.Common.Title.2014.Special.avi
+: type: episode
+  year: 2014
+  title: A Common Title
+  episode_title: Special
+  episode_details: Special
+
+? A.Common.Title.2014.Special.Edition.avi
+: type: movie
+  year: 2014
+  title: A Common Title
+  edition: Special Edition
+
+? Downton.Abbey.2013.Christmas.Special.HDTV.x264-FoV.mp4
+: type: episode
+  year: 2013
+  title: Downton Abbey
+  episode_title: Christmas Special
+  video_codec: h264
+  release_group: FoV
+  format: HDTV
+  episode_details: Special
+
+? Doctor_Who_2013_Christmas_Special.The_Time_of_The_Doctor.HD
+: type: episode
+  title: Doctor Who
+  other: HD
+  episode_details: Special
+  episode_title: Christmas Special The Time of The Doctor
+  year: 2013
+
+? Doctor Who 2005 50th Anniversary Special The Day of the Doctor 3.avi
+: type: episode
+  title: Doctor Who
+  episode_details: Special
+  episode_title: 50th Anniversary Special The Day of the Doctor 3
+  year: 2005
+
+? Robot Chicken S06-Born Again Virgin Christmas Special HDTV x264.avi
+: type: episode
+  title: Robot Chicken
+  format: HDTV
+  season: 6
+  episode_title: Born Again Virgin Christmas Special
+  video_codec: h264
+  episode_details: Special
+
+? Wicked.Tuna.S03E00.Head.To.Tail.Special.HDTV.x264-YesTV
+: type: episode
+  title: Wicked Tuna
+  episode_title: Head To Tail Special
+  release_group: YesTV
+  season: 3
+  episode: 0
+  video_codec: h264
+  format: HDTV
+  episode_details: Special
+
+? The.Voice.UK.S03E12.HDTV.x264-C4TV
+: episode: 12
+  video_codec: h264
+  format: HDTV
+  title: The Voice
+  release_group: C4TV
+  season: 3
+  country: United Kingdom
+  type: episode
+
+? /tmp/star.trek.9/star.trek.9.mkv
+: type: movie
+  title: star trek 9
+
+? star.trek.9.mkv
+: type: movie
+  title: star trek 9
+
+? FlexGet.S01E02.TheName.HDTV.xvid
+: episode: 2
+  format: HDTV
+  season: 1
+  title: FlexGet
+  episode_title: TheName
+  type: episode
+  video_codec: XviD
+
+? FlexGet.S01E02.TheName.HDTV.xvid
+: episode: 2
+  format: HDTV
+  season: 1
+  title: FlexGet
+  episode_title: TheName
+  type: episode
+  video_codec: XviD
+
+? some.series.S03E14.Title.Here.720p
+: episode: 14
+  screen_size: 720p
+  season: 3
+  title: some series
+  episode_title: Title Here
+  type: episode
+
+? '[the.group] Some.Series.S03E15.Title.Two.720p'
+: episode: 15
+  release_group: the.group
+  screen_size: 720p
+  season: 3
+  title: Some Series
+  episode_title: Title Two
+  type: episode
+
+? 'HD 720p: Some series.S03E16.Title.Three'
+: episode: 16
+  other: HD
+  screen_size: 720p
+  season: 3
+  title: Some series
+  episode_title: Title Three
+  type: episode
+
+? Something.Season.2.1of4.Ep.Title.HDTV.torrent
+: episode_count: 4
+  episode: 1
+  format: HDTV
+  season: 2
+  title: Something
+  episode_title: Title
+  type: episode
+  container: torrent
+
+? Show-A (US) - Episode Title S02E09 hdtv
+: country: US
+  episode: 9
+  format: HDTV
+  season: 2
+  title: Show-A
+  type: episode
+
+? Jack's.Show.S03E01.blah.1080p
+: episode: 1
+  screen_size: 1080p
+  season: 3
+  title: Jack's Show
+  episode_title: blah
+  type: episode
+
+? FlexGet.epic
+: title: FlexGet epic
+  type: movie
+
+? FlexGet.Apt.1
+: title: FlexGet Apt 1
+  type: movie
+
+? FlexGet.aptitude
+: title: FlexGet aptitude
+  type: movie
+
+? FlexGet.Step1
+: title: FlexGet Step1
+  type: movie
+
+? Movies/El Bosque Animado (1987)/El.Bosque.Animado.[Jose.Luis.Cuerda.1987].[Xvid-Dvdrip-720 * 432].avi
+: format: DVD
+  screen_size: 720x432
+  title: El Bosque Animado
+  video_codec: XviD
+  year: 1987
+  type: movie
+
+? Movies/El Bosque Animado (1987)/El.Bosque.Animado.[Jose.Luis.Cuerda.1987].[Xvid-Dvdrip-720x432].avi
+: format: DVD
+  screen_size: 720x432
+  title: El Bosque Animado
+  video_codec: XviD
+  year: 1987
+  type: movie
+
+? 2009.shoot.fruit.chan.multi.dvd9.pal
+: format: DVD
+  language: mul
+  other: PAL
+  title: shoot fruit chan
+  type: movie
+  year: 2009
+
+? 2009.shoot.fruit.chan.multi.dvd5.pal
+: format: DVD
+  language: mul
+  other: PAL
+  title: shoot fruit chan
+  type: movie
+  year: 2009
+
+? The.Flash.2014.S01E01.PREAIR.WEBRip.XviD-EVO.avi
+: episode: 1
+  format: WEBRip
+  other: Preair
+  release_group: EVO
+  season: 1
+  title: The Flash
+  type: episode
+  video_codec: XviD
+  year: 2014
+
+? Ice.Lake.Rebels.S01E06.Ice.Lake.Games.720p.HDTV.x264-DHD
+: episode: 6
+  format: HDTV
+  release_group: DHD
+  screen_size: 720p
+  season: 1
+  title: Ice Lake Rebels
+  episode_title: Ice Lake Games
+  type: episode
+  video_codec: h264
+
+? The League - S06E10 - Epi Sexy.mkv
+: episode: 10
+  season: 6
+  title: The League
+  episode_title: Epi Sexy
+  type: episode
+
+? Stay (2005) [1080p]/Stay.2005.1080p.BluRay.x264.YIFY.mp4
+: format: BluRay
+  release_group: YIFY
+  screen_size: 1080p
+  title: Stay
+  type: movie
+  video_codec: h264
+  year: 2005
+
+? /media/live/A/Anger.Management.S02E82.720p.HDTV.X264-DIMENSION.mkv
+: format: HDTV
+  release_group: DIMENSION
+  screen_size: 720p
+  title: Anger Management
+  type: episode
+  season: 2
+  episode: 82
+  video_codec: h264
+
+? "[Figmentos] Monster 34 - At the End of Darkness [781219F1].mkv"
+: type: episode
+  release_group: Figmentos
+  title: Monster
+  episode: 34
+  episode_title: At the End of Darkness
+  crc32: 781219F1
+
+? Game.of.Thrones.S05E07.720p.HDTV-KILLERS.mkv
+: type: episode
+  episode: 7
+  format: HDTV
+  release_group: KILLERS
+  screen_size: 720p
+  season: 5
+  title: Game of Thrones
+
+? Game.of.Thrones.S05E07.HDTV.720p-KILLERS.mkv
+: type: episode
+  episode: 7
+  format: HDTV
+  release_group: KILLERS
+  screen_size: 720p
+  season: 5
+  title: Game of Thrones
+
+? Parks and Recreation - [04x12] - Ad Campaign.avi
+: type: episode
+  title: Parks and Recreation
+  season: 4
+  episode: 12
+  episode_title: Ad Campaign
+
+? Star Trek Into Darkness (2013)/star.trek.into.darkness.2013.720p.web-dl.h264-publichd.mkv
+: type: movie
+  title: Star Trek Into Darkness
+  year: 2013
+  screen_size: 720p
+  format: WEB-DL
+  video_codec: h264
+  release_group: publichd
+
+? /var/medias/series/The Originals/Season 02/The.Originals.S02E15.720p.HDTV.X264-DIMENSION.mkv
+: type: episode
+  title: The Originals
+  season: 2
+  episode: 15
+  screen_size: 720p
+  format: HDTV
+  video_codec: h264
+  release_group: DIMENSION
+
+? Test.S01E01E07-FooBar-Group.avi
+: container: avi
+  episode:
+  - 1
+  - 7
+  episode_title: FooBar-Group  # Make sure it doesn't conflict with uuid
+  mimetype: video/x-msvideo
+  season: 1
+  title: Test
+  type: episode
diff --git a/lib/guessit2/tlds-alpha-by-domain.txt b/lib/guessit2/tlds-alpha-by-domain.txt
new file mode 100644
index 000000000..280c794c5
--- /dev/null
+++ b/lib/guessit2/tlds-alpha-by-domain.txt
@@ -0,0 +1,341 @@
+# Version 2013112900, Last Updated Fri Nov 29 07:07:01 2013 UTC
+AC
+AD
+AE
+AERO
+AF
+AG
+AI
+AL
+AM
+AN
+AO
+AQ
+AR
+ARPA
+AS
+ASIA
+AT
+AU
+AW
+AX
+AZ
+BA
+BB
+BD
+BE
+BF
+BG
+BH
+BI
+BIKE
+BIZ
+BJ
+BM
+BN
+BO
+BR
+BS
+BT
+BV
+BW
+BY
+BZ
+CA
+CAMERA
+CAT
+CC
+CD
+CF
+CG
+CH
+CI
+CK
+CL
+CLOTHING
+CM
+CN
+CO
+COM
+CONSTRUCTION
+CONTRACTORS
+COOP
+CR
+CU
+CV
+CW
+CX
+CY
+CZ
+DE
+DIAMONDS
+DIRECTORY
+DJ
+DK
+DM
+DO
+DZ
+EC
+EDU
+EE
+EG
+ENTERPRISES
+EQUIPMENT
+ER
+ES
+ESTATE
+ET
+EU
+FI
+FJ
+FK
+FM
+FO
+FR
+GA
+GALLERY
+GB
+GD
+GE
+GF
+GG
+GH
+GI
+GL
+GM
+GN
+GOV
+GP
+GQ
+GR
+GRAPHICS
+GS
+GT
+GU
+GURU
+GW
+GY
+HK
+HM
+HN
+HOLDINGS
+HR
+HT
+HU
+ID
+IE
+IL
+IM
+IN
+INFO
+INT
+IO
+IQ
+IR
+IS
+IT
+JE
+JM
+JO
+JOBS
+JP
+KE
+KG
+KH
+KI
+KITCHEN
+KM
+KN
+KP
+KR
+KW
+KY
+KZ
+LA
+LAND
+LB
+LC
+LI
+LIGHTING
+LK
+LR
+LS
+LT
+LU
+LV
+LY
+MA
+MC
+MD
+ME
+MG
+MH
+MIL
+MK
+ML
+MM
+MN
+MO
+MOBI
+MP
+MQ
+MR
+MS
+MT
+MU
+MUSEUM
+MV
+MW
+MX
+MY
+MZ
+NA
+NAME
+NC
+NE
+NET
+NF
+NG
+NI
+NL
+NO
+NP
+NR
+NU
+NZ
+OM
+ORG
+PA
+PE
+PF
+PG
+PH
+PHOTOGRAPHY
+PK
+PL
+PLUMBING
+PM
+PN
+POST
+PR
+PRO
+PS
+PT
+PW
+PY
+QA
+RE
+RO
+RS
+RU
+RW
+SA
+SB
+SC
+SD
+SE
+SEXY
+SG
+SH
+SI
+SINGLES
+SJ
+SK
+SL
+SM
+SN
+SO
+SR
+ST
+SU
+SV
+SX
+SY
+SZ
+TATTOO
+TC
+TD
+TECHNOLOGY
+TEL
+TF
+TG
+TH
+TIPS
+TJ
+TK
+TL
+TM
+TN
+TO
+TODAY
+TP
+TR
+TRAVEL
+TT
+TV
+TW
+TZ
+UA
+UG
+UK
+US
+UY
+UZ
+VA
+VC
+VE
+VENTURES
+VG
+VI
+VN
+VOYAGE
+VU
+WF
+WS
+XN--3E0B707E
+XN--45BRJ9C
+XN--80AO21A
+XN--80ASEHDB
+XN--80ASWG
+XN--90A3AC
+XN--CLCHC0EA0B2G2A9GCD
+XN--FIQS8S
+XN--FIQZ9S
+XN--FPCRJ9C3D
+XN--FZC2C9E2C
+XN--GECRJ9C
+XN--H2BRJ9C
+XN--J1AMH
+XN--J6W193G
+XN--KPRW13D
+XN--KPRY57D
+XN--L1ACC
+XN--LGBBAT1AD8J
+XN--MGB9AWBF
+XN--MGBA3A4F16A
+XN--MGBAAM7A8H
+XN--MGBAYH7GPA
+XN--MGBBH1A71E
+XN--MGBC0A9AZCG
+XN--MGBERP4A5D4AR
+XN--MGBX4CD0AB
+XN--NGBC5AZD
+XN--O3CW4H
+XN--OGBPF8FL
+XN--P1AI
+XN--PGBS0DH
+XN--Q9JYB4C
+XN--S9BRJ9C
+XN--UNUP4Y
+XN--WGBH1C
+XN--WGBL6A
+XN--XKC2AL3HYE2A
+XN--XKC2DL3A5EE0H
+XN--YFRO4I67O
+XN--YGBI2AMMX
+XXX
+YE
+YT
+ZA
+ZM
+ZW
diff --git a/lib/guessit2/yamlutils.py b/lib/guessit2/yamlutils.py
new file mode 100644
index 000000000..2824575da
--- /dev/null
+++ b/lib/guessit2/yamlutils.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Options
+"""
+try:
+    from collections import OrderedDict
+except ImportError:  # pragma: no-cover
+    from ordereddict import OrderedDict  # pylint:disable=import-error
+import babelfish
+
+import yaml
+
+
+class OrderedDictYAMLLoader(yaml.Loader):
+    """
+    A YAML loader that loads mappings into ordered dictionaries.
+    From https://gist.github.com/enaeseth/844388
+    """
+
+    def __init__(self, *args, **kwargs):
+        yaml.Loader.__init__(self, *args, **kwargs)
+
+        self.add_constructor(u'tag:yaml.org,2002:map', type(self).construct_yaml_map)
+        self.add_constructor(u'tag:yaml.org,2002:omap', type(self).construct_yaml_map)
+
+    def construct_yaml_map(self, node):
+        data = OrderedDict()
+        yield data
+        value = self.construct_mapping(node)
+        data.update(value)
+
+    def construct_mapping(self, node, deep=False):
+        if isinstance(node, yaml.MappingNode):
+            self.flatten_mapping(node)
+        else:  # pragma: no cover
+            raise yaml.constructor.ConstructorError(None, None,
+                                                    'expected a mapping node, but found %s' % node.id, node.start_mark)
+
+        mapping = OrderedDict()
+        for key_node, value_node in node.value:
+            key = self.construct_object(key_node, deep=deep)
+            try:
+                hash(key)
+            except TypeError as exc:  # pragma: no cover
+                raise yaml.constructor.ConstructorError('while constructing a mapping',
+                                                        node.start_mark, 'found unacceptable key (%s)'
+                                                        % exc, key_node.start_mark)
+            value = self.construct_object(value_node, deep=deep)
+            mapping[key] = value
+        return mapping
+
+
+class CustomDumper(yaml.SafeDumper):
+    """
+    Custom YAML Dumper.
+    """
+    pass
+
+
+def default_representer(dumper, data):
+    """Default representer"""
+    return dumper.represent_str(str(data))
+CustomDumper.add_representer(babelfish.Language, default_representer)
+CustomDumper.add_representer(babelfish.Country, default_representer)
+
+
+def ordered_dict_representer(dumper, data):
+    """OrderedDict representer"""
+    return dumper.represent_dict(data)
+CustomDumper.add_representer(OrderedDict, ordered_dict_representer)
diff --git a/lib/rebulk/__init__.py b/lib/rebulk/__init__.py
new file mode 100644
index 000000000..93d5e4774
--- /dev/null
+++ b/lib/rebulk/__init__.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Define simple search patterns in bulk to perform advanced matching on any string.
+"""
+#  pylint:disable=import-self
+from .rebulk import Rebulk
+from .rules import Rule, CustomRule, AppendMatch, RemoveMatch, RenameMatch, AppendTags, RemoveTags
+from .processors import ConflictSolver, PrivateRemover, POST_PROCESS, PRE_PROCESS
+from .pattern import REGEX_AVAILABLE
diff --git a/lib/rebulk/__version__.py b/lib/rebulk/__version__.py
new file mode 100644
index 000000000..59489449b
--- /dev/null
+++ b/lib/rebulk/__version__.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Version module
+"""
+# pragma: no cover
+__version__ = '0.6.5.dev0'
diff --git a/lib/rebulk/debug.py b/lib/rebulk/debug.py
new file mode 100644
index 000000000..2384b26ef
--- /dev/null
+++ b/lib/rebulk/debug.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Debug tools.
+
+Can be configured by changing values of those variable.
+
+DEBUG = False
+Enable this variable to activate debug features (like defined_at parameters). It can slow down Rebulk
+
+LOG_LEVEL = 0
+Default log level of generated rebulk logs.
+"""
+
+import inspect
+import logging
+import os
+from collections import namedtuple
+
+
+DEBUG = False
+LOG_LEVEL = logging.DEBUG
+
+
+class Frame(namedtuple('Frame', ['lineno', 'package', 'name', 'filename'])):
+    """
+    Stack frame representation.
+    """
+    __slots__ = ()
+
+    def __repr__(self):
+        return "%s#L%s" % (os.path.basename(self.filename), self.lineno)
+
+
+def defined_at():
+    """
+    Get definition location of a pattern or a match (outside of rebulk package).
+    :return:
+    :rtype:
+    """
+    if DEBUG:
+        frame = inspect.currentframe()
+        while frame:
+            try:
+                if frame.f_globals['__package__'] != __package__:
+                    break
+            except KeyError:  # pragma:no cover
+                # If package is missing, consider we are in. Workaround for python 3.3.
+                break
+            frame = frame.f_back
+        ret = Frame(frame.f_lineno,
+                    frame.f_globals.get('__package__'),
+                    frame.f_globals.get('__name__'),
+                    frame.f_code.co_filename)
+        del frame
+        return ret
diff --git a/lib/rebulk/formatters.py b/lib/rebulk/formatters.py
new file mode 100644
index 000000000..470469426
--- /dev/null
+++ b/lib/rebulk/formatters.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Formatter functions to use in patterns.
+
+All those function have last argument as match.value (str).
+"""
+
+
+def formatters(*chained_formatters):
+    """
+    Chain formatter functions.
+    :param chained_formatters:
+    :type chained_formatters:
+    :return:
+    :rtype:
+    """
+    def formatters_chain(input_string):  # pylint:disable=missing-docstring
+        for chained_formatter in chained_formatters:
+            input_string = chained_formatter(input_string)
+        return input_string
+
+    return formatters_chain
diff --git a/lib/rebulk/introspector.py b/lib/rebulk/introspector.py
new file mode 100644
index 000000000..64b9836f0
--- /dev/null
+++ b/lib/rebulk/introspector.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Introspect rebulk object to retrieve capabilities.
+"""
+from abc import ABCMeta, abstractproperty
+from collections import defaultdict
+
+import six
+from .pattern import StringPattern, RePattern, FunctionalPattern
+from .utils import extend_safe
+
+
+@six.add_metaclass(ABCMeta)
+class Description(object):
+    """
+    Abstract class for a description.
+    """
+    @abstractproperty
+    def properties(self):  # pragma: no cover
+        """
+        Properties of described object.
+        :return: all properties that described object can generate grouped by name.
+        :rtype: dict
+        """
+        pass
+
+
+class PatternDescription(Description):
+    """
+    Description of a pattern.
+    """
+    def __init__(self, pattern):  # pylint:disable=too-many-branches
+        self.pattern = pattern
+        self._properties = defaultdict(list)
+
+        if pattern.properties:
+            for key, values in pattern.properties.items():
+                extend_safe(self._properties[key], values)
+        elif 'value' in pattern.match_options:
+            self._properties[pattern.name].append(pattern.match_options['value'])
+        elif isinstance(pattern, StringPattern):
+            extend_safe(self._properties[pattern.name], pattern.patterns)
+        elif isinstance(pattern, RePattern):
+            if pattern.name and pattern.name not in pattern.private_names:
+                extend_safe(self._properties[pattern.name], [None])
+            if not pattern.private_children:
+                for regex_pattern in pattern.patterns:
+                    for group_name, values in regex_pattern.groupindex.items():
+                        if group_name not in pattern.private_names:
+                            extend_safe(self._properties[group_name], [None])
+        elif isinstance(pattern, FunctionalPattern):
+            if pattern.name and pattern.name not in pattern.private_names:
+                extend_safe(self._properties[pattern.name], [None])
+
+
+    @property
+    def properties(self):
+        """
+        Properties for this rule.
+        :return:
+        :rtype: dict
+        """
+        return self._properties
+
+
+class RuleDescription(Description):
+    """
+    Description of a rule.
+    """
+    def __init__(self, rule):
+        self.rule = rule
+
+        self._properties = defaultdict(list)
+
+        if rule.properties:
+            for key, values in rule.properties.items():
+                extend_safe(self._properties[key], values)
+
+    @property
+    def properties(self):
+        """
+        Properties for this rule.
+        :return:
+        :rtype: dict
+        """
+        return self._properties
+
+
+class Introspection(Description):
+    """
+    Introspection results.
+    """
+    def __init__(self, rebulk, context=None):
+        self.patterns = [PatternDescription(pattern) for pattern in rebulk.effective_patterns(context)
+                         if not pattern.private and not pattern.marker]
+        self.rules = [RuleDescription(rule) for rule in rebulk.effective_rules(context)]
+
+    @property
+    def properties(self):
+        """
+        Properties for Introspection results.
+        :return:
+        :rtype:
+        """
+        properties = defaultdict(list)
+        for pattern in self.patterns:
+            for key, values in pattern.properties.items():
+                extend_safe(properties[key], values)
+        for rule in self.rules:
+            for key, values in rule.properties.items():
+                extend_safe(properties[key], values)
+        return properties
+
+
+def introspect(rebulk, context=None):
+    """
+    Introspect a Rebulk instance to grab defined objects and properties that can be generated.
+    :param rebulk:
+    :type rebulk: Rebulk
+    :param context:
+    :type context:
+    :return: Introspection instance
+    :rtype: Introspection
+    """
+    return Introspection(rebulk, context)
diff --git a/lib/rebulk/loose.py b/lib/rebulk/loose.py
new file mode 100644
index 000000000..79e1a1f12
--- /dev/null
+++ b/lib/rebulk/loose.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Various utilities functions
+"""
+import inspect
+import sys
+from .utils import is_iterable
+
+if sys.version_info < (3, 4, 0):  # pragma: no cover
+    def _constructor(class_):
+        """
+        Retrieves constructor from given class
+
+        :param class_:
+        :type class_: class
+        :return: constructor from given class
+        :rtype: callable
+        """
+        return class_.__init__
+else:  # pragma: no cover
+    def _constructor(class_):
+        """
+        Retrieves constructor from given class
+
+        :param class_:
+        :type class_: class
+        :return: constructor from given class
+        :rtype: callable
+        """
+        return class_
+
+
+def call(function, *args, **kwargs):
+    """
+    Call a function or constructor with given args and kwargs after removing args and kwargs that doesn't match
+    function or constructor signature
+
+    :param function: Function or constructor to call
+    :type function: callable
+    :param args:
+    :type args:
+    :param kwargs:
+    :type kwargs:
+    :return: sale vakye as default function call
+    :rtype: object
+    """
+    func = constructor_args if inspect.isclass(function) else function_args
+    call_args, call_kwargs = func(function, *args, **kwargs)
+    return function(*call_args, **call_kwargs)
+
+
+def function_args(callable_, *args, **kwargs):
+    """
+    Return (args, kwargs) matching the function signature
+
+    :param callable: callable to inspect
+    :type callable: callable
+    :param args:
+    :type args:
+    :param kwargs:
+    :type kwargs:
+    :return: (args, kwargs) matching the function signature
+    :rtype: tuple
+    """
+    argspec = inspect.getargspec(callable_)  # pylint:disable=deprecated-method
+    return argspec_args(argspec, False, *args, **kwargs)
+
+
+def constructor_args(class_, *args, **kwargs):
+    """
+    Return (args, kwargs) matching the function signature
+
+    :param callable: callable to inspect
+    :type callable: Callable
+    :param args:
+    :type args:
+    :param kwargs:
+    :type kwargs:
+    :return: (args, kwargs) matching the function signature
+    :rtype: tuple
+    """
+    argspec = inspect.getargspec(_constructor(class_))  # pylint:disable=deprecated-method
+    return argspec_args(argspec, True, *args, **kwargs)
+
+
+def argspec_args(argspec, constructor, *args, **kwargs):
+    """
+    Return (args, kwargs) matching the argspec object
+
+    :param argspec: argspec to use
+    :type argspec: argspec
+    :param constructor: is it a constructor ?
+    :type constructor: bool
+    :param args:
+    :type args:
+    :param kwargs:
+    :type kwargs:
+    :return: (args, kwargs) matching the function signature
+    :rtype: tuple
+    """
+    if argspec.keywords:
+        call_kwarg = kwargs
+    else:
+        call_kwarg = dict((k, kwargs[k]) for k in kwargs if k in argspec.args)  # Python 2.6 dict comprehension
+    if argspec.varargs:
+        call_args = args
+    else:
+        call_args = args[:len(argspec.args) - (1 if constructor else 0)]
+    return call_args, call_kwarg
+
+
+def ensure_list(param):
+    """
+    Retrieves a list from given parameter.
+
+    :param param:
+    :type param:
+    :return:
+    :rtype:
+    """
+    if not param:
+        param = []
+    elif not is_iterable(param):
+        param = [param]
+    return param
+
+
+def ensure_dict(param, default_value, default_key=None):
+    """
+    Retrieves a dict and a default value from given parameter.
+
+    if parameter is not a dict, it will be promoted as the default value.
+
+    :param param:
+    :type param:
+    :param default_value:
+    :type default_value:
+    :param default_key:
+    :type default_key:
+    :return:
+    :rtype:
+    """
+    if not param:
+        param = default_value
+    if not isinstance(param, dict):
+        if param:
+            default_value = param
+        return {default_key: param}, default_value
+    return param, default_value
+
+
+def filter_index(collection, predicate=None, index=None):
+    """
+    Filter collection with predicate function and index.
+
+    If index is not found, returns None.
+    :param collection:
+    :type collection: collection supporting iteration and slicing
+    :param predicate: function to filter the collection with
+    :type predicate: function
+    :param index: position of a single element to retrieve
+    :type index: int
+    :return: filtered list, or single element of filtered list if index is defined
+    :rtype: list or object
+    """
+    if index is None and isinstance(predicate, int):
+        index = predicate
+        predicate = None
+    if predicate:
+        collection = collection.__class__(filter(predicate, collection))
+    if index is not None:
+        try:
+            collection = collection[index]
+        except IndexError:
+            collection = None
+    return collection
+
+
+def set_defaults(defaults, kwargs):
+    """
+    Set defaults from defaults dict to kwargs dict
+    :param defaults:
+    :type defaults:
+    :param kwargs:
+    :type kwargs:
+    :return:
+    :rtype:
+    """
+    for key, value in defaults.items():
+        if key not in kwargs:
+            kwargs[key] = value
+        elif isinstance(value, list) and isinstance(kwargs[key], list):
+            kwargs[key] = list(value) + kwargs[key]
diff --git a/lib/rebulk/match.py b/lib/rebulk/match.py
new file mode 100644
index 000000000..86034eb25
--- /dev/null
+++ b/lib/rebulk/match.py
@@ -0,0 +1,781 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Classes and functions related to matches
+"""
+from collections import defaultdict, MutableSequence
+import copy
+try:
+    from collections import OrderedDict  # pylint:disable=ungrouped-imports
+except ImportError:  # pragma: no cover
+    from ordereddict import OrderedDict  # pylint:disable=import-error
+import six
+
+from .loose import ensure_list, filter_index
+from .utils import is_iterable
+from .debug import defined_at
+
+
+class MatchesDict(OrderedDict):
+    """
+    A custom dict with matches property.
+    """
+    def __init__(self):
+        super(MatchesDict, self).__init__()
+        self.matches = defaultdict(list)
+        self.values_list = defaultdict(list)
+
+
+class _BaseMatches(MutableSequence):
+    """
+    A custom list[Match] that automatically maintains name, tag, start and end lookup structures.
+    """
+    _base = list
+    _base_add = _base.append
+    _base_remove = _base.remove
+
+    def __init__(self, matches=None, input_string=None):
+        self.input_string = input_string
+        self._max_end = 0
+        self._delegate = []
+        self._name_dict = defaultdict(_BaseMatches._base)
+        self._tag_dict = defaultdict(_BaseMatches._base)
+        self._start_dict = defaultdict(_BaseMatches._base)
+        self._end_dict = defaultdict(_BaseMatches._base)
+        self._index_dict = defaultdict(_BaseMatches._base)
+        if matches:
+            self.extend(matches)
+
+    def _add_match(self, match):
+        """
+        Add a match
+        :param match:
+        :type match: Match
+        """
+        if match.name:
+            _BaseMatches._base_add(self._name_dict[match.name], (match))
+        for tag in match.tags:
+            _BaseMatches._base_add(self._tag_dict[tag], match)
+        _BaseMatches._base_add(self._start_dict[match.start], match)
+        _BaseMatches._base_add(self._end_dict[match.end], match)
+        for index in range(*match.span):
+            _BaseMatches._base_add(self._index_dict[index], match)
+        if match.end > self._max_end:
+            self._max_end = match.end
+
+    def _remove_match(self, match):
+        """
+        Remove a match
+        :param match:
+        :type match: Match
+        """
+        if match.name:
+            _BaseMatches._base_remove(self._name_dict[match.name], match)
+        for tag in match.tags:
+            _BaseMatches._base_remove(self._tag_dict[tag], match)
+        _BaseMatches._base_remove(self._start_dict[match.start], match)
+        _BaseMatches._base_remove(self._end_dict[match.end], match)
+        for index in range(*match.span):
+            _BaseMatches._base_remove(self._index_dict[index], match)
+        if match.end >= self._max_end and not self._end_dict[match.end]:
+            self._max_end = max(self._end_dict.keys())
+
+    def previous(self, match, predicate=None, index=None):
+        """
+        Retrieves the nearest previous matches.
+        :param match:
+        :type match:
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index: int
+        :return:
+        :rtype:
+        """
+        current = match.start
+        while current > -1:
+            previous_matches = self.ending(current)
+            if previous_matches:
+                return filter_index(previous_matches, predicate, index)
+            current -= 1
+        return filter_index(_BaseMatches._base(), predicate, index)
+
+    def next(self, match, predicate=None, index=None):
+        """
+        Retrieves the nearest next matches.
+        :param match:
+        :type match:
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index: int
+        :return:
+        :rtype:
+        """
+        current = match.start + 1
+        while current <= self._max_end:
+            next_matches = self.starting(current)
+            if next_matches:
+                return filter_index(next_matches, predicate, index)
+            current += 1
+        return filter_index(_BaseMatches._base(), predicate, index)
+
+    def named(self, name, predicate=None, index=None):
+        """
+        Retrieves a set of Match objects that have the given name.
+        :param name:
+        :type name: str
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index: int
+        :return: set of matches
+        :rtype: set[Match]
+        """
+        return filter_index(_BaseMatches._base(self._name_dict[name]), predicate, index)
+
+    def tagged(self, tag, predicate=None, index=None):
+        """
+        Retrieves a set of Match objects that have the given tag defined.
+        :param tag:
+        :type tag: str
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index: int
+        :return: set of matches
+        :rtype: set[Match]
+        """
+        return filter_index(_BaseMatches._base(self._tag_dict[tag]), predicate, index)
+
+    def starting(self, start, predicate=None, index=None):
+        """
+        Retrieves a set of Match objects that starts at given index.
+        :param start: the starting index
+        :type start: int
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index: int
+        :return: set of matches
+        :rtype: set[Match]
+        """
+        return filter_index(_BaseMatches._base(self._start_dict[start]), predicate, index)
+
+    def ending(self, end, predicate=None, index=None):
+        """
+        Retrieves a set of Match objects that ends at given index.
+        :param end: the ending index
+        :type end: int
+        :param predicate:
+        :type predicate:
+        :return: set of matches
+        :rtype: set[Match]
+        """
+        return filter_index(_BaseMatches._base(self._end_dict[end]), predicate, index)
+
+    def range(self, start=0, end=None, predicate=None, index=None):
+        """
+        Retrieves a set of Match objects that are available in given range, sorted from start to end.
+        :param start: the starting index
+        :type start: int
+        :param end: the ending index
+        :type end: int
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index: int
+        :return: set of matches
+        :rtype: set[Match]
+        """
+        if end is None:
+            end = self.max_end
+        else:
+            end = min(self.max_end, end)
+        ret = _BaseMatches._base()
+        for match in sorted(self):
+            if match.start < end and match.end > start:
+                ret.append(match)
+        return filter_index(ret, predicate, index)
+
+    def chain_before(self, position, seps, start=0, predicate=None, index=None):
+        """
+        Retrieves a list of chained matches, before position, matching predicate and separated by characters from seps
+        only.
+        :param position:
+        :type position:
+        :param seps:
+        :type seps:
+        :param start:
+        :type start:
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index:
+        :return:
+        :rtype:
+        """
+        if hasattr(position, 'start'):
+            position = position.start
+
+        chain = _BaseMatches._base()
+        position = min(self.max_end, position)
+
+        for i in reversed(range(start, position)):
+            index_matches = self.at_index(i)
+            filtered_matches = [index_match for index_match in index_matches if not predicate or predicate(index_match)]
+            if filtered_matches:
+                for chain_match in filtered_matches:
+                    if chain_match not in chain:
+                        chain.append(chain_match)
+            elif self.input_string[i] not in seps:
+                break
+
+        return filter_index(chain, predicate, index)
+
+    def chain_after(self, position, seps, end=None, predicate=None, index=None):
+        """
+        Retrieves a list of chained matches, after position, matching predicate and separated by characters from seps
+        only.
+        :param position:
+        :type position:
+        :param seps:
+        :type seps:
+        :param end:
+        :type end:
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index:
+        :return:
+        :rtype:
+        """
+        if hasattr(position, 'end'):
+            position = position.end
+        chain = _BaseMatches._base()
+
+        if end is None:
+            end = self.max_end
+        else:
+            end = min(self.max_end, end)
+
+        for i in range(position, end):
+            index_matches = self.at_index(i)
+            filtered_matches = [index_match for index_match in index_matches if not predicate or predicate(index_match)]
+            if filtered_matches:
+                for chain_match in filtered_matches:
+                    if chain_match not in chain:
+                        chain.append(chain_match)
+            elif self.input_string[i] not in seps:
+                break
+
+        return filter_index(chain, predicate, index)
+
+    @property
+    def max_end(self):
+        """
+        Retrieves the maximum index.
+        :return:
+        """
+        return max(len(self.input_string), self._max_end) if self.input_string else self._max_end
+
+    def _hole_start(self, position, ignore=None):
+        """
+        Retrieves the start of hole index from position.
+        :param position:
+        :type position:
+        :param ignore:
+        :type ignore:
+        :return:
+        :rtype:
+        """
+        for lindex in reversed(range(0, position)):
+            for starting in self.starting(lindex):
+                if not ignore or not ignore(starting):
+                    return lindex
+        return 0
+
+    def _hole_end(self, position, ignore=None):
+        """
+        Retrieves the end of hole index from position.
+        :param position:
+        :type position:
+        :param ignore:
+        :type ignore:
+        :return:
+        :rtype:
+        """
+        for rindex in range(position, self.max_end):
+            for starting in self.starting(rindex):
+                if not ignore or not ignore(starting):
+                    return rindex
+        return self.max_end
+
+    def holes(self, start=0, end=None, formatter=None, ignore=None, seps=None, predicate=None, index=None):  # pylint: disable=too-many-branches,too-many-locals
+        """
+        Retrieves a set of Match objects that are not defined in given range.
+        :param start:
+        :type start:
+        :param end:
+        :type end:
+        :param formatter:
+        :type formatter:
+        :param ignore:
+        :type ignore:
+        :param seps:
+        :type seps:
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index:
+        :return:
+        :rtype:
+        """
+        assert self.input_string if seps else True, "input_string must be defined when using seps parameter"
+        if end is None:
+            end = self.max_end
+        else:
+            end = min(self.max_end, end)
+        ret = _BaseMatches._base()
+        hole = False
+        rindex = start
+
+        loop_start = self._hole_start(start, ignore)
+
+        for rindex in range(loop_start, end):
+            current = []
+            for at_index in self.at_index(rindex):
+                if not ignore or not ignore(at_index):
+                    current.append(at_index)
+
+            if seps and hole and self.input_string and self.input_string[rindex] in seps:
+                hole = False
+                ret[-1].end = rindex
+            else:
+                if not current and not hole:
+                    # Open a new hole match
+                    hole = True
+                    ret.append(Match(max(rindex, start), None, input_string=self.input_string, formatter=formatter))
+                elif current and hole:
+                    # Close current hole match
+                    hole = False
+                    ret[-1].end = rindex
+
+        if ret and hole:
+            # go the the next starting element ...
+            ret[-1].end = min(self._hole_end(rindex, ignore), end)
+        return filter_index(ret, predicate, index)
+
+    def conflicting(self, match, predicate=None, index=None):
+        """
+        Retrieves a list of ``Match`` objects that conflicts with given match.
+        :param match:
+        :type match:
+        :param predicate:
+        :type predicate:
+        :param index:
+        :type index:
+        :return:
+        :rtype:
+        """
+        ret = _BaseMatches._base()
+
+        for i in range(*match.span):
+            for at_match in self.at_index(i):
+                if at_match not in ret:
+                    ret.append(at_match)
+
+        ret.remove(match)
+
+        return filter_index(ret, predicate, index)
+
+    def at_match(self, match, predicate=None, index=None):
+        """
+        Retrieves a list of matches from given match.
+        """
+        return self.at_span(match.span, predicate, index)
+
+    def at_span(self, span, predicate=None, index=None):
+        """
+        Retrieves a list of matches from given (start, end) tuple.
+        """
+        starting = self._index_dict[span[0]]
+        ending = self._index_dict[span[1] - 1]
+
+        merged = list(starting)
+        for marker in ending:
+            if marker not in merged:
+                merged.append(marker)
+
+        return filter_index(merged, predicate, index)
+
+    def at_index(self, pos, predicate=None, index=None):
+        """
+        Retrieves a list of matches from given position
+        """
+        return filter_index(self._index_dict[pos], predicate, index)
+
+    @property
+    def names(self):
+        """
+        Retrieve all names.
+        :return:
+        """
+        return self._name_dict.keys()
+
+    @property
+    def tags(self):
+        """
+        Retrieve all tags.
+        :return:
+        """
+        return self._tag_dict.keys()
+
+    def to_dict(self, details=False, implicit=False):
+        """
+        Converts matches to a dict object.
+        :param details if True, values will be complete Match object, else it will be only string Match.value property
+        :type details: bool
+        :param implicit if True, multiple values will be set as a list in the dict. Else, only the first value
+        will be kept.
+        :type implicit: bool
+        :return:
+        :rtype: dict
+        """
+        ret = MatchesDict()
+        for match in sorted(self):
+            value = match if details else match.value
+            ret.matches[match.name].append(match)
+            if value not in ret.values_list[match.name]:
+                ret.values_list[match.name].append(value)
+            if match.name in ret.keys():
+                if implicit:
+                    if not isinstance(ret[match.name], list):
+                        if ret[match.name] == value:
+                            continue
+                        ret[match.name] = [ret[match.name]]
+                    else:
+                        if value in ret[match.name]:
+                            continue
+                    ret[match.name].append(value)
+            else:
+                ret[match.name] = value
+        return ret
+
+    if six.PY2:  # pragma: no cover
+        def clear(self):
+            """
+            Python 3 backport
+            """
+            del self[:]
+
+    def __len__(self):
+        return len(self._delegate)
+
+    def __getitem__(self, index):
+        ret = self._delegate[index]
+        if isinstance(ret, list):
+            return Matches(ret)
+        return ret
+
+    def __setitem__(self, index, match):
+        self._delegate[index] = match
+        if isinstance(index, slice):
+            for match_item in match:
+                self._add_match(match_item)
+            return
+        self._add_match(match)
+
+    def __delitem__(self, index):
+        match = self._delegate[index]
+        del self._delegate[index]
+        if isinstance(match, list):
+            # if index is a slice, we has a match list
+            for match_item in match:
+                self._remove_match(match_item)
+        else:
+            self._remove_match(match)
+
+    def __repr__(self):
+        return self._delegate.__repr__()
+
+    def insert(self, index, match):
+        self._delegate.insert(index, match)
+        self._add_match(match)
+
+
+class Matches(_BaseMatches):
+    """
+    A custom list[Match] contains matches list.
+    """
+    def __init__(self, matches=None, input_string=None):
+        self.markers = Markers(input_string=input_string)
+        super(Matches, self).__init__(matches=matches, input_string=input_string)
+
+    def _add_match(self, match):
+        assert not match.marker, "A marker match should not be added to <Matches> object"
+        super(Matches, self)._add_match(match)
+
+
+class Markers(_BaseMatches):
+    """
+    A custom list[Match] containing markers list.
+    """
+    def __init__(self, matches=None, input_string=None):
+        super(Markers, self).__init__(matches=None, input_string=input_string)
+
+    def _add_match(self, match):
+        assert match.marker, "A non-marker match should not be added to <Markers> object"
+        super(Markers, self)._add_match(match)
+
+
+class Match(object):
+    """
+    Object storing values related to a single match
+    """
+    def __init__(self, start, end, value=None, name=None, tags=None, marker=None, parent=None, private=None,
+                 pattern=None, input_string=None, formatter=None, conflict_solver=None):
+        self.start = start
+        self.end = end
+        self.name = name
+        self._value = value
+        self.tags = ensure_list(tags)
+        self.marker = marker
+        self.parent = parent
+        self.input_string = input_string
+        self.formatter = formatter
+        self.pattern = pattern
+        self.private = private
+        self.conflict_solver = conflict_solver
+        self.children = []
+        self._raw_start = None
+        self._raw_end = None
+        self.defined_at = pattern.defined_at if pattern else defined_at()
+
+    @property
+    def span(self):
+        """
+        2-tuple with start and end indices of the match
+        """
+        return self.start, self.end
+
+    @property
+    def value(self):
+        """
+        Get the value of the match, using formatter if defined.
+        :return:
+        :rtype:
+        """
+        if self._value:
+            return self._value
+        if self.formatter:
+            return self.formatter(self.raw)
+        return self.raw
+
+    @value.setter
+    def value(self, value):
+        """
+        Set the value (hardcode)
+        :param value:
+        :type value:
+        :return:
+        :rtype:
+        """
+        self._value = value  # pylint: disable=attribute-defined-outside-init
+
+    @property
+    def names(self):
+        """
+        Get all names of children
+        :return:
+        :rtype:
+        """
+        if not self.children:
+            return set([self.name])
+        else:
+            ret = set()
+            for child in self.children:
+                for name in child.names:
+                    ret.add(name)
+            return ret
+
+    @property
+    def raw_start(self):
+        """
+        start index of raw value
+        :return:
+        :rtype:
+        """
+        if self._raw_start is None:
+            return self.start
+        return self._raw_start
+
+    @raw_start.setter
+    def raw_start(self, value):
+        """
+        Set start index of raw value
+        :return:
+        :rtype:
+        """
+        self._raw_start = value
+
+    @property
+    def raw_end(self):
+        """
+        end index of raw value
+        :return:
+        :rtype:
+        """
+        if self._raw_end is None:
+            return self.end
+        return self._raw_end
+
+    @raw_end.setter
+    def raw_end(self, value):
+        """
+        Set end index of raw value
+        :return:
+        :rtype:
+        """
+        self._raw_end = value
+
+    @property
+    def raw(self):
+        """
+        Get the raw value of the match, without using hardcoded value nor formatter.
+        :return:
+        :rtype:
+        """
+        if self.input_string:
+            return self.input_string[self.raw_start:self.raw_end]
+        return None
+
+    @property
+    def initiator(self):
+        """
+        Retrieve the initiator parent of a match
+        :param match:
+        :type match:
+        :return:
+        :rtype:
+        """
+        match = self
+        while match.parent:
+            match = match.parent
+        return match
+
+    def crop(self, crops, predicate=None, index=None):
+        """
+        crop the match with given Match objects or spans tuples
+        :param crops:
+        :type crops: list or object
+        :return: a list of Match objects
+        :rtype: list[Match]
+        """
+        if not is_iterable(crops) or len(crops) == 2 and isinstance(crops[0], int):
+            crops = [crops]
+        initial = copy.deepcopy(self)
+        ret = [initial]
+        for crop in crops:
+            if hasattr(crop, 'span'):
+                start, end = crop.span
+            else:
+                start, end = crop
+            for current in list(ret):
+                if start <= current.start and end >= current.end:
+                    # self is included in crop, remove current ...
+                    ret.remove(current)
+                elif start >= current.start and end <= current.end:
+                    # crop is included in self, split current ...
+                    right = copy.deepcopy(current)
+                    current.end = start
+                    if len(current) <= 0:
+                        ret.remove(current)
+                    right.start = end
+                    if len(right) > 0:
+                        ret.append(right)
+                elif end <= current.end and end > current.start:
+                    current.start = end
+                elif start >= current.start and start < current.end:
+                    current.end = start
+        return filter_index(ret, predicate, index)
+
+    def split(self, seps, predicate=None, index=None):
+        """
+        Split this match in multiple matches using given separators.
+        :param seps:
+        :type seps: string containing separator characters
+        :return: list of new Match objects
+        :rtype: list
+        """
+        split_match = copy.deepcopy(self)
+        current_match = split_match
+        ret = []
+
+        for i in range(0, len(self.raw)):
+            if self.raw[i] in seps:
+                if not split_match:
+                    split_match = copy.deepcopy(current_match)
+                    current_match.end = self.start + i
+
+            else:
+                if split_match:
+                    split_match.start = self.start + i
+                    current_match = split_match
+                    ret.append(split_match)
+                    split_match = None
+
+        return filter_index(ret, predicate, index)
+
+    def __len__(self):
+        return self.end - self.start
+
+    def __hash__(self):
+        return hash(Match) + hash(self.start) + hash(self.end) + hash(self.value)
+
+    def __eq__(self, other):
+        if isinstance(other, Match):
+            return self.span == other.span and self.value == other.value and self.name == other.name and \
+                self.parent == other.parent
+        return NotImplemented
+
+    def __ne__(self, other):
+        if isinstance(other, Match):
+            return self.span != other.span or self.value != other.value or self.name != other.name or \
+                self.parent != other.parent
+        return NotImplemented
+
+    def __lt__(self, other):
+        if isinstance(other, Match):
+            return self.span < other.span
+        return NotImplemented
+
+    def __gt__(self, other):
+        if isinstance(other, Match):
+            return self.span > other.span
+        return NotImplemented
+
+    def __le__(self, other):
+        if isinstance(other, Match):
+            return self.span <= other.span
+        return NotImplemented
+
+    def __ge__(self, other):
+        if isinstance(other, Match):
+            return self.span >= other.span
+        return NotImplemented
+
+    def __repr__(self):
+        flags = ""
+        name = ""
+        tags = ""
+        defined = ""
+        if self.private:
+            flags += '+private'
+        if self.name:
+            name = "+name=" + self.name
+        if self.tags:
+            tags = "+tags=" + six.text_type(self.tags)
+        if self.defined_at:
+            defined += "@" + six.text_type(self.defined_at)
+        return "<%s:%s%s%s%s%s>" % (self.value, self.span, flags, name, tags, defined)
diff --git a/lib/rebulk/pattern.py b/lib/rebulk/pattern.py
new file mode 100644
index 000000000..e789cd60d
--- /dev/null
+++ b/lib/rebulk/pattern.py
@@ -0,0 +1,415 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Abstract pattern class definition along with various implementations (regexp, string, functional)
+"""
+# pylint: disable=super-init-not-called,wrong-import-position
+
+from abc import ABCMeta, abstractmethod, abstractproperty
+REGEX_AVAILABLE = None
+try:
+    import regex as re
+    REGEX_AVAILABLE = True
+except ImportError:  # pragma: no cover
+    import re  #pylint:disable=wrong-import-order
+    REGEX_AVAILABLE = False
+
+import six
+
+from .match import Match
+from .utils import find_all, is_iterable
+from .loose import call, ensure_list, ensure_dict
+from . import debug
+
+
+@six.add_metaclass(ABCMeta)
+class Pattern(object):
+    """
+    Definition of a particular pattern to search for.
+    """
+
+    def __init__(self, name=None, tags=None, formatter=None, validator=None, children=False, every=False,
+                 private_parent=False, private_children=False, private=False, private_names=None, marker=False,
+                 format_all=False, validate_all=False, disabled=lambda context: False, log_level=None, properties=None):
+        """
+        :param name: Name of this pattern
+        :type name: str
+        :param tags: List of tags related to this pattern
+        :type tags: list[str]
+        :param formatter: dict (name, func) of formatter to use with this pattern. name is the match name to support,
+        and func a function(input_string) that returns the formatted string. A single formatter function can also be
+        passed as a shortcut for {None: formatter}. The returned formatted string with be set in Match.value property.
+        :type formatter: dict[str, func] || func
+        :param validator: dict (name, func) of validator to use with this pattern. name is the match name to support,
+        and func a function(match) that returns the a boolean. A single validator function can also be
+        passed as a shortcut for {None: validator}. If return value is False, match will be ignored.
+        :param children: generates children instead of parent
+        :type children: bool
+        :param every: generates both parent and children.
+        :type every: bool
+        :param private: flag this pattern as beeing private.
+        :type private: bool
+        :param private_parent: force return of parent and flag parent matches as private.
+        :type private_parent: bool
+        :param private_children: force return of children and flag children matches as private.
+        :type private_children: bool
+        :param private_names: force return of named matches as private.
+        :type private_names: bool
+        :param marker: flag this pattern as beeing a marker.
+        :type private: bool
+        :param format_all if True, pattern will format every match in the hierarchy (even match not yield).
+        :type format_all: bool
+        :param validate_all if True, pattern will validate every match in the hierarchy (even match not yield).
+        :type validate_all: bool
+        :param disabled: if True, this pattern is disabled. Can also be a function(context).
+        :type disabled: bool|function
+        :param log_lvl: Log level associated to this pattern
+        :type log_lvl: int
+        """
+        # pylint:disable=too-many-locals
+        self.name = name
+        self.tags = ensure_list(tags)
+        self.formatters, self._default_formatter = ensure_dict(formatter, lambda x: x)
+        self.validators, self._default_validator = ensure_dict(validator, lambda match: True)
+        self.every = every
+        self.children = children
+        self.private = private
+        self.private_names = private_names if private_names else []
+        self.private_parent = private_parent
+        self.private_children = private_children
+        self.marker = marker
+        self.format_all = format_all
+        self.validate_all = validate_all
+        if not callable(disabled):
+            self.disabled = lambda context: disabled
+        else:
+            self.disabled = disabled
+        self._log_level = log_level
+        self._properties = properties
+        self.defined_at = debug.defined_at()
+
+    @property
+    def log_level(self):
+        """
+        Log level for this pattern.
+        :return:
+        :rtype:
+        """
+        return self._log_level if self._log_level is not None else debug.LOG_LEVEL
+
+    def _yield_children(self, match):
+        """
+        Does this mat
+        :param match:
+        :type match:
+        :return:
+        :rtype:
+        """
+        return match.children and (self.children or self.every)
+
+    def _yield_parent(self):
+        """
+        Does this mat
+        :param match:
+        :type match:
+        :return:
+        :rtype:
+        """
+        return not self.children or self.every
+
+    def _match_parent(self, match, yield_parent):
+        """
+        Handle a parent match
+        :param match:
+        :type match:
+        :param yield_parent:
+        :type yield_parent:
+        :return:
+        :rtype:
+        """
+        if yield_parent or self.format_all:
+            match.formatter = self.formatters.get(match.name,
+                                                  self.formatters.get('__parent__', self._default_formatter))
+        if yield_parent or self.validate_all:
+            validator = self.validators.get(match.name, self.validators.get('__parent__', self._default_validator))
+            if not validator(match):
+                return False
+        return True
+
+    def _match_child(self, child, yield_children):
+        """
+        Handle a children match
+        :param child:
+        :type child:
+        :param yield_children:
+        :type yield_children:
+        :return:
+        :rtype:
+        """
+        if yield_children or self.format_all:
+            child.formatter = self.formatters.get(child.name,
+                                                  self.formatters.get('__children__', self._default_formatter))
+        if yield_children or self.validate_all:
+            validator = self.validators.get(child.name, self.validators.get('__children__', self._default_validator))
+            if not validator(child):
+                return False
+        return True
+
+    def matches(self, input_string, context=None):
+        """
+        Computes all matches for a given input
+
+        :param input_string: the string to parse
+        :type input_string: str
+        :param context: the context
+        :type context: dict
+        :return: matches based on input_string for this pattern
+        :rtype: iterator[Match]
+        """
+
+        ret = []
+        for pattern in self.patterns:
+            yield_parent = self._yield_parent()
+            for match in self._match(pattern, input_string, context):
+                yield_children = self._yield_children(match)
+                if not self._match_parent(match, yield_parent):
+                    continue
+                validated = True
+                for child in match.children:
+                    if not self._match_child(child, yield_children):
+                        validated = False
+                        break
+                if validated:
+                    if self.private_parent:
+                        match.private = True
+                    if self.private_children:
+                        for child in match.children:
+                            child.private = True
+                    if yield_parent or self.private_parent:
+                        ret.append(match)
+                    if yield_children or self.private_children:
+                        for child in match.children:
+                            ret.append(child)
+        self._matches_privatize(ret)
+        return ret
+
+    def _matches_privatize(self, matches):
+        """
+        Mark matches included in private_names with private flag.
+        :param matches:
+        :type matches:
+        :return:
+        :rtype:
+        """
+        if self.private_names:
+            for child in matches:
+                if child.name in self.private_names:
+                    child.private = True
+
+    @abstractproperty
+    def patterns(self):  # pragma: no cover
+        """
+        List of base patterns defined
+
+        :return: A list of base patterns
+        :rtype: list
+        """
+        pass
+
+    @property
+    def properties(self):
+        """
+        Properties names and values that can ben retrieved by this pattern.
+        :return:
+        :rtype:
+        """
+        if self._properties:
+            return self._properties
+        return {}
+
+    @abstractproperty
+    def match_options(self):  # pragma: no cover
+        """
+        dict of default options for generated Match objects
+
+        :return: **options to pass to Match constructor
+        :rtype: dict
+        """
+        pass
+
+    @abstractmethod
+    def _match(self, pattern, input_string, context=None):  # pragma: no cover
+        """
+        Computes all matches for a given pattern and input
+
+        :param pattern: the pattern to use
+        :param input_string: the string to parse
+        :type input_string: str
+        :param context: the context
+        :type context: dict
+        :return: matches based on input_string for this pattern
+        :rtype: iterator[Match]
+        """
+        pass
+
+    def __repr__(self):
+        defined = ""
+        if self.defined_at:
+            defined = "@" + six.text_type(self.defined_at)
+        return "<%s%s:%s>" % (self.__class__.__name__, defined, self.patterns)
+
+
+class StringPattern(Pattern):
+    """
+    Definition of one or many strings to search for.
+    """
+
+    def __init__(self, *patterns, **kwargs):
+        call(super(StringPattern, self).__init__, **kwargs)
+        self._patterns = patterns
+        self._kwargs = kwargs
+        self._match_kwargs = _filter_match_kwargs(kwargs)
+
+    @property
+    def patterns(self):
+        return self._patterns
+
+    @property
+    def match_options(self):
+        return self._match_kwargs
+
+    def _match(self, pattern, input_string, context=None):
+        for index in call(find_all, input_string, pattern, **self._kwargs):
+            yield call(Match, index, index + len(pattern), pattern=self, input_string=input_string,
+                       **self._match_kwargs)
+
+
+class RePattern(Pattern):
+    """
+    Definition of one or many regular expression pattern to search for.
+    """
+
+    def __init__(self, *patterns, **kwargs):
+        call(super(RePattern, self).__init__, **kwargs)
+        self.repeated_captures = REGEX_AVAILABLE
+        if 'repeated_captures' in kwargs:
+            self.repeated_captures = kwargs.get('repeated_captures')
+        if self.repeated_captures and not REGEX_AVAILABLE:  # pragma: no cover
+            raise NotImplementedError("repeated_capture is available only with regex module.")
+        self.abbreviations = kwargs.get('abbreviations', [])
+        self._kwargs = kwargs
+        self._match_kwargs = _filter_match_kwargs(kwargs)
+        self._children_match_kwargs = _filter_match_kwargs(kwargs, children=True)
+        self._patterns = []
+        for pattern in patterns:
+            if isinstance(pattern, six.string_types):
+                if self.abbreviations and pattern:
+                    for key, replacement in self.abbreviations:
+                        pattern = pattern.replace(key, replacement)
+                pattern = call(re.compile, pattern, **self._kwargs)
+            elif isinstance(pattern, dict):
+                if self.abbreviations and 'pattern' in pattern:
+                    for key, replacement in self.abbreviations:
+                        pattern['pattern'] = pattern['pattern'].replace(key, replacement)
+                pattern = re.compile(**pattern)
+            elif hasattr(pattern, '__iter__'):
+                pattern = re.compile(*pattern)
+            self._patterns.append(pattern)
+
+    @property
+    def patterns(self):
+        return self._patterns
+
+    @property
+    def match_options(self):
+        return self._match_kwargs
+
+    def _match(self, pattern, input_string, context=None):
+        names = dict((v, k) for k, v in pattern.groupindex.items())
+        for match_object in pattern.finditer(input_string):
+            start = match_object.start()
+            end = match_object.end()
+            main_match = call(Match, start, end, pattern=self, input_string=input_string, **self._match_kwargs)
+
+            if pattern.groups:
+                for i in range(1, pattern.groups + 1):
+                    name = names.get(i, main_match.name)
+                    if self.repeated_captures:
+                        for start, end in match_object.spans(i):
+                            child_match = call(Match, start, end, name=name, parent=main_match, pattern=self,
+                                               input_string=input_string, **self._children_match_kwargs)
+                            main_match.children.append(child_match)
+                    else:
+                        start, end = match_object.span(i)
+                        child_match = call(Match, start, end, name=name, parent=main_match, pattern=self,
+                                           input_string=input_string, **self._children_match_kwargs)
+                        main_match.children.append(child_match)
+
+            yield main_match
+
+
+class FunctionalPattern(Pattern):
+    """
+    Definition of one or many functional pattern to search for.
+    """
+
+    def __init__(self, *patterns, **kwargs):
+        call(super(FunctionalPattern, self).__init__, **kwargs)
+        self._patterns = patterns
+        self._kwargs = kwargs
+        self._match_kwargs = _filter_match_kwargs(kwargs)
+
+    @property
+    def patterns(self):
+        return self._patterns
+
+    @property
+    def match_options(self):
+        return self._match_kwargs
+
+    def _match(self, pattern, input_string, context=None):
+        ret = call(pattern, input_string, context, **self._kwargs)
+        if ret:
+            if not is_iterable(ret) or isinstance(ret, dict) \
+                    or (is_iterable(ret) and hasattr(ret, '__getitem__') and isinstance(ret[0], int)):
+                args_iterable = [ret]
+            else:
+                args_iterable = ret
+            for args in args_iterable:
+                if isinstance(args, dict):
+                    options = args
+                    options.pop('input_string', None)
+                    options.pop('pattern', None)
+                    if self._match_kwargs:
+                        options = self._match_kwargs.copy()
+                        options.update(args)
+                    yield call(Match, pattern=self, input_string=input_string, **options)
+                else:
+                    kwargs = self._match_kwargs
+                    if isinstance(args[-1], dict):
+                        kwargs = dict(kwargs)
+                        kwargs.update(args[-1])
+                        args = args[:-1]
+                    yield call(Match, *args, pattern=self, input_string=input_string, **kwargs)
+
+
+def _filter_match_kwargs(kwargs, children=False):
+    """
+    Filters out kwargs for Match construction
+
+    :param kwargs:
+    :type kwargs: dict
+    :param children:
+    :type children: Flag to filter children matches
+    :return: A filtered dict
+    :rtype: dict
+    """
+    kwargs = kwargs.copy()
+    for key in ('pattern', 'start', 'end', 'parent', 'formatter'):
+        if key in kwargs:
+            del kwargs[key]
+    if children:
+        for key in ('name',):
+            if key in kwargs:
+                del kwargs[key]
+    return kwargs
diff --git a/lib/rebulk/processors.py b/lib/rebulk/processors.py
new file mode 100644
index 000000000..b0a69fc8e
--- /dev/null
+++ b/lib/rebulk/processors.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Processor functions
+"""
+from logging import getLogger
+
+from .utils import IdentitySet
+
+from .rules import Rule, RemoveMatch
+
+log = getLogger(__name__).log
+
+DEFAULT = '__default__'
+
+POST_PROCESS = -2048
+PRE_PROCESS = 2048
+
+
+def _default_conflict_solver(match, conflicting_match):
+    """
+    Default conflict solver for matches, shorter matches if they conflicts with longer ones
+
+    :param conflicting_match:
+    :type conflicting_match:
+    :param match:
+    :type match:
+    :return:
+    :rtype:
+    """
+    if len(conflicting_match.initiator) < len(match.initiator):
+        return conflicting_match
+    elif len(match.initiator) < len(conflicting_match.initiator):
+        return match
+    return None
+
+
+class ConflictSolver(Rule):
+    """
+    Remove conflicting matches.
+    """
+    priority = PRE_PROCESS
+
+    consequence = RemoveMatch
+
+    @property
+    def default_conflict_solver(self):  # pylint:disable=no-self-use
+        """
+        Default conflict solver to use.
+        """
+        return _default_conflict_solver
+
+    def when(self, matches, context):
+        to_remove_matches = IdentitySet()
+        for match in filter(lambda match: not match.private, matches):
+            conflicting_matches = matches.conflicting(match)
+
+            if conflicting_matches:
+                # keep the match only if it's the longest
+                for conflicting_match in filter(lambda match: not match.private, conflicting_matches):
+                    reverse = False
+                    conflict_solvers = [(self.default_conflict_solver, False)]
+
+                    if match.conflict_solver:
+                        conflict_solvers.append((match.conflict_solver, False))
+                    if conflicting_match.conflict_solver:
+                        conflict_solvers.append((conflicting_match.conflict_solver, True))
+
+                    for conflict_solver, reverse in reversed(conflict_solvers):
+                        if reverse:
+                            to_remove = conflict_solver(conflicting_match, match)
+                        else:
+                            to_remove = conflict_solver(match, conflicting_match)
+                        if to_remove == DEFAULT:
+                            continue
+                        if to_remove and to_remove not in to_remove_matches:
+                            to_remove_matches.add(to_remove)
+                        break
+        return to_remove_matches
+
+
+class PrivateRemover(Rule):
+    """
+    Removes private matches rule.
+    """
+    priority = POST_PROCESS
+
+    consequence = RemoveMatch
+
+    def when(self, matches, context):
+        return [match for match in matches if match.private]
+
diff --git a/lib/rebulk/rebulk.py b/lib/rebulk/rebulk.py
new file mode 100644
index 000000000..dde3699d6
--- /dev/null
+++ b/lib/rebulk/rebulk.py
@@ -0,0 +1,281 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Entry point functions and classes for Rebulk
+"""
+from logging import getLogger
+
+from .match import Matches
+
+from .pattern import RePattern, StringPattern, FunctionalPattern
+
+from .processors import ConflictSolver, PrivateRemover
+from .loose import set_defaults
+from .utils import extend_safe
+from .rules import Rules
+
+log = getLogger(__name__).log
+
+
+class Rebulk(object):
+    r"""
+    Regular expression, string and function based patterns are declared in a ``Rebulk`` object. It use a fluent API to
+    chain ``string``, ``regex``, and ``functional`` methods to define various patterns types.
+
+    .. code-block:: python
+
+        >>> from rebulk import Rebulk
+        >>> bulk = Rebulk().string('brown').regex(r'qu\w+').functional(lambda s: (20, 25))
+
+    When ``Rebulk`` object is fully configured, you can call ``matches`` method with an input string to retrieve all
+    ``Match`` objects found by registered pattern.
+
+    .. code-block:: python
+
+        >>> bulk.matches("The quick brown fox jumps over the lazy dog")
+        [<brown:(10, 15)>, <quick:(4, 9)>, <jumps:(20, 25)>]
+
+    If multiple ``Match`` objects are found at the same position, only the longer one is kept.
+
+    .. code-block:: python
+
+        >>> bulk = Rebulk().string('lakers').string('la')
+        >>> bulk.matches("the lakers are from la")
+        [<lakers:(4, 10)>, <la:(20, 22)>]
+    """
+    # pylint:disable=protected-access
+
+    def __init__(self, disabled=lambda context: False, default_rules=True):
+        """
+        Creates a new Rebulk object.
+        :param disabled: if True, this pattern is disabled. Can also be a function(context).
+        :type disabled: bool|function
+        :param default_rules: use default rules
+        :type default_rules:
+        :return:
+        :rtype:
+        """
+        if not callable(disabled):
+            self.disabled = lambda context: disabled
+        else:
+            self.disabled = disabled
+        self._patterns = []
+        self._rules = Rules()
+        if default_rules:
+            self.rules(ConflictSolver, PrivateRemover)
+        self._defaults = {}
+        self._regex_defaults = {}
+        self._string_defaults = {}
+        self._functional_defaults = {}
+        self._rebulks = []
+
+    def pattern(self, *pattern):
+        """
+        Add patterns objects
+
+        :param pattern:
+        :type pattern: rebulk.pattern.Pattern
+        :return: self
+        :rtype: Rebulk
+        """
+        self._patterns.extend(pattern)
+        return self
+
+    def defaults(self, **kwargs):
+        """
+        Define default keyword arguments for all patterns
+        :param kwargs:
+        :type kwargs:
+        :return:
+        :rtype:
+        """
+        self._defaults = kwargs
+        return self
+
+    def regex_defaults(self, **kwargs):
+        """
+        Define default keyword arguments for functional patterns.
+        :param kwargs:
+        :type kwargs:
+        :return:
+        :rtype:
+        """
+        self._regex_defaults = kwargs
+        return self
+
+    def regex(self, *pattern, **kwargs):
+        """
+        Add re pattern
+
+        :param pattern:
+        :type pattern:
+        :return: self
+        :rtype: Rebulk
+        """
+        set_defaults(self._regex_defaults, kwargs)
+        set_defaults(self._defaults, kwargs)
+        self.pattern(RePattern(*pattern, **kwargs))
+        return self
+
+    def string_defaults(self, **kwargs):
+        """
+        Define default keyword arguments for string patterns.
+        :param kwargs:
+        :type kwargs:
+        :return:
+        :rtype:
+        """
+        self._string_defaults = kwargs
+        return self
+
+    def string(self, *pattern, **kwargs):
+        """
+        Add string pattern
+
+        :param pattern:
+        :type pattern:
+        :return: self
+        :rtype: Rebulk
+        """
+        set_defaults(self._string_defaults, kwargs)
+        set_defaults(self._defaults, kwargs)
+        self.pattern(StringPattern(*pattern, **kwargs))
+        return self
+
+    def functional_defaults(self, **kwargs):
+        """
+        Define default keyword arguments for functional patterns.
+        :param kwargs:
+        :type kwargs:
+        :return:
+        :rtype:
+        """
+        self._functional_defaults = kwargs
+        return self
+
+    def functional(self, *pattern, **kwargs):
+        """
+        Add functional pattern
+
+        :param pattern:
+        :type pattern:
+        :return: self
+        :rtype: Rebulk
+        """
+        set_defaults(self._functional_defaults, kwargs)
+        set_defaults(self._defaults, kwargs)
+        self.pattern(FunctionalPattern(*pattern, **kwargs))
+        return self
+
+    def rules(self, *rules):
+        """
+        Add rules as a module, class or instance.
+        :param rules:
+        :type rules: list[Rule]
+        :return:
+        """
+        self._rules.load(*rules)
+        return self
+
+    def rebulk(self, *rebulks):
+        """
+        Add a children rebulk object
+        :param rebulks:
+        :type rebulks: Rebulk
+        :return:
+        """
+        self._rebulks.extend(rebulks)
+        return self
+
+    def matches(self, string, context=None):
+        """
+        Search for all matches with current configuration against input_string
+        :param string: string to search into
+        :type string: str
+        :param context: context to use
+        :type context: dict
+        :return: A custom list of matches
+        :rtype: Matches
+        """
+        matches = Matches(input_string=string)
+        if context is None:
+            context = {}
+
+        self._matches_patterns(matches, context)
+
+        self._execute_rules(matches, context)
+
+        return matches
+
+    def effective_rules(self, context=None):
+        """
+        Get effective rules for this rebulk object and its children.
+        :param context:
+        :type context:
+        :return:
+        :rtype:
+        """
+        rules = Rules()
+        rules.extend(self._rules)
+        for rebulk in self._rebulks:
+            if not rebulk.disabled(context):
+                extend_safe(rules, rebulk._rules)
+        return rules
+
+    def _execute_rules(self, matches, context):
+        """
+        Execute rules for this rebulk and children.
+        :param matches:
+        :type matches:
+        :param context:
+        :type context:
+        :return:
+        :rtype:
+        """
+        if not self.disabled(context):
+            rules = self.effective_rules(context)
+            rules.execute_all_rules(matches, context)
+
+    def effective_patterns(self, context=None):
+        """
+        Get effective patterns for this rebulk object and its children.
+        :param context:
+        :type context:
+        :return:
+        :rtype:
+        """
+        patterns = list(self._patterns)
+        for rebulk in self._rebulks:
+            if not rebulk.disabled(context):
+                extend_safe(patterns, rebulk._patterns)
+        return patterns
+
+    def _matches_patterns(self, matches, context):
+        """
+        Search for all matches with current paterns agains input_string
+        :param matches: matches list
+        :type matches: Matches
+        :param context: context to use
+        :type context: dict
+        :return:
+        :rtype:
+        """
+        if not self.disabled(context):
+            patterns = self.effective_patterns(context)
+            for pattern in patterns:
+                if not pattern.disabled(context):
+                    pattern_matches = pattern.matches(matches.input_string, context)
+                    if pattern_matches:
+                        log(pattern.log_level, "Pattern has %s match(es). (%s)", len(pattern_matches), pattern)
+                    else:
+                        pass
+                        # log(pattern.log_level, "Pattern doesn't match. (%s)" % (pattern,))
+                    for match in pattern_matches:
+                        if match.marker:
+                            log(pattern.log_level, "Marker found. (%s)", match)
+                            matches.markers.append(match)
+                        else:
+                            log(pattern.log_level, "Match found. (%s)", match)
+                            matches.append(match)
+                else:
+                    log(pattern.log_level, "Pattern is disabled. (%s)", pattern)
diff --git a/lib/rebulk/rules.py b/lib/rebulk/rules.py
new file mode 100644
index 000000000..c318cef93
--- /dev/null
+++ b/lib/rebulk/rules.py
@@ -0,0 +1,378 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Abstract rule class definition and rule engine implementation
+"""
+from abc import ABCMeta, abstractmethod
+import inspect
+from itertools import groupby
+from logging import getLogger
+
+import six
+from .utils import is_iterable
+
+from .toposort import toposort
+
+from . import debug
+
+log = getLogger(__name__).log
+
+
+@six.add_metaclass(ABCMeta)
+class Consequence(object):
+    """
+    Definition of a consequence to apply.
+    """
+    @abstractmethod
+    def then(self, matches, when_response, context):  # pragma: no cover
+        """
+        Action implementation.
+
+        :param matches:
+        :type matches: rebulk.match.Matches
+        :param context:
+        :type context:
+        :param when_response: return object from when call.
+        :type when_response: object
+        :return: True if the action was runned, False if it wasn't.
+        :rtype: bool
+        """
+        pass
+
+
+@six.add_metaclass(ABCMeta)
+class Condition(object):
+    """
+    Definition of a condition to check.
+    """
+    @abstractmethod
+    def when(self, matches, context):  # pragma: no cover
+        """
+        Condition implementation.
+
+        :param matches:
+        :type matches: rebulk.match.Matches
+        :param context:
+        :type context:
+        :return: truthy if rule should be triggered and execute then action, falsy if it should not.
+        :rtype: object
+        """
+        pass
+
+
+@six.add_metaclass(ABCMeta)
+class CustomRule(Condition, Consequence):
+    """
+    Definition of a rule to apply
+    """
+    # pylint: disable=no-self-use, unused-argument, abstract-method
+    priority = 0
+    name = None
+    dependency = None
+    properties = {}
+
+    def __init__(self, log_level=None):
+        self.defined_at = debug.defined_at()
+        if log_level is None and not hasattr(self, 'log_level'):
+            self.log_level = debug.LOG_LEVEL
+
+    def enabled(self, context):
+        """
+        Disable rule.
+
+        :param context:
+        :type context:
+        :return: True if rule is enabled, False if disabled
+        :rtype: bool
+        """
+        return True
+
+    def __lt__(self, other):
+        return self.priority > other.priority
+
+    def __repr__(self):
+        defined = ""
+        if self.defined_at:
+            defined = "@" + six.text_type(self.defined_at)
+        return "<%s%s>" % (self.name if self.name else self.__class__.__name__, defined)
+
+    def __eq__(self, other):
+        return self.__class__ == other.__class__
+
+    def __hash__(self):
+        return hash(self.__class__)
+
+
+class Rule(CustomRule):
+    """
+    Definition of a rule to apply
+    """
+    # pylint:disable=abstract-method
+    consequence = None
+
+    def then(self, matches, when_response, context):
+        assert self.consequence
+        if is_iterable(self.consequence):
+            if not is_iterable(when_response):
+                when_response = [when_response]
+            iterator = iter(when_response)
+            for cons in self.consequence:  #pylint: disable=not-an-iterable
+                if inspect.isclass(cons):
+                    cons = cons()
+                cons.then(matches, next(iterator), context)
+        else:
+            cons = self.consequence
+            if inspect.isclass(cons):
+                cons = cons()  # pylint:disable=not-callable
+            cons.then(matches, when_response, context)
+
+
+class RemoveMatch(Consequence):  # pylint: disable=abstract-method
+    """
+    Remove matches returned by then
+    """
+    def then(self, matches, when_response, context):
+        if is_iterable(when_response):
+            ret = []
+            when_response = list(when_response)
+            for match in when_response:
+                if match in matches:
+                    matches.remove(match)
+                    ret.append(match)
+            return ret
+        else:
+            if when_response in matches:
+                matches.remove(when_response)
+                return when_response
+
+
+class AppendMatch(Consequence):  # pylint: disable=abstract-method
+    """
+    Append matches returned by then
+    """
+    def __init__(self, match_name=None):
+        self.match_name = match_name
+
+    def then(self, matches, when_response, context):
+        if is_iterable(when_response):
+            ret = []
+            when_response = list(when_response)
+            for match in when_response:
+                if match not in matches:
+                    if self.match_name:
+                        match.name = self.match_name
+                    matches.append(match)
+                    ret.append(match)
+            return ret
+        else:
+            if self.match_name:
+                when_response.name = self.match_name
+            if when_response not in matches:
+                matches.append(when_response)
+                return when_response
+
+
+class RenameMatch(Consequence):  # pylint: disable=abstract-method
+    """
+    Rename matches returned by then
+    """
+    def __init__(self, match_name):
+        self.match_name = match_name
+        self.remove = RemoveMatch()
+        self.append = AppendMatch()
+
+    def then(self, matches, when_response, context):
+        removed = self.remove.then(matches, when_response, context)
+        if is_iterable(removed):
+            removed = list(removed)
+            for match in removed:
+                match.name = self.match_name
+        elif removed:
+            removed.name = self.match_name
+        if removed:
+            self.append.then(matches, removed, context)
+
+
+class AppendTags(Consequence):  # pylint: disable=abstract-method
+    """
+    Add tags to returned matches
+    """
+    def __init__(self, tags):
+        self.tags = tags
+        self.remove = RemoveMatch()
+        self.append = AppendMatch()
+
+    def then(self, matches, when_response, context):
+        removed = self.remove.then(matches, when_response, context)
+        if is_iterable(removed):
+            removed = list(removed)
+            for match in removed:
+                match.tags.extend(self.tags)
+        elif removed:
+            removed.tags.extend(self.tags)  # pylint: disable=no-member
+        if removed:
+            self.append.then(matches, removed, context)
+
+
+class RemoveTags(Consequence):  # pylint: disable=abstract-method
+    """
+    Remove tags from returned matches
+    """
+    def __init__(self, tags):
+        self.tags = tags
+        self.remove = RemoveMatch()
+        self.append = AppendMatch()
+
+    def then(self, matches, when_response, context):
+        removed = self.remove.then(matches, when_response, context)
+        if is_iterable(removed):
+            removed = list(removed)
+            for match in removed:
+                for tag in self.tags:
+                    if tag in match.tags:
+                        match.tags.remove(tag)
+        elif removed:
+            for tag in self.tags:
+                if tag in removed.tags:  # pylint: disable=no-member
+                    removed.tags.remove(tag)  # pylint: disable=no-member
+        if removed:
+            self.append.then(matches, removed, context)
+
+
+class Rules(list):
+    """
+    list of rules ready to execute.
+    """
+
+    def __init__(self, *rules):
+        super(Rules, self).__init__()
+        self.load(*rules)
+
+    def load(self, *rules):
+        """
+        Load rules from a Rule module, class or instance
+
+        :param rules:
+        :type rules:
+        :return:
+        :rtype:
+        """
+        for rule in rules:
+            if inspect.ismodule(rule):
+                self.load_module(rule)
+            elif inspect.isclass(rule):
+                self.load_class(rule)
+            else:
+                self.append(rule)
+
+    def load_module(self, module):
+        """
+        Load a rules module
+
+        :param module:
+        :type module:
+        :return:
+        :rtype:
+        """
+        # pylint: disable=unused-variable
+        for name, obj in inspect.getmembers(module,
+                                            lambda member: hasattr(member, '__module__')
+                                            and member.__module__ == module.__name__
+                                            and inspect.isclass):
+            self.load_class(obj)
+
+    def load_class(self, class_):
+        """
+        Load a Rule class.
+
+        :param class_:
+        :type class_:
+        :return:
+        :rtype:
+        """
+        self.append(class_())
+
+    def execute_all_rules(self, matches, context):
+        """
+        Execute all rules from this rules list. All when condition with same priority will be performed before
+        calling then actions.
+
+        :param matches:
+        :type matches:
+        :param context:
+        :type context:
+        :return:
+        :rtype:
+        """
+        ret = []
+        for priority, priority_rules in groupby(sorted(self), lambda rule: rule.priority):
+            sorted_rules = toposort_rules(list(priority_rules))  # Group by dependency graph toposort
+            for rules_group in sorted_rules:
+                rules_group = list(sorted(rules_group, key=self.index))  # Sort rules group based on initial ordering.
+                group_log_level = None
+                for rule in rules_group:
+                    if group_log_level is None or group_log_level < rule.log_level:
+                        group_log_level = rule.log_level
+                log(group_log_level, "%s independent rule(s) at priority %s.", len(rules_group), priority)
+                for rule in rules_group:
+                    when_response = execute_rule(rule, matches, context)
+                    if when_response is not None:
+                        ret.append((rule, when_response))
+
+        return ret
+
+
+def execute_rule(rule, matches, context):
+    """
+    Execute the given rule.
+    :param rule:
+    :type rule:
+    :param matches:
+    :type matches:
+    :param context:
+    :type context:
+    :return:
+    :rtype:
+    """
+    if rule.enabled(context):
+        log(rule.log_level, "Checking rule condition: %s", rule)
+        when_response = rule.when(matches, context)
+        if when_response:
+            log(rule.log_level, "Rule was triggered: %s", when_response)
+            log(rule.log_level, "Running rule consequence: %s %s", rule, when_response)
+            rule.then(matches, when_response, context)
+            return when_response
+    else:
+        log(rule.log_level, "Rule is disabled: %s", rule)
+
+def toposort_rules(rules):
+    """
+    Sort given rules using toposort with dependency parameter.
+    :param rules:
+    :type rules:
+    :return:
+    :rtype:
+    """
+    graph = {}
+    class_dict = {}
+    for rule in rules:
+        if rule.__class__ in class_dict:
+            raise ValueError("Duplicate class rules are not allowed: %s" % rule.__class__)
+        class_dict[rule.__class__] = rule
+    for rule in rules:
+        if not is_iterable(rule.dependency) and rule.dependency:
+            rule_dependencies = [rule.dependency]
+        else:
+            rule_dependencies = rule.dependency
+        dependencies = set()
+        if rule_dependencies:
+            for dependency in rule_dependencies:
+                if inspect.isclass(dependency):
+                    dependency = class_dict.get(dependency)
+                if dependency:
+                    dependencies.add(dependency)
+        graph[rule] = dependencies
+    return toposort(graph)
+
+
+
diff --git a/lib/rebulk/test/__init__.py b/lib/rebulk/test/__init__.py
new file mode 100644
index 000000000..0ab48c94b
--- /dev/null
+++ b/lib/rebulk/test/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring
diff --git a/lib/rebulk/test/default_rules_module.py b/lib/rebulk/test/default_rules_module.py
new file mode 100644
index 000000000..533752fc6
--- /dev/null
+++ b/lib/rebulk/test/default_rules_module.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
+from ..match import Match
+from ..rules import Rule, RemoveMatch, AppendMatch, RenameMatch, AppendTags, RemoveTags
+
+
+class RuleRemove0(Rule):
+    consequence = RemoveMatch
+    def when(self, matches, context):
+        return matches[0]
+
+
+class RuleAppend0(Rule):
+    consequence = AppendMatch()
+    def when(self, matches, context):
+        return Match(5, 10)
+
+class RuleRename0(Rule):
+    consequence = [RenameMatch('renamed')]
+    def when(self, matches, context):
+        return [Match(5, 10, name="original")]
+
+class RuleRemove1(Rule):
+    consequence = [RemoveMatch()]
+    def when(self, matches, context):
+        return [matches[0]]
+
+class RuleAppend1(Rule):
+    consequence = [AppendMatch]
+    def when(self, matches, context):
+        return [Match(5, 10)]
+
+class RuleRename1(Rule):
+    consequence = RenameMatch('renamed')
+    def when(self, matches, context):
+        return [Match(5, 10, name="original")]
+
+class RuleAppend2(Rule):
+    consequence = [AppendMatch('renamed')]
+    properties = {'renamed': [None]}
+    def when(self, matches, context):
+        return [Match(5, 10)]
+
+class RuleRename2(Rule):
+    consequence = RenameMatch('renamed')
+    def when(self, matches, context):
+        return Match(5, 10, name="original")
+
+class RuleAppend3(Rule):
+    consequence = AppendMatch('renamed')
+    properties = {'renamed': [None]}
+    def when(self, matches, context):
+        return [Match(5, 10)]
+
+class RuleRename3(Rule):
+    consequence = [RenameMatch('renamed')]
+    def when(self, matches, context):
+        return Match(5, 10, name="original")
+
+class RuleAppendTags0(Rule):
+    consequence = AppendTags(['new-tag'])
+    def when(self, matches, context):
+        return matches.named('tags', 0)
+
+class RuleRemoveTags0(Rule):
+    consequence = RemoveTags(['new-tag'])
+    def when(self, matches, context):
+        return matches.named('tags', 0)
+
+class RuleAppendTags1(Rule):
+    consequence = AppendTags(['new-tag'])
+    def when(self, matches, context):
+        return matches.named('tags')
+
+class RuleRemoveTags1(Rule):
+    consequence = RemoveTags(['new-tag'])
+    def when(self, matches, context):
+        return matches.named('tags')
+
diff --git a/lib/rebulk/test/rebulk_rules_module.py b/lib/rebulk/test/rebulk_rules_module.py
new file mode 100644
index 000000000..0bd5ef33a
--- /dev/null
+++ b/lib/rebulk/test/rebulk_rules_module.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
+from rebulk.rules import Rule, RemoveMatch, CustomRule
+
+
+class RemoveAllButLastYear(Rule):
+    consequence = RemoveMatch
+    def when(self, matches, context):
+        entries = matches.named('year')
+        return entries[:-1]
+
+
+class PrefixedSuffixedYear(CustomRule):
+    def when(self, matches, context):
+        toRemove = []
+        years = matches.named('year')
+        for year in years:
+            if not matches.previous(year, lambda p: p.name == 'yearPrefix') and \
+                   not matches.next(year, lambda n: n.name == 'yearSuffix'):
+                toRemove.append(year)
+        return toRemove
+
+    def then(self, matches, when_response, context):
+        for to_remove in when_response:
+            matches.remove(to_remove)
+
+
+class PrefixedSuffixedYearNoLambda(Rule):
+    consequence = RemoveMatch
+    def when(self, matches, context):
+        toRemove = []
+        years = matches.named('year')
+        for year in years:
+            if not [m for m in matches.previous(year) if m.name == 'yearPrefix'] and \
+                    not [m for m in matches.next(year) if m.name == 'yearSuffix']:
+                toRemove.append(year)
+        return toRemove
diff --git a/lib/rebulk/test/rules_module.py b/lib/rebulk/test/rules_module.py
new file mode 100644
index 000000000..887b81da8
--- /dev/null
+++ b/lib/rebulk/test/rules_module.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
+from ..match import Match
+from ..rules import Rule
+
+
+class Rule3(Rule):
+    def when(self, matches, context):
+        return context.get('when')
+
+    def then(self, matches, when_response, context):
+        assert when_response in [True, False]
+        matches.append(Match(3, 4))
+
+
+class Rule2(Rule):
+    dependency = Rule3
+
+    def when(self, matches, context):
+        return True
+
+    def then(self, matches, when_response, context):
+        assert when_response
+        matches.append(Match(3, 4))
+
+
+class Rule1(Rule):
+    dependency = Rule2
+
+    def when(self, matches, context):
+        return True
+
+    def then(self, matches, when_response, context):
+        assert when_response
+        matches.clear()
+
+
+class Rule0(Rule):
+    dependency = Rule1
+
+    def when(self, matches, context):
+        return True
+
+    def then(self, matches, when_response, context):
+        assert when_response
+        matches.append(Match(3, 4))
+
+
+class Rule1Disabled(Rule1):
+    name = "Disabled Rule1"
+
+    def enabled(self, context):
+        return False
diff --git a/lib/rebulk/test/test_debug.py b/lib/rebulk/test/test_debug.py
new file mode 100644
index 000000000..a35f95fdf
--- /dev/null
+++ b/lib/rebulk/test/test_debug.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, protected-access, invalid-name
+
+from ..pattern import StringPattern
+from ..rebulk import Rebulk
+from ..match import Match
+from .. import debug
+from .default_rules_module import RuleRemove0
+
+
+class TestDebug(object):
+
+
+    #request.addfinalizer(disable_debug)
+
+
+
+    debug.DEBUG = True
+    pattern = StringPattern(1, 3, value="es")
+
+    match = Match(1, 3, value="es")
+    rule = RuleRemove0()
+
+    input_string = "This is a debug test"
+    rebulk = Rebulk().string("debug") \
+        .string("is")
+
+    matches = rebulk.matches(input_string)
+    debug.DEBUG = False
+
+    @classmethod
+    def setup_class(cls):
+        debug.DEBUG = True
+
+    @classmethod
+    def teardown_class(cls):
+        debug.DEBUG = False
+
+    def test_pattern(self):
+        assert self.pattern.defined_at.lineno == 20
+        assert self.pattern.defined_at.name == 'rebulk.test.test_debug'
+        assert self.pattern.defined_at.filename.endswith('test_debug.py')
+
+        assert str(self.pattern.defined_at) == 'test_debug.py#L20'
+        assert repr(self.pattern) == '<StringPattern@test_debug.py#L20:(1, 3)>'
+
+    def test_match(self):
+        assert self.match.defined_at.lineno == 22
+        assert self.match.defined_at.name == 'rebulk.test.test_debug'
+        assert self.match.defined_at.filename.endswith('test_debug.py')
+
+        assert str(self.match.defined_at) == 'test_debug.py#L22'
+
+    def test_rule(self):
+        assert self.rule.defined_at.lineno == 23
+        assert self.rule.defined_at.name == 'rebulk.test.test_debug'
+        assert self.rule.defined_at.filename.endswith('test_debug.py')
+
+        assert str(self.rule.defined_at) == 'test_debug.py#L23'
+        assert repr(self.rule) == '<RuleRemove0@test_debug.py#L23>'
+
+    def test_rebulk(self):
+        """
+        This test fails on travis CI, can't find out why there's 1 line offset ...
+        """
+        assert self.rebulk._patterns[0].defined_at.lineno in [26, 27]
+        assert self.rebulk._patterns[0].defined_at.name == 'rebulk.test.test_debug'
+        assert self.rebulk._patterns[0].defined_at.filename.endswith('test_debug.py')
+
+        assert str(self.rebulk._patterns[0].defined_at) in ['test_debug.py#L26', 'test_debug.py#L27']
+
+        assert self.rebulk._patterns[1].defined_at.lineno in [27, 28]
+        assert self.rebulk._patterns[1].defined_at.name == 'rebulk.test.test_debug'
+        assert self.rebulk._patterns[1].defined_at.filename.endswith('test_debug.py')
+
+        assert str(self.rebulk._patterns[1].defined_at) in ['test_debug.py#L27', 'test_debug.py#L28']
+
+        assert self.matches[0].defined_at == self.rebulk._patterns[0].defined_at
+        assert self.matches[1].defined_at == self.rebulk._patterns[1].defined_at
+
+    def test_repr(self):
+        str(self.matches)
diff --git a/lib/rebulk/test/test_introspector.py b/lib/rebulk/test/test_introspector.py
new file mode 100644
index 000000000..24c0c5001
--- /dev/null
+++ b/lib/rebulk/test/test_introspector.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Introspector tests
+"""
+# pylint: disable=no-self-use,pointless-statement,missing-docstring,protected-access,invalid-name
+from ..rebulk import Rebulk
+from .. import introspector
+from .default_rules_module import RuleAppend2, RuleAppend3
+
+
+def test_string_introspector():
+    rebulk = Rebulk().string('One', 'Two', 'Three', name='first').string('1', '2', '3', name='second')
+
+    introspected = introspector.introspect(rebulk, None)
+
+    assert len(introspected.patterns) == 2
+
+    first_properties = introspected.patterns[0].properties
+    assert len(first_properties) == 1
+    first_properties['first'] == ['One', 'Two', 'Three']
+
+    second_properties = introspected.patterns[1].properties
+    assert len(second_properties) == 1
+    second_properties['second'] == ['1', '2', '3']
+
+    properties = introspected.properties
+    assert len(properties) == 2
+    assert properties['first'] == first_properties['first']
+    assert properties['second'] == second_properties['second']
+
+
+def test_string_properties():
+    rebulk = Rebulk()\
+        .string('One', 'Two', 'Three', name='first', properties={'custom': ['One']})\
+        .string('1', '2', '3', name='second', properties={'custom': [1]})
+
+    introspected = introspector.introspect(rebulk, None)
+
+    assert len(introspected.patterns) == 2
+    assert len(introspected.rules) == 2
+
+    first_properties = introspected.patterns[0].properties
+    assert len(first_properties) == 1
+    first_properties['custom'] == ['One']
+
+    second_properties = introspected.patterns[1].properties
+    assert len(second_properties) == 1
+    second_properties['custom'] == [1]
+
+    properties = introspected.properties
+    assert len(properties) == 1
+    assert properties['custom'] == ['One', 1]
+
+
+def test_various_pattern():
+    rebulk = Rebulk()\
+        .regex('One', 'Two', 'Three', name='first', value="string") \
+        .string('1', '2', '3', name='second', value="digit") \
+        .string('4', '5', '6', name='third') \
+        .string('private', private=True) \
+        .functional(lambda string: (0, 5), name='func', value='test') \
+        .regex('One', 'Two', 'Three', name='regex_name') \
+        .regex('(?P<one>One)(?P<two>Two)(?P<three>Three)') \
+        .functional(lambda string: (6, 10), name='func2') \
+        .string('7', name='third')
+
+    introspected = introspector.introspect(rebulk, None)
+
+    assert len(introspected.patterns) == 8
+    assert len(introspected.rules) == 2
+
+    first_properties = introspected.patterns[0].properties
+    assert len(first_properties) == 1
+    first_properties['first'] == ['string']
+
+    second_properties = introspected.patterns[1].properties
+    assert len(second_properties) == 1
+    second_properties['second'] == ['digit']
+
+    third_properties = introspected.patterns[2].properties
+    assert len(third_properties) == 1
+    third_properties['third'] == ['4', '5', '6']
+
+    func_properties = introspected.patterns[3].properties
+    assert len(func_properties) == 1
+    func_properties['func'] == ['test']
+
+    regex_name_properties = introspected.patterns[4].properties
+    assert len(regex_name_properties) == 1
+    regex_name_properties['regex_name'] == [None]
+
+    regex_groups_properties = introspected.patterns[5].properties
+    assert len(regex_groups_properties) == 3
+    regex_groups_properties['one'] == [None]
+    regex_groups_properties['two'] == [None]
+    regex_groups_properties['three'] == [None]
+
+    func2_properties = introspected.patterns[6].properties
+    assert len(func2_properties) == 1
+    func2_properties['func2'] == [None]
+
+    append_third_properties = introspected.patterns[7].properties
+    assert len(append_third_properties) == 1
+    append_third_properties['third'] == [None]
+
+    properties = introspected.properties
+    assert len(properties) == 9
+    assert properties['first'] == first_properties['first']
+    assert properties['second'] == second_properties['second']
+    assert properties['third'] == third_properties['third'] + append_third_properties['third']
+    assert properties['func'] == func_properties['func']
+    assert properties['regex_name'] == regex_name_properties['regex_name']
+    assert properties['one'] == regex_groups_properties['one']
+    assert properties['two'] == regex_groups_properties['two']
+    assert properties['three'] == regex_groups_properties['three']
+    assert properties['func2'] == func2_properties['func2']
+
+
+def test_rule_properties():
+    rebulk = Rebulk(default_rules=False).rules(RuleAppend2, RuleAppend3)
+
+    introspected = introspector.introspect(rebulk, None)
+
+    assert len(introspected.rules) == 2
+    assert len(introspected.patterns) == 0
+
+    rule_properties = introspected.rules[0].properties
+    assert len(rule_properties) == 1
+    assert rule_properties['renamed'] == [None]
+
+    rule_properties = introspected.rules[1].properties
+    assert len(rule_properties) == 1
+    assert rule_properties['renamed'] == [None]
+
+    properties = introspected.properties
+    assert len(properties) == 1
+    assert properties['renamed'] == [None]
diff --git a/lib/rebulk/test/test_loose.py b/lib/rebulk/test/test_loose.py
new file mode 100644
index 000000000..bc0c6bca1
--- /dev/null
+++ b/lib/rebulk/test/test_loose.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
+
+from ..loose import call
+
+
+def test_loose_function():
+
+    def func(v1, v2, v3=3, v4=4):
+        return v1 + v2 + v3 + v4
+
+    assert call(func, 1, 2) == func(1, 2)
+    assert call(func, 1, 2, 3, 5) == func(1, 2, 3, 5)
+    assert call(func, 1, 2, v3=4, v4=5) == func(1, 2, v3=4, v4=5)
+    assert call(func, 1, 2, 3, 4, 5) == func(1, 2, 3, 4)
+    assert call(func, 1, 2, 3, 4, more=5) == func(1, 2, 3, 4)
+
+
+def test_loose_varargs_function():
+    def func(v1, v2, *args):
+        return v1 + v2 + args[0] if len(args) > 0 else 3 + args[1] if len(args) > 1 else 4
+
+    assert call(func, 1, 2) == func(1, 2)
+    assert call(func, 1, 2, 3, 5) == func(1, 2, 3, 5)
+    assert call(func, 1, 2, 3, 4, 5) == func(1, 2, 3, 4)
+
+
+def test_loose_kwargs_function():
+    def func(v1, v2, **kwargs):
+        return v1 + v2 + kwargs.get('v3', 3) + kwargs.get('v4', 4)
+
+    assert call(func, v1=1, v2=2) == func(v1=1, v2=2)
+    assert call(func, v1=1, v2=2, v3=3, v4=5) == func(v1=1, v2=2, v3=3, v4=5)
+
+
+def test_loose_class():
+    class Dummy(object):
+        def __init__(self, v1, v2, v3=3, v4=4):
+            self.v1 = v1
+            self.v2 = v2
+            self.v3 = v3
+            self.v4 = v4
+
+        def call(self):
+            return self.v1 + self.v2 + self.v3 + self.v4
+
+    assert call(Dummy, 1, 2).call() == Dummy(1, 2).call()
+    assert call(Dummy, 1, 2, 3, 5).call() == Dummy(1, 2, 3, 5).call()
+    assert call(Dummy, 1, 2, v3=4, v4=5).call() == Dummy(1, 2, v3=4, v4=5).call()
+    assert call(Dummy, 1, 2, 3, 4, 5).call() == Dummy(1, 2, 3, 4).call()
+    assert call(Dummy, 1, 2, 3, 4, more=5).call() == Dummy(1, 2, 3, 4).call()
+
+
+def test_loose_varargs_class():
+    class Dummy(object):
+        def __init__(self, v1, v2, *args):
+            self.v1 = v1
+            self.v2 = v2
+            self.v3 = args[0] if len(args) > 0 else 3
+            self.v4 = args[1] if len(args) > 1 else 4
+
+        def call(self):
+            return self.v1 + self.v2 + self.v3 + self.v4
+
+    assert call(Dummy, 1, 2).call() == Dummy(1, 2).call()
+    assert call(Dummy, 1, 2, 3, 5).call() == Dummy(1, 2, 3, 5).call()
+    assert call(Dummy, 1, 2, 3, 4, 5).call() == Dummy(1, 2, 3, 4).call()
+
+
+def test_loose_kwargs_class():
+    class Dummy(object):
+        def __init__(self, v1, v2, **kwargs):
+            self.v1 = v1
+            self.v2 = v2
+            self.v3 = kwargs.get('v3', 3)
+            self.v4 = kwargs.get('v4', 4)
+
+        def call(self):
+            return self.v1 + self.v2 + self.v3 + self.v4
+
+    assert call(Dummy, v1=1, v2=2).call() == Dummy(v1=1, v2=2).call()
+    assert call(Dummy, v1=1, v2=2, v3=3, v4=5).call() == Dummy(v1=1, v2=2, v3=3, v4=5).call()
diff --git a/lib/rebulk/test/test_match.py b/lib/rebulk/test/test_match.py
new file mode 100644
index 000000000..c87311d1a
--- /dev/null
+++ b/lib/rebulk/test/test_match.py
@@ -0,0 +1,571 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, unneeded-not
+
+import pytest
+import six
+
+from ..match import Match, Matches
+from ..pattern import StringPattern, RePattern
+from ..formatters import formatters
+
+
+class TestMatchClass(object):
+    def test_repr(self):
+        match1 = Match(1, 3, value="es")
+
+        assert repr(match1) == '<es:(1, 3)>'
+
+        match2 = Match(0, 4, value="test", private=True, name="abc", tags=['one', 'two'])
+
+        assert repr(match2) == '<test:(0, 4)+private+name=abc+tags=[\'one\', \'two\']>'
+
+    def test_names(self):
+        parent = Match(0, 10, name="test")
+        parent.children.append(Match(0, 10, name="child1", parent=parent))
+        parent.children.append(Match(0, 10, name="child2", parent=parent))
+
+        assert set(parent.names) == set(["child1", "child2"])
+
+    def test_equality(self):
+        match1 = Match(1, 3, value="es")
+        match2 = Match(1, 3, value="es")
+
+        other = object()
+
+        assert hash(match1) == hash(match2)
+        assert hash(match1) != hash(other)
+
+        assert match1 == match2
+        assert not match1 == other
+
+    def test_inequality(self):
+        match1 = Match(0, 2, value="te")
+        match2 = Match(2, 4, value="st")
+        match3 = Match(0, 2, value="other")
+
+        other = object()
+
+        assert hash(match1) != hash(match2)
+        assert hash(match1) != hash(match3)
+
+        assert match1 != other
+        assert match1 != match2
+        assert match1 != match3
+
+    def test_length(self):
+        match1 = Match(0, 4, value="test")
+        match2 = Match(0, 2, value="spanIsUsed")
+
+        assert len(match1) == 4
+        assert len(match2) == 2
+
+    def test_compare(self):
+        match1 = Match(0, 2, value="te")
+        match2 = Match(2, 4, value="st")
+
+        other = object()
+
+        assert match1 < match2
+        assert match1 <= match2
+
+        assert match2 > match1
+        assert match2 >= match1
+
+        if six.PY3:
+            with pytest.raises(TypeError):
+                match1 < other
+
+            with pytest.raises(TypeError):
+                match1 <= other
+
+            with pytest.raises(TypeError):
+                match1 > other
+
+            with pytest.raises(TypeError):
+                match1 >= other
+        else:
+            assert match1 < other
+            assert match1 <= other
+            assert not match1 > other
+            assert not match1 >= other
+
+    def test_value(self):
+        match1 = Match(1, 3)
+        match1.value = "test"
+
+        assert match1.value == "test"
+
+
+class TestMatchesClass(object):
+    match1 = Match(0, 2, value="te", name="start")
+    match2 = Match(2, 3, value="s", tags="tag1")
+    match3 = Match(3, 4, value="t", tags=["tag1", "tag2"])
+    match4 = Match(2, 4, value="st", name="end")
+
+    def test_tag(self):
+        matches = Matches()
+        matches.append(self.match1)
+        matches.append(self.match2)
+        matches.append(self.match3)
+        matches.append(self.match4)
+
+        assert "start" in matches.names
+        assert "end" in matches.names
+
+        assert "tag1" in matches.tags
+        assert "tag2" in matches.tags
+
+        tag1 = matches.tagged("tag1")
+        assert len(tag1) == 2
+        assert tag1[0] == self.match2
+        assert tag1[1] == self.match3
+
+        tag2 = matches.tagged("tag2")
+        assert len(tag2) == 1
+        assert tag2[0] == self.match3
+
+        start = matches.named("start")
+        assert len(start) == 1
+        assert start[0] == self.match1
+
+        end = matches.named("end")
+        assert len(end) == 1
+        assert end[0] == self.match4
+
+    def test_base(self):
+        matches = Matches()
+        matches.append(self.match1)
+
+        assert len(matches) == 1
+        assert repr(matches) == repr([self.match1])
+        assert list(matches.starting(0)) == [self.match1]
+        assert list(matches.ending(2)) == [self.match1]
+
+        matches.append(self.match2)
+        matches.append(self.match3)
+        matches.append(self.match4)
+
+        assert len(matches) == 4
+        assert list(matches.starting(2)) == [self.match2, self.match4]
+        assert list(matches.starting(3)) == [self.match3]
+        assert list(matches.ending(3)) == [self.match2]
+        assert list(matches.ending(4)) == [self.match3, self.match4]
+        assert list(matches.range()) == [self.match1, self.match2, self.match4, self.match3]
+        assert list(matches.range(0)) == [self.match1, self.match2, self.match4, self.match3]
+        assert list(matches.range(0, 3)) == [self.match1, self.match2, self.match4]
+        assert list(matches.range(2, 3)) == [self.match2, self.match4]
+        assert list(matches.range(3, 4)) == [self.match4, self.match3]
+
+        matches.remove(self.match1)
+        assert len(matches) == 3
+        assert len(matches.starting(0)) == 0
+        assert len(matches.ending(2)) == 0
+
+        matches.clear()
+
+        assert len(matches) == 0
+        assert len(matches.starting(0)) == 0
+        assert len(matches.starting(2)) == 0
+        assert len(matches.starting(3)) == 0
+        assert len(matches.ending(2)) == 0
+        assert len(matches.ending(3)) == 0
+        assert len(matches.ending(4)) == 0
+
+    def test_get_slices(self):
+        matches = Matches()
+        matches.append(self.match1)
+        matches.append(self.match2)
+        matches.append(self.match3)
+        matches.append(self.match4)
+
+        slice_matches = matches[1:3]
+
+        assert isinstance(slice_matches, Matches)
+
+        assert len(slice_matches) == 2
+        assert slice_matches[0] == self.match2
+        assert slice_matches[1] == self.match3
+
+    def test_remove_slices(self):
+        matches = Matches()
+        matches.append(self.match1)
+        matches.append(self.match2)
+        matches.append(self.match3)
+        matches.append(self.match4)
+
+        del matches[1:3]
+
+        assert len(matches) == 2
+        assert matches[0] == self.match1
+        assert matches[1] == self.match4
+
+    def test_set_slices(self):
+        matches = Matches()
+        matches.append(self.match1)
+        matches.append(self.match2)
+        matches.append(self.match3)
+        matches.append(self.match4)
+
+        matches[1:3] = self.match1, self.match4
+
+        assert len(matches) == 4
+        assert matches[0] == self.match1
+        assert matches[1] == self.match1
+        assert matches[2] == self.match4
+        assert matches[3] == self.match4
+
+    def test_set_index(self):
+        matches = Matches()
+        matches.append(self.match1)
+        matches.append(self.match2)
+        matches.append(self.match3)
+
+        matches[1] = self.match4
+
+        assert len(matches) == 3
+        assert matches[0] == self.match1
+        assert matches[1] == self.match4
+        assert matches[2] == self.match3
+
+    def test_constructor(self):
+        matches = Matches([self.match1, self.match2, self.match3, self.match4])
+
+        assert len(matches) == 4
+        assert list(matches.starting(0)) == [self.match1]
+        assert list(matches.ending(2)) == [self.match1]
+        assert list(matches.starting(2)) == [self.match2, self.match4]
+        assert list(matches.starting(3)) == [self.match3]
+        assert list(matches.ending(3)) == [self.match2]
+        assert list(matches.ending(4)) == [self.match3, self.match4]
+
+    def test_constructor_kwargs(self):
+        matches = Matches([self.match1, self.match2, self.match3, self.match4], input_string="test")
+
+        assert len(matches) == 4
+        assert matches.input_string == "test"
+        assert list(matches.starting(0)) == [self.match1]
+        assert list(matches.ending(2)) == [self.match1]
+        assert list(matches.starting(2)) == [self.match2, self.match4]
+        assert list(matches.starting(3)) == [self.match3]
+        assert list(matches.ending(3)) == [self.match2]
+        assert list(matches.ending(4)) == [self.match3, self.match4]
+
+    def test_crop(self):
+        input_string = "abcdefghijklmnopqrstuvwxyz"
+
+        match1 = Match(1, 10, input_string=input_string)
+        match2 = Match(0, 2, input_string=input_string)
+        match3 = Match(8, 15, input_string=input_string)
+
+        ret = match1.crop([match2, match3.span])
+
+        assert len(ret) == 1
+
+        assert ret[0].span == (2, 8)
+        assert ret[0].value == "cdefgh"
+
+        ret = match1.crop((1, 10))
+        assert len(ret) == 0
+
+        ret = match1.crop((1, 3))
+        assert len(ret) == 1
+        assert ret[0].span == (3, 10)
+
+        ret = match1.crop((7, 10))
+        assert len(ret) == 1
+        assert ret[0].span == (1, 7)
+
+        ret = match1.crop((0, 12))
+        assert len(ret) == 0
+
+        ret = match1.crop((4, 6))
+        assert len(ret) == 2
+
+        assert ret[0].span == (1, 4)
+        assert ret[1].span == (6, 10)
+
+        ret = match1.crop([(3, 5), (7, 9)])
+        assert len(ret) == 3
+
+        assert ret[0].span == (1, 3)
+        assert ret[1].span == (5, 7)
+        assert ret[2].span == (9, 10)
+
+    def test_split(self):
+        input_string = "123 +word1  -  word2  + word3  456"
+        match = Match(3, len(input_string) - 3, input_string=input_string)
+        splitted = match.split(" -+")
+
+        assert len(splitted) == 3
+        assert [split.value for split in splitted] == ["word1", "word2", "word3"]
+
+
+class TestMaches(object):
+    def test_names(self):
+        input_string = "One Two Three"
+
+        matches = Matches()
+
+        matches.extend(StringPattern("One", name="1-str", tags=["One", "str"]).matches(input_string))
+        matches.extend(RePattern("One", name="1-re", tags=["One", "re"]).matches(input_string))
+        matches.extend(StringPattern("Two", name="2-str", tags=["Two", "str"]).matches(input_string))
+        matches.extend(RePattern("Two", name="2-re", tags=["Two", "re"]).matches(input_string))
+        matches.extend(StringPattern("Three", name="3-str", tags=["Three", "str"]).matches(input_string))
+        matches.extend(RePattern("Three", name="3-re", tags=["Three", "re"]).matches(input_string))
+
+        assert set(matches.names) == set(["1-str", "1-re", "2-str", "2-re", "3-str", "3-re"])
+
+    def test_filters(self):
+        input_string = "One Two Three"
+
+        matches = Matches()
+
+        matches.extend(StringPattern("One", name="1-str", tags=["One", "str"]).matches(input_string))
+        matches.extend(RePattern("One", name="1-re", tags=["One", "re"]).matches(input_string))
+        matches.extend(StringPattern("Two", name="2-str", tags=["Two", "str"]).matches(input_string))
+        matches.extend(RePattern("Two", name="2-re", tags=["Two", "re"]).matches(input_string))
+        matches.extend(StringPattern("Three", name="3-str", tags=["Three", "str"]).matches(input_string))
+        matches.extend(RePattern("Three", name="3-re", tags=["Three", "re"]).matches(input_string))
+
+        selection = matches.starting(0)
+        assert len(selection) == 2
+
+        selection = matches.starting(0, lambda m: "str" in m.tags)
+        assert len(selection) == 1
+        assert selection[0].pattern.name == "1-str"
+
+        selection = matches.ending(7, predicate=lambda m: "str" in m.tags)
+        assert len(selection) == 1
+        assert selection[0].pattern.name == "2-str"
+
+        selection = matches.previous(matches.named("2-str")[0])
+        assert len(selection) == 2
+        assert selection[0].pattern.name == "1-str"
+        assert selection[1].pattern.name == "1-re"
+
+        selection = matches.previous(matches.named("2-str", 0), lambda m: "str" in m.tags)
+        assert len(selection) == 1
+        assert selection[0].pattern.name == "1-str"
+
+        selection = matches.next(matches.named("2-str", 0))
+        assert len(selection) == 2
+        assert selection[0].pattern.name == "3-str"
+        assert selection[1].pattern.name == "3-re"
+
+        selection = matches.next(matches.named("2-str", 0), index=0, predicate=lambda m: "re" in m.tags)
+        assert selection is not None
+        assert selection.pattern.name == "3-re"
+
+        selection = matches.next(matches.named("2-str", index=0), lambda m: "re" in m.tags)
+        assert len(selection) == 1
+        assert selection[0].pattern.name == "3-re"
+
+        selection = matches.named("2-str", lambda m: "re" in m.tags)
+        assert len(selection) == 0
+
+        selection = matches.named("2-re", lambda m: "re" in m.tags, 0)
+        assert selection is not None
+        assert selection.name == "2-re"  # pylint:disable=no-member
+
+        selection = matches.named("2-re", lambda m: "re" in m.tags)
+        assert len(selection) == 1
+        assert selection[0].name == "2-re"
+
+        selection = matches.named("2-re", lambda m: "re" in m.tags, index=1000)
+        assert selection is None
+
+    def test_raw(self):
+        input_string = "0123456789"
+
+        match = Match(0, 10, input_string=input_string, formatter=lambda s: s*2)
+
+        assert match.value == match.raw * 2
+        assert match.raw == input_string
+
+        match.raw_end = 9
+        match.raw_start = 1
+
+        assert match.value == match.raw * 2
+        assert match.raw == input_string[1:9]
+
+        match.raw_end = None
+        match.raw_start = None
+
+        assert match.value == match.raw * 2
+        assert match.raw == input_string
+
+
+    def test_formatter_chain(self):
+        input_string = "100"
+
+        match = Match(0, 3, input_string=input_string, formatter=formatters(int, lambda s: s*2, lambda  s: s+10))
+
+        assert match.raw == input_string
+        assert match.value == 100 * 2 + 10
+
+
+    def test_to_dict(self):
+        input_string = "One Two Two Three"
+
+        matches = Matches()
+
+        matches.extend(StringPattern("One", name="1", tags=["One", "str"]).matches(input_string))
+        matches.extend(RePattern("One", name="1", tags=["One", "re"]).matches(input_string))
+        matches.extend(StringPattern("Two", name="2", tags=["Two", "str"]).matches(input_string))
+        matches.extend(RePattern("Two", name="2", tags=["Two", "re"]).matches(input_string))
+        matches.extend(RePattern("Two", name="2", tags=["Two", "reBis"]).matches(input_string))
+        matches.extend(StringPattern("Three", name="3", tags=["Three", "str"]).matches(input_string))
+        matches.extend(RePattern("Three", name="3bis", tags=["Three", "re"]).matches(input_string))
+        matches.extend(RePattern(r"(\w+)", name="words").matches(input_string))
+
+        kvalues = matches.to_dict()
+        assert kvalues == {"1": "One",
+                           "2": "Two",
+                           "3": "Three",
+                           "3bis": "Three",
+                           "words": "One"}
+        assert kvalues.values_list["words"] == ["One", "Two", "Three"]
+
+        kvalues = matches.to_dict(details=True, implicit=True)
+        assert kvalues["1"].value == "One"
+
+        assert len(kvalues["2"]) == 2
+        assert kvalues["2"][0].value == "Two"
+        assert kvalues["2"][1].value == "Two"
+
+        assert kvalues["3"].value == "Three"
+        assert kvalues["3bis"].value == "Three"
+
+        assert len(kvalues["words"]) == 4
+        assert kvalues["words"][0].value == "One"
+        assert kvalues["words"][1].value == "Two"
+        assert kvalues["words"][2].value == "Two"
+        assert kvalues["words"][3].value == "Three"
+
+        kvalues = matches.to_dict(details=True)
+        assert kvalues["1"].value == "One"
+
+        assert len(kvalues.values_list["2"]) == 2
+        assert kvalues.values_list["2"][0].value == "Two"
+        assert kvalues.values_list["2"][1].value == "Two"
+
+        assert kvalues["3"].value == "Three"
+        assert kvalues["3bis"].value == "Three"
+
+        assert len(kvalues.values_list["words"]) == 4
+        assert kvalues.values_list["words"][0].value == "One"
+        assert kvalues.values_list["words"][1].value == "Two"
+        assert kvalues.values_list["words"][2].value == "Two"
+        assert kvalues.values_list["words"][3].value == "Three"
+
+    def test_chains(self):
+        input_string = "wordX 10 20 30 40 wordA, wordB, wordC 70 80 wordX"
+
+        matches = Matches(input_string=input_string)
+
+        matches.extend(RePattern(r"\d+", name="digit").matches(input_string))
+        matches.extend(RePattern("[a-zA-Z]+", name="word").matches(input_string))
+
+        assert len(matches) == 11
+
+        a_start = input_string.find('wordA')
+
+        b_start = input_string.find('wordB')
+        b_end = b_start + len('wordB')
+
+        c_start = input_string.find('wordC')
+        c_end = c_start + len('wordC')
+
+        chain_before = matches.chain_before(b_start, " ,", predicate=lambda match: match.name == "word")
+        assert len(chain_before) == 1
+        assert chain_before[0].value == 'wordA'
+
+        chain_before = matches.chain_before(Match(b_start, b_start), " ,", predicate=lambda match: match.name == "word")
+        assert len(chain_before) == 1
+        assert chain_before[0].value == 'wordA'
+
+        chain_before = matches.chain_before(b_start, " ,", predicate=lambda match: match.name == "digit")
+        assert len(chain_before) == 0
+
+        chain_before = matches.chain_before(a_start, " ,", predicate=lambda match: match.name == "digit")
+        assert len(chain_before) == 4
+        assert [match.value for match in chain_before] == ["40", "30", "20", "10"]
+
+        chain_after = matches.chain_after(b_end, " ,", predicate=lambda match: match.name == "word")
+        assert len(chain_after) == 1
+        assert chain_after[0].value == 'wordC'
+
+        chain_after = matches.chain_after(Match(b_end, b_end), " ,", predicate=lambda match: match.name == "word")
+        assert len(chain_after) == 1
+        assert chain_after[0].value == 'wordC'
+
+        chain_after = matches.chain_after(b_end, " ,", predicate=lambda match: match.name == "digit")
+        assert len(chain_after) == 0
+
+        chain_after = matches.chain_after(c_end, " ,", predicate=lambda match: match.name == "digit")
+        assert len(chain_after) == 2
+        assert [match.value for match in chain_after] == ["70", "80"]
+
+        chain_after = matches.chain_after(c_end, " ,", end=10000, predicate=lambda match: match.name == "digit")
+        assert len(chain_after) == 2
+        assert [match.value for match in chain_after] == ["70", "80"]
+
+    def test_holes(self):
+        input_string = '1'*10+'2'*10+'3'*10+'4'*10+'5'*10+'6'*10+'7'*10
+
+        hole1 = Match(0, 10, input_string=input_string)
+        hole2 = Match(20, 30, input_string=input_string)
+        hole3 = Match(30, 40, input_string=input_string)
+        hole4 = Match(60, 70, input_string=input_string)
+
+        matches = Matches([hole1, hole2], input_string=input_string)
+        matches.append(hole3)
+        matches.append(hole4)
+
+        holes = list(matches.holes())
+        assert len(holes) == 2
+        assert holes[0].span == (10, 20)
+        assert holes[0].value == '2'*10
+        assert holes[1].span == (40, 60)
+        assert holes[1].value == '5' * 10 + '6' * 10
+
+        holes = list(matches.holes(5, 15))
+        assert len(holes) == 1
+        assert holes[0].span == (10, 15)
+        assert holes[0].value == '2'*5
+
+        holes = list(matches.holes(5, 15, formatter=lambda value: "formatted"))
+        assert len(holes) == 1
+        assert holes[0].span == (10, 15)
+        assert holes[0].value == "formatted"
+
+        holes = list(matches.holes(5, 15, predicate=lambda hole: False))
+        assert len(holes) == 0
+
+    def test_holes_empty(self):
+        input_string = "Test hole on empty matches"
+        matches = Matches(input_string=input_string)
+        holes = matches.holes()
+        assert len(holes) == 1
+        assert holes[0].value == input_string
+
+    def test_holes_seps(self):
+        input_string = "Test hole - with many separators + included"
+        match = StringPattern("many").matches(input_string)
+
+        matches = Matches(match, input_string)
+        holes = matches.holes()
+
+        assert len(holes) == 2
+
+        holes = matches.holes(seps="-+")
+
+        assert len(holes) == 4
+        assert [hole.value for hole in holes] == ["Test hole ", " with ", " separators ", " included"]
+
+
+
+
+
+
diff --git a/lib/rebulk/test/test_pattern.py b/lib/rebulk/test/test_pattern.py
new file mode 100644
index 000000000..0316aabaf
--- /dev/null
+++ b/lib/rebulk/test/test_pattern.py
@@ -0,0 +1,757 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, unbalanced-tuple-unpacking
+
+import re
+import pytest
+
+from ..pattern import StringPattern, RePattern, FunctionalPattern, REGEX_AVAILABLE
+from ..match import Match
+
+class TestStringPattern(object):
+    """
+    Tests for StringPattern matching
+    """
+
+    input_string = "An Abyssinian fly playing a Celtic violin was annoyed by trashy flags on " \
+                   "which were the Hebrew letter qoph."
+
+    def test_single(self):
+        pattern = StringPattern("Celtic")
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (28, 34)
+        assert matches[0].value == "Celtic"
+
+    def test_repr(self):
+        pattern = StringPattern("Celtic")
+
+        assert repr(pattern) == '<StringPattern:(\'Celtic\',)>'
+
+    def test_ignore_case(self):
+        pattern = StringPattern("celtic", ignore_case=False)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+        pattern = StringPattern("celtic", ignore_case=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert matches[0].value == "Celtic"
+
+    def test_private_names(self):
+        pattern = StringPattern("celtic", name="test", private_names=["test"], ignore_case=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert matches[0].private
+
+    def test_no_match(self):
+        pattern = StringPattern("Python")
+
+        matches = list(pattern.matches(self.input_string))
+        assert not matches
+
+    def test_multiple_patterns(self):
+        pattern = StringPattern("playing", "annoyed", "Hebrew")
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 3
+
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (18, 25)
+        assert matches[0].value == "playing"
+
+        assert isinstance(matches[1], Match)
+        assert matches[1].pattern == pattern
+        assert matches[1].span == (46, 53)
+        assert matches[1].value == "annoyed"
+
+        assert isinstance(matches[2], Match)
+        assert matches[2].pattern == pattern
+        assert matches[2].span == (88, 94)
+        assert matches[2].value == "Hebrew"
+
+    def test_start_end_kwargs(self):
+        pattern = StringPattern("Abyssinian", start=20, end=40)
+        matches = list(pattern.matches(self.input_string))
+
+        assert len(matches) == 0
+
+    def test_matches_kwargs(self):
+        pattern = StringPattern("Abyssinian", name="test", value="AB")
+        matches = list(pattern.matches(self.input_string))
+
+        assert len(matches) == 1
+        assert matches[0].name == "test"
+        assert matches[0].value == "AB"
+
+
+class TestRePattern(object):
+    """
+    Tests for RePattern matching
+    """
+
+    input_string = "An Abyssinian fly playing a Celtic violin was annoyed by trashy flags on " \
+                   "which were the Hebrew letter qoph."
+
+    def test_single_compiled(self):
+        pattern = RePattern(re.compile("Celt.?c"))
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (28, 34)
+        assert matches[0].value == "Celtic"
+
+    def test_single_string(self):
+        pattern = RePattern("Celt.?c")
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (28, 34)
+        assert matches[0].value == "Celtic"
+
+    def test_single_kwargs(self):
+        pattern = RePattern({"pattern": "celt.?c", "flags": re.IGNORECASE})
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (28, 34)
+        assert matches[0].value == "Celtic"
+
+    def test_single_vargs(self):
+        pattern = RePattern(("celt.?c", re.IGNORECASE))
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (28, 34)
+        assert matches[0].value == "Celtic"
+
+    def test_no_match(self):
+        pattern = RePattern("abc.?def")
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+    def test_shortcuts(self):
+        pattern = RePattern("Celtic-violin", abbreviations=[("-", r"[\W_]+")])
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+        pattern = RePattern({"pattern": "celtic-violin", "flags": re.IGNORECASE}, abbreviations=[("-", r"[\W_]+")])
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+    def test_multiple_patterns(self):
+        pattern = RePattern("pla.?ing", "ann.?yed", "Heb.?ew")
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 3
+
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (18, 25)
+        assert matches[0].value == "playing"
+
+        assert isinstance(matches[1], Match)
+        assert matches[1].pattern == pattern
+        assert matches[1].span == (46, 53)
+        assert matches[1].value == "annoyed"
+
+        assert isinstance(matches[2], Match)
+        assert matches[2].pattern == pattern
+        assert matches[2].span == (88, 94)
+        assert matches[2].value == "Hebrew"
+
+    def test_unnamed_groups(self):
+        pattern = RePattern(r"(Celt.?c)\s+(\w+)")
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+        parent = matches[0]
+
+        assert isinstance(parent, Match)
+        assert parent.pattern == pattern
+        assert parent.span == (28, 41)
+        assert parent.name is None
+        assert parent.value == "Celtic violin"
+
+        assert len(parent.children) == 2
+
+        group1, group2 = parent.children
+
+        assert isinstance(group1, Match)
+        assert group1.pattern == pattern
+        assert group1.span == (28, 34)
+        assert group1.name is None
+        assert group1.value == "Celtic"
+        assert group1.parent == parent
+
+        assert isinstance(group2, Match)
+        assert group2.pattern == pattern
+        assert group2.span == (35, 41)
+        assert group2.name is None
+        assert group2.value == "violin"
+        assert group2.parent == parent
+
+    def test_named_groups(self):
+        pattern = RePattern(r"(?P<param1>Celt.?c)\s+(?P<param2>\w+)")
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+        parent = matches[0]
+
+        assert isinstance(parent, Match)
+        assert parent.pattern == pattern
+        assert parent.span == (28, 41)
+        assert parent.name is None
+        assert parent.value == "Celtic violin"
+
+        assert len(parent.children) == 2
+        group1, group2 = parent.children
+
+        assert isinstance(group1, Match)
+        assert group1.pattern == pattern
+        assert group1.span == (28, 34)
+        assert group1.name == "param1"
+        assert group1.value == "Celtic"
+        assert group1.parent == parent
+
+        assert isinstance(group2, Match)
+        assert group2.pattern == pattern
+        assert group2.span == (35, 41)
+        assert group2.name == "param2"
+        assert group2.value == "violin"
+        assert group2.parent == parent
+
+    def test_children(self):
+        pattern = RePattern(r"(?P<param1>Celt.?c)\s+(?P<param2>\w+)", children=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 2
+        group1, group2 = matches
+
+        assert isinstance(group1, Match)
+        assert group1.pattern == pattern
+        assert group1.span == (28, 34)
+        assert group1.name == "param1"
+        assert group1.value == "Celtic"
+
+        assert isinstance(group2, Match)
+        assert group2.pattern == pattern
+        assert group2.span == (35, 41)
+        assert group2.name == "param2"
+        assert group2.value == "violin"
+
+    def test_children_parent_private(self):
+        pattern = RePattern(r"(?P<param1>Celt.?c)\s+(?P<param2>\w+)", children=True, private_parent=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 3
+        parent, group1, group2 = matches
+
+        assert isinstance(group1, Match)
+        assert parent.private
+        assert parent.pattern == pattern
+        assert parent.span == (28, 41)
+        assert parent.name is None
+        assert parent.value == "Celtic violin"
+
+        assert isinstance(group1, Match)
+        assert not group1.private
+        assert group1.pattern == pattern
+        assert group1.span == (28, 34)
+        assert group1.name == "param1"
+        assert group1.value == "Celtic"
+
+        assert isinstance(group2, Match)
+        assert not group2.private
+        assert group2.pattern == pattern
+        assert group2.span == (35, 41)
+        assert group2.name == "param2"
+        assert group2.value == "violin"
+
+    def test_parent_children_private(self):
+        pattern = RePattern(r"(?P<param1>Celt.?c)\s+(?P<param2>\w+)", private_children=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 3
+        parent, group1, group2 = matches
+
+        assert isinstance(group1, Match)
+        assert not parent.private
+        assert parent.pattern == pattern
+        assert parent.span == (28, 41)
+        assert parent.name is None
+        assert parent.value == "Celtic violin"
+
+        assert isinstance(group1, Match)
+        assert group1.private
+        assert group1.pattern == pattern
+        assert group1.span == (28, 34)
+        assert group1.name == "param1"
+        assert group1.value == "Celtic"
+
+        assert isinstance(group2, Match)
+        assert group2.private
+        assert group2.pattern == pattern
+        assert group2.span == (35, 41)
+        assert group2.name == "param2"
+        assert group2.value == "violin"
+
+    def test_every(self):
+        pattern = RePattern(r"(?P<param1>Celt.?c)\s+(?P<param2>\w+)", every=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 3
+        parent, group1, group2 = matches
+
+        assert isinstance(group1, Match)
+        assert not parent.private
+        assert parent.pattern == pattern
+        assert parent.span == (28, 41)
+        assert parent.name is None
+        assert parent.value == "Celtic violin"
+
+        assert isinstance(group1, Match)
+        assert not group1.private
+        assert group1.pattern == pattern
+        assert group1.span == (28, 34)
+        assert group1.name == "param1"
+        assert group1.value == "Celtic"
+
+        assert isinstance(group2, Match)
+        assert not group2.private
+        assert group2.pattern == pattern
+        assert group2.span == (35, 41)
+        assert group2.name == "param2"
+        assert group2.value == "violin"
+
+    def test_matches_kwargs(self):
+        pattern = RePattern("He.rew", name="test", value="HE")
+        matches = list(pattern.matches(self.input_string))
+
+        assert len(matches) == 1
+        assert matches[0].name == "test"
+        assert matches[0].value == "HE"
+
+        pattern = RePattern("H(e.)(rew)", name="test", value="HE")
+        matches = list(pattern.matches(self.input_string))
+
+        assert len(matches) == 1
+        assert matches[0].name == "test"
+        assert matches[0].value == "HE"
+
+        children = matches[0].children
+        assert len(children) == 2
+        assert children[0].name is "test"
+        assert children[0].value == "HE"
+
+        assert children[1].name is "test"
+        assert children[1].value == "HE"
+
+        pattern = RePattern("H(?P<first>e.)(?P<second>rew)", name="test", value="HE")
+        matches = list(pattern.matches(self.input_string))
+
+        assert len(matches) == 1
+        assert matches[0].name == "test"
+        assert matches[0].value == "HE"
+
+        children = matches[0].children
+        assert len(children) == 2
+        assert children[0].name == "first"
+        assert children[0].value == "HE"
+
+        assert children[1].name == "second"
+        assert children[1].value == "HE"
+
+
+class TestFunctionalPattern(object):
+    """
+    Tests for FunctionalPattern matching
+    """
+
+    input_string = "An Abyssinian fly playing a Celtic violin was annoyed by trashy flags on " \
+                   "which were the Hebrew letter qoph."
+
+    def test_single_vargs(self):
+        def func(input_string):
+            i = input_string.find("fly")
+            if i > -1:
+                return i, i + len("fly"), "fly", "functional"
+
+        pattern = FunctionalPattern(func)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (14, 17)
+        assert matches[0].name == "functional"
+        assert matches[0].value == "fly"
+
+    def test_single_kwargs(self):
+        def func(input_string):
+            i = input_string.find("fly")
+            if i > -1:
+                return {"start": i, "end": i + len("fly"), "name": "functional"}
+
+        pattern = FunctionalPattern(func)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (14, 17)
+        assert matches[0].name == "functional"
+        assert matches[0].value == "fly"
+
+    def test_multiple_objects(self):
+        def func(input_string):
+            i = input_string.find("fly")
+            matches = []
+            if i > -1:
+                matches.append((i, i + len("fly"), {'name': "functional"}))
+                i = input_string.find("annoyed")
+            if i > -1:
+                matches.append((i, i + len("annoyed")))
+            i = input_string.find("Hebrew")
+            if i > -1:
+                matches.append({"start": i, "end": i + len("Hebrew")})
+            return matches
+
+        pattern = FunctionalPattern(func)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 3
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (14, 17)
+        assert matches[0].name == "functional"
+        assert matches[0].value == "fly"
+
+        assert isinstance(matches[1], Match)
+        assert matches[1].pattern == pattern
+        assert matches[1].span == (46, 53)
+        assert matches[1].value == "annoyed"
+
+        assert isinstance(matches[2], Match)
+        assert matches[2].pattern == pattern
+        assert matches[2].span == (88, 94)
+        assert matches[2].value == "Hebrew"
+
+    def test_multiple_generator(self):
+        def func(input_string):
+            i = input_string.find("fly")
+            if i > -1:
+                yield (i, i + len("fly"), {'name': "functional"})
+            i = input_string.find("annoyed")
+            if i > -1:
+                yield (i, i + len("annoyed"))
+            i = input_string.find("Hebrew")
+            if i > -1:
+                yield (i, {"end": i + len("Hebrew")})
+
+        pattern = FunctionalPattern(func)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 3
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (14, 17)
+        assert matches[0].name == "functional"
+        assert matches[0].value == "fly"
+
+        assert isinstance(matches[1], Match)
+        assert matches[1].pattern == pattern
+        assert matches[1].span == (46, 53)
+        assert matches[1].value == "annoyed"
+
+        assert isinstance(matches[2], Match)
+        assert matches[2].pattern == pattern
+        assert matches[2].span == (88, 94)
+        assert matches[2].value == "Hebrew"
+
+    def test_no_match(self):
+        pattern = FunctionalPattern(lambda x: None)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+    def test_multiple_patterns(self):
+        def playing(input_string):
+            i = input_string.find("playing")
+            if i > -1:
+                return i, i + len("playing")
+
+        def annoyed(input_string):
+            i = input_string.find("annoyed")
+            if i > -1:
+                return i, i + len("annoyed")
+
+        def hebrew(input_string):
+            i = input_string.find("Hebrew")
+            if i > -1:
+                return i, i + len("Hebrew")
+
+        pattern = FunctionalPattern(playing, annoyed, hebrew)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 3
+
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (18, 25)
+        assert matches[0].value == "playing"
+
+        assert isinstance(matches[1], Match)
+        assert matches[1].pattern == pattern
+        assert matches[1].span == (46, 53)
+        assert matches[1].value == "annoyed"
+
+        assert isinstance(matches[2], Match)
+        assert matches[2].pattern == pattern
+        assert matches[2].span == (88, 94)
+        assert matches[2].value == "Hebrew"
+
+    def test_matches_kwargs(self):
+        def playing(input_string):
+            i = input_string.find("playing")
+            if i > -1:
+                return i, i + len("playing")
+
+        pattern = FunctionalPattern(playing, name="test", value="PLAY")
+        matches = list(pattern.matches(self.input_string))
+
+        assert len(matches) == 1
+        assert matches[0].name == "test"
+        assert matches[0].value == "PLAY"
+
+
+class TestFormatter(object):
+    """
+    Tests for formatter option
+    """
+
+    input_string = "This string contains 1849 a number"
+
+    def test_single_string(self):
+        pattern = StringPattern("1849", name="dummy", formatter=lambda x: int(x) / 2)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (21, 25)
+        assert matches[0].value == 1849 / 2
+
+    def test_single_re_no_group(self):
+        pattern = RePattern(r"\d+", formatter=lambda x: int(x) * 2)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (21, 25)
+        assert matches[0].value == 1849 * 2
+
+    def test_single_re_named_groups(self):
+        pattern = RePattern(r"(?P<strParam>cont.?ins)\s+(?P<intParam>\d+)",
+                            formatter={'intParam': lambda x: int(x) * 2,
+                                       'strParam': lambda x: "really " + x}, format_all=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+        parent = matches[0]
+        assert len(parent.children) == 2
+
+        group1, group2 = parent.children
+
+        assert isinstance(group1, Match)
+        assert group1.pattern == pattern
+        assert group1.span == (12, 20)
+        assert group1.value == "really contains"
+
+        assert isinstance(group2, Match)
+        assert group2.pattern == pattern
+        assert group2.span == (21, 25)
+        assert group2.value == 1849 * 2
+
+    def test_repeated_captures_option(self):
+        pattern = RePattern(r"\[(\d+)\](?:-(\d+))*")
+
+        matches = list(pattern.matches("[02]-03-04-05-06"))
+        assert len(matches) == 1
+
+        match = matches[0]
+        if REGEX_AVAILABLE:
+            assert len(match.children) == 5
+            assert [child.value for child in match.children] == ["02", "03", "04", "05", "06"]
+        else:
+            assert len(match.children) == 2
+            assert [child.value for child in match.children] == ["02", "06"]
+
+            with pytest.raises(NotImplementedError):
+                RePattern(r"\[(\d+)\](?:-(\d+))*", repeated_captures=True)
+
+        pattern = RePattern(r"\[(\d+)\](?:-(\d+))*", repeated_captures=False)
+
+        matches = list(pattern.matches("[02]-03-04-05-06"))
+        assert len(matches) == 1
+
+        match = matches[0]
+        assert len(match.children) == 2
+        assert [child.value for child in match.children] == ["02", "06"]
+
+    def test_single_functional(self):
+        def digit(input_string):
+            i = input_string.find("1849")
+            if i > -1:
+                return i, i + len("1849")
+
+        pattern = FunctionalPattern(digit, formatter=lambda x: int(x) * 3)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        assert isinstance(matches[0], Match)
+        assert matches[0].pattern == pattern
+        assert matches[0].span == (21, 25)
+        assert matches[0].value == 1849 * 3
+
+
+class TestValidator(object):
+    """
+    Tests for validator option
+    """
+
+    input_string = "This string contains 1849 a number"
+
+    @staticmethod
+    def true_validator(match):
+        return int(match.value) < 1850
+
+    @staticmethod
+    def false_validator(match):
+        return int(match.value) >= 1850
+
+    def test_single_string(self):
+        pattern = StringPattern("1849", name="dummy", validator=self.false_validator)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+        pattern = StringPattern("1849", validator=self.true_validator)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+    def test_single_re_no_group(self):
+        pattern = RePattern(r"\d+", validator=self.false_validator)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+        pattern = RePattern(r"\d+", validator=self.true_validator)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+    def test_single_re_named_groups(self):
+        pattern = RePattern(r"(?P<strParam>cont.?ins)\s+(?P<intParam>\d+)",
+                            validator={'intParam': self.false_validator}, validate_all=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+        pattern = RePattern(r"(?P<strParam>cont.?ins)\s+(?P<intParam>\d+)",
+                            validator={'intParam': self.true_validator}, validate_all=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+    def test_validate_all(self):
+        pattern = RePattern(r"contains (?P<intParam>\d+)", formatter=int, validator=lambda match: match.value < 100,
+                            children=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+        pattern = RePattern(r"contains (?P<intParam>\d+)", formatter=int, validator=lambda match: match.value > 100,
+                            children=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+        def invalid_func(match):
+            if match.name == 'intParam':
+                return True
+            else:
+                return match.value.startswith('abc')
+
+        pattern = RePattern(r"contains (?P<intParam>\d+)", formatter=int, validator=invalid_func, validate_all=True,
+                            children=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+        def func(match):
+            if match.name == 'intParam':
+                return True
+            else:
+                return match.value.startswith('contains')
+
+        pattern = RePattern(r"contains (?P<intParam>\d+)", formatter=int, validator=func, validate_all=True,
+                            children=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
+    def test_format_all(self):
+        pattern = RePattern(r"contains (?P<intParam>\d+)", formatter=int,
+                            children=True)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+        for match in matches:
+            assert match.value is not None
+
+        with pytest.raises(ValueError):
+            pattern = RePattern(r"contains (?P<intParam>\d+)", formatter=int, format_all=True)
+            matches = list(pattern.matches(self.input_string))
+            for match in matches:
+                assert match.value is not None
+
+    def test_single_functional(self):
+        def digit(input_string):
+            i = input_string.find("1849")
+            if i > -1:
+                return i, i + len("1849")
+
+        pattern = FunctionalPattern(digit, validator=self.false_validator)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 0
+
+        pattern = FunctionalPattern(digit, validator=self.true_validator)
+
+        matches = list(pattern.matches(self.input_string))
+        assert len(matches) == 1
+
diff --git a/lib/rebulk/test/test_processors.py b/lib/rebulk/test/test_processors.py
new file mode 100644
index 000000000..099cc47dc
--- /dev/null
+++ b/lib/rebulk/test/test_processors.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, no-member
+
+from ..pattern import StringPattern, RePattern
+from ..processors import ConflictSolver
+from ..rules import execute_rule
+from rebulk.match import Matches
+
+
+def test_conflict_1():
+    input_string = "abcdefghijklmnopqrstuvwxyz"
+
+    pattern = StringPattern("ijklmn", "kl", "abcdef", "ab", "ef", "yz")
+    matches = Matches(pattern.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+
+    values = [x.value for x in matches]
+
+    assert values == ["ijklmn", "abcdef", "yz"]
+
+
+def test_conflict_2():
+    input_string = "abcdefghijklmnopqrstuvwxyz"
+
+    pattern = StringPattern("ijklmn", "jklmnopqrst")
+    matches = Matches(pattern.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+
+    values = [x.value for x in matches]
+
+    assert values == ["jklmnopqrst"]
+
+
+def test_conflict_3():
+    input_string = "abcdefghijklmnopqrstuvwxyz"
+
+    pattern = StringPattern("ijklmnopqrst", "jklmnopqrst")
+    matches = Matches(pattern.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+
+    values = [x.value for x in matches]
+
+    assert values == ["ijklmnopqrst"]
+
+
+def test_conflict_4():
+    input_string = "123456789"
+
+    pattern = StringPattern("123", "456789")
+    matches = Matches(pattern.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+
+    values = [x.value for x in matches]
+    assert values == ["123", "456789"]
+
+
+def test_conflict_5():
+    input_string = "123456789"
+
+    pattern = StringPattern("123456", "789")
+    matches = Matches(pattern.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+
+    values = [x.value for x in matches]
+    assert values == ["123456", "789"]
+
+
+def test_prefer_longer_parent():
+    input_string = "xxx.1x02.xxx"
+
+    re1 = RePattern("([0-9]+)x([0-9]+)", name='prefer', children=True, formatter=int)
+    re2 = RePattern("x([0-9]+)", name='skip', children=True)
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 2
+    assert matches[0].value == 1
+    assert matches[1].value == 2
+
+
+def test_conflict_solver_1():
+    input_string = "123456789"
+
+    re1 = StringPattern("2345678", conflict_solver=lambda match, conflicting: '__default__')
+    re2 = StringPattern("34567")
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 1
+    assert matches[0].value == "2345678"
+
+
+def test_conflict_solver_2():
+    input_string = "123456789"
+
+    re1 = StringPattern("2345678", conflict_solver=lambda match, conflicting: '__default__')
+    re2 = StringPattern("34567", conflict_solver=lambda match, conflicting: conflicting)
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 1
+    assert matches[0].value == "34567"
+
+
+def test_conflict_solver_3():
+    input_string = "123456789"
+
+    re1 = StringPattern("2345678", conflict_solver=lambda match, conflicting: match)
+    re2 = StringPattern("34567")
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 1
+    assert matches[0].value == "34567"
+
+
+def test_conflict_solver_4():
+    input_string = "123456789"
+
+    re1 = StringPattern("2345678")
+    re2 = StringPattern("34567", conflict_solver=lambda match, conflicting: conflicting)
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 1
+    assert matches[0].value == "34567"
+
+
+def test_conflict_solver_5():
+    input_string = "123456789"
+
+    re1 = StringPattern("2345678", conflict_solver=lambda match, conflicting: conflicting)
+    re2 = StringPattern("34567")
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 1
+    assert matches[0].value == "2345678"
+
+
+def test_conflict_solver_6():
+    input_string = "123456789"
+
+    re1 = StringPattern("2345678")
+    re2 = StringPattern("34567", conflict_solver=lambda match, conflicting: conflicting)
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 1
+    assert matches[0].value == "34567"
+
+
+def test_conflict_solver_7():
+    input_string = "102"
+
+    re1 = StringPattern("102")
+    re2 = StringPattern("02")
+
+    matches = Matches(re2.matches(input_string))
+    matches.extend(re1.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 1
+    assert matches[0].value == "102"
+
+
+def test_unresolved():
+    input_string = "123456789"
+
+    re1 = StringPattern("23456")
+    re2 = StringPattern("34567")
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 2
+
+    re1 = StringPattern("34567")
+    re2 = StringPattern("2345678", conflict_solver=lambda match, conflicting: None)
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 2
+
+    re1 = StringPattern("34567", conflict_solver=lambda match, conflicting: None)
+    re2 = StringPattern("2345678")
+
+    matches = Matches(re1.matches(input_string))
+    matches.extend(re2.matches(input_string))
+
+    execute_rule(ConflictSolver(), matches, None)
+    assert len(matches) == 2
diff --git a/lib/rebulk/test/test_rebulk.py b/lib/rebulk/test/test_rebulk.py
new file mode 100644
index 000000000..a29361ca9
--- /dev/null
+++ b/lib/rebulk/test/test_rebulk.py
@@ -0,0 +1,408 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, no-member
+
+from ..rebulk import Rebulk
+from ..rules import Rule
+import rebulk.test.rebulk_rules_module as rm
+
+
+def test_rebulk_simple():
+    rebulk = Rebulk()
+
+    rebulk.string("quick")
+    rebulk.regex("f.x")
+
+    def func(input_string):
+        i = input_string.find("over")
+        if i > -1:
+            return i, i + len("over")
+
+    rebulk.functional(func)
+
+    input_string = "The quick brown fox jumps over the lazy dog"
+
+    matches = rebulk.matches(input_string)
+    assert len(matches) == 3
+
+    assert matches[0].value == "quick"
+    assert matches[1].value == "fox"
+    assert matches[2].value == "over"
+
+
+def test_rebulk_composition():
+    rebulk = Rebulk()
+
+    rebulk.string("quick")
+    rebulk.rebulk(Rebulk().regex("f.x"))
+
+    rebulk.rebulk(Rebulk(disabled=lambda context: True).functional(lambda string: None))
+
+    input_string = "The quick brown fox jumps over the lazy dog"
+
+    matches = rebulk.matches(input_string)
+    assert len(matches) == 2
+
+    assert matches[0].value == "quick"
+    assert matches[1].value == "fox"
+
+
+def test_rebulk_context():
+    rebulk = Rebulk()
+
+    context = {'nostring': True, 'word': 'lazy'}
+
+    rebulk.string("quick", disabled=lambda context: context.get('nostring', False))
+    rebulk.regex("f.x", disabled=lambda context: context.get('noregex', False))
+
+    def func(input_string, context):
+        word = context.get('word', 'over')
+        i = input_string.find(word)
+        if i > -1:
+            return i, i + len(word)
+
+    rebulk.functional(func)
+
+    input_string = "The quick brown fox jumps over the lazy dog"
+
+    matches = rebulk.matches(input_string, context)
+    assert len(matches) == 2
+
+    assert matches[0].value == "fox"
+    assert matches[1].value == "lazy"
+
+
+def test_rebulk_prefer_longer():
+    input_string = "The quick brown fox jumps over the lazy dog"
+
+    matches = Rebulk().string("quick").string("own").regex("br.{2}n").matches(input_string)
+
+    assert len(matches) == 2
+
+    assert matches[0].value == "quick"
+    assert matches[1].value == "brown"
+
+
+def test_rebulk_defaults():
+    input_string = "The quick brown fox jumps over the lazy dog"
+
+    def func(input_string):
+        i = input_string.find("fox")
+        if i > -1:
+            return i, i + len("fox")
+
+    matches = Rebulk()\
+        .string_defaults(name="string", tags=["a", "b"])\
+        .regex_defaults(name="regex") \
+        .functional_defaults(name="functional") \
+        .string("quick", tags=["c"])\
+        .functional(func)\
+        .regex("br.{2}n") \
+        .matches(input_string)
+    assert matches[0].name == "string"
+    assert matches[0].tags == ["a", "b", "c"]
+    assert matches[1].name == "functional"
+    assert matches[2].name == "regex"
+
+    matches = Rebulk() \
+        .defaults(name="default", tags=["0"])\
+        .string_defaults(name="string", tags=["a", "b"]) \
+        .functional_defaults(name="functional", tags=["1"]) \
+        .string("quick", tags=["c"]) \
+        .functional(func) \
+        .regex("br.{2}n") \
+        .matches(input_string)
+    assert matches[0].name == "string"
+    assert matches[0].tags == ["0", "a", "b", "c"]
+    assert matches[1].name == "functional"
+    assert matches[1].tags == ["0", "1"]
+    assert matches[2].name == "default"
+    assert matches[2].tags == ["0"]
+
+
+def test_rebulk_rebulk():
+    input_string = "The quick brown fox jumps over the lazy dog"
+
+    base = Rebulk().string("quick")
+    child = Rebulk().string("own").regex("br.{2}n")
+
+    matches = base.rebulk(child).matches(input_string)
+
+    assert len(matches) == 2
+
+    assert matches[0].value == "quick"
+    assert matches[1].value == "brown"
+
+
+def test_rebulk_no_default():
+    input_string = "The quick brown fox jumps over the lazy dog"
+
+    matches = Rebulk(default_rules=False).string("quick").string("own").regex("br.{2}n").matches(input_string)
+
+    assert len(matches) == 3
+
+    assert matches[0].value == "quick"
+    assert matches[1].value == "own"
+    assert matches[2].value == "brown"
+
+
+def test_rebulk_tags_names():
+    rebulk = Rebulk()
+
+    rebulk.string("quick", name="str", tags=["first", "other"])
+    rebulk.regex("f.x", tags="other")
+
+    def func(input_string):
+        i = input_string.find("over")
+        if i > -1:
+            return i, i + len("over"), {'tags': ['custom']}
+
+    rebulk.functional(func, name="fn")
+
+    def func2(input_string):
+        i = input_string.find("lazy")
+        if i > -1:
+            return {'start': i, 'end': i + len("lazy"), 'tags': ['custom']}
+
+    rebulk.functional(func2, name="fn")
+
+    input_string = "The quick brown fox jumps over the lazy dog"
+
+    matches = rebulk.matches(input_string)
+    assert len(matches) == 4
+
+    assert len(matches.named("str")) == 1
+    assert len(matches.named("fn")) == 2
+    assert len(matches.named("false")) == 0
+    assert len(matches.tagged("false")) == 0
+    assert len(matches.tagged("first")) == 1
+    assert len(matches.tagged("other")) == 2
+    assert len(matches.tagged("custom")) == 2
+
+
+def test_rebulk_rules_1():
+    rebulk = Rebulk()
+
+    rebulk.regex(r'\d{4}', name="year")
+    rebulk.rules(rm.RemoveAllButLastYear)
+
+    matches = rebulk.matches("1984 keep only last 1968 entry 1982 case")
+    assert len(matches) == 1
+    assert matches[0].value == "1982"
+
+
+def test_rebulk_rules_2():
+    rebulk = Rebulk()
+
+    rebulk.regex(r'\d{4}', name="year")
+    rebulk.string(r'year', name="yearPrefix", private=True)
+    rebulk.string(r'keep', name="yearSuffix", private=True)
+    rebulk.rules(rm.PrefixedSuffixedYear)
+
+    matches = rebulk.matches("Keep suffix 1984 keep prefixed year 1968 and remove the rest 1982")
+    assert len(matches) == 2
+    assert matches[0].value == "1984"
+    assert matches[1].value == "1968"
+
+
+def test_rebulk_rules_3():
+    rebulk = Rebulk()
+
+    rebulk.regex(r'\d{4}', name="year")
+    rebulk.string(r'year', name="yearPrefix", private=True)
+    rebulk.string(r'keep', name="yearSuffix", private=True)
+    rebulk.rules(rm.PrefixedSuffixedYearNoLambda)
+
+    matches = rebulk.matches("Keep suffix 1984 keep prefixed year 1968 and remove the rest 1982")
+    assert len(matches) == 2
+    assert matches[0].value == "1984"
+    assert matches[1].value == "1968"
+
+
+def test_rebulk_rules_4():
+    class FirstOnlyRule(Rule):
+        def when(self, matches, context):
+            grabbed = matches.named("grabbed", 0)
+            if grabbed and matches.previous(grabbed):
+                return grabbed
+
+        def then(self, matches, when_response, context):
+            matches.remove(when_response)
+
+    rebulk = Rebulk()
+
+    rebulk.regex("This match (.*?)grabbed", name="grabbed")
+    rebulk.regex("if it's (.*?)first match", private=True)
+
+    rebulk.rules(FirstOnlyRule)
+
+    matches = rebulk.matches("This match is grabbed only if it's the first match")
+    assert len(matches) == 1
+    assert matches[0].value == "This match is grabbed"
+
+    matches = rebulk.matches("if it's NOT the first match, This match is NOT grabbed")
+    assert len(matches) == 0
+
+
+class TestMarkers(object):
+    def test_one_marker(self):
+        class MarkerRule(Rule):
+            def when(self, matches, context):
+                word_match = matches.named("word", 0)
+                marker = matches.markers.at_match(word_match, lambda marker: marker.name == "mark1", 0)
+                if not marker:
+                    return word_match
+
+            def then(self, matches, when_response, context):
+                matches.remove(when_response)
+
+        rebulk = Rebulk().regex(r'\(.*?\)', marker=True, name="mark1") \
+            .regex(r'\[.*?\]', marker=True, name="mark2") \
+            .string("word", name="word") \
+            .rules(MarkerRule)
+
+        matches = rebulk.matches("grab (word) only if it's in parenthesis")
+
+        assert len(matches) == 1
+        assert matches[0].value == "word"
+
+        matches = rebulk.matches("don't grab [word] if it's in braket")
+        assert len(matches) == 0
+
+        matches = rebulk.matches("don't grab word at all")
+        assert len(matches) == 0
+
+    def test_multiple_marker(self):
+        class MarkerRule(Rule):
+            def when(self, matches, context):
+                word_match = matches.named("word", 0)
+                marker = matches.markers.at_match(word_match,
+                                                  lambda marker: marker.name == "mark1" or marker.name == "mark2")
+                if len(marker) < 2:
+                    return word_match
+
+            def then(self, matches, when_response, context):
+                matches.remove(when_response)
+
+        rebulk = Rebulk().regex(r'\(.*?\)', marker=True, name="mark1") \
+            .regex(r'\[.*?\]', marker=True, name="mark2") \
+            .regex("w.*?d", name="word") \
+            .rules(MarkerRule)
+
+        matches = rebulk.matches("[grab (word) only] if it's in parenthesis and brakets")
+
+        assert len(matches) == 1
+        assert matches[0].value == "word"
+
+        matches = rebulk.matches("[don't grab](word)[if brakets are outside]")
+        assert len(matches) == 0
+
+        matches = rebulk.matches("(grab w[or)d even] if it's partially in parenthesis and brakets")
+        assert len(matches) == 1
+        assert matches[0].value == "w[or)d"
+
+    def test_at_index_marker(self):
+        class MarkerRule(Rule):
+            def when(self, matches, context):
+                word_match = matches.named("word", 0)
+                marker = matches.markers.at_index(word_match.start,
+                                                  lambda marker: marker.name == "mark1", 0)
+                if not marker:
+                    return word_match
+
+            def then(self, matches, when_response, context):
+                matches.remove(when_response)
+
+        rebulk = Rebulk().regex(r'\(.*?\)', marker=True, name="mark1") \
+            .regex("w.*?d", name="word") \
+            .rules(MarkerRule)
+
+        matches = rebulk.matches("gr(ab wo)rd only if starting of match is inside parenthesis")
+
+        assert len(matches) == 1
+        assert matches[0].value == "wo)rd"
+
+        matches = rebulk.matches("don't grab wo(rd if starting of match is not inside parenthesis")
+
+        assert len(matches) == 0
+
+    def test_remove_marker(self):
+        class MarkerRule(Rule):
+            def when(self, matches, context):
+                marker = matches.markers.named("mark1", 0)
+                if marker:
+                    return marker
+
+            def then(self, matches, when_response, context):
+                matches.markers.remove(when_response)
+
+        rebulk = Rebulk().regex(r'\(.*?\)', marker=True, name="mark1") \
+            .regex("w.*?d", name="word") \
+            .rules(MarkerRule)
+
+        matches = rebulk.matches("grab word event (if it's not) inside parenthesis")
+
+        assert len(matches) == 1
+        assert matches[0].value == "word"
+
+        assert not matches.markers
+
+
+class TestUnicode(object):
+    def test_rebulk_simple(self):
+        input_string = u"敏捷的棕色狐狸跳過懶狗"
+
+        rebulk = Rebulk()
+
+        rebulk.string(u"敏")
+        rebulk.regex(u"捷")
+
+        def func(input_string):
+            i = input_string.find(u"的")
+            if i > -1:
+                return i, i + len(u"的")
+
+        rebulk.functional(func)
+
+        matches = rebulk.matches(input_string)
+        assert len(matches) == 3
+
+        assert matches[0].value == u"敏"
+        assert matches[1].value == u"捷"
+        assert matches[2].value == u"的"
+
+
+class TestImmutable(object):
+    def test_starting(self):
+        input_string = "The quick brown fox jumps over the lazy dog"
+        matches = Rebulk().string("quick").string("over").string("fox").matches(input_string)
+
+        for i in range(0, len(input_string)):
+            starting = matches.starting(i)
+            for match in list(starting):
+                starting.remove(match)
+
+        assert len(matches) == 3
+
+    def test_ending(self):
+        input_string = "The quick brown fox jumps over the lazy dog"
+        matches = Rebulk().string("quick").string("over").string("fox").matches(input_string)
+
+        for i in range(0, len(input_string)):
+            starting = matches.ending(i)
+            for match in list(starting):
+                starting.remove(match)
+
+        assert len(matches) == 3
+
+    def test_named(self):
+        input_string = "The quick brown fox jumps over the lazy dog"
+        matches = Rebulk().defaults(name='test').string("quick").string("over").string("fox").matches(input_string)
+
+        named = matches.named('test')
+        for match in list(named):
+            named.remove(match)
+
+        assert len(named) == 0
+        assert len(matches) == 3
+
diff --git a/lib/rebulk/test/test_rules.py b/lib/rebulk/test/test_rules.py
new file mode 100644
index 000000000..3d53b591e
--- /dev/null
+++ b/lib/rebulk/test/test_rules.py
@@ -0,0 +1,197 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name, no-member
+import pytest
+from rebulk.test.default_rules_module import RuleRemove0, RuleAppend0, RuleRename0, RuleAppend1, RuleRemove1, \
+    RuleRename1, RuleAppend2, RuleRename2, RuleAppend3, RuleRename3, RuleAppendTags0, RuleRemoveTags0, \
+    RuleAppendTags1, RuleRemoveTags1
+
+from ..rules import Rules
+from ..match import Matches, Match
+
+from .rules_module import Rule1, Rule2, Rule3, Rule0, Rule1Disabled
+import rebulk.test.rules_module as rm
+
+
+def test_rule_priority():
+    matches = Matches([Match(1, 2)])
+
+    rules = Rules(Rule1, Rule2())
+
+    rules.execute_all_rules(matches, {})
+    assert len(matches) == 0
+    matches = Matches([Match(1, 2)])
+
+    rules = Rules(Rule1(), Rule0)
+
+    rules.execute_all_rules(matches, {})
+    assert len(matches) == 1
+    assert matches[0] == Match(3, 4)
+
+
+def test_rules_duplicates():
+    matches = Matches([Match(1, 2)])
+
+    rules = Rules(Rule1, Rule1)
+
+    with pytest.raises(ValueError):
+        rules.execute_all_rules(matches, {})
+
+
+def test_rule_disabled():
+    matches = Matches([Match(1, 2)])
+
+    rules = Rules(Rule1Disabled(), Rule2())
+
+    rules.execute_all_rules(matches, {})
+    assert len(matches) == 2
+    assert matches[0] == Match(1, 2)
+    assert matches[1] == Match(3, 4)
+
+
+def test_rule_when():
+    matches = Matches([Match(1, 2)])
+
+    rules = Rules(Rule3())
+
+    rules.execute_all_rules(matches, {'when': False})
+    assert len(matches) == 1
+    assert matches[0] == Match(1, 2)
+
+    matches = Matches([Match(1, 2)])
+
+    rules.execute_all_rules(matches, {'when': True})
+    assert len(matches) == 2
+    assert matches[0] == Match(1, 2)
+    assert matches[1] == Match(3, 4)
+
+
+class TestDefaultRules(object):
+    def test_remove(self):
+        rules = Rules(RuleRemove0)
+
+        matches = Matches([Match(1, 2)])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches) == 0
+
+        rules = Rules(RuleRemove1)
+
+        matches = Matches([Match(1, 2)])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches) == 0
+
+    def test_append(self):
+        rules = Rules(RuleAppend0)
+
+        matches = Matches([Match(1, 2)])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches) == 2
+
+        rules = Rules(RuleAppend1)
+
+        matches = Matches([Match(1, 2)])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches) == 2
+
+        rules = Rules(RuleAppend2)
+
+        matches = Matches([Match(1, 2)])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches) == 2
+        assert len(matches.named('renamed')) == 1
+
+        rules = Rules(RuleAppend3)
+
+        matches = Matches([Match(1, 2)])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches) == 2
+        assert len(matches.named('renamed')) == 1
+
+    def test_rename(self):
+        rules = Rules(RuleRename0)
+
+        matches = Matches([Match(1, 2, name='original')])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches.named('original')) == 1
+        assert len(matches.named('renamed')) == 0
+
+        rules = Rules(RuleRename1)
+
+        matches = Matches([Match(5, 10, name='original')])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches.named('original')) == 0
+        assert len(matches.named('renamed')) == 1
+
+        rules = Rules(RuleRename2)
+
+        matches = Matches([Match(5, 10, name='original')])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches.named('original')) == 0
+        assert len(matches.named('renamed')) == 1
+
+        rules = Rules(RuleRename3)
+
+        matches = Matches([Match(5, 10, name='original')])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches.named('original')) == 0
+        assert len(matches.named('renamed')) == 1
+
+    def test_append_tags(self):
+        rules = Rules(RuleAppendTags0)
+
+        matches = Matches([Match(1, 2, name='tags', tags=['other'])])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches.named('tags')) == 1
+        assert matches.named('tags', index=0).tags == ['other', 'new-tag']
+
+        rules = Rules(RuleAppendTags1)
+
+        matches = Matches([Match(1, 2, name='tags', tags=['other'])])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches.named('tags')) == 1
+        assert matches.named('tags', index=0).tags == ['other', 'new-tag']
+
+    def test_remove_tags(self):
+        rules = Rules(RuleRemoveTags0)
+
+        matches = Matches([Match(1, 2, name='tags', tags=['other', 'new-tag'])])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches.named('tags')) == 1
+        assert matches.named('tags', index=0).tags == ['other']
+
+        rules = Rules(RuleRemoveTags1)
+
+        matches = Matches([Match(1, 2, name='tags', tags=['other', 'new-tag'])])
+        rules.execute_all_rules(matches, {})
+
+        assert len(matches.named('tags')) == 1
+        assert matches.named('tags', index=0).tags == ['other']
+
+
+def test_rule_module():
+    rules = Rules(rm)
+
+    matches = Matches([Match(1, 2)])
+    rules.execute_all_rules(matches, {})
+
+    assert len(matches) == 1
+
+
+def test_rule_repr():
+    assert str(Rule0()) == "<Rule0>"
+    assert str(Rule1()) == "<Rule1>"
+    assert str(Rule2()) == "<Rule2>"
+    assert str(Rule1Disabled()) == "<Disabled Rule1>"
diff --git a/lib/rebulk/test/test_toposort.py b/lib/rebulk/test/test_toposort.py
new file mode 100644
index 000000000..76ea60313
--- /dev/null
+++ b/lib/rebulk/test/test_toposort.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright 2014 True Blade Systems, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Original:
+#   - https://bitbucket.org/ericvsmith/toposort (1.4)
+# Modifications:
+#   - port to pytest
+# pylint: skip-file
+
+import pytest
+from ..toposort import toposort, toposort_flatten, CyclicDependency
+
+
+class TestCase(object):
+    def test_simple(self):
+        results = list(toposort({2: set([11]), 9: set([11, 8]), 10: set([11, 3]), 11: set([7, 5]), 8: set([7, 3])}))
+        expected = [set([3, 5, 7]), set([8, 11]), set([2, 9, 10])]
+        assert results == expected
+
+        # make sure self dependencies are ignored
+        results = list(toposort({2: set([2, 11]), 9: set([11, 8]), 10: set([10, 11, 3]), 11: set([7, 5]), 8: set([7, 3])}))
+        expected = [set([3, 5, 7]), set([8, 11]), set([2, 9, 10])]
+        assert results == expected
+
+        assert list(toposort({1: set()})) == [set([1])]
+        assert list(toposort({1: set([1])})) == [set([1])]
+
+    def test_no_dependencies(self):
+        assert list(toposort({1: set([2]), 3: set([4]), 5: set([6])})) == [set([2, 4, 6]), set([1, 3, 5])]
+        assert list(toposort({1: set(), 3: set(), 5: set()})) == [set([1, 3, 5])]
+
+    def test_empty(self):
+        assert list(toposort({})) == []
+
+    def test_strings(self):
+        results = list(toposort({'2': set(['11']), '9': set(['11', '8']), '10': set(['11', '3']), '11': set(['7', '5']), '8': set(['7', '3'])}))
+        expected = [set(['3', '5', '7']), set(['8', '11']), set(['2', '9', '10'])]
+        assert results == expected
+
+    def test_objects(self):
+        o2 = object()
+        o3 = object()
+        o5 = object()
+        o7 = object()
+        o8 = object()
+        o9 = object()
+        o10 = object()
+        o11 = object()
+        results = list(toposort({o2: set([o11]), o9: set([o11, o8]), o10: set([o11, o3]), o11: set([o7, o5]), o8: set([o7, o3, o8])}))
+        expected = [set([o3, o5, o7]), set([o8, o11]), set([o2, o9, o10])]
+        assert results == expected
+
+    def test_cycle(self):
+        # a simple, 2 element cycle
+        with pytest.raises(CyclicDependency):
+            list(toposort({1: set([2]), 2: set([1])}))
+
+        # an indirect cycle
+        with pytest.raises(CyclicDependency):
+            list(toposort({1: set([2]), 2: set([3]), 3: set([1])}))
+
+    def test_input_not_modified(self):
+        data = {2: set([11]),
+                9: set([11, 8]),
+                10: set([11, 3]),
+                11: set([7, 5]),
+                8: set([7, 3, 8]),  # includes something self-referential
+                }
+        orig = data.copy()
+        results = list(toposort(data))
+        assert data == orig
+
+    def test_input_not_modified_when_cycle_error(self):
+        data = {1: set([2]),
+                2: set([1]),
+                3: set([4]),
+                }
+        orig = data.copy()
+        with pytest.raises(CyclicDependency):
+            list(toposort(data))
+        assert data == orig
+
+
+class TestCaseAll(object):
+    def test_sort_flatten(self):
+        data = {2: set([11]),
+                9: set([11, 8]),
+                10: set([11, 3]),
+                11: set([7, 5]),
+                8: set([7, 3, 8]),  # includes something self-referential
+                }
+        expected = [set([3, 5, 7]), set([8, 11]), set([2, 9, 10])]
+        assert list(toposort(data)) == expected
+
+        # now check the sorted results
+        results = []
+        for item in expected:
+            results.extend(sorted(item))
+        assert toposort_flatten(data) == results
+
+        # and the unsorted results. break the results up into groups to compare them
+        actual = toposort_flatten(data, False)
+        results = [set([i for i in actual[0:3]]), set([i for i in actual[3:5]]), set([i for i in actual[5:8]])]
+        assert results == expected
diff --git a/lib/rebulk/test/test_validators.py b/lib/rebulk/test/test_validators.py
new file mode 100644
index 000000000..ef5c756d8
--- /dev/null
+++ b/lib/rebulk/test/test_validators.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# pylint: disable=no-self-use, pointless-statement, missing-docstring, invalid-name
+
+from functools import partial
+
+from rebulk.pattern import StringPattern
+
+from ..validators import chars_before, chars_after, chars_surround, validators
+
+chars = ' _.'
+left = partial(chars_before, chars)
+right = partial(chars_after, chars)
+surrounding = partial(chars_surround, chars)
+
+
+def test_left_chars():
+    matches = list(StringPattern("word", validator=left).matches("xxxwordxxx"))
+    assert len(matches) == 0
+
+    matches = list(StringPattern("word", validator=left).matches("xxx_wordxxx"))
+    assert len(matches) == 1
+
+    matches = list(StringPattern("word", validator=left).matches("wordxxx"))
+    assert len(matches) == 1
+
+
+def test_right_chars():
+    matches = list(StringPattern("word", validator=right).matches("xxxwordxxx"))
+    assert len(matches) == 0
+
+    matches = list(StringPattern("word", validator=right).matches("xxxword.xxx"))
+    assert len(matches) == 1
+
+    matches = list(StringPattern("word", validator=right).matches("xxxword"))
+    assert len(matches) == 1
+
+
+def test_surrounding_chars():
+    matches = list(StringPattern("word", validator=surrounding).matches("xxxword xxx"))
+    assert len(matches) == 0
+
+    matches = list(StringPattern("word", validator=surrounding).matches("xxx.wordxxx"))
+    assert len(matches) == 0
+
+    matches = list(StringPattern("word", validator=surrounding).matches("xxx word_xxx"))
+    assert len(matches) == 1
+
+    matches = list(StringPattern("word", validator=surrounding).matches("word"))
+    assert len(matches) == 1
+
+
+def test_chain():
+    matches = list(StringPattern("word", validator=validators(left, right)).matches("xxxword xxx"))
+    assert len(matches) == 0
+
+    matches = list(StringPattern("word", validator=validators(left, right)).matches("xxx.wordxxx"))
+    assert len(matches) == 0
+
+    matches = list(StringPattern("word", validator=validators(left, right)).matches("xxx word_xxx"))
+    assert len(matches) == 1
+
+    matches = list(StringPattern("word", validator=validators(left, right)).matches("word"))
+    assert len(matches) == 1
+
+
+
+
diff --git a/lib/rebulk/toposort.py b/lib/rebulk/toposort.py
new file mode 100644
index 000000000..2bcba9ae6
--- /dev/null
+++ b/lib/rebulk/toposort.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright 2014 True Blade Systems, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Original:
+#   - https://bitbucket.org/ericvsmith/toposort (1.4)
+# Modifications:
+#   - merged Pull request #2 for CyclicDependency error
+#   - import reduce as original name
+#   - support python 2.6 dict comprehension
+
+# pylint: skip-file
+from functools import reduce
+
+
+class CyclicDependency(ValueError):
+    def __init__(self, cyclic):
+        s = 'Cyclic dependencies exist among these items: {0}'.format(', '.join(repr(x) for x in cyclic.items()))
+        super(CyclicDependency, self).__init__(s)
+        self.cyclic = cyclic
+
+
+def toposort(data):
+    """
+    Dependencies are expressed as a dictionary whose keys are items
+    and whose values are a set of dependent items. Output is a list of
+    sets in topological order. The first set consists of items with no
+    dependences, each subsequent set consists of items that depend upon
+    items in the preceeding sets.
+    :param data:
+    :type data:
+    :return:
+    :rtype:
+    """
+
+    # Special case empty input.
+    if len(data) == 0:
+        return
+
+    # Copy the input so as to leave it unmodified.
+    data = data.copy()
+
+    # Ignore self dependencies.
+    for k, v in data.items():
+        v.discard(k)
+    # Find all items that don't depend on anything.
+    extra_items_in_deps = reduce(set.union, data.values()) - set(data.keys())
+    # Add empty dependences where needed.
+    data.update(dict((item, set()) for item in extra_items_in_deps))
+    while True:
+        ordered = set(item for item, dep in data.items() if len(dep) == 0)
+        if not ordered:
+            break
+        yield ordered
+        data = dict((item, (dep - ordered))
+                for item, dep in data.items()
+                if item not in ordered)
+    if len(data) != 0:
+        raise CyclicDependency(data)
+
+
+def toposort_flatten(data, sort=True):
+    """
+    Returns a single list of dependencies. For any set returned by
+    toposort(), those items are sorted and appended to the result (just to
+    make the results deterministic).
+    :param data:
+    :type data:
+    :param sort:
+    :type sort:
+    :return: Single list of dependencies.
+    :rtype: list
+    """
+
+    result = []
+    for d in toposort(data):
+        result.extend((sorted if sort else list)(d))
+    return result
diff --git a/lib/rebulk/utils.py b/lib/rebulk/utils.py
new file mode 100644
index 000000000..6e8ffb23a
--- /dev/null
+++ b/lib/rebulk/utils.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Various utilities functions
+"""
+from types import GeneratorType
+
+from collections import MutableSet
+
+
+def find_all(string, sub, start=None, end=None, ignore_case=False):
+    """
+    Return all indices in string s where substring sub is
+    found, such that sub is contained in the slice s[start:end].
+
+    >>> list(find_all('The quick brown fox jumps over the lazy dog', 'fox'))
+    [16]
+
+    >>> list(find_all('The quick brown fox jumps over the lazy dog', 'mountain'))
+    []
+
+    >>> list(find_all('The quick brown fox jumps over the lazy dog', 'The'))
+    [0]
+
+    >>> list(find_all(
+    ... 'Carved symbols in a mountain hollow on the bank of an inlet irritated an eccentric person',
+    ... 'an'))
+    [44, 51, 70]
+
+    >>> list(find_all(
+    ... 'Carved symbols in a mountain hollow on the bank of an inlet irritated an eccentric person',
+    ... 'an',
+    ... 50,
+    ... 60))
+    [51]
+
+    :param string: the input string
+    :type string: str
+    :param sub: the substring
+    :type sub: str
+    :return: all indices in the input string
+    :rtype: __generator[str]
+    """
+    if ignore_case:
+        sub = sub.lower()
+        string = string.lower()
+    while True:
+        start = string.find(sub, start, end)
+        if start == -1:
+            return
+        yield start
+        start += len(sub)
+
+
+def is_iterable(obj):
+    """
+    Are we being asked to look up a list of things, instead of a single thing?
+    We check for the `__iter__` attribute so that this can cover types that
+    don't have to be known by this module, such as NumPy arrays.
+
+    Strings, however, should be considered as atomic values to look up, not
+    iterables.
+
+    We don't need to check for the Python 2 `unicode` type, because it doesn't
+    have an `__iter__` attribute anyway.
+    """
+    return hasattr(obj, '__iter__') and not isinstance(obj, str) or isinstance(obj, GeneratorType)
+
+
+def extend_safe(target, source):
+    """
+    Extends source list to target list only if elements doesn't exists in target list.
+    :param target:
+    :type target: list
+    :param source:
+    :type source: list
+    """
+    for elt in source:
+        if elt not in target:
+            target.append(elt)
+
+
+class _Ref(object):
+    """
+    Reference for IdentitySet
+    """
+    def __init__(self, value):
+        self.value = value
+
+    def __eq__(self, other):
+        return self.value is other.value
+
+    def __hash__(self):
+        return id(self.value)
+
+
+class IdentitySet(MutableSet):  # pragma: no cover
+    """
+    Set based on identity
+    """
+    def __init__(self, items=None):
+        if items is None:
+            items = []
+        self.refs = set(map(_Ref, items))
+
+    def __contains__(self, elem):
+        return _Ref(elem) in self.refs
+
+    def __iter__(self):
+        return (ref.value for ref in self.refs)
+
+    def __len__(self):
+        return len(self.refs)
+
+    def add(self, elem):
+        self.refs.add(_Ref(elem))
+
+    def discard(self, elem):
+        self.refs.discard(_Ref(elem))
+
+    def update(self, iterable):
+        """
+        Update set with iterable
+        :param iterable:
+        :type iterable:
+        :return:
+        :rtype:
+        """
+        for elem in iterable:
+            self.add(elem)
+
+    def __repr__(self):  # pragma: no cover
+        return "%s(%s)" % (type(self).__name__, list(self))
diff --git a/lib/rebulk/validators.py b/lib/rebulk/validators.py
new file mode 100644
index 000000000..7d5e6303b
--- /dev/null
+++ b/lib/rebulk/validators.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Validator functions to use in patterns.
+
+All those function have last argument as match, so it's possible to use functools.partial to bind previous arguments.
+"""
+
+
+def chars_before(chars, match):
+    """
+    Validate the match if left character is in a given sequence.
+
+    :param chars:
+    :type chars:
+    :param match:
+    :type match:
+    :return:
+    :rtype:
+    """
+    if match.start <= 0:
+        return True
+    return match.input_string[match.start - 1] in chars
+
+
+def chars_after(chars, match):
+    """
+    Validate the match if left character is in a given sequence.
+
+    :param chars:
+    :type chars:
+    :param match:
+    :type match:
+    :return:
+    :rtype:
+    """
+    if match.end >= len(match.input_string):
+        return True
+    return match.input_string[match.end] in chars
+
+
+def chars_surround(chars, match):
+    """
+    Validate the match if surrounding characters are in a given sequence.
+
+    :param chars:
+    :type chars:
+    :param match:
+    :type match:
+    :return:
+    :rtype:
+    """
+    return chars_before(chars, match) and chars_after(chars, match)
+
+
+def validators(*chained_validators):
+    """
+    Creates a validator chain from several validator functions.
+
+    :param chained_validators:
+    :type chained_validators:
+    :return:
+    :rtype:
+    """
+    def validator_chain(match):  # pylint:disable=missing-docstring
+        for chained_validator in chained_validators:
+            if not chained_validator(match):
+                return False
+        return True
+    return validator_chain
diff --git a/lib/regex/__init__.py b/lib/regex/__init__.py
new file mode 100644
index 000000000..098b02f2a
--- /dev/null
+++ b/lib/regex/__init__.py
@@ -0,0 +1,703 @@
+#
+# Secret Labs' Regular Expression Engine
+#
+# Copyright (c) 1998-2001 by Secret Labs AB.  All rights reserved.
+#
+# This version of the SRE library can be redistributed under CNRI's
+# Python 1.6 license.  For any other use, please contact Secret Labs
+# AB (info@pythonware.com).
+#
+# Portions of this engine have been developed in cooperation with
+# CNRI.  Hewlett-Packard provided funding for 1.6 integration and
+# other compatibility work.
+#
+# 2010-01-16 mrab Python front-end re-written and extended
+
+r"""Support for regular expressions (RE).
+
+This module provides regular expression matching operations similar to those
+found in Perl. It supports both 8-bit and Unicode strings; both the pattern and
+the strings being processed can contain null bytes and characters outside the
+US ASCII range.
+
+Regular expressions can contain both special and ordinary characters. Most
+ordinary characters, like "A", "a", or "0", are the simplest regular
+expressions; they simply match themselves. You can concatenate ordinary
+characters, so last matches the string 'last'.
+
+There are a few differences between the old (legacy) behaviour and the new
+(enhanced) behaviour, which are indicated by VERSION0 or VERSION1.
+
+The special characters are:
+    "."                 Matches any character except a newline.
+    "^"                 Matches the start of the string.
+    "$"                 Matches the end of the string or just before the
+                        newline at the end of the string.
+    "*"                 Matches 0 or more (greedy) repetitions of the preceding
+                        RE. Greedy means that it will match as many repetitions
+                        as possible.
+    "+"                 Matches 1 or more (greedy) repetitions of the preceding
+                        RE.
+    "?"                 Matches 0 or 1 (greedy) of the preceding RE.
+    *?,+?,??            Non-greedy versions of the previous three special
+                        characters.
+    *+,++,?+            Possessive versions of the previous three special
+                        characters.
+    {m,n}               Matches from m to n repetitions of the preceding RE.
+    {m,n}?              Non-greedy version of the above.
+    {m,n}+              Possessive version of the above.
+    {...}               Fuzzy matching constraints.
+    "\\"                Either escapes special characters or signals a special
+                        sequence.
+    [...]               Indicates a set of characters. A "^" as the first
+                        character indicates a complementing set.
+    "|"                 A|B, creates an RE that will match either A or B.
+    (...)               Matches the RE inside the parentheses. The contents are
+                        captured and can be retrieved or matched later in the
+                        string.
+    (?flags-flags)      VERSION1: Sets/clears the flags for the remainder of
+                        the group or pattern; VERSION0: Sets the flags for the
+                        entire pattern.
+    (?:...)             Non-capturing version of regular parentheses.
+    (?>...)             Atomic non-capturing version of regular parentheses.
+    (?flags-flags:...)  Non-capturing version of regular parentheses with local
+                        flags.
+    (?P<name>...)       The substring matched by the group is accessible by
+                        name.
+    (?<name>...)        The substring matched by the group is accessible by
+                        name.
+    (?P=name)           Matches the text matched earlier by the group named
+                        name.
+    (?#...)             A comment; ignored.
+    (?=...)             Matches if ... matches next, but doesn't consume the
+                        string.
+    (?!...)             Matches if ... doesn't match next.
+    (?<=...)            Matches if preceded by ....
+    (?<!...)            Matches if not preceded by ....
+    (?(id)yes|no)       Matches yes pattern if group id matched, the (optional)
+                        no pattern otherwise.
+    (?(DEFINE)...)      If there's no group called "DEFINE", then ... will be
+                        ignored, but any group definitions will be available.
+    (?|...|...)         (?|A|B), creates an RE that will match either A or B,
+                        but reuses capture group numbers across the
+                        alternatives.
+    (*FAIL)             Forces matching to fail, which means immediate
+                        backtracking.
+    (*F)                Abbreviation for (*FAIL).
+    (*PRUNE)            Discards the current backtracking information. Its
+                        effect doesn't extend outside an atomic group or a
+                        lookaround.
+    (*SKIP)             Similar to (*PRUNE), except that it also sets where in
+                        the text the next attempt at matching the entire
+                        pattern will start. Its effect doesn't extend outside
+                        an atomic group or a lookaround.
+
+The fuzzy matching constraints are: "i" to permit insertions, "d" to permit
+deletions, "s" to permit substitutions, "e" to permit any of these. Limits are
+optional with "<=" and "<". If any type of error is provided then any type not
+provided is not permitted.
+
+A cost equation may be provided.
+
+Examples:
+    (?:fuzzy){i<=2}
+    (?:fuzzy){i<=1,s<=2,d<=1,1i+1s+1d<3}
+
+VERSION1: Set operators are supported, and a set can include nested sets. The
+set operators, in order of increasing precedence, are:
+    ||  Set union ("x||y" means "x or y").
+    ~~  (double tilde) Symmetric set difference ("x~~y" means "x or y, but not
+        both").
+    &&  Set intersection ("x&&y" means "x and y").
+    --  (double dash) Set difference ("x--y" means "x but not y").
+
+Implicit union, ie, simple juxtaposition like in [ab], has the highest
+precedence.
+
+VERSION0 and VERSION1:
+The special sequences consist of "\\" and a character from the list below. If
+the ordinary character is not on the list, then the resulting RE will match the
+second character.
+    \number         Matches the contents of the group of the same number if
+                    number is no more than 2 digits, otherwise the character
+                    with the 3-digit octal code.
+    \a              Matches the bell character.
+    \A              Matches only at the start of the string.
+    \b              Matches the empty string, but only at the start or end of a
+                    word.
+    \B              Matches the empty string, but not at the start or end of a
+                    word.
+    \d              Matches any decimal digit; equivalent to the set [0-9] when
+                    matching a bytestring or a Unicode string with the ASCII
+                    flag, or the whole range of Unicode digits when matching a
+                    Unicode string.
+    \D              Matches any non-digit character; equivalent to [^\d].
+    \f              Matches the formfeed character.
+    \g<name>        Matches the text matched by the group named name.
+    \G              Matches the empty string, but only at the position where
+                    the search started.
+    \K              Keeps only what follows for the entire match.
+    \L<name>        Named list. The list is provided as a keyword argument.
+    \m              Matches the empty string, but only at the start of a word.
+    \M              Matches the empty string, but only at the end of a word.
+    \n              Matches the newline character.
+    \N{name}        Matches the named character.
+    \p{name=value}  Matches the character if its property has the specified
+                    value.
+    \P{name=value}  Matches the character if its property hasn't the specified
+                    value.
+    \r              Matches the carriage-return character.
+    \s              Matches any whitespace character; equivalent to
+                    [ \t\n\r\f\v].
+    \S              Matches any non-whitespace character; equivalent to [^\s].
+    \t              Matches the tab character.
+    \uXXXX          Matches the Unicode codepoint with 4-digit hex code XXXX.
+    \UXXXXXXXX      Matches the Unicode codepoint with 8-digit hex code
+                    XXXXXXXX.
+    \v              Matches the vertical tab character.
+    \w              Matches any alphanumeric character; equivalent to
+                    [a-zA-Z0-9_] when matching a bytestring or a Unicode string
+                    with the ASCII flag, or the whole range of Unicode
+                    alphanumeric characters (letters plus digits plus
+                    underscore) when matching a Unicode string. With LOCALE, it
+                    will match the set [0-9_] plus characters defined as
+                    letters for the current locale.
+    \W              Matches the complement of \w; equivalent to [^\w].
+    \xXX            Matches the character with 2-digit hex code XX.
+    \X              Matches a grapheme.
+    \Z              Matches only at the end of the string.
+    \\              Matches a literal backslash.
+
+This module exports the following functions:
+    match      Match a regular expression pattern at the beginning of a string.
+    fullmatch  Match a regular expression pattern against all of a string.
+    search     Search a string for the presence of a pattern.
+    sub        Substitute occurrences of a pattern found in a string using a
+               template string.
+    subf       Substitute occurrences of a pattern found in a string using a
+               format string.
+    subn       Same as sub, but also return the number of substitutions made.
+    subfn      Same as subf, but also return the number of substitutions made.
+    split      Split a string by the occurrences of a pattern. VERSION1: will
+               split at zero-width match; VERSION0: won't split at zero-width
+               match.
+    splititer  Return an iterator yielding the parts of a split string.
+    findall    Find all occurrences of a pattern in a string.
+    finditer   Return an iterator yielding a match object for each match.
+    compile    Compile a pattern into a Pattern object.
+    purge      Clear the regular expression cache.
+    escape     Backslash all non-alphanumerics or special characters in a
+               string.
+
+Most of the functions support a concurrent parameter: if True, the GIL will be
+released during matching, allowing other Python threads to run concurrently. If
+the string changes during matching, the behaviour is undefined. This parameter
+is not needed when working on the builtin (immutable) string classes.
+
+Some of the functions in this module take flags as optional parameters. Most of
+these flags can also be set within an RE:
+    A   a   ASCII         Make \w, \W, \b, \B, \d, and \D match the
+                          corresponding ASCII character categories. Default
+                          when matching a bytestring.
+    B   b   BESTMATCH     Find the best fuzzy match (default is first).
+    D       DEBUG         Print the parsed pattern.
+    E   e   ENHANCEMATCH  Attempt to improve the fit after finding the first
+                          fuzzy match.
+    F   f   FULLCASE      Use full case-folding when performing
+                          case-insensitive matching in Unicode.
+    I   i   IGNORECASE    Perform case-insensitive matching.
+    L   L   LOCALE        Make \w, \W, \b, \B, \d, and \D dependent on the
+                          current locale. (One byte per character only.)
+    M   m   MULTILINE     "^" matches the beginning of lines (after a newline)
+                          as well as the string. "$" matches the end of lines
+                          (before a newline) as well as the end of the string.
+    P   p   POSIX         Perform POSIX-standard matching (leftmost longest).
+    R   r   REVERSE       Searches backwards.
+    S   s   DOTALL        "." matches any character at all, including the
+                          newline.
+    U   u   UNICODE       Make \w, \W, \b, \B, \d, and \D dependent on the
+                          Unicode locale. Default when matching a Unicode
+                          string.
+    V0  V0  VERSION0      Turn on the old legacy behaviour.
+    V1  V1  VERSION1      Turn on the new enhanced behaviour. This flag
+                          includes the FULLCASE flag.
+    W   w   WORD          Make \b and \B work with default Unicode word breaks
+                          and make ".", "^" and "$" work with Unicode line
+                          breaks.
+    X   x   VERBOSE       Ignore whitespace and comments for nicer looking REs.
+
+This module also defines an exception 'error'.
+
+"""
+
+# Public symbols.
+__all__ = ["compile", "escape", "findall", "finditer", "fullmatch", "match",
+  "purge", "search", "split", "splititer", "sub", "subf", "subfn", "subn",
+  "template", "Scanner", "A", "ASCII", "B", "BESTMATCH", "D", "DEBUG", "E",
+  "ENHANCEMATCH", "S", "DOTALL", "F", "FULLCASE", "I", "IGNORECASE", "L",
+  "LOCALE", "M", "MULTILINE", "P", "POSIX", "R", "REVERSE", "T", "TEMPLATE",
+  "U", "UNICODE", "V0", "VERSION0", "V1", "VERSION1", "X", "VERBOSE", "W",
+  "WORD", "error", "Regex"]
+
+__version__ = "2.4.85"
+
+# --------------------------------------------------------------------
+# Public interface.
+
+def match(pattern, string, flags=0, pos=None, endpos=None, partial=False,
+  concurrent=None, **kwargs):
+    """Try to apply the pattern at the start of the string, returning a match
+    object, or None if no match was found."""
+    return _compile(pattern, flags, kwargs).match(string, pos, endpos,
+      concurrent, partial)
+
+def fullmatch(pattern, string, flags=0, pos=None, endpos=None, partial=False,
+  concurrent=None, **kwargs):
+    """Try to apply the pattern against all of the string, returning a match
+    object, or None if no match was found."""
+    return _compile(pattern, flags, kwargs).fullmatch(string, pos, endpos,
+      concurrent, partial)
+
+def search(pattern, string, flags=0, pos=None, endpos=None, partial=False,
+  concurrent=None, **kwargs):
+    """Search through string looking for a match to the pattern, returning a
+    match object, or None if no match was found."""
+    return _compile(pattern, flags, kwargs).search(string, pos, endpos,
+      concurrent, partial)
+
+def sub(pattern, repl, string, count=0, flags=0, pos=None, endpos=None,
+  concurrent=None, **kwargs):
+    """Return the string obtained by replacing the leftmost (or rightmost with a
+    reverse pattern) non-overlapping occurrences of the pattern in string by the
+    replacement repl. repl can be either a string or a callable; if a string,
+    backslash escapes in it are processed; if a callable, it's passed the match
+    object and must return a replacement string to be used."""
+    return _compile(pattern, flags, kwargs).sub(repl, string, count, pos,
+      endpos, concurrent)
+
+def subf(pattern, format, string, count=0, flags=0, pos=None, endpos=None,
+  concurrent=None, **kwargs):
+    """Return the string obtained by replacing the leftmost (or rightmost with a
+    reverse pattern) non-overlapping occurrences of the pattern in string by the
+    replacement format. format can be either a string or a callable; if a string,
+    it's treated as a format string; if a callable, it's passed the match object
+    and must return a replacement string to be used."""
+    return _compile(pattern, flags, kwargs).subf(format, string, count, pos,
+      endpos, concurrent)
+
+def subn(pattern, repl, string, count=0, flags=0, pos=None, endpos=None,
+  concurrent=None, **kwargs):
+    """Return a 2-tuple containing (new_string, number). new_string is the string
+    obtained by replacing the leftmost (or rightmost with a reverse pattern)
+    non-overlapping occurrences of the pattern in the source string by the
+    replacement repl. number is the number of substitutions that were made. repl
+    can be either a string or a callable; if a string, backslash escapes in it
+    are processed; if a callable, it's passed the match object and must return a
+    replacement string to be used."""
+    return _compile(pattern, flags, kwargs).subn(repl, string, count, pos,
+      endpos, concurrent)
+
+def subfn(pattern, format, string, count=0, flags=0, pos=None, endpos=None,
+  concurrent=None, **kwargs):
+    """Return a 2-tuple containing (new_string, number). new_string is the string
+    obtained by replacing the leftmost (or rightmost with a reverse pattern)
+    non-overlapping occurrences of the pattern in the source string by the
+    replacement format. number is the number of substitutions that were made. format
+    can be either a string or a callable; if a string, it's treated as a format
+    string; if a callable, it's passed the match object and must return a
+    replacement string to be used."""
+    return _compile(pattern, flags, kwargs).subfn(format, string, count, pos,
+      endpos, concurrent)
+
+def split(pattern, string, maxsplit=0, flags=0, concurrent=None, **kwargs):
+    """Split the source string by the occurrences of the pattern, returning a
+    list containing the resulting substrings.  If capturing parentheses are used
+    in pattern, then the text of all groups in the pattern are also returned as
+    part of the resulting list.  If maxsplit is nonzero, at most maxsplit splits
+    occur, and the remainder of the string is returned as the final element of
+    the list."""
+    return _compile(pattern, flags, kwargs).split(string, maxsplit, concurrent)
+
+def splititer(pattern, string, maxsplit=0, flags=0, concurrent=None, **kwargs):
+    "Return an iterator yielding the parts of a split string."
+    return _compile(pattern, flags, kwargs).splititer(string, maxsplit,
+      concurrent)
+
+def findall(pattern, string, flags=0, pos=None, endpos=None, overlapped=False,
+  concurrent=None, **kwargs):
+    """Return a list of all matches in the string. The matches may be overlapped
+    if overlapped is True. If one or more groups are present in the pattern,
+    return a list of groups; this will be a list of tuples if the pattern has
+    more than one group. Empty matches are included in the result."""
+    return _compile(pattern, flags, kwargs).findall(string, pos, endpos,
+      overlapped, concurrent)
+
+def finditer(pattern, string, flags=0, pos=None, endpos=None, overlapped=False,
+  partial=False, concurrent=None, **kwargs):
+    """Return an iterator over all matches in the string. The matches may be
+    overlapped if overlapped is True. For each match, the iterator returns a
+    match object. Empty matches are included in the result."""
+    return _compile(pattern, flags, kwargs).finditer(string, pos, endpos,
+      overlapped, concurrent, partial)
+
+def compile(pattern, flags=0, **kwargs):
+    "Compile a regular expression pattern, returning a pattern object."
+    return _compile(pattern, flags, kwargs)
+
+def purge():
+    "Clear the regular expression cache"
+    _cache.clear()
+    _locale_sensitive.clear()
+
+def template(pattern, flags=0):
+    "Compile a template pattern, returning a pattern object."
+    return _compile(pattern, flags | TEMPLATE)
+
+def escape(pattern, special_only=False):
+    "Escape all non-alphanumeric characters or special characters in pattern."
+    s = []
+    if special_only:
+        for c in pattern:
+            if c in _METACHARS:
+                s.append("\\")
+                s.append(c)
+            elif c == "\x00":
+                s.append("\\000")
+            else:
+                s.append(c)
+    else:
+        for c in pattern:
+            if c in _ALNUM:
+                s.append(c)
+            elif c == "\x00":
+                s.append("\\000")
+            else:
+                s.append("\\")
+                s.append(c)
+
+    return pattern[ : 0].join(s)
+
+# --------------------------------------------------------------------
+# Internals.
+
+import _regex_core
+import _regex
+from threading import RLock as _RLock
+from locale import getlocale as _getlocale
+from _regex_core import *
+from _regex_core import (_ALL_VERSIONS, _ALL_ENCODINGS, _FirstSetError,
+  _UnscopedFlagSet, _check_group_features, _compile_firstset,
+  _compile_replacement, _flatten_code, _fold_case, _get_required_string,
+  _parse_pattern, _shrink_cache)
+from _regex_core import (ALNUM as _ALNUM, Info as _Info, OP as _OP, Source as
+  _Source, Fuzzy as _Fuzzy)
+
+# Version 0 is the old behaviour, compatible with the original 're' module.
+# Version 1 is the new behaviour, which differs slightly.
+
+DEFAULT_VERSION = VERSION0
+
+_METACHARS = frozenset("()[]{}?*+|^$\\.")
+
+_regex_core.DEFAULT_VERSION = DEFAULT_VERSION
+
+# Caches for the patterns and replacements.
+_cache = {}
+_cache_lock = _RLock()
+_named_args = {}
+_replacement_cache = {}
+_locale_sensitive = {}
+
+# Maximum size of the cache.
+_MAXCACHE = 500
+_MAXREPCACHE = 500
+
+def _compile(pattern, flags=0, kwargs={}):
+    "Compiles a regular expression to a PatternObject."
+
+    # We won't bother to cache the pattern if we're debugging.
+    debugging = (flags & DEBUG) != 0
+
+    # What locale is this pattern using?
+    locale_key = (type(pattern), pattern)
+    if _locale_sensitive.get(locale_key, True) or (flags & LOCALE) != 0:
+        # This pattern is, or might be, locale-sensitive.
+        pattern_locale = _getlocale()[1]
+    else:
+        # This pattern is definitely not locale-sensitive.
+        pattern_locale = None
+
+    if not debugging:
+        try:
+            # Do we know what keyword arguments are needed?
+            args_key = pattern, type(pattern), flags
+            args_needed = _named_args[args_key]
+
+            # Are we being provided with its required keyword arguments?
+            args_supplied = set()
+            if args_needed:
+                for k, v in args_needed:
+                    try:
+                        args_supplied.add((k, frozenset(kwargs[k])))
+                    except KeyError:
+                        raise error("missing named list: {!r}".format(k))
+
+            args_supplied = frozenset(args_supplied)
+
+            # Have we already seen this regular expression and named list?
+            pattern_key = (pattern, type(pattern), flags, args_supplied,
+              DEFAULT_VERSION, pattern_locale)
+            return _cache[pattern_key]
+        except KeyError:
+            # It's a new pattern, or new named list for a known pattern.
+            pass
+
+    # Guess the encoding from the class of the pattern string.
+    if isinstance(pattern, unicode):
+        guess_encoding = UNICODE
+    elif isinstance(pattern, str):
+        guess_encoding = ASCII
+    elif isinstance(pattern, _pattern_type):
+        if flags:
+            raise ValueError("cannot process flags argument with a compiled pattern")
+
+        return pattern
+    else:
+        raise TypeError("first argument must be a string or compiled pattern")
+
+    # Set the default version in the core code in case it has been changed.
+    _regex_core.DEFAULT_VERSION = DEFAULT_VERSION
+
+    global_flags = flags
+
+    while True:
+        caught_exception = None
+        try:
+            source = _Source(pattern)
+            info = _Info(global_flags, source.char_type, kwargs)
+            info.guess_encoding = guess_encoding
+            source.ignore_space = bool(info.flags & VERBOSE)
+            parsed = _parse_pattern(source, info)
+            break
+        except _UnscopedFlagSet:
+            # Remember the global flags for the next attempt.
+            global_flags = info.global_flags
+        except error, e:
+            caught_exception = e
+
+        if caught_exception:
+            raise error(caught_exception.msg, caught_exception.pattern,
+              caught_exception.pos)
+
+    if not source.at_end():
+        raise error("unbalanced parenthesis", pattern, source.pos)
+
+    # Check the global flags for conflicts.
+    version = (info.flags & _ALL_VERSIONS) or DEFAULT_VERSION
+    if version not in (0, VERSION0, VERSION1):
+        raise ValueError("VERSION0 and VERSION1 flags are mutually incompatible")
+
+    if (info.flags & _ALL_ENCODINGS) not in (0, ASCII, LOCALE, UNICODE):
+        raise ValueError("ASCII, LOCALE and UNICODE flags are mutually incompatible")
+
+    if not (info.flags & _ALL_ENCODINGS):
+        if isinstance(pattern, unicode):
+            info.flags |= UNICODE
+        else:
+            info.flags |= ASCII
+
+    reverse = bool(info.flags & REVERSE)
+    fuzzy = isinstance(parsed, _Fuzzy)
+
+    # Remember whether this pattern as an inline locale flag.
+    _locale_sensitive[locale_key] = info.inline_locale
+
+    # Fix the group references.
+    caught_exception = None
+    try:
+        parsed.fix_groups(pattern, reverse, False)
+    except error, e:
+        caught_exception = e
+
+    if caught_exception:
+        raise error(caught_exception.msg, caught_exception.pattern,
+          caught_exception.pos)
+
+    # Should we print the parsed pattern?
+    if flags & DEBUG:
+        parsed.dump(indent=0, reverse=reverse)
+
+    # Optimise the parsed pattern.
+    parsed = parsed.optimise(info)
+    parsed = parsed.pack_characters(info)
+
+    # Get the required string.
+    req_offset, req_chars, req_flags = _get_required_string(parsed, info.flags)
+
+    # Build the named lists.
+    named_lists = {}
+    named_list_indexes = [None] * len(info.named_lists_used)
+    args_needed = set()
+    for key, index in info.named_lists_used.items():
+        name, case_flags = key
+        values = frozenset(kwargs[name])
+        if case_flags:
+            items = frozenset(_fold_case(info, v) for v in values)
+        else:
+            items = values
+        named_lists[name] = values
+        named_list_indexes[index] = items
+        args_needed.add((name, values))
+
+    # Check the features of the groups.
+    _check_group_features(info, parsed)
+
+    # Compile the parsed pattern. The result is a list of tuples.
+    code = parsed.compile(reverse)
+
+    # Is there a group call to the pattern as a whole?
+    key = (0, reverse, fuzzy)
+    ref = info.call_refs.get(key)
+    if ref is not None:
+        code = [(_OP.CALL_REF, ref)] + code + [(_OP.END, )]
+
+    # Add the final 'success' opcode.
+    code += [(_OP.SUCCESS, )]
+
+    # Compile the additional copies of the groups that we need.
+    for group, rev, fuz in info.additional_groups:
+        code += group.compile(rev, fuz)
+
+    # Flatten the code into a list of ints.
+    code = _flatten_code(code)
+
+    if not parsed.has_simple_start():
+        # Get the first set, if possible.
+        try:
+            fs_code = _compile_firstset(info, parsed.get_firstset(reverse))
+            fs_code = _flatten_code(fs_code)
+            code = fs_code + code
+        except _FirstSetError:
+            pass
+
+    # The named capture groups.
+    index_group = dict((v, n) for n, v in info.group_index.items())
+
+    # Create the PatternObject.
+    #
+    # Local flags like IGNORECASE affect the code generation, but aren't needed
+    # by the PatternObject itself. Conversely, global flags like LOCALE _don't_
+    # affect the code generation but _are_ needed by the PatternObject.
+    compiled_pattern = _regex.compile(pattern, info.flags | version, code,
+      info.group_index, index_group, named_lists, named_list_indexes,
+      req_offset, req_chars, req_flags, info.group_count)
+
+    # Do we need to reduce the size of the cache?
+    if len(_cache) >= _MAXCACHE:
+        _cache_lock.acquire()
+        try:
+            _shrink_cache(_cache, _named_args, _locale_sensitive, _MAXCACHE)
+        finally:
+            _cache_lock.release()
+
+    if not debugging:
+        if (info.flags & LOCALE) == 0:
+            pattern_locale = None
+
+        args_needed = frozenset(args_needed)
+
+        # Store this regular expression and named list.
+        pattern_key = (pattern, type(pattern), flags, args_needed,
+          DEFAULT_VERSION, pattern_locale)
+        _cache[pattern_key] = compiled_pattern
+
+        # Store what keyword arguments are needed.
+        _named_args[args_key] = args_needed
+
+    return compiled_pattern
+
+def _compile_replacement_helper(pattern, template):
+    "Compiles a replacement template."
+    # This function is called by the _regex module.
+
+    # Have we seen this before?
+    key = pattern.pattern, pattern.flags, template
+    compiled = _replacement_cache.get(key)
+    if compiled is not None:
+        return compiled
+
+    if len(_replacement_cache) >= _MAXREPCACHE:
+        _replacement_cache.clear()
+
+    is_unicode = isinstance(template, unicode)
+    source = _Source(template)
+    if is_unicode:
+        def make_string(char_codes):
+            return u"".join(unichr(c) for c in char_codes)
+    else:
+        def make_string(char_codes):
+            return "".join(chr(c) for c in char_codes)
+
+    compiled = []
+    literal = []
+    while True:
+        ch = source.get()
+        if not ch:
+            break
+        if ch == "\\":
+            # '_compile_replacement' will return either an int group reference
+            # or a string literal. It returns items (plural) in order to handle
+            # a 2-character literal (an invalid escape sequence).
+            is_group, items = _compile_replacement(source, pattern, is_unicode)
+            if is_group:
+                # It's a group, so first flush the literal.
+                if literal:
+                    compiled.append(make_string(literal))
+                    literal = []
+                compiled.extend(items)
+            else:
+                literal.extend(items)
+        else:
+            literal.append(ord(ch))
+
+    # Flush the literal.
+    if literal:
+        compiled.append(make_string(literal))
+
+    _replacement_cache[key] = compiled
+
+    return compiled
+
+# We define _pattern_type here after all the support objects have been defined.
+_pattern_type = type(_compile("", 0, {}))
+
+# We'll define an alias for the 'compile' function so that the repr of a
+# pattern object is eval-able.
+Regex = compile
+
+# Register myself for pickling.
+import copy_reg as _copy_reg
+
+def _pickle(p):
+    return _compile, (p.pattern, p.flags)
+
+_copy_reg.pickle(_pattern_type, _pickle, _compile)
+
+if not hasattr(str, "format"):
+    # Strings don't have the .format method (below Python 2.6).
+    while True:
+        _start = __doc__.find("    subf")
+        if _start < 0:
+            break
+
+        _end = __doc__.find("\n", _start) + 1
+        while __doc__.startswith("     ", _end):
+            _end = __doc__.find("\n", _end) + 1
+
+        __doc__ = __doc__[ : _start] + __doc__[_end : ]
+
+    __all__ = [_name for _name in __all__ if not _name.startswith("subf")]
+
+    del _start, _end
+
+    del subf, subfn
diff --git a/lib/regex/_regex.c b/lib/regex/_regex.c
new file mode 100644
index 000000000..e9602102a
--- /dev/null
+++ b/lib/regex/_regex.c
@@ -0,0 +1,24497 @@
+/* Secret Labs' Regular Expression Engine
+ *
+ * regular expression matching engine
+ *
+ * partial history:
+ * 1999-10-24 fl   created (based on existing template matcher code)
+ * 2000-03-06 fl   first alpha, sort of
+ * 2000-08-01 fl   fixes for 1.6b1
+ * 2000-08-07 fl   use PyOS_CheckStack() if available
+ * 2000-09-20 fl   added expand method
+ * 2001-03-20 fl   lots of fixes for 2.1b2
+ * 2001-04-15 fl   export copyright as Python attribute, not global
+ * 2001-04-28 fl   added __copy__ methods (work in progress)
+ * 2001-05-14 fl   fixes for 1.5.2 compatibility
+ * 2001-07-01 fl   added BIGCHARSET support (from Martin von Loewis)
+ * 2001-10-18 fl   fixed group reset issue (from Matthew Mueller)
+ * 2001-10-20 fl   added split primitive; reenable unicode for 1.6/2.0/2.1
+ * 2001-10-21 fl   added sub/subn primitive
+ * 2001-10-24 fl   added finditer primitive (for 2.2 only)
+ * 2001-12-07 fl   fixed memory leak in sub/subn (Guido van Rossum)
+ * 2002-11-09 fl   fixed empty sub/subn return type
+ * 2003-04-18 mvl  fully support 4-byte codes
+ * 2003-10-17 gn   implemented non recursive scheme
+ * 2009-07-26 mrab completely re-designed matcher code
+ * 2011-11-18 mrab added support for PEP 393 strings
+ *
+ * Copyright (c) 1997-2001 by Secret Labs AB.  All rights reserved.
+ *
+ * This version of the SRE library can be redistributed under CNRI's
+ * Python 1.6 license.  For any other use, please contact Secret Labs
+ * AB (info@pythonware.com).
+ *
+ * Portions of this engine have been developed in cooperation with
+ * CNRI.  Hewlett-Packard provided funding for 1.6 integration and
+ * other compatibility work.
+ */
+
+/* #define VERBOSE */
+
+#if defined(VERBOSE)
+#define TRACE(X) printf X;
+#else
+#define TRACE(X)
+#endif
+
+#include "Python.h"
+#include "structmember.h" /* offsetof */
+#include <ctype.h>
+#include "_regex.h"
+#include "pyport.h"
+#include "pythread.h"
+
+#if PY_VERSION_HEX < 0x02060000
+#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
+#define T_PYSSIZET T_LONGLONG
+#elif SIZEOF_SIZE_T == SIZEOF_LONG
+#define T_PYSSIZET T_LONG
+#else
+#error size_t is the same size as neither LONG nor LONGLONG
+#endif
+
+#endif
+typedef unsigned char Py_UCS1;
+typedef unsigned short Py_UCS2;
+
+typedef RE_UINT32 RE_CODE;
+
+/* Properties in the General Category. */
+#define RE_PROP_GC_CN ((RE_PROP_GC << 16) | RE_PROP_CN)
+#define RE_PROP_GC_LU ((RE_PROP_GC << 16) | RE_PROP_LU)
+#define RE_PROP_GC_LL ((RE_PROP_GC << 16) | RE_PROP_LL)
+#define RE_PROP_GC_LT ((RE_PROP_GC << 16) | RE_PROP_LT)
+#define RE_PROP_GC_P ((RE_PROP_GC << 16) | RE_PROP_P)
+
+/* Unlimited repeat count. */
+#define RE_UNLIMITED (~(RE_CODE)0)
+
+/* The status of a . */
+typedef RE_UINT32 RE_STATUS_T;
+
+/* Whether to match concurrently, i.e. release the GIL while matching. */
+#define RE_CONC_NO 0
+#define RE_CONC_YES 1
+#define RE_CONC_DEFAULT 2
+
+/* The side that could truncate in a partial match.
+ *
+ * The values RE_PARTIAL_LEFT and RE_PARTIAL_RIGHT are also used as array
+ * indexes, so they need to be 0 and 1.
+ */
+#define RE_PARTIAL_NONE -1
+#define RE_PARTIAL_LEFT 0
+#define RE_PARTIAL_RIGHT 1
+
+/* Flags for the kind of 'sub' call: 'sub', 'subn', 'subf', 'subfn'. */
+#define RE_SUB 0x0
+#define RE_SUBN 0x1
+#if PY_VERSION_HEX >= 0x02060000
+#define RE_SUBF 0x2
+#endif
+
+/* The name of this module, minus the leading underscore. */
+#define RE_MODULE "regex"
+
+/* Error codes. */
+#define RE_ERROR_SUCCESS 1 /* Successful match. */
+#define RE_ERROR_FAILURE 0 /* Unsuccessful match. */
+#define RE_ERROR_ILLEGAL -1 /* Illegal code. */
+#define RE_ERROR_INTERNAL -2 /* Internal error. */
+#define RE_ERROR_CONCURRENT -3 /* "concurrent" invalid. */
+#define RE_ERROR_MEMORY -4 /* Out of memory. */
+#define RE_ERROR_INTERRUPTED -5 /* Signal handler raised exception. */
+#define RE_ERROR_REPLACEMENT -6 /* Invalid replacement string. */
+#define RE_ERROR_INVALID_GROUP_REF -7 /* Invalid group reference. */
+#define RE_ERROR_GROUP_INDEX_TYPE -8 /* Group index type error. */
+#define RE_ERROR_NO_SUCH_GROUP -9 /* No such group. */
+#define RE_ERROR_INDEX -10 /* String index. */
+#define RE_ERROR_BACKTRACKING -11 /* Too much backtracking. */
+#define RE_ERROR_NOT_STRING -12 /* Not a string. */
+#define RE_ERROR_NOT_UNICODE -13 /* Not a Unicode string. */
+#define RE_ERROR_PARTIAL -15 /* Partial match. */
+
+/* The number of backtrack entries per allocated block. */
+#define RE_BACKTRACK_BLOCK_SIZE 64
+
+/* The maximum number of backtrack entries to allocate. */
+#define RE_MAX_BACKTRACK_ALLOC (1024 * 1024)
+
+/* The number of atomic entries per allocated block. */
+#define RE_ATOMIC_BLOCK_SIZE 64
+
+/* The initial maximum capacity of the guard block. */
+#define RE_INIT_GUARDS_BLOCK_SIZE 16
+
+/* The initial maximum capacity of the node list. */
+#define RE_INIT_NODE_LIST_SIZE 16
+
+/* The size increment for various allocation lists. */
+#define RE_LIST_SIZE_INC 16
+
+/* The initial maximum capacity of the capture groups. */
+#define RE_INIT_CAPTURE_SIZE 16
+
+/* Node bitflags. */
+#define RE_POSITIVE_OP 0x1
+#define RE_ZEROWIDTH_OP 0x2
+#define RE_FUZZY_OP 0x4
+#define RE_REVERSE_OP 0x8
+#define RE_REQUIRED_OP 0x10
+
+/* Guards against further matching can occur at the start of the body and the
+ * tail of a repeat containing a repeat.
+ */
+#define RE_STATUS_BODY 0x1
+#define RE_STATUS_TAIL 0x2
+
+/* Whether a guard is added depends on whether there's a repeat in the body of
+ * the repeat or a group reference in the body or tail of the repeat.
+ */
+#define RE_STATUS_NEITHER 0x0
+#define RE_STATUS_REPEAT 0x4
+#define RE_STATUS_LIMITED 0x8
+#define RE_STATUS_REF 0x10
+#define RE_STATUS_VISITED_AG 0x20
+#define RE_STATUS_VISITED_REP 0x40
+
+/* Whether a string node has been initialised for fast searching. */
+#define RE_STATUS_FAST_INIT 0x80
+
+/* Whether a node us being used. (Additional nodes may be created while the
+ * pattern is being built.
+ */
+#define RE_STATUS_USED 0x100
+
+/* Whether a node is a string node. */
+#define RE_STATUS_STRING 0x200
+
+/* Whether a repeat node is within another repeat. */
+#define RE_STATUS_INNER 0x400
+
+/* Various flags stored in a node status member. */
+#define RE_STATUS_SHIFT 11
+
+#define RE_STATUS_FUZZY (RE_FUZZY_OP << RE_STATUS_SHIFT)
+#define RE_STATUS_REVERSE (RE_REVERSE_OP << RE_STATUS_SHIFT)
+#define RE_STATUS_REQUIRED (RE_REQUIRED_OP << RE_STATUS_SHIFT)
+#define RE_STATUS_HAS_GROUPS 0x10000
+#define RE_STATUS_HAS_REPEATS 0x20000
+
+/* The different error types for fuzzy matching. */
+#define RE_FUZZY_SUB 0
+#define RE_FUZZY_INS 1
+#define RE_FUZZY_DEL 2
+#define RE_FUZZY_ERR 3
+#define RE_FUZZY_COUNT 3
+
+/* The various values in a FUZZY node. */
+#define RE_FUZZY_VAL_MAX_BASE 1
+#define RE_FUZZY_VAL_MAX_SUB (RE_FUZZY_VAL_MAX_BASE + RE_FUZZY_SUB)
+#define RE_FUZZY_VAL_MAX_INS (RE_FUZZY_VAL_MAX_BASE + RE_FUZZY_INS)
+#define RE_FUZZY_VAL_MAX_DEL (RE_FUZZY_VAL_MAX_BASE + RE_FUZZY_DEL)
+#define RE_FUZZY_VAL_MAX_ERR (RE_FUZZY_VAL_MAX_BASE + RE_FUZZY_ERR)
+
+#define RE_FUZZY_VAL_COST_BASE 5
+#define RE_FUZZY_VAL_SUB_COST (RE_FUZZY_VAL_COST_BASE + RE_FUZZY_SUB)
+#define RE_FUZZY_VAL_INS_COST (RE_FUZZY_VAL_COST_BASE + RE_FUZZY_INS)
+#define RE_FUZZY_VAL_DEL_COST (RE_FUZZY_VAL_COST_BASE + RE_FUZZY_DEL)
+#define RE_FUZZY_VAL_MAX_COST (RE_FUZZY_VAL_COST_BASE + RE_FUZZY_ERR)
+
+/* The various values in an END_FUZZY node. */
+#define RE_FUZZY_VAL_MIN_BASE 1
+#define RE_FUZZY_VAL_MIN_SUB (RE_FUZZY_VAL_MIN_BASE + RE_FUZZY_SUB)
+#define RE_FUZZY_VAL_MIN_INS (RE_FUZZY_VAL_MIN_BASE + RE_FUZZY_INS)
+#define RE_FUZZY_VAL_MIN_DEL (RE_FUZZY_VAL_MIN_BASE + RE_FUZZY_DEL)
+#define RE_FUZZY_VAL_MIN_ERR (RE_FUZZY_VAL_MIN_BASE + RE_FUZZY_ERR)
+
+/* The maximum number of errors when trying to improve a fuzzy match. */
+#define RE_MAX_ERRORS 10
+
+/* The flags which will be set for full Unicode case folding. */
+#define RE_FULL_CASE_FOLDING (RE_FLAG_UNICODE | RE_FLAG_FULLCASE | RE_FLAG_IGNORECASE)
+
+/* The shortest string prefix for which we'll use a fast string search. */
+#define RE_MIN_FAST_LENGTH 5
+
+static char copyright[] =
+    " RE 2.3.0 Copyright (c) 1997-2002 by Secret Labs AB ";
+
+/* The exception to raise on error. */
+static PyObject* error_exception;
+
+/* The dictionary of Unicode properties. */
+static PyObject* property_dict;
+
+typedef struct RE_State* RE_StatePtr;
+
+/* Bit-flags for the common character properties supported by locale-sensitive
+ * matching.
+ */
+#define RE_LOCALE_ALNUM 0x001
+#define RE_LOCALE_ALPHA 0x002
+#define RE_LOCALE_CNTRL 0x004
+#define RE_LOCALE_DIGIT 0x008
+#define RE_LOCALE_GRAPH 0x010
+#define RE_LOCALE_LOWER 0x020
+#define RE_LOCALE_PRINT 0x040
+#define RE_LOCALE_PUNCT 0x080
+#define RE_LOCALE_SPACE 0x100
+#define RE_LOCALE_UPPER 0x200
+
+/* Info about the current locale.
+ *
+ * Used by patterns that are locale-sensitive.
+ */
+typedef struct RE_LocaleInfo {
+    unsigned short properties[0x100];
+    unsigned char uppercase[0x100];
+    unsigned char lowercase[0x100];
+} RE_LocaleInfo;
+
+/* Handlers for ASCII, locale and Unicode. */
+typedef struct RE_EncodingTable {
+    BOOL (*has_property)(RE_LocaleInfo* locale_info, RE_CODE property, Py_UCS4
+      ch);
+    BOOL (*at_boundary)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*at_word_start)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*at_word_end)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*at_default_boundary)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*at_default_word_start)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*at_default_word_end)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*at_grapheme_boundary)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*is_line_sep)(Py_UCS4 ch);
+    BOOL (*at_line_start)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*at_line_end)(RE_StatePtr state, Py_ssize_t text_pos);
+    BOOL (*possible_turkic)(RE_LocaleInfo* locale_info, Py_UCS4 ch);
+    int (*all_cases)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+      codepoints);
+    Py_UCS4 (*simple_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch);
+    int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+      folded);
+    int (*all_turkic_i)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+      cases);
+} RE_EncodingTable;
+
+/* Position within the regex and text. */
+typedef struct RE_Position {
+    struct RE_Node* node;
+    Py_ssize_t text_pos;
+} RE_Position;
+
+/* Info about fuzzy matching. */
+typedef struct RE_FuzzyInfo {
+    struct RE_Node* node;
+    size_t counts[RE_FUZZY_COUNT + 1]; /* Add 1 for total errors. */
+    size_t total_cost;
+} RE_FuzzyInfo;
+
+/* Storage for backtrack data. */
+typedef struct RE_BacktrackData {
+    union {
+        struct {
+            size_t capture_change;
+            BOOL too_few_errors;
+        } atomic;
+        struct {
+            RE_Position position;
+        } branch;
+        struct {
+            RE_FuzzyInfo fuzzy_info;
+            Py_ssize_t text_pos;
+            RE_CODE index;
+        } fuzzy;
+        struct {
+            RE_Position position;
+            size_t count;
+            struct RE_Node* fuzzy_node;
+            BOOL too_few_errors;
+        } fuzzy_insert;
+        struct {
+            RE_Position position;
+            RE_INT8 fuzzy_type;
+            RE_INT8 step;
+        } fuzzy_item;
+        struct {
+            RE_Position position;
+            Py_ssize_t string_pos;
+            RE_INT8 fuzzy_type;
+            RE_INT8 folded_pos;
+            RE_INT8 folded_len;
+            RE_INT8 gfolded_pos;
+            RE_INT8 gfolded_len;
+            RE_INT8 step;
+        } fuzzy_string;
+        struct {
+            Py_ssize_t text_pos;
+            Py_ssize_t current_capture;
+            RE_CODE private_index;
+            RE_CODE public_index;
+            BOOL capture;
+        } group;
+        struct {
+            struct RE_Node* node;
+            size_t capture_change;
+        } group_call;
+        struct {
+            Py_ssize_t match_pos;
+        } keep;
+        struct {
+            struct RE_Node* node;
+            size_t capture_change;
+            BOOL too_few_errors;
+            BOOL inside;
+        } lookaround;
+        struct {
+            RE_Position position;
+            Py_ssize_t text_pos;
+            size_t count;
+            Py_ssize_t start;
+            size_t capture_change;
+            RE_CODE index;
+        } repeat;
+    };
+    RE_UINT8 op;
+} RE_BacktrackData;
+
+/* Storage for backtrack data is allocated in blocks for speed. */
+typedef struct RE_BacktrackBlock {
+    RE_BacktrackData items[RE_BACKTRACK_BLOCK_SIZE];
+    struct RE_BacktrackBlock* previous;
+    struct RE_BacktrackBlock* next;
+    size_t capacity;
+    size_t count;
+} RE_BacktrackBlock;
+
+/* Storage for atomic data. */
+typedef struct RE_AtomicData {
+    RE_BacktrackBlock* current_backtrack_block;
+    size_t backtrack_count;
+    struct RE_Node* node;
+    RE_BacktrackData* backtrack;
+    struct RE_SavedGroups* saved_groups;
+    struct RE_SavedRepeats* saved_repeats;
+    Py_ssize_t slice_start;
+    Py_ssize_t slice_end;
+    Py_ssize_t text_pos;
+    BOOL is_lookaround;
+    BOOL has_groups;
+    BOOL has_repeats;
+} RE_AtomicData;
+
+/* Storage for atomic data is allocated in blocks for speed. */
+typedef struct RE_AtomicBlock {
+    RE_AtomicData items[RE_ATOMIC_BLOCK_SIZE];
+    struct RE_AtomicBlock* previous;
+    struct RE_AtomicBlock* next;
+    size_t capacity;
+    size_t count;
+} RE_AtomicBlock;
+
+/* Storage for saved groups. */
+typedef struct RE_SavedGroups {
+    struct RE_SavedGroups* previous;
+    struct RE_SavedGroups* next;
+    struct RE_GroupSpan* spans;
+    size_t* counts;
+} RE_SavedGroups;
+
+/* Storage for info around a recursive by 'basic'match'. */
+typedef struct RE_Info {
+    RE_BacktrackBlock* current_backtrack_block;
+    size_t backtrack_count;
+    RE_SavedGroups* current_saved_groups;
+    struct RE_GroupCallFrame* current_group_call_frame;
+    BOOL must_advance;
+} RE_Info;
+
+/* Storage for the next node. */
+typedef struct RE_NextNode {
+    struct RE_Node* node;
+    struct RE_Node* test;
+    struct RE_Node* match_next;
+    Py_ssize_t match_step;
+} RE_NextNode;
+
+/* A pattern node. */
+typedef struct RE_Node {
+    RE_NextNode next_1;
+    union {
+        struct {
+            RE_NextNode next_2;
+        } nonstring;
+        struct {
+            /* Used only if (node->status & RE_STATUS_STRING) is true. */
+            Py_ssize_t* bad_character_offset;
+            Py_ssize_t* good_suffix_offset;
+        } string;
+    };
+    Py_ssize_t step;
+    size_t value_count;
+    RE_CODE* values;
+    RE_STATUS_T status;
+    RE_UINT8 op;
+    BOOL match;
+} RE_Node;
+
+/* Info about a group's span. */
+typedef struct RE_GroupSpan {
+    Py_ssize_t start;
+    Py_ssize_t end;
+} RE_GroupSpan;
+
+/* Span of a guard (inclusive range). */
+typedef struct RE_GuardSpan {
+    Py_ssize_t low;
+    Py_ssize_t high;
+    BOOL protect;
+} RE_GuardSpan;
+
+/* Spans guarded against further matching. */
+typedef struct RE_GuardList {
+    size_t capacity;
+    size_t count;
+    RE_GuardSpan* spans;
+    Py_ssize_t last_text_pos;
+    size_t last_low;
+} RE_GuardList;
+
+/* Info about a group. */
+typedef struct RE_GroupData {
+    RE_GroupSpan span;
+    size_t capture_count;
+    size_t capture_capacity;
+    Py_ssize_t current_capture;
+    RE_GroupSpan* captures;
+} RE_GroupData;
+
+/* Info about a repeat. */
+typedef struct RE_RepeatData {
+    RE_GuardList body_guard_list;
+    RE_GuardList tail_guard_list;
+    size_t count;
+    Py_ssize_t start;
+    size_t capture_change;
+} RE_RepeatData;
+
+/* Storage for saved repeats. */
+typedef struct RE_SavedRepeats {
+    struct RE_SavedRepeats* previous;
+    struct RE_SavedRepeats* next;
+    RE_RepeatData* repeats;
+} RE_SavedRepeats;
+
+/* Guards for fuzzy sections. */
+typedef struct RE_FuzzyGuards {
+    RE_GuardList body_guard_list;
+    RE_GuardList tail_guard_list;
+} RE_FuzzyGuards;
+
+/* Info about a capture group. */
+typedef struct RE_GroupInfo {
+    Py_ssize_t end_index;
+    RE_Node* node;
+    BOOL referenced;
+    BOOL has_name;
+} RE_GroupInfo;
+
+/* Info about a call_ref. */
+typedef struct RE_CallRefInfo {
+    RE_Node* node;
+    BOOL defined;
+    BOOL used;
+} RE_CallRefInfo;
+
+/* Info about a repeat. */
+typedef struct RE_RepeatInfo {
+    RE_STATUS_T status;
+} RE_RepeatInfo;
+
+/* Stack frame for a group call. */
+typedef struct RE_GroupCallFrame {
+    struct RE_GroupCallFrame* previous;
+    struct RE_GroupCallFrame* next;
+    RE_Node* node;
+    RE_GroupData* groups;
+    RE_RepeatData* repeats;
+} RE_GroupCallFrame;
+
+/* Info about a string argument. */
+typedef struct RE_StringInfo {
+#if PY_VERSION_HEX >= 0x02060000
+    Py_buffer view; /* View of the string if it's a buffer object. */
+#endif
+    void* characters; /* Pointer to the characters of the string. */
+    Py_ssize_t length; /* Length of the string. */
+    Py_ssize_t charsize; /* Size of the characters in the string. */
+    BOOL is_unicode; /* Whether the string is Unicode. */
+    BOOL should_release; /* Whether the buffer should be released. */
+} RE_StringInfo;
+
+/* Info about where the next match was found, starting from a certain search
+ * position. This is used when a pattern starts with a BRANCH.
+ */
+#define MAX_SEARCH_POSITIONS 7
+
+/* Info about a search position. */
+typedef struct {
+    Py_ssize_t start_pos;
+    Py_ssize_t match_pos;
+} RE_SearchPosition;
+
+/* The state object used during matching. */
+typedef struct RE_State {
+    struct PatternObject* pattern; /* Parent PatternObject. */
+    /* Info about the string being matched. */
+    PyObject* string;
+#if PY_VERSION_HEX >= 0x02060000
+    Py_buffer view; /* View of the string if it's a buffer object. */
+#endif
+    Py_ssize_t charsize;
+    void* text;
+    Py_ssize_t text_length;
+    /* The slice of the string being searched. */
+    Py_ssize_t slice_start;
+    Py_ssize_t slice_end;
+    /* Info about the capture groups. */
+    RE_GroupData* groups;
+    Py_ssize_t lastindex;
+    Py_ssize_t lastgroup;
+    /* Info about the repeats. */
+    RE_RepeatData* repeats;
+    Py_ssize_t search_anchor; /* Where the last match finished. */
+    Py_ssize_t match_pos; /* The start position of the match. */
+    Py_ssize_t text_pos; /* The current position of the match. */
+    Py_ssize_t final_newline; /* The index of newline at end of string, or -1. */
+    Py_ssize_t final_line_sep; /* The index of line separator at end of string, or -1. */
+    /* Storage for backtrack info. */
+    RE_BacktrackBlock backtrack_block;
+    RE_BacktrackBlock* current_backtrack_block;
+    Py_ssize_t backtrack_allocated;
+    RE_BacktrackData* backtrack;
+    RE_AtomicBlock* current_atomic_block;
+    /* Storage for saved capture groups. */
+    RE_SavedGroups* first_saved_groups;
+    RE_SavedGroups* current_saved_groups;
+    RE_SavedRepeats* first_saved_repeats;
+    RE_SavedRepeats* current_saved_repeats;
+    /* Info about the best POSIX match (leftmost longest). */
+    Py_ssize_t best_match_pos;
+    Py_ssize_t best_text_pos;
+    RE_GroupData* best_match_groups;
+    /* Miscellaneous. */
+    Py_ssize_t min_width; /* The minimum width of the string to match (assuming it's not a fuzzy pattern). */
+    RE_EncodingTable* encoding; /* The 'encoding' of the string being searched. */
+    RE_LocaleInfo* locale_info; /* Info about the locale, if needed. */
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    void (*set_char_at)(void* text, Py_ssize_t pos, Py_UCS4 ch);
+    void* (*point_to)(void* text, Py_ssize_t pos);
+    PyThread_type_lock lock; /* A lock for accessing the state across threads. */
+    RE_FuzzyInfo fuzzy_info; /* Info about fuzzy matching. */
+    size_t total_fuzzy_counts[RE_FUZZY_COUNT]; /* Totals for fuzzy matching. */
+    size_t best_fuzzy_counts[RE_FUZZY_COUNT]; /* Best totals for fuzzy matching. */
+    RE_FuzzyGuards* fuzzy_guards; /* The guards for a fuzzy match. */
+    size_t total_errors; /* The total number of errors of a fuzzy match. */
+    size_t max_errors; /* The maximum permitted number of errors. */
+    size_t fewest_errors; /* The fewest errors so far of an enhanced fuzzy match. */
+    /* The group call stack. */
+    RE_GroupCallFrame* first_group_call_frame;
+    RE_GroupCallFrame* current_group_call_frame;
+    RE_GuardList* group_call_guard_list;
+    RE_SearchPosition search_positions[MAX_SEARCH_POSITIONS]; /* Where the search matches next. */
+    size_t capture_change; /* Incremented every time a captive group changes. */
+    Py_ssize_t req_pos; /* The position where the required string matched. */
+    Py_ssize_t req_end; /* The end position where the required string matched. */
+    int partial_side; /* The side that could truncate in a partial match. */
+    RE_UINT16 iterations; /* The number of iterations the matching engine has performed since checking for KeyboardInterrupt. */
+    BOOL is_unicode; /* Whether the string to be matched is Unicode. */
+    BOOL should_release; /* Whether the buffer should be released. */
+    BOOL overlapped; /* Whether the matches can be overlapped. */
+    BOOL reverse; /* Whether it's a reverse pattern. */
+    BOOL visible_captures; /* Whether the 'captures' method will be visible. */
+    BOOL version_0; /* Whether to perform version_0 behaviour (same as re module). */
+    BOOL must_advance; /* Whether the end of the match must advance past its start. */
+    BOOL is_multithreaded; /* Whether to release the GIL while matching. */
+    BOOL too_few_errors; /* Whether there were too few fuzzy errors. */
+    BOOL match_all; /* Whether to match all of the string ('fullmatch'). */
+    BOOL found_match; /* Whether a POSIX match has been found. */
+} RE_State;
+
+/* Storage for the regex state and thread state.
+ *
+ * Scanner objects can sometimes be shared across threads, which means that
+ * their RE_State structs are also shared. This isn't safe when the GIL is
+ * released, so in such instances we have a lock (mutex) in the RE_State struct
+ * to protect it during matching. We also need a thread-safe place to store the
+ * thread state when releasing the GIL.
+ */
+typedef struct RE_SafeState {
+    RE_State* re_state;
+    PyThreadState* thread_state;
+} RE_SafeState;
+
+/* The PatternObject created from a regular expression. */
+typedef struct PatternObject {
+    PyObject_HEAD
+    PyObject* pattern; /* Pattern source (or None). */
+    Py_ssize_t flags; /* Flags used when compiling pattern source. */
+    PyObject* weakreflist; /* List of weak references */
+    /* Nodes into which the regular expression is compiled. */
+    RE_Node* start_node;
+    RE_Node* start_test;
+    size_t true_group_count; /* The true number of capture groups. */
+    size_t public_group_count; /* The number of public capture groups. */
+    size_t repeat_count; /* The number of repeats. */
+    Py_ssize_t group_end_index; /* The number of group closures. */
+    PyObject* groupindex;
+    PyObject* indexgroup;
+    PyObject* named_lists;
+    size_t named_lists_count;
+    PyObject** partial_named_lists[2];
+    PyObject* named_list_indexes;
+    /* Storage for the pattern nodes. */
+    size_t node_capacity;
+    size_t node_count;
+    RE_Node** node_list;
+    /* Info about the capture groups. */
+    size_t group_info_capacity;
+    RE_GroupInfo* group_info;
+    /* Info about the call_refs. */
+    size_t call_ref_info_capacity;
+    size_t call_ref_info_count;
+    RE_CallRefInfo* call_ref_info;
+    Py_ssize_t pattern_call_ref;
+    /* Info about the repeats. */
+    size_t repeat_info_capacity;
+    RE_RepeatInfo* repeat_info;
+    Py_ssize_t min_width; /* The minimum width of the string to match (assuming it isn't a fuzzy pattern). */
+    RE_EncodingTable* encoding; /* Encoding handlers. */
+    RE_LocaleInfo* locale_info; /* Info about the locale, if needed. */
+    RE_GroupData* groups_storage;
+    RE_RepeatData* repeats_storage;
+    size_t fuzzy_count; /* The number of fuzzy sections. */
+    Py_ssize_t req_offset; /* The offset to the required string. */
+    RE_Node* req_string; /* The required string. */
+    BOOL is_fuzzy; /* Whether it's a fuzzy pattern. */
+    BOOL do_search_start; /* Whether to do an initial search. */
+    BOOL recursive; /* Whether the entire pattern is recursive. */
+} PatternObject;
+
+/* The MatchObject created when a match is found. */
+typedef struct MatchObject {
+    PyObject_HEAD
+    PyObject* string; /* Link to the target string or NULL if detached. */
+    PyObject* substring; /* Link to (a substring of) the target string. */
+    Py_ssize_t substring_offset; /* Offset into the target string. */
+    PatternObject* pattern; /* Link to the regex (pattern) object. */
+    Py_ssize_t pos; /* Start of current slice. */
+    Py_ssize_t endpos; /* End of current slice. */
+    Py_ssize_t match_start; /* Start of matched slice. */
+    Py_ssize_t match_end; /* End of matched slice. */
+    Py_ssize_t lastindex; /* Last group seen by the engine (-1 if none). */
+    Py_ssize_t lastgroup; /* Last named group seen by the engine (-1 if none). */
+    size_t group_count; /* The number of groups. */
+    RE_GroupData* groups; /* The capture groups. */
+    PyObject* regs;
+    size_t fuzzy_counts[RE_FUZZY_COUNT];
+    BOOL partial; /* Whether it's a partial match. */
+} MatchObject;
+
+/* The ScannerObject. */
+typedef struct ScannerObject {
+    PyObject_HEAD
+    PatternObject* pattern;
+    RE_State state;
+    int status;
+} ScannerObject;
+
+/* The SplitterObject. */
+typedef struct SplitterObject {
+    PyObject_HEAD
+    PatternObject* pattern;
+    RE_State state;
+    Py_ssize_t maxsplit;
+    Py_ssize_t last_pos;
+    Py_ssize_t split_count;
+    Py_ssize_t index;
+    int status;
+} SplitterObject;
+#if PY_VERSION_HEX >= 0x02060000
+
+/* The CaptureObject. */
+typedef struct CaptureObject {
+    PyObject_HEAD
+    Py_ssize_t group_index;
+    MatchObject** match_indirect;
+} CaptureObject;
+#endif
+
+/* Info used when compiling a pattern to nodes. */
+typedef struct RE_CompileArgs {
+    RE_CODE* code; /* The start of the compiled pattern. */
+    RE_CODE* end_code; /* The end of the compiled pattern. */
+    PatternObject* pattern; /* The pattern object. */
+    Py_ssize_t min_width; /* The minimum width of the string to match (assuming it isn't a fuzzy pattern). */
+    RE_Node* start; /* The start node. */
+    RE_Node* end; /* The end node. */
+    size_t repeat_depth; /* The nesting depth of the repeat. */
+    BOOL forward; /* Whether it's a forward (not reverse) pattern. */
+    BOOL visible_captures; /* Whether all of the captures will be visible. */
+    BOOL has_captures; /* Whether the pattern has capture groups. */
+    BOOL is_fuzzy; /* Whether the pattern (or some part of it) is fuzzy. */
+    BOOL within_fuzzy; /* Whether the subpattern is within a fuzzy section. */
+    BOOL has_groups; /* Whether the subpattern contains captures. */
+    BOOL has_repeats; /* Whether the subpattern contains repeats. */
+} RE_CompileArgs;
+
+/* The string slices which will be concatenated to make the result string of
+ * the 'sub' method.
+ *
+ * This allows us to avoid creating a list of slices if there of fewer than 2
+ * of them. Empty strings aren't recorded, so if 'list' and 'item' are both
+ * NULL then the result is an empty string.
+ */
+typedef struct JoinInfo {
+    PyObject* list; /* The list of slices if there are more than 2 of them. */
+    PyObject* item; /* The slice if there is only 1 of them. */
+    BOOL reversed; /* Whether the slices have been found in reverse order. */
+    BOOL is_unicode; /* Whether the string is Unicode. */
+} JoinInfo;
+
+/* Info about fuzzy matching. */
+typedef struct {
+    RE_Node* new_node;
+    Py_ssize_t new_text_pos;
+    Py_ssize_t limit;
+    Py_ssize_t new_string_pos;
+    int step;
+    int new_folded_pos;
+    int folded_len;
+    int new_gfolded_pos;
+    int new_group_pos;
+    int fuzzy_type;
+    BOOL permit_insertion;
+} RE_FuzzyData;
+
+typedef struct RE_BestEntry {
+     Py_ssize_t match_pos;
+     Py_ssize_t text_pos;
+} RE_BestEntry;
+
+typedef struct RE_BestList {
+    size_t capacity;
+    size_t count;
+    RE_BestEntry* entries;
+} RE_BestList;
+
+/* Function types for getting info from a MatchObject. */
+typedef PyObject* (*RE_GetByIndexFunc)(MatchObject* self, Py_ssize_t index);
+
+/* Returns the magnitude of a 'Py_ssize_t' value. */
+Py_LOCAL_INLINE(Py_ssize_t) abs_ssize_t(Py_ssize_t x) {
+    return x >= 0 ? x : -x;
+}
+
+/* Returns the minimum of 2 'Py_ssize_t' values. */
+Py_LOCAL_INLINE(Py_ssize_t) min_ssize_t(Py_ssize_t x, Py_ssize_t y) {
+    return x <= y ? x : y;
+}
+
+/* Returns the maximum of 2 'Py_ssize_t' values. */
+Py_LOCAL_INLINE(Py_ssize_t) max_ssize_t(Py_ssize_t x, Py_ssize_t y) {
+    return x >= y ? x : y;
+}
+
+/* Returns the minimum of 2 'size_t' values. */
+Py_LOCAL_INLINE(size_t) min_size_t(size_t x, size_t y) {
+    return x <= y ? x : y;
+}
+
+/* Returns the maximum of 2 'size_t' values. */
+Py_LOCAL_INLINE(size_t) max_size_t(size_t x, size_t y) {
+    return x >= y ? x : y;
+}
+
+/* Returns the 'maximum' of 2 RE_STATUS_T values. */
+Py_LOCAL_INLINE(RE_STATUS_T) max_status_2(RE_STATUS_T x, RE_STATUS_T y) {
+    return x >= y ? x : y;
+}
+
+/* Returns the 'maximum' of 3 RE_STATUS_T values. */
+Py_LOCAL_INLINE(RE_STATUS_T) max_status_3(RE_STATUS_T x, RE_STATUS_T y,
+  RE_STATUS_T z) {
+    return max_status_2(x, max_status_2(y, z));
+}
+
+/* Returns the 'maximum' of 4 RE_STATUS_T values. */
+Py_LOCAL_INLINE(RE_STATUS_T) max_status_4(RE_STATUS_T w, RE_STATUS_T x,
+  RE_STATUS_T y, RE_STATUS_T z) {
+    return max_status_2(max_status_2(w, x), max_status_2(y, z));
+}
+
+/* Gets a character at a position assuming 1 byte per character. */
+static Py_UCS4 bytes1_char_at(void* text, Py_ssize_t pos) {
+    return *((Py_UCS1*)text + pos);
+}
+
+/* Sets a character at a position assuming 1 byte per character. */
+static void bytes1_set_char_at(void* text, Py_ssize_t pos, Py_UCS4 ch) {
+    *((Py_UCS1*)text + pos) = (Py_UCS1)ch;
+}
+
+/* Gets a pointer to a position assuming 1 byte per character. */
+static void* bytes1_point_to(void* text, Py_ssize_t pos) {
+    return (Py_UCS1*)text + pos;
+}
+
+/* Gets a character at a position assuming 2 bytes per character. */
+static Py_UCS4 bytes2_char_at(void* text, Py_ssize_t pos) {
+    return *((Py_UCS2*)text + pos);
+}
+
+/* Sets a character at a position assuming 2 bytes per character. */
+static void bytes2_set_char_at(void* text, Py_ssize_t pos, Py_UCS4 ch) {
+    *((Py_UCS2*)text + pos) = (Py_UCS2)ch;
+}
+
+/* Gets a pointer to a position assuming 2 bytes per character. */
+static void* bytes2_point_to(void* text, Py_ssize_t pos) {
+    return (Py_UCS2*)text + pos;
+}
+
+/* Gets a character at a position assuming 4 bytes per character. */
+static Py_UCS4 bytes4_char_at(void* text, Py_ssize_t pos) {
+    return *((Py_UCS4*)text + pos);
+}
+
+/* Sets a character at a position assuming 4 bytes per character. */
+static void bytes4_set_char_at(void* text, Py_ssize_t pos, Py_UCS4 ch) {
+    *((Py_UCS4*)text + pos) = (Py_UCS4)ch;
+}
+
+/* Gets a pointer to a position assuming 4 bytes per character. */
+static void* bytes4_point_to(void* text, Py_ssize_t pos) {
+    return (Py_UCS4*)text + pos;
+}
+
+/* Default for whether a position is on a word boundary. */
+static BOOL at_boundary_always(RE_State* state, Py_ssize_t text_pos) {
+    return TRUE;
+}
+
+/* Converts a BOOL to success/failure. */
+Py_LOCAL_INLINE(int) bool_as_status(BOOL value) {
+    return value ? RE_ERROR_SUCCESS : RE_ERROR_FAILURE;
+}
+
+/* ASCII-specific. */
+
+Py_LOCAL_INLINE(BOOL) unicode_has_property(RE_CODE property, Py_UCS4 ch);
+
+/* Checks whether a character has a property. */
+Py_LOCAL_INLINE(BOOL) ascii_has_property(RE_CODE property, Py_UCS4 ch) {
+    if (ch > RE_ASCII_MAX) {
+        /* Outside the ASCII range. */
+        RE_UINT32 value;
+
+        value = property & 0xFFFF;
+
+        return value == 0;
+    }
+
+    return unicode_has_property(property, ch);
+}
+
+/* Wrapper for calling 'ascii_has_property' via a pointer. */
+static BOOL ascii_has_property_wrapper(RE_LocaleInfo* locale_info, RE_CODE
+  property, Py_UCS4 ch) {
+    return ascii_has_property(property, ch);
+}
+
+/* Checks whether there's a word character to the left. */
+Py_LOCAL_INLINE(BOOL) ascii_word_left(RE_State* state, Py_ssize_t text_pos) {
+    return text_pos > 0 && ascii_has_property(RE_PROP_WORD,
+      state->char_at(state->text, text_pos - 1));
+}
+
+/* Checks whether there's a word character to the right. */
+Py_LOCAL_INLINE(BOOL) ascii_word_right(RE_State* state, Py_ssize_t text_pos) {
+    return text_pos < state->text_length && ascii_has_property(RE_PROP_WORD,
+      state->char_at(state->text, text_pos));
+}
+
+/* Checks whether a position is on a word boundary. */
+static BOOL ascii_at_boundary(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = ascii_word_left(state, text_pos);
+    right = ascii_word_right(state, text_pos);
+
+    return left != right;
+}
+
+/* Checks whether a position is at the start of a word. */
+static BOOL ascii_at_word_start(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = ascii_word_left(state, text_pos);
+    right = ascii_word_right(state, text_pos);
+
+    return !left && right;
+}
+
+/* Checks whether a position is at the end of a word. */
+static BOOL ascii_at_word_end(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = ascii_word_left(state, text_pos);
+    right = ascii_word_right(state, text_pos);
+
+    return left && !right;
+}
+
+/* Checks whether a character is a line separator. */
+static BOOL ascii_is_line_sep(Py_UCS4 ch) {
+    return 0x0A <= ch && ch <= 0x0D;
+}
+
+/* Checks whether a position is at the start of a line. */
+static BOOL ascii_at_line_start(RE_State* state, Py_ssize_t text_pos) {
+    Py_UCS4 ch;
+
+    if (text_pos <= 0)
+        return TRUE;
+
+    ch = state->char_at(state->text, text_pos - 1);
+
+    if (ch == 0x0D) {
+        if (text_pos >= state->text_length)
+            return TRUE;
+
+        /* No line break inside CRLF. */
+        return state->char_at(state->text, text_pos) != 0x0A;
+    }
+
+    return 0x0A <= ch && ch <= 0x0D;
+}
+
+/* Checks whether a position is at the end of a line. */
+static BOOL ascii_at_line_end(RE_State* state, Py_ssize_t text_pos) {
+    Py_UCS4 ch;
+
+    if (text_pos >= state->text_length)
+        return TRUE;
+
+    ch = state->char_at(state->text, text_pos);
+
+    if (ch == 0x0A) {
+        if (text_pos <= 0)
+            return TRUE;
+
+        /* No line break inside CRLF. */
+        return state->char_at(state->text, text_pos - 1) != 0x0D;
+    }
+
+    return 0x0A <= ch && ch <= 0x0D;
+}
+
+/* Checks whether a character could be Turkic (variants of I/i). For ASCII, it
+ * won't be.
+ */
+static BOOL ascii_possible_turkic(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return FALSE;
+}
+
+/* Gets all the cases of a character. */
+static int ascii_all_cases(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+  codepoints) {
+    int count;
+
+    count = 0;
+
+    codepoints[count++] = ch;
+
+    if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z'))
+        /* It's a letter, so add the other case. */
+        codepoints[count++] = ch ^ 0x20;
+
+    return count;
+}
+
+/* Returns a character with its case folded. */
+static Py_UCS4 ascii_simple_case_fold(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    if ('A' <= ch && ch <= 'Z')
+        /* Uppercase folds to lowercase. */
+        return ch ^ 0x20;
+
+    return ch;
+}
+
+/* Returns a character with its case folded. */
+static int ascii_full_case_fold(RE_LocaleInfo* locale_info, Py_UCS4 ch,
+  Py_UCS4* folded) {
+    if ('A' <= ch && ch <= 'Z')
+        /* Uppercase folds to lowercase. */
+        folded[0] = ch ^ 0x20;
+    else
+        folded[0] = ch;
+
+    return 1;
+}
+
+/* Gets all the case variants of Turkic 'I'. The given character will be listed
+ * first.
+ */
+static int ascii_all_turkic_i(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+  cases) {
+    int count;
+
+    count = 0;
+
+    cases[count++] = ch;
+
+    if (ch != 'I')
+        cases[count++] = 'I';
+
+    if (ch != 'i')
+        cases[count++] = 'i';
+
+    return count;
+}
+
+/* The handlers for ASCII characters. */
+static RE_EncodingTable ascii_encoding = {
+    ascii_has_property_wrapper,
+    ascii_at_boundary,
+    ascii_at_word_start,
+    ascii_at_word_end,
+    ascii_at_boundary, /* No special "default word boundary" for ASCII. */
+    ascii_at_word_start, /* No special "default start of word" for ASCII. */
+    ascii_at_word_end, /* No special "default end of a word" for ASCII. */
+    at_boundary_always, /* No special "grapheme boundary" for ASCII. */
+    ascii_is_line_sep,
+    ascii_at_line_start,
+    ascii_at_line_end,
+    ascii_possible_turkic,
+    ascii_all_cases,
+    ascii_simple_case_fold,
+    ascii_full_case_fold,
+    ascii_all_turkic_i,
+};
+
+/* Locale-specific. */
+
+/* Checks whether a character has the 'alnum' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_isalnum(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_ALNUM) != 0;
+}
+
+/* Checks whether a character has the 'alpha' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_isalpha(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_ALPHA) != 0;
+}
+
+/* Checks whether a character has the 'cntrl' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_iscntrl(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_CNTRL) != 0;
+}
+
+/* Checks whether a character has the 'digit' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_isdigit(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_DIGIT) != 0;
+}
+
+/* Checks whether a character has the 'graph' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_isgraph(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_GRAPH) != 0;
+}
+
+/* Checks whether a character has the 'lower' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_islower(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_LOWER) != 0;
+}
+
+/* Checks whether a character has the 'print' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_isprint(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_PRINT) != 0;
+}
+
+/* Checks whether a character has the 'punct' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_ispunct(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_PUNCT) != 0;
+}
+
+/* Checks whether a character has the 'space' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_isspace(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_SPACE) != 0;
+}
+
+/* Checks whether a character has the 'upper' property in the given locale. */
+Py_LOCAL_INLINE(BOOL) locale_isupper(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch <= RE_LOCALE_MAX && (locale_info->properties[ch] &
+      RE_LOCALE_UPPER) != 0;
+}
+
+/* Converts a character to lowercase in the given locale. */
+Py_LOCAL_INLINE(Py_UCS4) locale_tolower(RE_LocaleInfo* locale_info, Py_UCS4 ch)
+  {
+    return ch <= RE_LOCALE_MAX ? locale_info->lowercase[ch] : ch;
+}
+
+/* Converts a character to uppercase in the given locale. */
+Py_LOCAL_INLINE(Py_UCS4) locale_toupper(RE_LocaleInfo* locale_info, Py_UCS4 ch)
+  {
+    return ch <= RE_LOCALE_MAX ? locale_info->uppercase[ch] : ch;
+}
+
+/* Checks whether a character has a property. */
+Py_LOCAL_INLINE(BOOL) locale_has_property(RE_LocaleInfo* locale_info, RE_CODE
+  property, Py_UCS4 ch) {
+    RE_UINT32 value;
+    RE_UINT32 v;
+
+    value = property & 0xFFFF;
+
+    if (ch > RE_LOCALE_MAX)
+        /* Outside the locale range. */
+        return value == 0;
+
+    switch (property >> 16) {
+    case RE_PROP_ALNUM >> 16:
+        v = locale_isalnum(locale_info, ch) != 0;
+        break;
+    case RE_PROP_ALPHA >> 16:
+        v = locale_isalpha(locale_info, ch) != 0;
+        break;
+    case RE_PROP_ANY >> 16:
+        v = 1;
+        break;
+    case RE_PROP_ASCII >> 16:
+        v = ch <= RE_ASCII_MAX;
+        break;
+    case RE_PROP_BLANK >> 16:
+        v = ch == '\t' || ch == ' ';
+        break;
+    case RE_PROP_GC:
+        switch (property) {
+        case RE_PROP_ASSIGNED:
+            v = ch <= RE_LOCALE_MAX;
+            break;
+        case RE_PROP_CASEDLETTER:
+            v = locale_isalpha(locale_info, ch) ? value : 0xFFFF;
+            break;
+        case RE_PROP_CNTRL:
+            v = locale_iscntrl(locale_info, ch) ? value : 0xFFFF;
+            break;
+        case RE_PROP_DIGIT:
+            v = locale_isdigit(locale_info, ch) ? value : 0xFFFF;
+            break;
+        case RE_PROP_GC_CN:
+            v = ch > RE_LOCALE_MAX;
+            break;
+        case RE_PROP_GC_LL:
+            v = locale_islower(locale_info, ch) ? value : 0xFFFF;
+            break;
+        case RE_PROP_GC_LU:
+            v = locale_isupper(locale_info, ch) ? value : 0xFFFF;
+            break;
+        case RE_PROP_GC_P:
+            v = locale_ispunct(locale_info, ch) ? value : 0xFFFF;
+            break;
+        default:
+            v = 0xFFFF;
+            break;
+        }
+        break;
+    case RE_PROP_GRAPH >> 16:
+        v = locale_isgraph(locale_info, ch) != 0;
+        break;
+    case RE_PROP_LOWER >> 16:
+        v = locale_islower(locale_info, ch) != 0;
+        break;
+    case RE_PROP_POSIX_ALNUM >> 16:
+        v = re_get_posix_alnum(ch) != 0;
+        break;
+    case RE_PROP_POSIX_DIGIT >> 16:
+        v = re_get_posix_digit(ch) != 0;
+        break;
+    case RE_PROP_POSIX_PUNCT >> 16:
+        v = re_get_posix_punct(ch) != 0;
+        break;
+    case RE_PROP_POSIX_XDIGIT >> 16:
+        v = re_get_posix_xdigit(ch) != 0;
+        break;
+    case RE_PROP_PRINT >> 16:
+        v = locale_isprint(locale_info, ch) != 0;
+        break;
+    case RE_PROP_SPACE >> 16:
+        v = locale_isspace(locale_info, ch) != 0;
+        break;
+    case RE_PROP_UPPER >> 16:
+        v = locale_isupper(locale_info, ch) != 0;
+        break;
+    case RE_PROP_WORD >> 16:
+        v = ch == '_' || locale_isalnum(locale_info, ch) != 0;
+        break;
+    case RE_PROP_XDIGIT >> 16:
+        v = re_get_hex_digit(ch) != 0;
+        break;
+    default:
+        v = 0;
+        break;
+    }
+
+    return v == value;
+}
+
+/* Wrapper for calling 'locale_has_property' via a pointer. */
+static BOOL locale_has_property_wrapper(RE_LocaleInfo* locale_info, RE_CODE
+  property, Py_UCS4 ch) {
+    return locale_has_property(locale_info, property, ch);
+}
+
+/* Checks whether there's a word character to the left. */
+Py_LOCAL_INLINE(BOOL) locale_word_left(RE_State* state, Py_ssize_t text_pos) {
+    return text_pos > 0 && locale_has_property(state->locale_info,
+      RE_PROP_WORD, state->char_at(state->text, text_pos - 1));
+}
+
+/* Checks whether there's a word character to the right. */
+Py_LOCAL_INLINE(BOOL) locale_word_right(RE_State* state, Py_ssize_t text_pos) {
+    return text_pos < state->text_length &&
+      locale_has_property(state->locale_info, RE_PROP_WORD,
+      state->char_at(state->text, text_pos));
+}
+
+/* Checks whether a position is on a word boundary. */
+static BOOL locale_at_boundary(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = locale_word_left(state, text_pos);
+    right = locale_word_right(state, text_pos);
+
+    return left != right;
+}
+
+/* Checks whether a position is at the start of a word. */
+static BOOL locale_at_word_start(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = locale_word_left(state, text_pos);
+    right = locale_word_right(state, text_pos);
+
+    return !left && right;
+}
+
+/* Checks whether a position is at the end of a word. */
+static BOOL locale_at_word_end(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = locale_word_left(state, text_pos);
+    right = locale_word_right(state, text_pos);
+
+    return left && !right;
+}
+
+/* Checks whether a character could be Turkic (variants of I/i). */
+static BOOL locale_possible_turkic(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return locale_toupper(locale_info, ch) == 'I' ||
+      locale_tolower(locale_info, ch) == 'i';
+}
+
+/* Gets all the cases of a character. */
+static int locale_all_cases(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+  codepoints) {
+    int count;
+    Py_UCS4 other;
+
+    count = 0;
+
+    codepoints[count++] = ch;
+
+    other = locale_toupper(locale_info, ch);
+    if (other != ch)
+        codepoints[count++] = other;
+
+    other = locale_tolower(locale_info, ch);
+    if (other != ch)
+        codepoints[count++] = other;
+
+    return count;
+}
+
+/* Returns a character with its case folded. */
+static Py_UCS4 locale_simple_case_fold(RE_LocaleInfo* locale_info, Py_UCS4 ch)
+  {
+    return locale_tolower(locale_info, ch);
+}
+
+/* Returns a character with its case folded. */
+static int locale_full_case_fold(RE_LocaleInfo* locale_info, Py_UCS4 ch,
+  Py_UCS4* folded) {
+    folded[0] = locale_tolower(locale_info, ch);
+
+    return 1;
+}
+
+/* Gets all the case variants of Turkic 'I'. The given character will be listed
+ * first.
+ */
+static int locale_all_turkic_i(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+  cases) {
+    int count;
+    Py_UCS4 other;
+
+    count = 0;
+
+    cases[count++] = ch;
+
+    if (ch != 'I')
+        cases[count++] = 'I';
+
+    if (ch != 'i')
+        cases[count++] = 'i';
+
+    /* Uppercase 'i' will be either dotted (Turkic) or dotless (non-Turkic). */
+    other = locale_toupper(locale_info, 'i');
+    if (other != ch && other != 'I')
+        cases[count++] = other;
+
+    /* Lowercase 'I' will be either dotless (Turkic) or dotted (non-Turkic). */
+    other = locale_tolower(locale_info, 'I');
+    if (other != ch && other != 'i')
+        cases[count++] = other;
+
+    return count;
+}
+
+/* The handlers for locale characters. */
+static RE_EncodingTable locale_encoding = {
+    locale_has_property_wrapper,
+    locale_at_boundary,
+    locale_at_word_start,
+    locale_at_word_end,
+    locale_at_boundary, /* No special "default word boundary" for locale. */
+    locale_at_word_start, /* No special "default start of a word" for locale. */
+    locale_at_word_end, /* No special "default end of a word" for locale. */
+    at_boundary_always, /* No special "grapheme boundary" for locale. */
+    ascii_is_line_sep, /* Assume locale line separators are same as ASCII. */
+    ascii_at_line_start, /* Assume locale line separators are same as ASCII. */
+    ascii_at_line_end, /* Assume locale line separators are same as ASCII. */
+    locale_possible_turkic,
+    locale_all_cases,
+    locale_simple_case_fold,
+    locale_full_case_fold,
+    locale_all_turkic_i,
+};
+
+/* Unicode-specific. */
+
+/* Checks whether a Unicode character has a property. */
+Py_LOCAL_INLINE(BOOL) unicode_has_property(RE_CODE property, Py_UCS4 ch) {
+    RE_UINT32 prop;
+    RE_UINT32 value;
+    RE_UINT32 v;
+
+    prop = property >> 16;
+    if (prop >= sizeof(re_get_property) / sizeof(re_get_property[0]))
+        return FALSE;
+
+    value = property & 0xFFFF;
+    v = re_get_property[prop](ch);
+
+    if (v == value)
+        return TRUE;
+
+    if (prop == RE_PROP_GC) {
+        switch (value) {
+        case RE_PROP_ASSIGNED:
+            return v != RE_PROP_CN;
+        case RE_PROP_C:
+            return (RE_PROP_C_MASK & (1 << v)) != 0;
+        case RE_PROP_CASEDLETTER:
+            return v == RE_PROP_LU || v == RE_PROP_LL || v == RE_PROP_LT;
+        case RE_PROP_L:
+            return (RE_PROP_L_MASK & (1 << v)) != 0;
+        case RE_PROP_M:
+            return (RE_PROP_M_MASK & (1 << v)) != 0;
+        case RE_PROP_N:
+            return (RE_PROP_N_MASK & (1 << v)) != 0;
+        case RE_PROP_P:
+            return (RE_PROP_P_MASK & (1 << v)) != 0;
+        case RE_PROP_S:
+            return (RE_PROP_S_MASK & (1 << v)) != 0;
+        case RE_PROP_Z:
+            return (RE_PROP_Z_MASK & (1 << v)) != 0;
+        }
+    }
+
+    return FALSE;
+}
+
+/* Wrapper for calling 'unicode_has_property' via a pointer. */
+static BOOL unicode_has_property_wrapper(RE_LocaleInfo* locale_info, RE_CODE
+  property, Py_UCS4 ch) {
+    return unicode_has_property(property, ch);
+}
+
+/* Checks whether there's a word character to the left. */
+Py_LOCAL_INLINE(BOOL) unicode_word_left(RE_State* state, Py_ssize_t text_pos) {
+    return text_pos > 0 && unicode_has_property(RE_PROP_WORD,
+      state->char_at(state->text, text_pos - 1));
+}
+
+/* Checks whether there's a word character to the right. */
+Py_LOCAL_INLINE(BOOL) unicode_word_right(RE_State* state, Py_ssize_t text_pos)
+  {
+    return text_pos < state->text_length && unicode_has_property(RE_PROP_WORD,
+      state->char_at(state->text, text_pos));
+}
+
+/* Checks whether a position is on a word boundary. */
+static BOOL unicode_at_boundary(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = unicode_word_left(state, text_pos);
+    right = unicode_word_right(state, text_pos);
+
+    return left != right;
+}
+
+/* Checks whether a position is at the start of a word. */
+static BOOL unicode_at_word_start(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = unicode_word_left(state, text_pos);
+    right = unicode_word_right(state, text_pos);
+
+    return !left && right;
+}
+
+/* Checks whether a position is at the end of a word. */
+static BOOL unicode_at_word_end(RE_State* state, Py_ssize_t text_pos) {
+    BOOL left;
+    BOOL right;
+
+    left = unicode_word_left(state, text_pos);
+    right = unicode_word_right(state, text_pos);
+
+    return left && !right;
+}
+
+/* Checks whether a character is a Unicode vowel.
+ *
+ * Only a limited number are treated as vowels.
+ */
+Py_LOCAL_INLINE(BOOL) is_unicode_vowel(Py_UCS4 ch) {
+    switch (Py_UNICODE_TOLOWER((Py_UNICODE)ch)) {
+    case 'a': case 0xE0: case 0xE1: case 0xE2:
+    case 'e': case 0xE8: case 0xE9: case 0xEA:
+    case 'i': case 0xEC: case 0xED: case 0xEE:
+    case 'o': case 0xF2: case 0xF3: case 0xF4:
+    case 'u': case 0xF9: case 0xFA: case 0xFB:
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+
+/* Checks whether a position is on a default word boundary.
+ *
+ * The rules are defined here:
+ * http://www.unicode.org/reports/tr29/#Default_Word_Boundaries
+ */
+static BOOL unicode_at_default_boundary(RE_State* state, Py_ssize_t text_pos) {
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    int prop;
+    int prop_m1;
+    Py_ssize_t pos_m1;
+    Py_ssize_t pos_m2;
+    int prop_m2;
+    Py_ssize_t pos_p0;
+    int prop_p0;
+    Py_ssize_t pos_p1;
+    int prop_p1;
+
+    /* Break at the start and end of the text. */
+    /* WB1 */
+    if (text_pos <= 0)
+        return TRUE;
+
+    /* WB2 */
+    if (text_pos >= state->text_length)
+        return TRUE;
+
+    char_at = state->char_at;
+
+    prop = (int)re_get_word_break(char_at(state->text, text_pos));
+    prop_m1 = (int)re_get_word_break(char_at(state->text, text_pos - 1));
+
+    /* Don't break within CRLF. */
+    /* WB3 */
+    if (prop_m1 == RE_BREAK_CR && prop == RE_BREAK_LF)
+        return FALSE;
+
+    /* Otherwise break before and after Newlines (including CR and LF). */
+    /* WB3a and WB3b */
+    if (prop_m1 == RE_BREAK_NEWLINE || prop_m1 == RE_BREAK_CR || prop_m1 ==
+      RE_BREAK_LF || prop == RE_BREAK_NEWLINE || prop == RE_BREAK_CR || prop ==
+      RE_BREAK_LF)
+        return TRUE;
+
+    /* WB4 */
+    /* Get the property of the previous character, ignoring Format and Extend
+     * characters.
+     */
+    pos_m1 = text_pos - 1;
+    prop_m1 = RE_BREAK_OTHER;
+    while (pos_m1 >= 0) {
+        prop_m1 = (int)re_get_word_break(char_at(state->text, pos_m1));
+        if (prop_m1 != RE_BREAK_EXTEND && prop_m1 != RE_BREAK_FORMAT)
+            break;
+
+        --pos_m1;
+    }
+
+    /* Get the property of the preceding character, ignoring Format and Extend
+     * characters.
+     */
+    pos_m2 = pos_m1 - 1;
+    prop_m2 = RE_BREAK_OTHER;
+    while (pos_m2 >= 0) {
+        prop_m2 = (int)re_get_word_break(char_at(state->text, pos_m2));
+        if (prop_m2 != RE_BREAK_EXTEND && prop_m2 != RE_BREAK_FORMAT)
+            break;
+
+        --pos_m2;
+    }
+
+    /* Get the property of the next character, ignoring Format and Extend
+     * characters.
+     */
+    pos_p0 = text_pos;
+    prop_p0 = prop;
+    while (pos_p0 < state->text_length) {
+        prop_p0 = (int)re_get_word_break(char_at(state->text, pos_p0));
+        if (prop_p0 != RE_BREAK_EXTEND && prop_p0 != RE_BREAK_FORMAT)
+            break;
+
+        ++pos_p0;
+    }
+
+    /* Get the property of the following character, ignoring Format and Extend
+     * characters.
+     */
+    pos_p1 = pos_p0 + 1;
+    prop_p1 = RE_BREAK_OTHER;
+    while (pos_p1 < state->text_length) {
+        prop_p1 = (int)re_get_word_break(char_at(state->text, pos_p1));
+        if (prop_p1 != RE_BREAK_EXTEND && prop_p1 != RE_BREAK_FORMAT)
+            break;
+
+        ++pos_p1;
+    }
+
+    /* Don't break between most letters. */
+    /* WB5 */
+    if ((prop_m1 == RE_BREAK_ALETTER || prop_m1 == RE_BREAK_HEBREWLETTER) &&
+      (prop_p0 == RE_BREAK_ALETTER || prop_p0 == RE_BREAK_HEBREWLETTER))
+        return FALSE;
+
+    /* Break between apostrophe and vowels (French, Italian). */
+    /* WB5a */
+    if (pos_m1 >= 0 && char_at(state->text, pos_m1) == '\'' &&
+      is_unicode_vowel(char_at(state->text, text_pos)))
+        return TRUE;
+
+    /* Don't break letters across certain punctuation. */
+    /* WB6 */
+    if ((prop_m1 == RE_BREAK_ALETTER || prop_m1 == RE_BREAK_HEBREWLETTER) &&
+      (prop_p0 == RE_BREAK_MIDLETTER || prop_p0 == RE_BREAK_MIDNUMLET ||
+      prop_p0 == RE_BREAK_SINGLEQUOTE) && (prop_p1 == RE_BREAK_ALETTER ||
+      prop_p1 == RE_BREAK_HEBREWLETTER))
+        return FALSE;
+    /* WB7 */
+    if ((prop_m2 == RE_BREAK_ALETTER || prop_m2 == RE_BREAK_HEBREWLETTER) &&
+      (prop_m1 == RE_BREAK_MIDLETTER || prop_m1 == RE_BREAK_MIDNUMLET ||
+      prop_m1 == RE_BREAK_SINGLEQUOTE) && (prop_p0 == RE_BREAK_ALETTER ||
+      prop_p0 == RE_BREAK_HEBREWLETTER))
+        return FALSE;
+    /* WB7a */
+    if (prop_m1 == RE_BREAK_HEBREWLETTER && prop_p0 == RE_BREAK_SINGLEQUOTE)
+        return FALSE;
+    /* WB7b */
+    if (prop_m1 == RE_BREAK_HEBREWLETTER && prop_p0 == RE_BREAK_DOUBLEQUOTE &&
+      prop_p1 == RE_BREAK_HEBREWLETTER)
+        return FALSE;
+    /* WB7c */
+    if (prop_m2 == RE_BREAK_HEBREWLETTER && prop_m1 == RE_BREAK_DOUBLEQUOTE &&
+      prop_p0 == RE_BREAK_HEBREWLETTER)
+        return FALSE;
+
+    /* Don't break within sequences of digits, or digits adjacent to letters
+     * ("3a", or "A3").
+     */
+    /* WB8 */
+    if (prop_m1 == RE_BREAK_NUMERIC && prop_p0 == RE_BREAK_NUMERIC)
+        return FALSE;
+    /* WB9 */
+    if ((prop_m1 == RE_BREAK_ALETTER || prop_m1 == RE_BREAK_HEBREWLETTER) &&
+      prop_p0 == RE_BREAK_NUMERIC)
+        return FALSE;
+    /* WB10 */
+    if (prop_m1 == RE_BREAK_NUMERIC && (prop_p0 == RE_BREAK_ALETTER || prop_p0
+      == RE_BREAK_HEBREWLETTER))
+        return FALSE;
+
+    /* Don't break within sequences, such as "3.2" or "3,456.789". */
+    /* WB11 */
+    if (prop_m2 == RE_BREAK_NUMERIC && (prop_m1 == RE_BREAK_MIDNUM || prop_m1
+      == RE_BREAK_MIDNUMLET || prop_m1 == RE_BREAK_SINGLEQUOTE) && prop_p0 ==
+      RE_BREAK_NUMERIC)
+        return FALSE;
+    /* WB12 */
+    if (prop_m1 == RE_BREAK_NUMERIC && (prop_p0 == RE_BREAK_MIDNUM || prop_p0
+      == RE_BREAK_MIDNUMLET || prop_p0 == RE_BREAK_SINGLEQUOTE) && prop_p1 ==
+      RE_BREAK_NUMERIC)
+        return FALSE;
+
+    /* Don't break between Katakana. */
+    /* WB13 */
+    if (prop_m1 == RE_BREAK_KATAKANA && prop_p0 == RE_BREAK_KATAKANA)
+        return FALSE;
+
+    /* Don't break from extenders. */
+    /* WB13a */
+    if ((prop_m1 == RE_BREAK_ALETTER || prop_m1 == RE_BREAK_HEBREWLETTER ||
+      prop_m1 == RE_BREAK_NUMERIC || prop_m1 == RE_BREAK_KATAKANA || prop_m1 ==
+      RE_BREAK_EXTENDNUMLET) && prop_p0 == RE_BREAK_EXTENDNUMLET)
+        return FALSE;
+    /* WB13b */
+    if (prop_m1 == RE_BREAK_EXTENDNUMLET && (prop_p0 == RE_BREAK_ALETTER ||
+      prop_p0 == RE_BREAK_HEBREWLETTER || prop_p0 == RE_BREAK_NUMERIC ||
+      prop_p0 == RE_BREAK_KATAKANA))
+        return FALSE;
+
+    /* Don't break between regional indicator symbols. */
+    /* WB13c */
+    if (prop_m1 == RE_BREAK_REGIONALINDICATOR && prop_p0 ==
+      RE_BREAK_REGIONALINDICATOR)
+        return FALSE;
+
+    /* Otherwise, break everywhere (including around ideographs). */
+    /* WB14 */
+    return TRUE;
+}
+
+/* Checks whether a position is at the start/end of a word. */
+Py_LOCAL_INLINE(BOOL) unicode_at_default_word_start_or_end(RE_State* state,
+  Py_ssize_t text_pos, BOOL at_start) {
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    BOOL before;
+    BOOL after;
+    Py_UCS4 char_0;
+    Py_UCS4 char_m1;
+    int prop;
+    int prop_m1;
+    Py_ssize_t pos_m1;
+    Py_ssize_t pos_p1;
+    int prop_p1;
+    Py_UCS4 char_p1;
+    Py_ssize_t pos_m2;
+    int prop_m2;
+    Py_UCS4 char_m2;
+
+    char_at = state->char_at;
+
+    /* At the start or end of the text. */
+    if (text_pos <= 0 || text_pos >= state->text_length) {
+        before = unicode_word_left(state, text_pos);
+        after = unicode_word_right(state, text_pos);
+
+        return before != at_start && after == at_start;
+    }
+
+    char_0 = char_at(state->text, text_pos);
+    char_m1 = char_at(state->text, text_pos - 1);
+    prop = (int)re_get_word_break(char_0);
+    prop_m1 = (int)re_get_word_break(char_m1);
+
+    /* No break within CRLF. */
+    if (prop_m1 == RE_BREAK_CR && prop == RE_BREAK_LF)
+        return FALSE;
+
+    /* Break before and after Newlines (including CR and LF). */
+    if (prop_m1 == RE_BREAK_NEWLINE || prop_m1 == RE_BREAK_CR || prop_m1 ==
+      RE_BREAK_LF || prop == RE_BREAK_NEWLINE || prop == RE_BREAK_CR || prop ==
+      RE_BREAK_LF) {
+        before = unicode_has_property(RE_PROP_WORD, char_m1);
+        after = unicode_has_property(RE_PROP_WORD, char_0);
+
+        return before != at_start && after == at_start;
+    }
+
+    /* No break just before Format or Extend characters. */
+    if (prop == RE_BREAK_EXTEND || prop == RE_BREAK_FORMAT)
+        return FALSE;
+
+    /* Get the property of the previous character. */
+    pos_m1 = text_pos - 1;
+    prop_m1 = RE_BREAK_OTHER;
+    while (pos_m1 >= 0) {
+        char_m1 = char_at(state->text, pos_m1);
+        prop_m1 = (int)re_get_word_break(char_m1);
+        if (prop_m1 != RE_BREAK_EXTEND && prop_m1 != RE_BREAK_FORMAT)
+            break;
+
+        --pos_m1;
+    }
+
+    /* No break between most letters. */
+    if (prop_m1 == RE_BREAK_ALETTER && prop == RE_BREAK_ALETTER)
+        return FALSE;
+
+    if (pos_m1 >= 0 && char_m1 == '\'' && is_unicode_vowel(char_0))
+        return TRUE;
+
+    pos_p1 = text_pos + 1;
+    prop_p1 = RE_BREAK_OTHER;
+    while (pos_p1 < state->text_length) {
+        char_p1 = char_at(state->text, pos_p1);
+        prop_p1 = (int)re_get_word_break(char_p1);
+        if (prop_p1 != RE_BREAK_EXTEND && prop_p1 != RE_BREAK_FORMAT)
+            break;
+
+        ++pos_p1;
+    }
+
+    /* No break letters across certain punctuation. */
+    if (prop_m1 == RE_BREAK_ALETTER && (prop == RE_BREAK_MIDLETTER || prop ==
+      RE_BREAK_MIDNUMLET) && prop_p1 == RE_BREAK_ALETTER)
+        return FALSE;
+
+    pos_m2 = pos_m1 - 1;
+    prop_m2 = RE_BREAK_OTHER;
+    while (pos_m2 >= 0) {
+        char_m2 = char_at(state->text, pos_m2);
+        prop_m2 = (int)re_get_word_break(char_m2);
+        if (prop_m2 != RE_BREAK_EXTEND && prop_m1 != RE_BREAK_FORMAT)
+            break;
+
+        --pos_m2;
+    }
+
+    if (prop_m2 == RE_BREAK_ALETTER && (prop_m1 == RE_BREAK_MIDLETTER ||
+      prop_m1 == RE_BREAK_MIDNUMLET) && prop == RE_BREAK_ALETTER)
+        return FALSE;
+
+    /* No break within sequences of digits, or digits adjacent to letters
+     * ("3a", or "A3").
+     */
+    if ((prop_m1 == RE_BREAK_NUMERIC || prop_m1 == RE_BREAK_ALETTER) && prop ==
+      RE_BREAK_NUMERIC)
+        return FALSE;
+
+    if (prop_m1 == RE_BREAK_NUMERIC && prop == RE_BREAK_ALETTER)
+        return FALSE;
+
+    /* No break within sequences, such as "3.2" or "3,456.789". */
+    if (prop_m2 == RE_BREAK_NUMERIC && (prop_m1 == RE_BREAK_MIDNUM || prop_m1
+      == RE_BREAK_MIDNUMLET) && prop == RE_BREAK_NUMERIC)
+        return FALSE;
+
+    if (prop_m1 == RE_BREAK_NUMERIC && (prop == RE_BREAK_MIDNUM || prop ==
+      RE_BREAK_MIDNUMLET) && prop_p1 == RE_BREAK_NUMERIC)
+        return FALSE;
+
+    /* No break between Katakana. */
+    if (prop_m1 == RE_BREAK_KATAKANA && prop == RE_BREAK_KATAKANA)
+        return FALSE;
+
+    /* No break from extenders. */
+    if ((prop_m1 == RE_BREAK_ALETTER || prop_m1 == RE_BREAK_NUMERIC || prop_m1
+      == RE_BREAK_KATAKANA || prop_m1 == RE_BREAK_EXTENDNUMLET) && prop ==
+      RE_BREAK_EXTENDNUMLET)
+        return FALSE;
+
+    if (prop_m1 == RE_BREAK_EXTENDNUMLET && (prop == RE_BREAK_ALETTER || prop
+      == RE_BREAK_NUMERIC || prop == RE_BREAK_KATAKANA))
+        return FALSE;
+
+    /* Otherwise, break everywhere (including around ideographs). */
+    before = unicode_has_property(RE_PROP_WORD, char_m1);
+    after = unicode_has_property(RE_PROP_WORD, char_0);
+
+    return before != at_start && after == at_start;
+}
+
+/* Checks whether a position is at the start of a word. */
+static BOOL unicode_at_default_word_start(RE_State* state, Py_ssize_t text_pos)
+  {
+    return unicode_at_default_word_start_or_end(state, text_pos, TRUE);
+}
+
+/* Checks whether a position is at the end of a word. */
+static BOOL unicode_at_default_word_end(RE_State* state, Py_ssize_t text_pos) {
+    return unicode_at_default_word_start_or_end(state, text_pos, FALSE);
+}
+
+/* Checks whether a position is on a grapheme boundary.
+ *
+ * The rules are defined here:
+ * http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
+ */
+static BOOL unicode_at_grapheme_boundary(RE_State* state, Py_ssize_t text_pos)
+  {
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    int prop;
+    int prop_m1;
+
+    /* Break at the start and end of the text. */
+    /* GB1 */
+    if (text_pos <= 0)
+        return TRUE;
+
+    /* GB2 */
+    if (text_pos >= state->text_length)
+        return TRUE;
+
+    char_at = state->char_at;
+
+    prop = (int)re_get_grapheme_cluster_break(char_at(state->text, text_pos));
+    prop_m1 = (int)re_get_grapheme_cluster_break(char_at(state->text, text_pos
+      - 1));
+
+    /* Don't break within CRLF. */
+    /* GB3 */
+    if (prop_m1 == RE_GBREAK_CR && prop == RE_GBREAK_LF)
+        return FALSE;
+
+    /* Otherwise break before and after controls (including CR and LF). */
+    /* GB4 and GB5 */
+    if (prop_m1 == RE_GBREAK_CONTROL || prop_m1 == RE_GBREAK_CR || prop_m1 ==
+      RE_GBREAK_LF || prop == RE_GBREAK_CONTROL || prop == RE_GBREAK_CR || prop
+      == RE_GBREAK_LF)
+        return TRUE;
+
+    /* Don't break Hangul syllable sequences. */
+    /* GB6 */
+    if (prop_m1 == RE_GBREAK_L && (prop == RE_GBREAK_L || prop == RE_GBREAK_V
+      || prop == RE_GBREAK_LV || prop == RE_GBREAK_LVT))
+        return FALSE;
+    /* GB7 */
+    if ((prop_m1 == RE_GBREAK_LV || prop_m1 == RE_GBREAK_V) && (prop ==
+      RE_GBREAK_V || prop == RE_GBREAK_T))
+        return FALSE;
+    /* GB8 */
+    if ((prop_m1 == RE_GBREAK_LVT || prop_m1 == RE_GBREAK_T) && (prop ==
+      RE_GBREAK_T))
+        return FALSE;
+
+    /* Don't break between regional indicator symbols. */
+    /* GB8a */
+    if (prop_m1 == RE_GBREAK_REGIONALINDICATOR && prop ==
+      RE_GBREAK_REGIONALINDICATOR)
+        return FALSE;
+
+    /* Don't break just before Extend characters. */
+    /* GB9 */
+    if (prop == RE_GBREAK_EXTEND)
+        return FALSE;
+
+    /* Don't break before SpacingMarks, or after Prepend characters. */
+    /* GB9a */
+    if (prop == RE_GBREAK_SPACINGMARK)
+        return FALSE;
+
+    /* GB9b */
+    if (prop_m1 == RE_GBREAK_PREPEND)
+        return FALSE;
+
+    /* Otherwise, break everywhere. */
+    /* GB10 */
+    return TRUE;
+}
+
+/* Checks whether a character is a line separator. */
+static BOOL unicode_is_line_sep(Py_UCS4 ch) {
+    return (0x0A <= ch && ch <= 0x0D) || ch == 0x85 || ch == 0x2028 || ch ==
+      0x2029;
+}
+
+/* Checks whether a position is at the start of a line. */
+static BOOL unicode_at_line_start(RE_State* state, Py_ssize_t text_pos) {
+    Py_UCS4 ch;
+
+    if (text_pos <= 0)
+        return TRUE;
+
+    ch = state->char_at(state->text, text_pos - 1);
+
+    if (ch == 0x0D) {
+        if (text_pos >= state->text_length)
+            return TRUE;
+
+        /* No line break inside CRLF. */
+        return state->char_at(state->text, text_pos) != 0x0A;
+    }
+
+    return (0x0A <= ch && ch <= 0x0D) || ch == 0x85 || ch == 0x2028 || ch ==
+      0x2029;
+}
+
+/* Checks whether a position is at the end of a line. */
+static BOOL unicode_at_line_end(RE_State* state, Py_ssize_t text_pos) {
+    Py_UCS4 ch;
+
+    if (text_pos >= state->text_length)
+        return TRUE;
+
+    ch = state->char_at(state->text, text_pos);
+
+    if (ch == 0x0A) {
+        if (text_pos <= 0)
+            return TRUE;
+
+        /* No line break inside CRLF. */
+        return state->char_at(state->text, text_pos - 1) != 0x0D;
+    }
+
+    return (0x0A <= ch && ch <= 0x0D) || ch == 0x85 || ch == 0x2028 || ch ==
+      0x2029;
+}
+
+/* Checks whether a character could be Turkic (variants of I/i). */
+static BOOL unicode_possible_turkic(RE_LocaleInfo* locale_info, Py_UCS4 ch) {
+    return ch == 'I' || ch == 'i' || ch == 0x0130 || ch == 0x0131;
+}
+
+/* Gets all the cases of a character. */
+static int unicode_all_cases(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+  codepoints) {
+    return re_get_all_cases(ch, codepoints);
+}
+
+/* Returns a character with its case folded, unless it could be Turkic
+ * (variants of I/i).
+ */
+static Py_UCS4 unicode_simple_case_fold(RE_LocaleInfo* locale_info, Py_UCS4 ch)
+  {
+    /* Is it a possible Turkic character? If so, pass it through unchanged. */
+    if (ch == 'I' || ch == 'i' || ch == 0x0130 || ch == 0x0131)
+        return ch;
+
+    return (Py_UCS4)re_get_simple_case_folding(ch);
+}
+
+/* Returns a character with its case folded, unless it could be Turkic
+ * (variants of I/i).
+ */
+static int unicode_full_case_fold(RE_LocaleInfo* locale_info, Py_UCS4 ch,
+  Py_UCS4* folded) {
+    /* Is it a possible Turkic character? If so, pass it through unchanged. */
+    if (ch == 'I' || ch == 'i' || ch == 0x0130 || ch == 0x0131) {
+        folded[0] = ch;
+        return 1;
+    }
+
+    return re_get_full_case_folding(ch, folded);
+}
+
+/* Gets all the case variants of Turkic 'I'. */
+static int unicode_all_turkic_i(RE_LocaleInfo* locale_info, Py_UCS4 ch,
+  Py_UCS4* cases) {
+    int count;
+
+    count = 0;
+
+    cases[count++] = ch;
+
+    if (ch != 'I')
+        cases[count++] = 'I';
+
+    if (ch != 'i')
+        cases[count++] = 'i';
+
+    if (ch != 0x130)
+        cases[count++] = 0x130;
+
+    if (ch != 0x131)
+        cases[count++] = 0x131;
+
+    return count;
+
+}
+
+/* The handlers for Unicode characters. */
+static RE_EncodingTable unicode_encoding = {
+    unicode_has_property_wrapper,
+    unicode_at_boundary,
+    unicode_at_word_start,
+    unicode_at_word_end,
+    unicode_at_default_boundary,
+    unicode_at_default_word_start,
+    unicode_at_default_word_end,
+    unicode_at_grapheme_boundary,
+    unicode_is_line_sep,
+    unicode_at_line_start,
+    unicode_at_line_end,
+    unicode_possible_turkic,
+    unicode_all_cases,
+    unicode_simple_case_fold,
+    unicode_full_case_fold,
+    unicode_all_turkic_i,
+};
+
+Py_LOCAL_INLINE(PyObject*) get_object(char* module_name, char* object_name);
+
+/* Sets the error message. */
+Py_LOCAL_INLINE(void) set_error(int status, PyObject* object) {
+    TRACE(("<<set_error>>\n"))
+
+    if (!error_exception)
+        error_exception = get_object("_" RE_MODULE "_core", "error");
+
+    switch (status) {
+    case RE_ERROR_BACKTRACKING:
+        PyErr_SetString(error_exception, "too much backtracking");
+        break;
+    case RE_ERROR_CONCURRENT:
+        PyErr_SetString(PyExc_ValueError, "concurrent not int or None");
+        break;
+    case RE_ERROR_GROUP_INDEX_TYPE:
+        if (object)
+            PyErr_Format(PyExc_TypeError,
+              "group indices must be integers or strings, not %.200s",
+              object->ob_type->tp_name);
+        else
+            PyErr_Format(PyExc_TypeError,
+              "group indices must be integers or strings");
+        break;
+    case RE_ERROR_ILLEGAL:
+        PyErr_SetString(PyExc_RuntimeError, "invalid RE code");
+        break;
+    case RE_ERROR_INDEX:
+        PyErr_SetString(PyExc_TypeError, "string indices must be integers");
+        break;
+    case RE_ERROR_INTERRUPTED:
+        /* An exception has already been raised, so let it fly. */
+        break;
+    case RE_ERROR_INVALID_GROUP_REF:
+        PyErr_SetString(error_exception, "invalid group reference");
+        break;
+    case RE_ERROR_MEMORY:
+        PyErr_NoMemory();
+        break;
+    case RE_ERROR_NOT_STRING:
+        PyErr_Format(PyExc_TypeError, "expected string instance, %.200s found",
+          object->ob_type->tp_name);
+        break;
+    case RE_ERROR_NOT_UNICODE:
+        PyErr_Format(PyExc_TypeError, "expected unicode instance, not %.200s",
+          object->ob_type->tp_name);
+        break;
+    case RE_ERROR_NO_SUCH_GROUP:
+        PyErr_SetString(PyExc_IndexError, "no such group");
+        break;
+    case RE_ERROR_REPLACEMENT:
+        PyErr_SetString(error_exception, "invalid replacement");
+        break;
+    default:
+        /* Other error codes indicate compiler/engine bugs. */
+        PyErr_SetString(PyExc_RuntimeError,
+          "internal error in regular expression engine");
+        break;
+    }
+}
+
+/* Allocates memory.
+ *
+ * Sets the Python error handler and returns NULL if the allocation fails.
+ */
+Py_LOCAL_INLINE(void*) re_alloc(size_t size) {
+    void* new_ptr;
+
+    new_ptr = PyMem_Malloc(size);
+    if (!new_ptr)
+        set_error(RE_ERROR_MEMORY, NULL);
+
+    return new_ptr;
+}
+
+/* Reallocates memory.
+ *
+ * Sets the Python error handler and returns NULL if the reallocation fails.
+ */
+Py_LOCAL_INLINE(void*) re_realloc(void* ptr, size_t size) {
+    void* new_ptr;
+
+    new_ptr = PyMem_Realloc(ptr, size);
+    if (!new_ptr)
+        set_error(RE_ERROR_MEMORY, NULL);
+
+    return new_ptr;
+}
+
+/* Deallocates memory. */
+Py_LOCAL_INLINE(void) re_dealloc(void* ptr) {
+    PyMem_Free(ptr);
+}
+
+/* Releases the GIL if multithreading is enabled. */
+Py_LOCAL_INLINE(void) release_GIL(RE_SafeState* safe_state) {
+    if (safe_state->re_state->is_multithreaded)
+        safe_state->thread_state = PyEval_SaveThread();
+}
+
+/* Acquires the GIL if multithreading is enabled. */
+Py_LOCAL_INLINE(void) acquire_GIL(RE_SafeState* safe_state) {
+    if (safe_state->re_state->is_multithreaded)
+        PyEval_RestoreThread(safe_state->thread_state);
+}
+
+/* Allocates memory, holding the GIL during the allocation.
+ *
+ * Sets the Python error handler and returns NULL if the allocation fails.
+ */
+Py_LOCAL_INLINE(void*) safe_alloc(RE_SafeState* safe_state, size_t size) {
+    void* new_ptr;
+
+    acquire_GIL(safe_state);
+
+    new_ptr = re_alloc(size);
+
+    release_GIL(safe_state);
+
+    return new_ptr;
+}
+
+/* Reallocates memory, holding the GIL during the reallocation.
+ *
+ * Sets the Python error handler and returns NULL if the reallocation fails.
+ */
+Py_LOCAL_INLINE(void*) safe_realloc(RE_SafeState* safe_state, void* ptr, size_t
+  size) {
+    void* new_ptr;
+
+    acquire_GIL(safe_state);
+
+    new_ptr = re_realloc(ptr, size);
+
+    release_GIL(safe_state);
+
+    return new_ptr;
+}
+
+/* Deallocates memory, holding the GIL during the deallocation. */
+Py_LOCAL_INLINE(void) safe_dealloc(RE_SafeState* safe_state, void* ptr) {
+    acquire_GIL(safe_state);
+
+    re_dealloc(ptr);
+
+    release_GIL(safe_state);
+}
+
+/* Checks for KeyboardInterrupt, holding the GIL during the check. */
+Py_LOCAL_INLINE(BOOL) safe_check_signals(RE_SafeState* safe_state) {
+    BOOL result;
+
+    acquire_GIL(safe_state);
+
+    result = (BOOL)PyErr_CheckSignals();
+
+    release_GIL(safe_state);
+
+    return result;
+}
+
+/* Checks whether a character is in a range. */
+Py_LOCAL_INLINE(BOOL) in_range(Py_UCS4 lower, Py_UCS4 upper, Py_UCS4 ch) {
+    return lower <= ch && ch <= upper;
+}
+
+/* Checks whether a character is in a range, ignoring case. */
+Py_LOCAL_INLINE(BOOL) in_range_ign(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, Py_UCS4 lower, Py_UCS4 upper, Py_UCS4 ch) {
+    int count;
+    Py_UCS4 cases[RE_MAX_CASES];
+    int i;
+
+    count = encoding->all_cases(locale_info, ch, cases);
+
+    for (i = 0; i < count; i++) {
+        if (in_range(lower, upper, cases[i]))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Checks whether 2 characters are the same. */
+Py_LOCAL_INLINE(BOOL) same_char(Py_UCS4 ch1, Py_UCS4 ch2) {
+    return ch1 == ch2;
+}
+
+/* Wrapper for calling 'same_char' via a pointer. */
+static BOOL same_char_wrapper(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, Py_UCS4 ch1, Py_UCS4 ch2) {
+    return same_char(ch1, ch2);
+}
+
+/* Checks whether 2 characters are the same, ignoring case. */
+Py_LOCAL_INLINE(BOOL) same_char_ign(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, Py_UCS4 ch1, Py_UCS4 ch2) {
+    int count;
+    Py_UCS4 cases[RE_MAX_CASES];
+    int i;
+
+    if (ch1 == ch2)
+        return TRUE;
+
+    count = encoding->all_cases(locale_info, ch1, cases);
+
+    for (i = 1; i < count; i++) {
+        if (cases[i] == ch2)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Wrapper for calling 'same_char' via a pointer. */
+static BOOL same_char_ign_wrapper(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, Py_UCS4 ch1, Py_UCS4 ch2) {
+    return same_char_ign(encoding, locale_info, ch1, ch2);
+}
+
+/* Checks whether a character is anything except a newline. */
+Py_LOCAL_INLINE(BOOL) matches_ANY(RE_EncodingTable* encoding, RE_Node* node,
+  Py_UCS4 ch) {
+    return ch != '\n';
+}
+
+/* Checks whether a character is anything except a line separator. */
+Py_LOCAL_INLINE(BOOL) matches_ANY_U(RE_EncodingTable* encoding, RE_Node* node,
+  Py_UCS4 ch) {
+    return !encoding->is_line_sep(ch);
+}
+
+/* Checks whether 2 characters are the same. */
+Py_LOCAL_INLINE(BOOL) matches_CHARACTER(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch) {
+    return same_char(node->values[0], ch);
+}
+
+/* Checks whether 2 characters are the same, ignoring case. */
+Py_LOCAL_INLINE(BOOL) matches_CHARACTER_IGN(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch) {
+    return same_char_ign(encoding, locale_info, node->values[0], ch);
+}
+
+/* Checks whether a character has a property. */
+Py_LOCAL_INLINE(BOOL) matches_PROPERTY(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch) {
+    return encoding->has_property(locale_info, node->values[0], ch);
+}
+
+/* Checks whether a character has a property, ignoring case. */
+Py_LOCAL_INLINE(BOOL) matches_PROPERTY_IGN(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch) {
+    RE_UINT32 property;
+    RE_UINT32 prop;
+
+    property = node->values[0];
+    prop = property >> 16;
+
+    /* We need to do special handling of case-sensitive properties according to
+     * the 'encoding'.
+     */
+    if (encoding == &unicode_encoding) {
+        /* We are working with Unicode. */
+        if (property == RE_PROP_GC_LU || property == RE_PROP_GC_LL || property
+          == RE_PROP_GC_LT) {
+            RE_UINT32 value;
+
+            value = re_get_general_category(ch);
+
+            return value == RE_PROP_LU || value == RE_PROP_LL || value ==
+              RE_PROP_LT;
+        } else if (prop == RE_PROP_UPPERCASE || prop == RE_PROP_LOWERCASE)
+            return (BOOL)re_get_cased(ch);
+
+        /* The property is case-insensitive. */
+        return unicode_has_property(property, ch);
+    } else if (encoding == &ascii_encoding) {
+        /* We are working with ASCII. */
+        if (property == RE_PROP_GC_LU || property == RE_PROP_GC_LL || property
+          == RE_PROP_GC_LT) {
+            RE_UINT32 value;
+
+            value = re_get_general_category(ch);
+
+            return value == RE_PROP_LU || value == RE_PROP_LL || value ==
+              RE_PROP_LT;
+        } else if (prop == RE_PROP_UPPERCASE || prop == RE_PROP_LOWERCASE)
+            return (BOOL)re_get_cased(ch);
+
+        /* The property is case-insensitive. */
+        return ascii_has_property(property, ch);
+    } else {
+        /* We are working with Locale. */
+        if (property == RE_PROP_GC_LU || property == RE_PROP_GC_LL || property
+          == RE_PROP_GC_LT)
+            return locale_isupper(locale_info, ch) ||
+              locale_islower(locale_info, ch);
+        else if (prop == RE_PROP_UPPERCASE || prop == RE_PROP_LOWERCASE)
+            return locale_isupper(locale_info, ch) ||
+              locale_islower(locale_info, ch);
+
+        /* The property is case-insensitive. */
+        return locale_has_property(locale_info, property, ch);
+    }
+}
+
+/* Checks whether a character is in a range. */
+Py_LOCAL_INLINE(BOOL) matches_RANGE(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, RE_Node* node, Py_UCS4 ch) {
+    return in_range(node->values[0], node->values[1], ch);
+}
+
+/* Checks whether a character is in a range, ignoring case. */
+Py_LOCAL_INLINE(BOOL) matches_RANGE_IGN(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch) {
+    return in_range_ign(encoding, locale_info, node->values[0],
+      node->values[1], ch);
+}
+
+Py_LOCAL_INLINE(BOOL) in_set_diff(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, RE_Node* node, Py_UCS4 ch);
+Py_LOCAL_INLINE(BOOL) in_set_inter(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, RE_Node* node, Py_UCS4 ch);
+Py_LOCAL_INLINE(BOOL) in_set_sym_diff(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch);
+Py_LOCAL_INLINE(BOOL) in_set_union(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, RE_Node* node, Py_UCS4 ch);
+
+/* Checks whether a character matches a set member. */
+Py_LOCAL_INLINE(BOOL) matches_member(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, RE_Node* member, Py_UCS4 ch) {
+    switch (member->op) {
+    case RE_OP_CHARACTER:
+        /* values are: char_code */
+        TRACE(("%s %d %d\n", re_op_text[member->op], member->match,
+          member->values[0]))
+        return ch == member->values[0];
+    case RE_OP_PROPERTY:
+        /* values are: property */
+        TRACE(("%s %d %d\n", re_op_text[member->op], member->match,
+          member->values[0]))
+        return encoding->has_property(locale_info, member->values[0], ch);
+    case RE_OP_RANGE:
+        /* values are: lower, upper */
+        TRACE(("%s %d %d %d\n", re_op_text[member->op], member->match,
+          member->values[0], member->values[1]))
+        return in_range(member->values[0], member->values[1], ch);
+    case RE_OP_SET_DIFF:
+        TRACE(("%s\n", re_op_text[member->op]))
+        return in_set_diff(encoding, locale_info, member, ch);
+    case RE_OP_SET_INTER:
+        TRACE(("%s\n", re_op_text[member->op]))
+        return in_set_inter(encoding, locale_info, member, ch);
+    case RE_OP_SET_SYM_DIFF:
+        TRACE(("%s\n", re_op_text[member->op]))
+        return in_set_sym_diff(encoding, locale_info, member, ch);
+    case RE_OP_SET_UNION:
+        TRACE(("%s\n", re_op_text[member->op]))
+        return in_set_union(encoding, locale_info, member, ch);
+    case RE_OP_STRING:
+    {
+        /* values are: char_code, char_code, ... */
+        size_t i;
+        TRACE(("%s %d %d\n", re_op_text[member->op], member->match,
+          member->value_count))
+
+        for (i = 0; i < member->value_count; i++) {
+            if (ch == member->values[i])
+                return TRUE;
+        }
+        return FALSE;
+    }
+    default:
+        return FALSE;
+    }
+}
+
+/* Checks whether a character matches a set member, ignoring case. */
+Py_LOCAL_INLINE(BOOL) matches_member_ign(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* member, int case_count, Py_UCS4* cases)
+  {
+    int i;
+
+    for (i = 0; i < case_count; i++) {
+        switch (member->op) {
+        case RE_OP_CHARACTER:
+            /* values are: char_code */
+            TRACE(("%s %d %d\n", re_op_text[member->op], member->match,
+              member->values[0]))
+            if (cases[i] == member->values[0])
+                return TRUE;
+            break;
+        case RE_OP_PROPERTY:
+            /* values are: property */
+            TRACE(("%s %d %d\n", re_op_text[member->op], member->match,
+              member->values[0]))
+            if (encoding->has_property(locale_info, member->values[0],
+              cases[i]))
+                return TRUE;
+            break;
+        case RE_OP_RANGE:
+            /* values are: lower, upper */
+            TRACE(("%s %d %d %d\n", re_op_text[member->op], member->match,
+              member->values[0], member->values[1]))
+            if (in_range(member->values[0], member->values[1], cases[i]))
+                return TRUE;
+            break;
+        case RE_OP_SET_DIFF:
+            TRACE(("%s\n", re_op_text[member->op]))
+            if (in_set_diff(encoding, locale_info, member, cases[i]))
+                return TRUE;
+            break;
+        case RE_OP_SET_INTER:
+            TRACE(("%s\n", re_op_text[member->op]))
+            if (in_set_inter(encoding, locale_info, member, cases[i]))
+                return TRUE;
+            break;
+        case RE_OP_SET_SYM_DIFF:
+            TRACE(("%s\n", re_op_text[member->op]))
+            if (in_set_sym_diff(encoding, locale_info, member, cases[i]))
+                return TRUE;
+            break;
+        case RE_OP_SET_UNION:
+            TRACE(("%s\n", re_op_text[member->op]))
+            if (in_set_union(encoding, locale_info, member, cases[i]))
+                return TRUE;
+            break;
+        case RE_OP_STRING:
+        {
+            size_t j;
+            TRACE(("%s %d %d\n", re_op_text[member->op], member->match,
+              member->value_count))
+
+            for (j = 0; j < member->value_count; j++) {
+                if (cases[i] == member->values[j])
+                    return TRUE;
+            }
+            break;
+        }
+        default:
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+/* Checks whether a character is in a set difference. */
+Py_LOCAL_INLINE(BOOL) in_set_diff(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, RE_Node* node, Py_UCS4 ch) {
+    RE_Node* member;
+
+    member = node->nonstring.next_2.node;
+
+    if (matches_member(encoding, locale_info, member, ch) != member->match)
+        return FALSE;
+
+    member = member->next_1.node;
+
+    while (member) {
+        if (matches_member(encoding, locale_info, member, ch) == member->match)
+            return FALSE;
+
+        member = member->next_1.node;
+    }
+
+    return TRUE;
+}
+
+/* Checks whether a character is in a set difference, ignoring case. */
+Py_LOCAL_INLINE(BOOL) in_set_diff_ign(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, int case_count, Py_UCS4* cases) {
+    RE_Node* member;
+
+    member = node->nonstring.next_2.node;
+
+    if (matches_member_ign(encoding, locale_info, member, case_count, cases) !=
+      member->match)
+        return FALSE;
+
+    member = member->next_1.node;
+
+    while (member) {
+        if (matches_member_ign(encoding, locale_info, member, case_count,
+          cases) == member->match)
+            return FALSE;
+
+        member = member->next_1.node;
+    }
+
+    return TRUE;
+}
+
+/* Checks whether a character is in a set intersection. */
+Py_LOCAL_INLINE(BOOL) in_set_inter(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, RE_Node* node, Py_UCS4 ch) {
+    RE_Node* member;
+
+    member = node->nonstring.next_2.node;
+
+    while (member) {
+        if (matches_member(encoding, locale_info, member, ch) != member->match)
+            return FALSE;
+
+        member = member->next_1.node;
+    }
+
+    return TRUE;
+}
+
+/* Checks whether a character is in a set intersection, ignoring case. */
+Py_LOCAL_INLINE(BOOL) in_set_inter_ign(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, int case_count, Py_UCS4* cases) {
+    RE_Node* member;
+
+    member = node->nonstring.next_2.node;
+
+    while (member) {
+        if (matches_member_ign(encoding, locale_info, member, case_count,
+          cases) != member->match)
+            return FALSE;
+
+        member = member->next_1.node;
+    }
+
+    return TRUE;
+}
+
+/* Checks whether a character is in a set symmetric difference. */
+Py_LOCAL_INLINE(BOOL) in_set_sym_diff(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch) {
+    RE_Node* member;
+    BOOL result;
+
+    member = node->nonstring.next_2.node;
+
+    result = FALSE;
+
+    while (member) {
+        if (matches_member(encoding, locale_info, member, ch) == member->match)
+            result = !result;
+
+        member = member->next_1.node;
+    }
+
+    return result;
+}
+
+/* Checks whether a character is in a set symmetric difference, ignoring case.
+ */
+Py_LOCAL_INLINE(BOOL) in_set_sym_diff_ign(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, int case_count, Py_UCS4* cases) {
+    RE_Node* member;
+    BOOL result;
+
+    member = node->nonstring.next_2.node;
+
+    result = FALSE;
+
+    while (member) {
+        if (matches_member_ign(encoding, locale_info, member, case_count,
+          cases) == member->match)
+            result = !result;
+
+        member = member->next_1.node;
+    }
+
+    return result;
+}
+
+/* Checks whether a character is in a set union. */
+Py_LOCAL_INLINE(BOOL) in_set_union(RE_EncodingTable* encoding, RE_LocaleInfo*
+  locale_info, RE_Node* node, Py_UCS4 ch) {
+    RE_Node* member;
+
+    member = node->nonstring.next_2.node;
+
+    while (member) {
+        if (matches_member(encoding, locale_info, member, ch) == member->match)
+            return TRUE;
+
+        member = member->next_1.node;
+    }
+
+    return FALSE;
+}
+
+/* Checks whether a character is in a set union, ignoring case. */
+Py_LOCAL_INLINE(BOOL) in_set_union_ign(RE_EncodingTable* encoding,
+  RE_LocaleInfo* locale_info, RE_Node* node, int case_count, Py_UCS4* cases) {
+    RE_Node* member;
+
+    member = node->nonstring.next_2.node;
+
+    while (member) {
+        if (matches_member_ign(encoding, locale_info, member, case_count,
+          cases) == member->match)
+            return TRUE;
+
+        member = member->next_1.node;
+    }
+
+    return FALSE;
+}
+
+/* Checks whether a character is in a set. */
+Py_LOCAL_INLINE(BOOL) matches_SET(RE_EncodingTable* encoding,
+RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch) {
+    switch (node->op) {
+    case RE_OP_SET_DIFF:
+    case RE_OP_SET_DIFF_REV:
+        return in_set_diff(encoding, locale_info, node, ch);
+    case RE_OP_SET_INTER:
+    case RE_OP_SET_INTER_REV:
+        return in_set_inter(encoding, locale_info, node, ch);
+    case RE_OP_SET_SYM_DIFF:
+    case RE_OP_SET_SYM_DIFF_REV:
+        return in_set_sym_diff(encoding, locale_info, node, ch);
+    case RE_OP_SET_UNION:
+    case RE_OP_SET_UNION_REV:
+        return in_set_union(encoding, locale_info, node, ch);
+    }
+
+    return FALSE;
+}
+
+/* Checks whether a character is in a set, ignoring case. */
+Py_LOCAL_INLINE(BOOL) matches_SET_IGN(RE_EncodingTable* encoding,
+RE_LocaleInfo* locale_info, RE_Node* node, Py_UCS4 ch) {
+    Py_UCS4 cases[RE_MAX_CASES];
+    int case_count;
+
+    case_count = encoding->all_cases(locale_info, ch, cases);
+
+    switch (node->op) {
+    case RE_OP_SET_DIFF_IGN:
+    case RE_OP_SET_DIFF_IGN_REV:
+        return in_set_diff_ign(encoding, locale_info, node, case_count, cases);
+    case RE_OP_SET_INTER_IGN:
+    case RE_OP_SET_INTER_IGN_REV:
+        return in_set_inter_ign(encoding, locale_info, node, case_count,
+          cases);
+    case RE_OP_SET_SYM_DIFF_IGN:
+    case RE_OP_SET_SYM_DIFF_IGN_REV:
+        return in_set_sym_diff_ign(encoding, locale_info, node, case_count,
+          cases);
+    case RE_OP_SET_UNION_IGN:
+    case RE_OP_SET_UNION_IGN_REV:
+        return in_set_union_ign(encoding, locale_info, node, case_count,
+          cases);
+    }
+
+    return FALSE;
+}
+
+/* Resets a guard list. */
+Py_LOCAL_INLINE(void) reset_guard_list(RE_GuardList* guard_list) {
+    guard_list->count = 0;
+    guard_list->last_text_pos = -1;
+}
+
+/* Clears the groups. */
+Py_LOCAL_INLINE(void) clear_groups(RE_State* state) {
+    size_t i;
+
+    for (i = 0; i < state->pattern->true_group_count; i++) {
+        RE_GroupData* group;
+
+        group = &state->groups[i];
+        group->span.start = -1;
+        group->span.end = -1;
+        group->capture_count = 0;
+        group->current_capture = -1;
+    }
+}
+
+/* Initialises the state for a match. */
+Py_LOCAL_INLINE(void) init_match(RE_State* state) {
+    RE_AtomicBlock* current;
+    size_t i;
+
+    /* Reset the backtrack. */
+    state->current_backtrack_block = &state->backtrack_block;
+    state->current_backtrack_block->count = 0;
+    state->current_saved_groups = state->first_saved_groups;
+    state->backtrack = NULL;
+    state->search_anchor = state->text_pos;
+    state->match_pos = state->text_pos;
+
+    /* Reset the atomic stack. */
+    current = state->current_atomic_block;
+    if (current) {
+        while (current->previous)
+            current = current->previous;
+
+        state->current_atomic_block = current;
+        state->current_atomic_block->count = 0;
+    }
+
+    /* Reset the guards for the repeats. */
+    for (i = 0; i < state->pattern->repeat_count; i++) {
+        reset_guard_list(&state->repeats[i].body_guard_list);
+        reset_guard_list(&state->repeats[i].tail_guard_list);
+    }
+
+    /* Reset the guards for the fuzzy sections. */
+    for (i = 0; i < state->pattern->fuzzy_count; i++) {
+        reset_guard_list(&state->fuzzy_guards[i].body_guard_list);
+        reset_guard_list(&state->fuzzy_guards[i].tail_guard_list);
+    }
+
+    /* Clear the groups. */
+    clear_groups(state);
+
+    /* Reset the guards for the group calls. */
+    for (i = 0; i < state->pattern->call_ref_info_count; i++)
+        reset_guard_list(&state->group_call_guard_list[i]);
+
+    /* Clear the counts and cost for matching. */
+    if (state->pattern->is_fuzzy) {
+        memset(state->fuzzy_info.counts, 0, sizeof(state->fuzzy_info.counts));
+        memset(state->total_fuzzy_counts, 0,
+          sizeof(state->total_fuzzy_counts));
+    }
+
+    state->fuzzy_info.total_cost = 0;
+    state->total_errors = 0;
+    state->too_few_errors = FALSE;
+    state->found_match = FALSE;
+    state->capture_change = 0;
+    state->iterations = 0;
+}
+
+/* Adds a new backtrack entry. */
+Py_LOCAL_INLINE(BOOL) add_backtrack(RE_SafeState* safe_state, RE_UINT8 op) {
+    RE_State* state;
+    RE_BacktrackBlock* current;
+
+    state = safe_state->re_state;
+
+    current = state->current_backtrack_block;
+    if (current->count >= current->capacity) {
+        if (!current->next) {
+            RE_BacktrackBlock* next;
+
+            /* Is there too much backtracking? */
+            if (state->backtrack_allocated >= RE_MAX_BACKTRACK_ALLOC)
+                return FALSE;
+
+            next = (RE_BacktrackBlock*)safe_alloc(safe_state,
+              sizeof(RE_BacktrackBlock));
+            if (!next)
+                return FALSE;
+
+            next->previous = current;
+            next->next = NULL;
+            next->capacity = RE_BACKTRACK_BLOCK_SIZE;
+            current->next = next;
+
+            state->backtrack_allocated += RE_BACKTRACK_BLOCK_SIZE;
+        }
+
+        current = current->next;
+        current->count = 0;
+        state->current_backtrack_block = current;
+    }
+
+    state->backtrack = &current->items[current->count++];
+    state->backtrack->op = op;
+
+    return TRUE;
+}
+
+/* Gets the last backtrack entry.
+ *
+ * It'll never be called when there are _no_ entries.
+ */
+Py_LOCAL_INLINE(RE_BacktrackData*) last_backtrack(RE_State* state) {
+    RE_BacktrackBlock* current;
+
+    current = state->current_backtrack_block;
+    state->backtrack = &current->items[current->count - 1];
+
+    return state->backtrack;
+}
+
+/* Discards the last backtrack entry.
+ *
+ * It'll never be called to discard the _only_ entry.
+ */
+Py_LOCAL_INLINE(void) discard_backtrack(RE_State* state) {
+    RE_BacktrackBlock* current;
+
+    current = state->current_backtrack_block;
+    --current->count;
+    if (current->count == 0 && current->previous)
+        state->current_backtrack_block = current->previous;
+}
+
+/* Pushes a new empty entry onto the atomic stack. */
+Py_LOCAL_INLINE(RE_AtomicData*) push_atomic(RE_SafeState* safe_state) {
+    RE_State* state;
+    RE_AtomicBlock* current;
+
+    state = safe_state->re_state;
+
+    current = state->current_atomic_block;
+    if (!current || current->count >= current->capacity) {
+        /* The current block is full. */
+        if (current && current->next)
+            /* Advance to the next block. */
+            current = current->next;
+        else {
+            /* Add a new block. */
+            RE_AtomicBlock* next;
+
+            next = (RE_AtomicBlock*)safe_alloc(safe_state,
+              sizeof(RE_AtomicBlock));
+            if (!next)
+                return NULL;
+
+            next->previous = current;
+            next->next = NULL;
+            next->capacity = RE_ATOMIC_BLOCK_SIZE;
+            if (current)
+                /* The current block is the last one. */
+                current->next = next;
+            else
+                /* The new block is the first one. */
+                state->current_atomic_block = next;
+            current = next;
+        }
+
+        current->count = 0;
+    }
+
+    return &current->items[current->count++];
+}
+
+/* Pops the top entry from the atomic stack. */
+Py_LOCAL_INLINE(RE_AtomicData*) pop_atomic(RE_SafeState* safe_state) {
+    RE_State* state;
+    RE_AtomicBlock* current;
+    RE_AtomicData* atomic;
+
+    state = safe_state->re_state;
+
+    current = state->current_atomic_block;
+    atomic = &current->items[--current->count];
+    if (current->count == 0 && current->previous)
+        state->current_atomic_block = current->previous;
+
+    return atomic;
+}
+
+/* Gets the top entry from the atomic stack. */
+Py_LOCAL_INLINE(RE_AtomicData*) top_atomic(RE_SafeState* safe_state) {
+    RE_State* state;
+    RE_AtomicBlock* current;
+
+    state = safe_state->re_state;
+
+    current = state->current_atomic_block;
+    return &current->items[current->count - 1];
+}
+
+/* Copies a repeat guard list. */
+Py_LOCAL_INLINE(BOOL) copy_guard_data(RE_SafeState* safe_state, RE_GuardList*
+  dst, RE_GuardList* src) {
+    if (dst->capacity < src->count) {
+        RE_GuardSpan* new_spans;
+
+        if (!safe_state)
+            return FALSE;
+
+        dst->capacity = src->count;
+        new_spans = (RE_GuardSpan*)safe_realloc(safe_state, dst->spans,
+          dst->capacity * sizeof(RE_GuardSpan));
+        if (!new_spans)
+            return FALSE;
+
+        dst->spans = new_spans;
+    }
+
+    dst->count = src->count;
+    memmove(dst->spans, src->spans, dst->count * sizeof(RE_GuardSpan));
+
+    dst->last_text_pos = -1;
+
+    return TRUE;
+}
+
+/* Copies a repeat. */
+Py_LOCAL_INLINE(BOOL) copy_repeat_data(RE_SafeState* safe_state, RE_RepeatData*
+  dst, RE_RepeatData* src) {
+    if (!copy_guard_data(safe_state, &dst->body_guard_list,
+      &src->body_guard_list) || !copy_guard_data(safe_state,
+      &dst->tail_guard_list, &src->tail_guard_list)) {
+        safe_dealloc(safe_state, dst->body_guard_list.spans);
+        safe_dealloc(safe_state, dst->tail_guard_list.spans);
+
+        return FALSE;
+    }
+
+    dst->count = src->count;
+    dst->start = src->start;
+    dst->capture_change = src->capture_change;
+
+    return TRUE;
+}
+
+/* Pushes a return node onto the group call stack. */
+Py_LOCAL_INLINE(BOOL) push_group_return(RE_SafeState* safe_state, RE_Node*
+  return_node) {
+    RE_State* state;
+    PatternObject* pattern;
+    RE_GroupCallFrame* frame;
+
+    state = safe_state->re_state;
+    pattern = state->pattern;
+
+    if (state->current_group_call_frame &&
+      state->current_group_call_frame->next)
+        /* Advance to the next allocated frame. */
+        frame = state->current_group_call_frame->next;
+    else if (!state->current_group_call_frame && state->first_group_call_frame)
+        /* Advance to the first allocated frame. */
+        frame = state->first_group_call_frame;
+    else {
+        /* Create a new frame. */
+        frame = (RE_GroupCallFrame*)safe_alloc(safe_state,
+          sizeof(RE_GroupCallFrame));
+        if (!frame)
+            return FALSE;
+
+        frame->groups = (RE_GroupData*)safe_alloc(safe_state,
+          pattern->true_group_count * sizeof(RE_GroupData));
+        frame->repeats = (RE_RepeatData*)safe_alloc(safe_state,
+          pattern->repeat_count * sizeof(RE_RepeatData));
+        if (!frame->groups || !frame->repeats) {
+            safe_dealloc(safe_state, frame->groups);
+            safe_dealloc(safe_state, frame->repeats);
+            safe_dealloc(safe_state, frame);
+
+            return FALSE;
+        }
+
+        memset(frame->groups, 0, pattern->true_group_count *
+          sizeof(RE_GroupData));
+        memset(frame->repeats, 0, pattern->repeat_count *
+          sizeof(RE_RepeatData));
+
+        frame->previous = state->current_group_call_frame;
+        frame->next = NULL;
+
+        if (frame->previous)
+            frame->previous->next = frame;
+        else
+            state->first_group_call_frame = frame;
+    }
+
+    frame->node = return_node;
+
+    /* Push the groups and guards. */
+    if (return_node) {
+        size_t g;
+        size_t r;
+
+        for (g = 0; g < pattern->true_group_count; g++) {
+            frame->groups[g].span = state->groups[g].span;
+            frame->groups[g].current_capture =
+              state->groups[g].current_capture;
+        }
+
+        for (r = 0; r < pattern->repeat_count; r++) {
+            if (!copy_repeat_data(safe_state, &frame->repeats[r],
+              &state->repeats[r]))
+                return FALSE;
+        }
+    }
+
+    state->current_group_call_frame = frame;
+
+    return TRUE;
+}
+
+/* Pops a return node from the group call stack. */
+Py_LOCAL_INLINE(RE_Node*) pop_group_return(RE_State* state) {
+    RE_GroupCallFrame* frame;
+
+    frame = state->current_group_call_frame;
+
+    /* Pop the groups and repeats. */
+    if (frame->node) {
+        PatternObject* pattern;
+        size_t g;
+        size_t r;
+
+        pattern = state->pattern;
+
+        for (g = 0; g < pattern->true_group_count; g++) {
+            state->groups[g].span = frame->groups[g].span;
+            state->groups[g].current_capture =
+              frame->groups[g].current_capture;
+        }
+
+        for (r = 0; r < pattern->repeat_count; r++)
+            copy_repeat_data(NULL, &state->repeats[r], &frame->repeats[r]);
+    }
+
+    /* Withdraw to previous frame. */
+    state->current_group_call_frame = frame->previous;
+
+    return frame->node;
+}
+
+/* Returns the return node from the top of the group call stack. */
+Py_LOCAL_INLINE(RE_Node*) top_group_return(RE_State* state) {
+    RE_GroupCallFrame* frame;
+
+    frame = state->current_group_call_frame;
+
+    return frame->node;
+}
+
+/* Checks whether a node matches only 1 character. */
+Py_LOCAL_INLINE(BOOL) node_matches_one_character(RE_Node* node) {
+    switch (node->op) {
+    case RE_OP_ANY:
+    case RE_OP_ANY_ALL:
+    case RE_OP_ANY_ALL_REV:
+    case RE_OP_ANY_REV:
+    case RE_OP_ANY_U:
+    case RE_OP_ANY_U_REV:
+    case RE_OP_CHARACTER:
+    case RE_OP_CHARACTER_IGN:
+    case RE_OP_CHARACTER_IGN_REV:
+    case RE_OP_CHARACTER_REV:
+    case RE_OP_PROPERTY:
+    case RE_OP_PROPERTY_IGN:
+    case RE_OP_PROPERTY_IGN_REV:
+    case RE_OP_PROPERTY_REV:
+    case RE_OP_RANGE:
+    case RE_OP_RANGE_IGN:
+    case RE_OP_RANGE_IGN_REV:
+    case RE_OP_RANGE_REV:
+    case RE_OP_SET_DIFF:
+    case RE_OP_SET_DIFF_IGN:
+    case RE_OP_SET_DIFF_IGN_REV:
+    case RE_OP_SET_DIFF_REV:
+    case RE_OP_SET_INTER:
+    case RE_OP_SET_INTER_IGN:
+    case RE_OP_SET_INTER_IGN_REV:
+    case RE_OP_SET_INTER_REV:
+    case RE_OP_SET_SYM_DIFF:
+    case RE_OP_SET_SYM_DIFF_IGN:
+    case RE_OP_SET_SYM_DIFF_IGN_REV:
+    case RE_OP_SET_SYM_DIFF_REV:
+    case RE_OP_SET_UNION:
+    case RE_OP_SET_UNION_IGN:
+    case RE_OP_SET_UNION_IGN_REV:
+    case RE_OP_SET_UNION_REV:
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+
+/* Checks whether the node is a firstset. */
+Py_LOCAL_INLINE(BOOL) is_firstset(RE_Node* node) {
+    if (node->step != 0)
+        return FALSE;
+
+    return node_matches_one_character(node);
+}
+
+/* Locates the start node for testing ahead. */
+Py_LOCAL_INLINE(RE_Node*) locate_test_start(RE_Node* node) {
+    for (;;) {
+        switch (node->op) {
+        case RE_OP_BOUNDARY:
+            switch (node->next_1.node->op) {
+            case RE_OP_STRING:
+            case RE_OP_STRING_FLD:
+            case RE_OP_STRING_FLD_REV:
+            case RE_OP_STRING_IGN:
+            case RE_OP_STRING_IGN_REV:
+            case RE_OP_STRING_REV:
+                return node->next_1.node;
+            default:
+                return node;
+            }
+        case RE_OP_CALL_REF:
+        case RE_OP_END_GROUP:
+        case RE_OP_START_GROUP:
+            node = node->next_1.node;
+            break;
+        case RE_OP_GREEDY_REPEAT:
+        case RE_OP_LAZY_REPEAT:
+            if (node->values[1] == 0)
+                return node;
+            node = node->next_1.node;
+            break;
+        case RE_OP_GREEDY_REPEAT_ONE:
+        case RE_OP_LAZY_REPEAT_ONE:
+            if (node->values[1] == 0)
+                return node;
+            return node->nonstring.next_2.node;
+        case RE_OP_LOOKAROUND:
+            node = node->nonstring.next_2.node;
+            break;
+        default:
+            if (is_firstset(node)) {
+                switch (node->next_1.node->op) {
+                case RE_OP_END_OF_STRING:
+                case RE_OP_START_OF_STRING:
+                    return node->next_1.node;
+                }
+            }
+
+            return node;
+        }
+    }
+}
+
+/* Checks whether a character matches any of a set of case characters. */
+Py_LOCAL_INLINE(BOOL) any_case(Py_UCS4 ch, int case_count, Py_UCS4* cases) {
+    int i;
+
+    for (i = 0; i < case_count; i++) {
+        if (ch == cases[i])
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Matches many ANYs, up to a limit. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_ANY(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+
+    text = state->text;
+    encoding = state->encoding;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_ANY(encoding, node, text_ptr[0])
+          == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_ANY(encoding, node, text_ptr[0])
+          == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_ANY(encoding, node, text_ptr[0])
+          == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many ANYs, up to a limit, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_ANY_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+
+    text = state->text;
+    encoding = state->encoding;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_ANY(encoding, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_ANY(encoding, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_ANY(encoding, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many ANY_Us, up to a limit. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_ANY_U(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+
+    text = state->text;
+    encoding = state->encoding;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_ANY_U(encoding, node,
+          text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_ANY_U(encoding, node,
+          text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_ANY_U(encoding, node,
+          text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many ANY_Us, up to a limit, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_ANY_U_REV(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+
+    text = state->text;
+    encoding = state->encoding;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_ANY_U(encoding, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_ANY_U(encoding, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_ANY_U(encoding, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many CHARACTERs, up to a limit. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_CHARACTER(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    Py_UCS4 ch;
+
+    text = state->text;
+    match = node->match == match;
+    ch = node->values[0];
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && (text_ptr[0] == ch) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && (text_ptr[0] == ch) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && (text_ptr[0] == ch) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many CHARACTERs, up to a limit, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_CHARACTER_IGN(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    Py_UCS4 cases[RE_MAX_CASES];
+    int case_count;
+
+    text = state->text;
+    match = node->match == match;
+    case_count = state->encoding->all_cases(state->locale_info,
+      node->values[0], cases);
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && any_case(text_ptr[0], case_count, cases)
+          == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && any_case(text_ptr[0], case_count, cases)
+          == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && any_case(text_ptr[0], case_count, cases)
+          == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many CHARACTERs, up to a limit, backwards, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_CHARACTER_IGN_REV(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    Py_UCS4 cases[RE_MAX_CASES];
+    int case_count;
+
+    text = state->text;
+    match = node->match == match;
+    case_count = state->encoding->all_cases(state->locale_info,
+      node->values[0], cases);
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && any_case(text_ptr[-1], case_count,
+          cases) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && any_case(text_ptr[-1], case_count,
+          cases) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && any_case(text_ptr[-1], case_count,
+          cases) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many CHARACTERs, up to a limit, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_CHARACTER_REV(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    Py_UCS4 ch;
+
+    text = state->text;
+    match = node->match == match;
+    ch = node->values[0];
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && (text_ptr[-1] == ch) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && (text_ptr[-1] == ch) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && (text_ptr[-1] == ch) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many PROPERTYs, up to a limit. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_PROPERTY(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_PROPERTY(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_PROPERTY(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_PROPERTY(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many PROPERTYs, up to a limit, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_PROPERTY_IGN(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_PROPERTY_IGN(encoding,
+          locale_info, node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_PROPERTY_IGN(encoding,
+          locale_info, node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_PROPERTY_IGN(encoding,
+          locale_info, node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many PROPERTYs, up to a limit, backwards, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_PROPERTY_IGN_REV(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_PROPERTY_IGN(encoding,
+          locale_info, node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_PROPERTY_IGN(encoding,
+          locale_info, node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_PROPERTY_IGN(encoding,
+          locale_info, node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many PROPERTYs, up to a limit, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_PROPERTY_REV(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_PROPERTY(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_PROPERTY(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_PROPERTY(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many RANGEs, up to a limit. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_RANGE(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_RANGE(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_RANGE(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_RANGE(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many RANGEs, up to a limit, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_RANGE_IGN(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_RANGE_IGN(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_RANGE_IGN(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_RANGE_IGN(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many RANGEs, up to a limit, backwards, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_RANGE_IGN_REV(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_RANGE_IGN(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_RANGE_IGN(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_RANGE_IGN(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many RANGEs, up to a limit, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_RANGE_REV(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_RANGE(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_RANGE(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_RANGE(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many SETs, up to a limit. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_SET(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_SET(encoding, locale_info, node,
+          text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_SET(encoding, locale_info, node,
+          text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_SET(encoding, locale_info, node,
+          text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many SETs, up to a limit, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_SET_IGN(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_SET_IGN(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_SET_IGN(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr < limit_ptr && matches_SET_IGN(encoding, locale_info,
+          node, text_ptr[0]) == match)
+            ++text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many SETs, up to a limit, backwards, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_SET_IGN_REV(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_SET_IGN(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_SET_IGN(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_SET_IGN(encoding, locale_info,
+          node, text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Matches many SETs, up to a limit, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) match_many_SET_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit, BOOL match) {
+    void* text;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+
+    text = state->text;
+    match = node->match == match;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_SET(encoding, locale_info, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS1*)text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_SET(encoding, locale_info, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS2*)text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr > limit_ptr && matches_SET(encoding, locale_info, node,
+          text_ptr[-1]) == match)
+            --text_ptr;
+
+        text_pos = text_ptr - (Py_UCS4*)text;
+        break;
+    }
+    }
+
+    return text_pos;
+}
+
+/* Counts a repeated character pattern. */
+Py_LOCAL_INLINE(size_t) count_one(RE_State* state, RE_Node* node, Py_ssize_t
+  text_pos, size_t max_count, BOOL* is_partial) {
+    size_t count;
+
+    *is_partial = FALSE;
+
+    if (max_count < 1)
+        return 0;
+
+    switch (node->op) {
+    case RE_OP_ANY:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_ANY(state, node, text_pos, text_pos +
+          (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_ANY_ALL:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_ANY_ALL_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_ANY_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_ANY_REV(state, node, text_pos,
+          text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_ANY_U:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_ANY_U(state, node, text_pos, text_pos +
+          (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_ANY_U_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_ANY_U_REV(state, node, text_pos,
+          text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_CHARACTER:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_CHARACTER(state, node, text_pos, text_pos +
+          (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_CHARACTER_IGN:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_CHARACTER_IGN(state, node, text_pos,
+          text_pos + (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_CHARACTER_IGN_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_CHARACTER_IGN_REV(state, node,
+          text_pos, text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_CHARACTER_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_CHARACTER_REV(state, node,
+          text_pos, text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_PROPERTY:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_PROPERTY(state, node, text_pos, text_pos +
+          (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_PROPERTY_IGN:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_PROPERTY_IGN(state, node, text_pos,
+          text_pos + (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_PROPERTY_IGN_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_PROPERTY_IGN_REV(state, node,
+          text_pos, text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_PROPERTY_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_PROPERTY_REV(state, node,
+          text_pos, text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_RANGE:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_RANGE(state, node, text_pos, text_pos +
+          (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_RANGE_IGN:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_RANGE_IGN(state, node, text_pos, text_pos +
+          (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_RANGE_IGN_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_RANGE_IGN_REV(state, node,
+          text_pos, text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_RANGE_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_RANGE_REV(state, node, text_pos,
+          text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_SET_DIFF:
+    case RE_OP_SET_INTER:
+    case RE_OP_SET_SYM_DIFF:
+    case RE_OP_SET_UNION:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_SET(state, node, text_pos, text_pos +
+          (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_SET_DIFF_IGN:
+    case RE_OP_SET_INTER_IGN:
+    case RE_OP_SET_SYM_DIFF_IGN:
+    case RE_OP_SET_UNION_IGN:
+        count = min_size_t((size_t)(state->slice_end - text_pos), max_count);
+
+        count = (size_t)(match_many_SET_IGN(state, node, text_pos, text_pos +
+          (Py_ssize_t)count, TRUE) - text_pos);
+
+        *is_partial = count == (size_t)(state->text_length - text_pos) && count
+          < max_count && state->partial_side == RE_PARTIAL_RIGHT;
+
+        return count;
+    case RE_OP_SET_DIFF_IGN_REV:
+    case RE_OP_SET_INTER_IGN_REV:
+    case RE_OP_SET_SYM_DIFF_IGN_REV:
+    case RE_OP_SET_UNION_IGN_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_SET_IGN_REV(state, node,
+          text_pos, text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    case RE_OP_SET_DIFF_REV:
+    case RE_OP_SET_INTER_REV:
+    case RE_OP_SET_SYM_DIFF_REV:
+    case RE_OP_SET_UNION_REV:
+        count = min_size_t((size_t)(text_pos - state->slice_start), max_count);
+
+        count = (size_t)(text_pos - match_many_SET_REV(state, node, text_pos,
+          text_pos - (Py_ssize_t)count, TRUE));
+
+        *is_partial = count == (size_t)(text_pos) && count < max_count &&
+          state->partial_side == RE_PARTIAL_LEFT;
+
+        return count;
+    }
+
+    return 0;
+}
+
+/* Performs a simple string search. */
+Py_LOCAL_INLINE(Py_ssize_t) simple_string_search(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL* is_partial) {
+    Py_ssize_t length;
+    RE_CODE* values;
+    Py_UCS4 check_char;
+
+    length = (Py_ssize_t)node->value_count;
+    values = node->values;
+    check_char = values[0];
+
+    *is_partial = FALSE;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text = (Py_UCS1*)state->text;
+        Py_UCS1* text_ptr = text + text_pos;
+        Py_UCS1* limit_ptr = text + limit;
+
+        while (text_ptr < limit_ptr) {
+            if (text_ptr[0] == check_char) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr + s_pos >= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_RIGHT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char(text_ptr[s_pos], values[s_pos]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            ++text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text = (Py_UCS2*)state->text;
+        Py_UCS2* text_ptr = text + text_pos;
+        Py_UCS2* limit_ptr = text + limit;
+
+        while (text_ptr < limit_ptr) {
+            if (text_ptr[0] == check_char) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr + s_pos >= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_RIGHT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char(text_ptr[s_pos], values[s_pos]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            ++text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text = (Py_UCS4*)state->text;
+        Py_UCS4* text_ptr = text + text_pos;
+        Py_UCS4* limit_ptr = text + limit;
+
+        while (text_ptr < limit_ptr) {
+            if (text_ptr[0] == check_char) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr + s_pos >= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_RIGHT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char(text_ptr[s_pos], values[s_pos]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            ++text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    }
+
+    /* Off the end of the text. */
+    if (state->partial_side == RE_PARTIAL_RIGHT) {
+        /* Partial match. */
+        *is_partial = TRUE;
+        return text_pos;
+    }
+
+    return -1;
+}
+
+/* Performs a simple string search, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) simple_string_search_ign(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL* is_partial) {
+    Py_ssize_t length;
+    RE_CODE* values;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    Py_UCS4 cases[RE_MAX_CASES];
+    int case_count;
+
+    length = (Py_ssize_t)node->value_count;
+    values = node->values;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    case_count = encoding->all_cases(locale_info, values[0], cases);
+
+    *is_partial = FALSE;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text = (Py_UCS1*)state->text;
+        Py_UCS1* text_ptr = text + text_pos;
+        Py_UCS1* limit_ptr = text + limit;
+
+        while (text_ptr < limit_ptr) {
+            if (any_case(text_ptr[0], case_count, cases)) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr + s_pos >= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_RIGHT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char_ign(encoding, locale_info, text_ptr[s_pos],
+                      values[s_pos]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            ++text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text = (Py_UCS2*)state->text;
+        Py_UCS2* text_ptr = text + text_pos;
+        Py_UCS2* limit_ptr = text + limit;
+
+        while (text_ptr < limit_ptr) {
+            if (any_case(text_ptr[0], case_count, cases)) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr + s_pos >= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_RIGHT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char_ign(encoding, locale_info, text_ptr[s_pos],
+                      values[s_pos]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            ++text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text = (Py_UCS4*)state->text;
+        Py_UCS4* text_ptr = text + text_pos;
+        Py_UCS4* limit_ptr = text + limit;
+
+        while (text_ptr < limit_ptr) {
+            if (any_case(text_ptr[0], case_count, cases)) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr + s_pos >= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_RIGHT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char_ign(encoding, locale_info, text_ptr[s_pos],
+                      values[s_pos]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            ++text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    }
+
+    /* Off the end of the text. */
+    if (state->partial_side == RE_PARTIAL_RIGHT) {
+        /* Partial match. */
+        *is_partial = TRUE;
+        return text_pos;
+    }
+
+    return -1;
+}
+
+/* Performs a simple string search, backwards, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) simple_string_search_ign_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL* is_partial) {
+    Py_ssize_t length;
+    RE_CODE* values;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    Py_UCS4 cases[RE_MAX_CASES];
+    int case_count;
+
+    length = (Py_ssize_t)node->value_count;
+    values = node->values;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    case_count = encoding->all_cases(locale_info, values[length - 1], cases);
+
+    *is_partial = FALSE;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text = (Py_UCS1*)state->text;
+        Py_UCS1* text_ptr = text + text_pos;
+        Py_UCS1* limit_ptr = text + limit;
+
+        while (text_ptr > limit_ptr) {
+            if (any_case(text_ptr[-1], case_count, cases)) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr - s_pos <= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_LEFT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char_ign(encoding, locale_info, text_ptr[- s_pos
+                      - 1], values[length - s_pos - 1]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            --text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text = (Py_UCS2*)state->text;
+        Py_UCS2* text_ptr = text + text_pos;
+        Py_UCS2* limit_ptr = text + limit;
+
+        while (text_ptr > limit_ptr) {
+            if (any_case(text_ptr[-1], case_count, cases)) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr - s_pos <= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_LEFT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char_ign(encoding, locale_info, text_ptr[- s_pos
+                      - 1], values[length - s_pos - 1]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            --text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text = (Py_UCS4*)state->text;
+        Py_UCS4* text_ptr = text + text_pos;
+        Py_UCS4* limit_ptr = text + limit;
+
+        while (text_ptr > limit_ptr) {
+            if (any_case(text_ptr[-1], case_count, cases)) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr - s_pos <= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_LEFT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char_ign(encoding, locale_info, text_ptr[- s_pos
+                      - 1], values[length - s_pos - 1]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            --text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    }
+
+    /* Off the end of the text. */
+    if (state->partial_side == RE_PARTIAL_LEFT) {
+        /* Partial match. */
+        *is_partial = TRUE;
+        return text_pos;
+    }
+
+    return -1;
+}
+
+/* Performs a simple string search, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) simple_string_search_rev(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL* is_partial) {
+    Py_ssize_t length;
+    RE_CODE* values;
+    Py_UCS4 check_char;
+
+    length = (Py_ssize_t)node->value_count;
+    values = node->values;
+    check_char = values[length - 1];
+
+    *is_partial = FALSE;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text = (Py_UCS1*)state->text;
+        Py_UCS1* text_ptr = text + text_pos;
+        Py_UCS1* limit_ptr = text + limit;
+
+        while (text_ptr > limit_ptr) {
+            if (text_ptr[-1] == check_char) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr - s_pos <= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_LEFT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char(text_ptr[- s_pos - 1], values[length - s_pos
+                      - 1]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            --text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text = (Py_UCS2*)state->text;
+        Py_UCS2* text_ptr = text + text_pos;
+        Py_UCS2* limit_ptr = text + limit;
+
+        while (text_ptr > limit_ptr) {
+            if (text_ptr[-1] == check_char) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr - s_pos <= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_LEFT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char(text_ptr[- s_pos - 1], values[length - s_pos
+                      - 1]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            --text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text = (Py_UCS4*)state->text;
+        Py_UCS4* text_ptr = text + text_pos;
+        Py_UCS4* limit_ptr = text + limit;
+
+        while (text_ptr > limit_ptr) {
+            if (text_ptr[-1] == check_char) {
+                Py_ssize_t s_pos;
+
+                s_pos = 1;
+
+                for (;;) {
+                    if (s_pos >= length)
+                        /* End of search string. */
+                        return text_ptr - text;
+
+                    if (text_ptr - s_pos <= limit_ptr) {
+                        /* Off the end of the text. */
+                        if (state->partial_side == RE_PARTIAL_LEFT) {
+                            /* Partial match. */
+                            *is_partial = TRUE;
+                            return text_ptr - text;
+                        }
+
+                        return -1;
+
+                    }
+
+                    if (!same_char(text_ptr[- s_pos - 1], values[length - s_pos
+                      - 1]))
+                        break;
+
+                    ++s_pos;
+                }
+            }
+
+            --text_ptr;
+        }
+        text_pos = text_ptr - text;
+        break;
+    }
+    }
+
+    /* Off the end of the text. */
+    if (state->partial_side == RE_PARTIAL_LEFT) {
+        /* Partial match. */
+        *is_partial = TRUE;
+        return text_pos;
+    }
+
+    return -1;
+}
+
+/* Performs a Boyer-Moore fast string search. */
+Py_LOCAL_INLINE(Py_ssize_t) fast_string_search(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos, Py_ssize_t limit) {
+    void* text;
+    Py_ssize_t length;
+    RE_CODE* values;
+    Py_ssize_t* bad_character_offset;
+    Py_ssize_t* good_suffix_offset;
+    Py_ssize_t last_pos;
+    Py_UCS4 check_char;
+
+    text = state->text;
+    length = (Py_ssize_t)node->value_count;
+    values = node->values;
+    good_suffix_offset = node->string.good_suffix_offset;
+    bad_character_offset = node->string.bad_character_offset;
+    last_pos = length - 1;
+    check_char = values[last_pos];
+    limit -= length;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr <= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[last_pos];
+            if (ch == check_char) {
+                Py_ssize_t pos;
+
+                pos = last_pos - 1;
+                while (pos >= 0 && same_char(text_ptr[pos], values[pos]))
+                    --pos;
+
+                if (pos < 0)
+                    return text_ptr - (Py_UCS1*)text;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr <= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[last_pos];
+            if (ch == check_char) {
+                Py_ssize_t pos;
+
+                pos = last_pos - 1;
+                while (pos >= 0 && same_char(text_ptr[pos], values[pos]))
+                    --pos;
+
+                if (pos < 0)
+                    return text_ptr - (Py_UCS2*)text;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr <= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[last_pos];
+            if (ch == check_char) {
+                Py_ssize_t pos;
+
+                pos = last_pos - 1;
+                while (pos >= 0 && same_char(text_ptr[pos], values[pos]))
+                    --pos;
+
+                if (pos < 0)
+                    return text_ptr - (Py_UCS4*)text;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    }
+
+    return -1;
+}
+
+/* Performs a Boyer-Moore fast string search, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) fast_string_search_ign(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit) {
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    void* text;
+    Py_ssize_t length;
+    RE_CODE* values;
+    Py_ssize_t* bad_character_offset;
+    Py_ssize_t* good_suffix_offset;
+    Py_ssize_t last_pos;
+    Py_UCS4 cases[RE_MAX_CASES];
+    int case_count;
+
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    text = state->text;
+    length = (Py_ssize_t)node->value_count;
+    values = node->values;
+    good_suffix_offset = node->string.good_suffix_offset;
+    bad_character_offset = node->string.bad_character_offset;
+    last_pos = length - 1;
+    case_count = encoding->all_cases(locale_info, values[last_pos], cases);
+    limit -= length;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr <= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[last_pos];
+            if (any_case(ch, case_count, cases)) {
+                Py_ssize_t pos;
+
+                pos = last_pos - 1;
+                while (pos >= 0 && same_char_ign(encoding, locale_info,
+                  text_ptr[pos], values[pos]))
+                    --pos;
+
+                if (pos < 0)
+                    return text_ptr - (Py_UCS1*)text;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr <= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[last_pos];
+            if (any_case(ch, case_count, cases)) {
+                Py_ssize_t pos;
+
+                pos = last_pos - 1;
+                while (pos >= 0 && same_char_ign(encoding, locale_info,
+                  text_ptr[pos], values[pos]))
+                    --pos;
+
+                if (pos < 0)
+                    return text_ptr - (Py_UCS2*)text;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr <= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[last_pos];
+            if (any_case(ch, case_count, cases)) {
+                Py_ssize_t pos;
+
+                pos = last_pos - 1;
+                while (pos >= 0 && same_char_ign(encoding, locale_info,
+                  text_ptr[pos], values[pos]))
+                    --pos;
+
+                if (pos < 0)
+                    return text_ptr - (Py_UCS4*)text;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    }
+
+    return -1;
+}
+
+/* Performs a Boyer-Moore fast string search, backwards, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) fast_string_search_ign_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit) {
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    void* text;
+    Py_ssize_t length;
+    RE_CODE* values;
+    Py_ssize_t* bad_character_offset;
+    Py_ssize_t* good_suffix_offset;
+    Py_UCS4 cases[RE_MAX_CASES];
+    int case_count;
+
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    text = state->text;
+    length = (Py_ssize_t)node->value_count;
+    values = node->values;
+    good_suffix_offset = node->string.good_suffix_offset;
+    bad_character_offset = node->string.bad_character_offset;
+    case_count = encoding->all_cases(locale_info, values[0], cases);
+    text_pos -= length;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr >= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[0];
+            if (any_case(ch, case_count, cases)) {
+                Py_ssize_t pos;
+
+                pos = 1;
+                while (pos < length && same_char_ign(encoding, locale_info,
+                  text_ptr[pos], values[pos]))
+                    ++pos;
+
+                if (pos >= length)
+                    return text_ptr - (Py_UCS1*)text + length;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr >= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[0];
+            if (any_case(ch, case_count, cases)) {
+                Py_ssize_t pos;
+
+                pos = 1;
+                while (pos < length && same_char_ign(encoding, locale_info,
+                  text_ptr[pos], values[pos]))
+                    ++pos;
+
+                if (pos >= length)
+                    return text_ptr - (Py_UCS2*)text + length;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr >= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[0];
+            if (any_case(ch, case_count, cases)) {
+                Py_ssize_t pos;
+
+                pos = 1;
+                while (pos < length && same_char_ign(encoding, locale_info,
+                  text_ptr[pos], values[pos]))
+                    ++pos;
+
+                if (pos >= length)
+                    return text_ptr - (Py_UCS4*)text + length;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    }
+
+    return -1;
+}
+
+/* Performs a Boyer-Moore fast string search, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) fast_string_search_rev(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit) {
+    void* text;
+    Py_ssize_t length;
+    RE_CODE* values;
+    Py_ssize_t* bad_character_offset;
+    Py_ssize_t* good_suffix_offset;
+    Py_UCS4 check_char;
+
+    text = state->text;
+    length = (Py_ssize_t)node->value_count;
+    values = node->values;
+    good_suffix_offset = node->string.good_suffix_offset;
+    bad_character_offset = node->string.bad_character_offset;
+    check_char = values[0];
+    text_pos -= length;
+
+    switch (state->charsize) {
+    case 1:
+    {
+        Py_UCS1* text_ptr;
+        Py_UCS1* limit_ptr;
+
+        text_ptr = (Py_UCS1*)text + text_pos;
+        limit_ptr = (Py_UCS1*)text + limit;
+
+        while (text_ptr >= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[0];
+            if (ch == check_char) {
+                Py_ssize_t pos;
+
+                pos = 1;
+                while (pos < length && same_char(text_ptr[pos], values[pos]))
+                    ++pos;
+
+                if (pos >= length)
+                    return text_ptr - (Py_UCS1*)text + length;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    case 2:
+    {
+        Py_UCS2* text_ptr;
+        Py_UCS2* limit_ptr;
+
+        text_ptr = (Py_UCS2*)text + text_pos;
+        limit_ptr = (Py_UCS2*)text + limit;
+
+        while (text_ptr >= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[0];
+            if (ch == check_char) {
+                Py_ssize_t pos;
+
+                pos = 1;
+                while (pos < length && same_char(text_ptr[pos], values[pos]))
+                    ++pos;
+
+                if (pos >= length)
+                    return text_ptr - (Py_UCS2*)text + length;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    case 4:
+    {
+        Py_UCS4* text_ptr;
+        Py_UCS4* limit_ptr;
+
+        text_ptr = (Py_UCS4*)text + text_pos;
+        limit_ptr = (Py_UCS4*)text + limit;
+
+        while (text_ptr >= limit_ptr) {
+            Py_UCS4 ch;
+
+            ch = text_ptr[0];
+            if (ch == check_char) {
+                Py_ssize_t pos;
+
+                pos = 1;
+                while (pos < length && same_char(text_ptr[pos], values[pos]))
+                    ++pos;
+
+                if (pos >= length)
+                    return text_ptr - (Py_UCS4*)text + length;
+
+                text_ptr += good_suffix_offset[pos];
+            } else
+                text_ptr += bad_character_offset[ch & 0xFF];
+        }
+        break;
+    }
+    }
+
+    return -1;
+}
+
+/* Builds the tables for a Boyer-Moore fast string search. */
+Py_LOCAL_INLINE(BOOL) build_fast_tables(RE_State* state, RE_Node* node, BOOL
+  ignore) {
+    Py_ssize_t length;
+    RE_CODE* values;
+    Py_ssize_t* bad;
+    Py_ssize_t* good;
+    Py_UCS4 ch;
+    Py_ssize_t last_pos;
+    Py_ssize_t pos;
+    BOOL (*is_same_char)(RE_EncodingTable* encoding, RE_LocaleInfo*
+      locale_info, Py_UCS4 ch1, Py_UCS4 ch2);
+    Py_ssize_t suffix_len;
+    BOOL saved_start;
+    Py_ssize_t s;
+    Py_ssize_t i;
+    Py_ssize_t s_start;
+    Py_UCS4 codepoints[RE_MAX_CASES];
+
+    length = (Py_ssize_t)node->value_count;
+
+    if (length < RE_MIN_FAST_LENGTH)
+        return TRUE;
+
+    values = node->values;
+    bad = (Py_ssize_t*)re_alloc(256 * sizeof(bad[0]));
+    good = (Py_ssize_t*)re_alloc((size_t)length * sizeof(good[0]));
+
+    if (!bad || !good) {
+        re_dealloc(bad);
+        re_dealloc(good);
+
+        return FALSE;
+    }
+
+    for (ch = 0; ch < 0x100; ch++)
+        bad[ch] = length;
+
+    last_pos = length - 1;
+
+    for (pos = 0; pos < last_pos; pos++) {
+        Py_ssize_t offset;
+
+        offset = last_pos - pos;
+        ch = values[pos];
+        if (ignore) {
+            int count;
+            int i;
+
+            count = state->encoding->all_cases(state->locale_info, ch,
+              codepoints);
+
+            for (i = 0; i < count; i++)
+                bad[codepoints[i] & 0xFF] = offset;
+        } else
+            bad[ch & 0xFF] = offset;
+    }
+
+    is_same_char = ignore ? same_char_ign_wrapper : same_char_wrapper;
+
+    suffix_len = 2;
+    pos = length - suffix_len;
+    saved_start = FALSE;
+    s = pos - 1;
+    i = suffix_len - 1;
+    s_start = s;
+
+    while (pos >= 0) {
+        /* Look for another occurrence of the suffix. */
+        while (i > 0) {
+            /* Have we dropped off the end of the string? */
+            if (s + i < 0)
+                break;
+
+            if (is_same_char(state->encoding, state->locale_info, values[s +
+              i], values[pos + i]))
+                /* It still matches. */
+                --i;
+            else {
+                /* Start again further along. */
+                --s;
+                i = suffix_len - 1;
+            }
+        }
+
+        if (s >= 0 && is_same_char(state->encoding, state->locale_info,
+          values[s], values[pos])) {
+            /* We haven't dropped off the end of the string, and the suffix has
+             * matched this far, so this is a good starting point for the next
+             * iteration.
+             */
+            --s;
+            if (!saved_start) {
+                s_start = s;
+                saved_start = TRUE;
+            }
+        } else {
+            /* Calculate the suffix offset. */
+            good[pos] = pos - s;
+
+            /* Extend the suffix and start searching for _this_ one. */
+            --pos;
+            ++suffix_len;
+
+            /* Where's a good place to start searching? */
+            if (saved_start) {
+                s = s_start;
+                saved_start = FALSE;
+            } else
+                --s;
+
+            /* Can we short-circuit the searching? */
+            if (s < 0)
+                break;
+        }
+
+        i = suffix_len - 1;
+    }
+
+    /* Fill-in any remaining entries. */
+    while (pos >= 0) {
+        good[pos] = pos - s;
+        --pos;
+        --s;
+    }
+
+    node->string.bad_character_offset = bad;
+    node->string.good_suffix_offset = good;
+
+    return TRUE;
+}
+
+/* Builds the tables for a Boyer-Moore fast string search, backwards. */
+Py_LOCAL_INLINE(BOOL) build_fast_tables_rev(RE_State* state, RE_Node* node,
+  BOOL ignore) {
+    Py_ssize_t length;
+    RE_CODE* values;
+    Py_ssize_t* bad;
+    Py_ssize_t* good;
+    Py_UCS4 ch;
+    Py_ssize_t last_pos;
+    Py_ssize_t pos;
+    BOOL (*is_same_char)(RE_EncodingTable* encoding, RE_LocaleInfo*
+      locale_info, Py_UCS4 ch1, Py_UCS4 ch2);
+    Py_ssize_t suffix_len;
+    BOOL saved_start;
+    Py_ssize_t s;
+    Py_ssize_t i;
+    Py_ssize_t s_start;
+    Py_UCS4 codepoints[RE_MAX_CASES];
+
+    length = (Py_ssize_t)node->value_count;
+
+    if (length < RE_MIN_FAST_LENGTH)
+        return TRUE;
+
+    values = node->values;
+    bad = (Py_ssize_t*)re_alloc(256 * sizeof(bad[0]));
+    good = (Py_ssize_t*)re_alloc((size_t)length * sizeof(good[0]));
+
+    if (!bad || !good) {
+        re_dealloc(bad);
+        re_dealloc(good);
+
+        return FALSE;
+    }
+
+    for (ch = 0; ch < 0x100; ch++)
+        bad[ch] = -length;
+
+    last_pos = length - 1;
+
+    for (pos = last_pos; pos > 0; pos--) {
+        Py_ssize_t offset;
+
+        offset = -pos;
+        ch = values[pos];
+        if (ignore) {
+            int count;
+            int i;
+
+            count = state->encoding->all_cases(state->locale_info, ch,
+              codepoints);
+
+            for (i = 0; i < count; i++)
+                bad[codepoints[i] & 0xFF] = offset;
+        } else
+            bad[ch & 0xFF] = offset;
+    }
+
+    is_same_char = ignore ? same_char_ign_wrapper : same_char_wrapper;
+
+    suffix_len = 2;
+    pos = suffix_len - 1;
+    saved_start = FALSE;
+    s = pos + 1;
+    i = suffix_len - 1;
+    s_start = s;
+
+    while (pos < length) {
+        /* Look for another occurrence of the suffix. */
+        while (i > 0) {
+            /* Have we dropped off the end of the string? */
+            if (s - i >= length)
+                break;
+
+            if (is_same_char(state->encoding, state->locale_info, values[s -
+              i], values[pos - i]))
+                /* It still matches. */
+                --i;
+            else {
+                /* Start again further along. */
+                ++s;
+                i = suffix_len - 1;
+            }
+        }
+
+        if (s < length && is_same_char(state->encoding, state->locale_info,
+          values[s], values[pos])) {
+            /* We haven't dropped off the end of the string, and the suffix has
+             * matched this far, so this is a good starting point for the next
+             * iteration.
+             */
+            ++s;
+            if (!saved_start) {
+                s_start = s;
+                saved_start = TRUE;
+            }
+        } else {
+            /* Calculate the suffix offset. */
+            good[pos] = pos - s;
+
+            /* Extend the suffix and start searching for _this_ one. */
+            ++pos;
+            ++suffix_len;
+
+            /* Where's a good place to start searching? */
+            if (saved_start) {
+                s = s_start;
+                saved_start = FALSE;
+            } else
+                ++s;
+
+            /* Can we short-circuit the searching? */
+            if (s >= length)
+                break;
+        }
+
+        i = suffix_len - 1;
+    }
+
+    /* Fill-in any remaining entries. */
+    while (pos < length) {
+        good[pos] = pos - s;
+        ++pos;
+        ++s;
+    }
+
+    node->string.bad_character_offset = bad;
+    node->string.good_suffix_offset = good;
+
+    return TRUE;
+}
+
+/* Performs a string search. */
+Py_LOCAL_INLINE(Py_ssize_t) string_search(RE_SafeState* safe_state, RE_Node*
+  node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL* is_partial) {
+    RE_State* state;
+    Py_ssize_t found_pos;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    /* Has the node been initialised for fast searching, if necessary? */
+    if (!(node->status & RE_STATUS_FAST_INIT)) {
+        /* Ideally the pattern should immutable and shareable across threads.
+         * Internally, however, it isn't. For safety we need to hold the GIL.
+         */
+        acquire_GIL(safe_state);
+
+        /* Double-check because of multithreading. */
+        if (!(node->status & RE_STATUS_FAST_INIT)) {
+            build_fast_tables(state, node, FALSE);
+            node->status |= RE_STATUS_FAST_INIT;
+        }
+
+        release_GIL(safe_state);
+    }
+
+    if (node->string.bad_character_offset) {
+        /* Start with a fast search. This will find the string if it's complete
+         * (i.e. not truncated).
+         */
+        found_pos = fast_string_search(state, node, text_pos, limit);
+        if (found_pos < 0 && state->partial_side == RE_PARTIAL_RIGHT)
+            /* We didn't find the string, but it could've been truncated, so
+             * try again, starting close to the end.
+             */
+            found_pos = simple_string_search(state, node, limit -
+              (Py_ssize_t)(node->value_count - 1), limit, is_partial);
+    } else
+        found_pos = simple_string_search(state, node, text_pos, limit,
+          is_partial);
+
+    return found_pos;
+}
+
+/* Performs a string search, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) string_search_fld(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit, Py_ssize_t* new_pos,
+  BOOL* is_partial) {
+    RE_State* state;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+      folded);
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    void* text;
+    RE_CODE* values;
+    Py_ssize_t start_pos;
+    int f_pos;
+    int folded_len;
+    Py_ssize_t length;
+    Py_ssize_t s_pos;
+    Py_UCS4 folded[RE_MAX_FOLDED];
+
+    state = safe_state->re_state;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    full_case_fold = encoding->full_case_fold;
+    char_at = state->char_at;
+    text = state->text;
+
+    values = node->values;
+    start_pos = text_pos;
+    f_pos = 0;
+    folded_len = 0;
+    length = (Py_ssize_t)node->value_count;
+    s_pos = 0;
+
+    *is_partial = FALSE;
+
+    while (s_pos < length || f_pos < folded_len) {
+        if (f_pos >= folded_len) {
+            /* Fetch and casefold another character. */
+            if (text_pos >= limit) {
+                if (text_pos >= state->text_length && state->partial_side ==
+                  RE_PARTIAL_RIGHT) {
+                    *is_partial = TRUE;
+                    return start_pos;
+                }
+
+                return -1;
+            }
+
+            folded_len = full_case_fold(locale_info, char_at(text, text_pos),
+              folded);
+            f_pos = 0;
+        }
+
+        if (s_pos < length && same_char_ign(encoding, locale_info,
+          values[s_pos], folded[f_pos])) {
+            ++s_pos;
+            ++f_pos;
+
+            if (f_pos >= folded_len)
+                ++text_pos;
+        } else {
+            ++start_pos;
+            text_pos = start_pos;
+            f_pos = 0;
+            folded_len = 0;
+            s_pos = 0;
+        }
+    }
+
+    /* We found the string. */
+    if (new_pos)
+        *new_pos = text_pos;
+
+    return start_pos;
+}
+
+/* Performs a string search, backwards, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) string_search_fld_rev(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit, Py_ssize_t* new_pos,
+  BOOL* is_partial) {
+    RE_State* state;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+      folded);
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    void* text;
+    RE_CODE* values;
+    Py_ssize_t start_pos;
+    int f_pos;
+    int folded_len;
+    Py_ssize_t length;
+    Py_ssize_t s_pos;
+    Py_UCS4 folded[RE_MAX_FOLDED];
+
+    state = safe_state->re_state;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    full_case_fold = encoding->full_case_fold;
+    char_at = state->char_at;
+    text = state->text;
+
+    values = node->values;
+    start_pos = text_pos;
+    f_pos = 0;
+    folded_len = 0;
+    length = (Py_ssize_t)node->value_count;
+    s_pos = 0;
+
+    *is_partial = FALSE;
+
+    while (s_pos < length || f_pos < folded_len) {
+        if (f_pos >= folded_len) {
+            /* Fetch and casefold another character. */
+            if (text_pos <= limit) {
+                if (text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT) {
+                    *is_partial = TRUE;
+                    return start_pos;
+                }
+
+                return -1;
+            }
+
+            folded_len = full_case_fold(locale_info, char_at(text, text_pos -
+              1), folded);
+            f_pos = 0;
+        }
+
+        if (s_pos < length && same_char_ign(encoding, locale_info,
+          values[length - s_pos - 1], folded[folded_len - f_pos - 1])) {
+            ++s_pos;
+            ++f_pos;
+
+            if (f_pos >= folded_len)
+                --text_pos;
+        } else {
+            --start_pos;
+            text_pos = start_pos;
+            f_pos = 0;
+            folded_len = 0;
+            s_pos = 0;
+        }
+    }
+
+    /* We found the string. */
+    if (new_pos)
+        *new_pos = text_pos;
+
+    return start_pos;
+}
+
+/* Performs a string search, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) string_search_ign(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL* is_partial) {
+    RE_State* state;
+    Py_ssize_t found_pos;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    /* Has the node been initialised for fast searching, if necessary? */
+    if (!(node->status & RE_STATUS_FAST_INIT)) {
+        /* Ideally the pattern should immutable and shareable across threads.
+         * Internally, however, it isn't. For safety we need to hold the GIL.
+         */
+        acquire_GIL(safe_state);
+
+        /* Double-check because of multithreading. */
+        if (!(node->status & RE_STATUS_FAST_INIT)) {
+            build_fast_tables(state, node, TRUE);
+            node->status |= RE_STATUS_FAST_INIT;
+        }
+
+        release_GIL(safe_state);
+    }
+
+    if (node->string.bad_character_offset) {
+        /* Start with a fast search. This will find the string if it's complete
+         * (i.e. not truncated).
+         */
+        found_pos = fast_string_search_ign(state, node, text_pos, limit);
+        if (found_pos < 0 && state->partial_side == RE_PARTIAL_RIGHT)
+            /* We didn't find the string, but it could've been truncated, so
+             * try again, starting close to the end.
+             */
+            found_pos = simple_string_search_ign(state, node, limit -
+              (Py_ssize_t)(node->value_count - 1), limit, is_partial);
+    } else
+        found_pos = simple_string_search_ign(state, node, text_pos, limit,
+          is_partial);
+
+    return found_pos;
+}
+
+/* Performs a string search, backwards, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) string_search_ign_rev(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL* is_partial) {
+    RE_State* state;
+    Py_ssize_t found_pos;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    /* Has the node been initialised for fast searching, if necessary? */
+    if (!(node->status & RE_STATUS_FAST_INIT)) {
+        /* Ideally the pattern should immutable and shareable across threads.
+         * Internally, however, it isn't. For safety we need to hold the GIL.
+         */
+        acquire_GIL(safe_state);
+
+        /* Double-check because of multithreading. */
+        if (!(node->status & RE_STATUS_FAST_INIT)) {
+            build_fast_tables_rev(state, node, TRUE);
+            node->status |= RE_STATUS_FAST_INIT;
+        }
+
+        release_GIL(safe_state);
+    }
+
+    if (node->string.bad_character_offset) {
+        /* Start with a fast search. This will find the string if it's complete
+         * (i.e. not truncated).
+         */
+        found_pos = fast_string_search_ign_rev(state, node, text_pos, limit);
+        if (found_pos < 0 && state->partial_side == RE_PARTIAL_LEFT)
+            /* We didn't find the string, but it could've been truncated, so
+             * try again, starting close to the end.
+             */
+            found_pos = simple_string_search_ign_rev(state, node, limit +
+              (Py_ssize_t)(node->value_count - 1), limit, is_partial);
+    } else
+        found_pos = simple_string_search_ign_rev(state, node, text_pos, limit,
+          is_partial);
+
+    return found_pos;
+}
+
+/* Performs a string search, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) string_search_rev(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t limit, BOOL* is_partial) {
+    RE_State* state;
+    Py_ssize_t found_pos;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    /* Has the node been initialised for fast searching, if necessary? */
+    if (!(node->status & RE_STATUS_FAST_INIT)) {
+        /* Ideally the pattern should immutable and shareable across threads.
+         * Internally, however, it isn't. For safety we need to hold the GIL.
+         */
+        acquire_GIL(safe_state);
+
+        /* Double-check because of multithreading. */
+        if (!(node->status & RE_STATUS_FAST_INIT)) {
+            build_fast_tables_rev(state, node, FALSE);
+            node->status |= RE_STATUS_FAST_INIT;
+        }
+
+        release_GIL(safe_state);
+    }
+
+    if (node->string.bad_character_offset) {
+        /* Start with a fast search. This will find the string if it's complete
+         * (i.e. not truncated).
+         */
+        found_pos = fast_string_search_rev(state, node, text_pos, limit);
+        if (found_pos < 0 && state->partial_side == RE_PARTIAL_LEFT)
+            /* We didn't find the string, but it could've been truncated, so
+             * try again, starting close to the end.
+             */
+            found_pos = simple_string_search_rev(state, node, limit +
+              (Py_ssize_t)(node->value_count - 1), limit, is_partial);
+    } else
+        found_pos = simple_string_search_rev(state, node, text_pos, limit,
+          is_partial);
+
+    return found_pos;
+}
+
+/* Returns how many characters there could be before full case-folding. */
+Py_LOCAL_INLINE(Py_ssize_t) possible_unfolded_length(Py_ssize_t length) {
+    if (length == 0)
+        return 0;
+
+    if (length < RE_MAX_FOLDED)
+        return 1;
+
+    return length / RE_MAX_FOLDED;
+}
+
+/* Checks whether there's any character except a newline at a position. */
+Py_LOCAL_INLINE(int) try_match_ANY(RE_State* state, RE_Node* node, Py_ssize_t
+  text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_ANY(state->encoding, node, state->char_at(state->text,
+      text_pos)));
+}
+
+/* Checks whether there's any character at all at a position. */
+Py_LOCAL_INLINE(int) try_match_ANY_ALL(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end);
+}
+
+/* Checks whether there's any character at all at a position, backwards. */
+Py_LOCAL_INLINE(int) try_match_ANY_ALL_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start);
+}
+
+/* Checks whether there's any character except a newline at a position,
+ * backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_ANY_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_ANY(state->encoding, node, state->char_at(state->text, text_pos -
+      1)));
+}
+
+/* Checks whether there's any character except a line separator at a position.
+ */
+Py_LOCAL_INLINE(int) try_match_ANY_U(RE_State* state, RE_Node* node, Py_ssize_t
+  text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_ANY_U(state->encoding, node, state->char_at(state->text,
+      text_pos)));
+}
+
+/* Checks whether there's any character except a line separator at a position,
+ * backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_ANY_U_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_ANY_U(state->encoding, node, state->char_at(state->text, text_pos
+      - 1)));
+}
+
+/* Checks whether a position is on a word boundary. */
+Py_LOCAL_INLINE(int) try_match_BOUNDARY(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_boundary(state, text_pos) ==
+      node->match);
+}
+
+/* Checks whether there's a character at a position. */
+Py_LOCAL_INLINE(int) try_match_CHARACTER(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_CHARACTER(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos)) == node->match);
+}
+
+/* Checks whether there's a character at a position, ignoring case. */
+Py_LOCAL_INLINE(int) try_match_CHARACTER_IGN(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_CHARACTER_IGN(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos)) == node->match);
+}
+
+/* Checks whether there's a character at a position, ignoring case, backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_CHARACTER_IGN_REV(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_CHARACTER_IGN(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos - 1)) == node->match);
+}
+
+/* Checks whether there's a character at a position, backwards. */
+Py_LOCAL_INLINE(int) try_match_CHARACTER_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_CHARACTER(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos - 1)) == node->match);
+}
+
+/* Checks whether a position is on a default word boundary. */
+Py_LOCAL_INLINE(int) try_match_DEFAULT_BOUNDARY(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_default_boundary(state, text_pos)
+      == node->match);
+}
+
+/* Checks whether a position is at the default end of a word. */
+Py_LOCAL_INLINE(int) try_match_DEFAULT_END_OF_WORD(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_default_word_end(state,
+      text_pos));
+}
+
+/* Checks whether a position is at the default start of a word. */
+Py_LOCAL_INLINE(int) try_match_DEFAULT_START_OF_WORD(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_default_word_start(state,
+      text_pos));
+}
+
+/* Checks whether a position is at the end of a line. */
+Py_LOCAL_INLINE(int) try_match_END_OF_LINE(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(text_pos >= state->slice_end ||
+      state->char_at(state->text, text_pos) == '\n');
+}
+
+/* Checks whether a position is at the end of a line. */
+Py_LOCAL_INLINE(int) try_match_END_OF_LINE_U(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_line_end(state, text_pos));
+}
+
+/* Checks whether a position is at the end of the string. */
+Py_LOCAL_INLINE(int) try_match_END_OF_STRING(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(text_pos >= state->text_length);
+}
+
+/* Checks whether a position is at the end of a line or the string. */
+Py_LOCAL_INLINE(int) try_match_END_OF_STRING_LINE(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos) {
+    return bool_as_status(text_pos >= state->text_length || text_pos ==
+      state->final_newline);
+}
+
+/* Checks whether a position is at the end of the string. */
+Py_LOCAL_INLINE(int) try_match_END_OF_STRING_LINE_U(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos) {
+    return bool_as_status(text_pos >= state->text_length || text_pos ==
+      state->final_line_sep);
+}
+
+/* Checks whether a position is at the end of a word. */
+Py_LOCAL_INLINE(int) try_match_END_OF_WORD(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_word_end(state, text_pos));
+}
+
+/* Checks whether a position is on a grapheme boundary. */
+Py_LOCAL_INLINE(int) try_match_GRAPHEME_BOUNDARY(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_grapheme_boundary(state,
+      text_pos));
+}
+
+/* Checks whether there's a character with a certain property at a position. */
+Py_LOCAL_INLINE(int) try_match_PROPERTY(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_PROPERTY(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos)) == node->match);
+}
+
+/* Checks whether there's a character with a certain property at a position,
+ * ignoring case.
+ */
+Py_LOCAL_INLINE(int) try_match_PROPERTY_IGN(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_PROPERTY_IGN(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos)) == node->match);
+}
+
+/* Checks whether there's a character with a certain property at a position,
+ * ignoring case, backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_PROPERTY_IGN_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_PROPERTY_IGN(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos - 1)) == node->match);
+}
+
+/* Checks whether there's a character with a certain property at a position,
+ * backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_PROPERTY_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_PROPERTY(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos - 1)) == node->match);
+}
+
+/* Checks whether there's a character in a certain range at a position. */
+Py_LOCAL_INLINE(int) try_match_RANGE(RE_State* state, RE_Node* node, Py_ssize_t
+  text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_RANGE(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos)) == node->match);
+}
+
+/* Checks whether there's a character in a certain range at a position,
+ * ignoring case.
+ */
+Py_LOCAL_INLINE(int) try_match_RANGE_IGN(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_RANGE_IGN(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos)) == node->match);
+}
+
+/* Checks whether there's a character in a certain range at a position,
+ * ignoring case, backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_RANGE_IGN_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_RANGE_IGN(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos - 1)) == node->match);
+}
+
+/* Checks whether there's a character in a certain range at a position,
+ * backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_RANGE_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_RANGE(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos - 1)) == node->match);
+}
+
+/* Checks whether a position is at the search anchor. */
+Py_LOCAL_INLINE(int) try_match_SEARCH_ANCHOR(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(text_pos == state->search_anchor);
+}
+
+/* Checks whether there's a character in a certain set at a position. */
+Py_LOCAL_INLINE(int) try_match_SET(RE_State* state, RE_Node* node, Py_ssize_t
+  text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_SET(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos)) == node->match);
+}
+
+/* Checks whether there's a character in a certain set at a position, ignoring
+ * case.
+ */
+Py_LOCAL_INLINE(int) try_match_SET_IGN(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos >= state->text_length) {
+        if (state->partial_side == RE_PARTIAL_RIGHT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos < state->slice_end &&
+      matches_SET_IGN(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos)) == node->match);
+}
+
+/* Checks whether there's a character in a certain set at a position, ignoring
+ * case, backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_SET_IGN_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_SET_IGN(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos - 1)) == node->match);
+}
+
+/* Checks whether there's a character in a certain set at a position,
+ * backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_SET_REV(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    if (text_pos <= 0) {
+        if (state->partial_side == RE_PARTIAL_LEFT)
+            return RE_ERROR_PARTIAL;
+
+        return RE_ERROR_FAILURE;
+    }
+
+    return bool_as_status(text_pos > state->slice_start &&
+      matches_SET(state->encoding, state->locale_info, node,
+      state->char_at(state->text, text_pos - 1)) == node->match);
+}
+
+/* Checks whether a position is at the start of a line. */
+Py_LOCAL_INLINE(int) try_match_START_OF_LINE(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(text_pos <= 0 || state->char_at(state->text, text_pos
+      - 1) == '\n');
+}
+
+/* Checks whether a position is at the start of a line. */
+Py_LOCAL_INLINE(int) try_match_START_OF_LINE_U(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_line_start(state, text_pos));
+}
+
+/* Checks whether a position is at the start of the string. */
+Py_LOCAL_INLINE(int) try_match_START_OF_STRING(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(text_pos <= 0);
+}
+
+/* Checks whether a position is at the start of a word. */
+Py_LOCAL_INLINE(int) try_match_START_OF_WORD(RE_State* state, RE_Node* node,
+  Py_ssize_t text_pos) {
+    return bool_as_status(state->encoding->at_word_start(state, text_pos));
+}
+
+/* Checks whether there's a certain string at a position. */
+Py_LOCAL_INLINE(int) try_match_STRING(RE_State* state, RE_NextNode* next,
+  RE_Node* node, Py_ssize_t text_pos, RE_Position* next_position) {
+    Py_ssize_t length;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    RE_CODE* values;
+    Py_ssize_t s_pos;
+
+    length = (Py_ssize_t)node->value_count;
+    char_at = state->char_at;
+    values = node->values;
+
+    for (s_pos = 0; s_pos < length; s_pos++) {
+        if (text_pos + s_pos >= state->slice_end) {
+            if (state->partial_side == RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            return RE_ERROR_FAILURE;
+        }
+
+        if (!same_char(char_at(state->text, text_pos + s_pos), values[s_pos]))
+            return RE_ERROR_FAILURE;
+    }
+
+    next_position->node = next->match_next;
+    next_position->text_pos = text_pos + next->match_step;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Checks whether there's a certain string at a position, ignoring case. */
+Py_LOCAL_INLINE(int) try_match_STRING_FLD(RE_State* state, RE_NextNode* next,
+  RE_Node* node, Py_ssize_t text_pos, RE_Position* next_position) {
+    Py_ssize_t length;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+      folded);
+    Py_ssize_t s_pos;
+    RE_CODE* values;
+    int folded_len;
+    int f_pos;
+    Py_ssize_t start_pos;
+    Py_UCS4 folded[RE_MAX_FOLDED];
+
+    length = (Py_ssize_t)node->value_count;
+    char_at = state->char_at;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    full_case_fold = encoding->full_case_fold;
+
+    s_pos = 0;
+    values = node->values;
+    folded_len = 0;
+    f_pos = 0;
+    start_pos = text_pos;
+
+    while (s_pos < length) {
+        if (f_pos >= folded_len) {
+            /* Fetch and casefold another character. */
+            if (text_pos >= state->slice_end) {
+                if (state->partial_side == RE_PARTIAL_RIGHT)
+                    return RE_ERROR_PARTIAL;
+
+                return RE_ERROR_FAILURE;
+            }
+
+            folded_len = full_case_fold(locale_info, char_at(state->text,
+              text_pos), folded);
+            f_pos = 0;
+        }
+
+        if (!same_char_ign(encoding, locale_info, folded[f_pos],
+          values[s_pos]))
+            return RE_ERROR_FAILURE;
+
+        ++s_pos;
+        ++f_pos;
+
+        if (f_pos >= folded_len)
+            ++text_pos;
+    }
+
+    if (f_pos < folded_len)
+        return RE_ERROR_FAILURE;
+
+    next_position->node = next->match_next;
+    if (next->match_step == 0)
+        next_position->text_pos = start_pos;
+    else
+        next_position->text_pos = text_pos;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Checks whether there's a certain string at a position, ignoring case,
+ * backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_STRING_FLD_REV(RE_State* state, RE_NextNode*
+  next, RE_Node* node, Py_ssize_t text_pos, RE_Position* next_position) {
+    Py_ssize_t length;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+      folded);
+    Py_ssize_t s_pos;
+    RE_CODE* values;
+    int folded_len;
+    int f_pos;
+    Py_ssize_t start_pos;
+    Py_UCS4 folded[RE_MAX_FOLDED];
+
+    length = (Py_ssize_t)node->value_count;
+    char_at = state->char_at;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    full_case_fold = encoding->full_case_fold;
+
+    s_pos = 0;
+    values = node->values;
+    folded_len = 0;
+    f_pos = 0;
+    start_pos = text_pos;
+
+    while (s_pos < length) {
+        if (f_pos >= folded_len) {
+            /* Fetch and casefold another character. */
+            if (text_pos <= state->slice_start) {
+                if (state->partial_side == RE_PARTIAL_LEFT)
+                    return RE_ERROR_PARTIAL;
+
+                return RE_ERROR_FAILURE;
+            }
+
+            folded_len = full_case_fold(locale_info, char_at(state->text,
+              text_pos - 1), folded);
+            f_pos = 0;
+        }
+
+        if (!same_char_ign(encoding, locale_info, folded[folded_len - f_pos -
+          1], values[length - s_pos - 1]))
+            return RE_ERROR_FAILURE;
+
+        ++s_pos;
+        ++f_pos;
+
+        if (f_pos >= folded_len)
+            --text_pos;
+    }
+
+    if (f_pos < folded_len)
+        return RE_ERROR_FAILURE;
+
+    next_position->node = next->match_next;
+    if (next->match_step == 0)
+        next_position->text_pos = start_pos;
+    else
+        next_position->text_pos = text_pos;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Checks whether there's a certain string at a position, ignoring case. */
+Py_LOCAL_INLINE(int) try_match_STRING_IGN(RE_State* state, RE_NextNode* next,
+  RE_Node* node, Py_ssize_t text_pos, RE_Position* next_position) {
+    Py_ssize_t length;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    RE_CODE* values;
+    Py_ssize_t s_pos;
+
+    length = (Py_ssize_t)node->value_count;
+    char_at = state->char_at;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    values = node->values;
+
+    for (s_pos = 0; s_pos < length; s_pos++) {
+        if (text_pos + s_pos >= state->slice_end) {
+            if (state->partial_side == RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            return RE_ERROR_FAILURE;
+        }
+
+        if (!same_char_ign(encoding, locale_info, char_at(state->text, text_pos
+          + s_pos), values[s_pos]))
+            return RE_ERROR_FAILURE;
+    }
+
+    next_position->node = next->match_next;
+    next_position->text_pos = text_pos + next->match_step;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Checks whether there's a certain string at a position, ignoring case,
+ * backwards.
+ */
+Py_LOCAL_INLINE(int) try_match_STRING_IGN_REV(RE_State* state, RE_NextNode*
+  next, RE_Node* node, Py_ssize_t text_pos, RE_Position* next_position) {
+    Py_ssize_t length;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    RE_CODE* values;
+    Py_ssize_t s_pos;
+
+    length = (Py_ssize_t)node->value_count;
+    char_at = state->char_at;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    values = node->values;
+
+    for (s_pos = 0; s_pos < length; s_pos++) {
+        if (text_pos - s_pos <= state->slice_start) {
+            if (state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            return RE_ERROR_FAILURE;
+        }
+
+        if (!same_char_ign(encoding, locale_info, char_at(state->text, text_pos
+          - s_pos - 1), values[length - s_pos - 1]))
+            return RE_ERROR_FAILURE;
+    }
+
+    next_position->node = next->match_next;
+    next_position->text_pos = text_pos + next->match_step;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Checks whether there's a certain string at a position, backwards. */
+Py_LOCAL_INLINE(int) try_match_STRING_REV(RE_State* state, RE_NextNode* next,
+  RE_Node* node, Py_ssize_t text_pos, RE_Position* next_position) {
+    Py_ssize_t length;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    RE_CODE* values;
+    Py_ssize_t s_pos;
+
+    length = (Py_ssize_t)node->value_count;
+    char_at = state->char_at;
+    values = node->values;
+
+    for (s_pos = 0; s_pos < length; s_pos++) {
+        if (text_pos - s_pos <= state->slice_start) {
+            if (state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            return RE_ERROR_FAILURE;
+        }
+
+        if (!same_char(char_at(state->text, text_pos - s_pos - 1),
+          values[length - s_pos - 1]))
+            return RE_ERROR_FAILURE;
+    }
+
+    next_position->node = next->match_next;
+    next_position->text_pos = text_pos + next->match_step;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Tries a match at the current text position.
+ *
+ * Returns the next node and text position if the match succeeds.
+ */
+Py_LOCAL_INLINE(int) try_match(RE_State* state, RE_NextNode* next, Py_ssize_t
+  text_pos, RE_Position* next_position) {
+    RE_Node* test;
+    int status;
+
+    test = next->test;
+
+    if (test->status & RE_STATUS_FUZZY) {
+        next_position->node = next->node;
+        next_position->text_pos = text_pos;
+        return RE_ERROR_SUCCESS;
+    }
+
+    switch (test->op) {
+    case RE_OP_ANY:
+        status = try_match_ANY(state, test, text_pos);
+        break;
+    case RE_OP_ANY_ALL:
+        status = try_match_ANY_ALL(state, test, text_pos);
+        break;
+    case RE_OP_ANY_ALL_REV:
+        status = try_match_ANY_ALL_REV(state, test, text_pos);
+        break;
+    case RE_OP_ANY_REV:
+        status = try_match_ANY_REV(state, test, text_pos);
+        break;
+    case RE_OP_ANY_U:
+        status = try_match_ANY_U(state, test, text_pos);
+        break;
+    case RE_OP_ANY_U_REV:
+        status = try_match_ANY_U_REV(state, test, text_pos);
+        break;
+    case RE_OP_BOUNDARY:
+        status = try_match_BOUNDARY(state, test, text_pos);
+        break;
+    case RE_OP_BRANCH:
+        status = try_match(state, &test->next_1, text_pos, next_position);
+        if (status == RE_ERROR_FAILURE)
+            status = try_match(state, &test->nonstring.next_2, text_pos,
+              next_position);
+        break;
+    case RE_OP_CHARACTER:
+        status = try_match_CHARACTER(state, test, text_pos);
+        break;
+    case RE_OP_CHARACTER_IGN:
+        status = try_match_CHARACTER_IGN(state, test, text_pos);
+        break;
+    case RE_OP_CHARACTER_IGN_REV:
+        status = try_match_CHARACTER_IGN_REV(state, test, text_pos);
+        break;
+    case RE_OP_CHARACTER_REV:
+        status = try_match_CHARACTER_REV(state, test, text_pos);
+        break;
+    case RE_OP_DEFAULT_BOUNDARY:
+        status = try_match_DEFAULT_BOUNDARY(state, test, text_pos);
+        break;
+    case RE_OP_DEFAULT_END_OF_WORD:
+        status = try_match_DEFAULT_END_OF_WORD(state, test, text_pos);
+        break;
+    case RE_OP_DEFAULT_START_OF_WORD:
+        status = try_match_DEFAULT_START_OF_WORD(state, test, text_pos);
+        break;
+    case RE_OP_END_OF_LINE:
+        status = try_match_END_OF_LINE(state, test, text_pos);
+        break;
+    case RE_OP_END_OF_LINE_U:
+        status = try_match_END_OF_LINE_U(state, test, text_pos);
+        break;
+    case RE_OP_END_OF_STRING:
+        status = try_match_END_OF_STRING(state, test, text_pos);
+        break;
+    case RE_OP_END_OF_STRING_LINE:
+        status = try_match_END_OF_STRING_LINE(state, test, text_pos);
+        break;
+    case RE_OP_END_OF_STRING_LINE_U:
+        status = try_match_END_OF_STRING_LINE_U(state, test, text_pos);
+        break;
+    case RE_OP_END_OF_WORD:
+        status = try_match_END_OF_WORD(state, test, text_pos);
+        break;
+    case RE_OP_GRAPHEME_BOUNDARY:
+        status = try_match_GRAPHEME_BOUNDARY(state, test, text_pos);
+        break;
+    case RE_OP_PROPERTY:
+        status = try_match_PROPERTY(state, test, text_pos);
+        break;
+    case RE_OP_PROPERTY_IGN:
+        status = try_match_PROPERTY_IGN(state, test, text_pos);
+        break;
+    case RE_OP_PROPERTY_IGN_REV:
+        status = try_match_PROPERTY_IGN_REV(state, test, text_pos);
+        break;
+    case RE_OP_PROPERTY_REV:
+        status = try_match_PROPERTY_REV(state, test, text_pos);
+        break;
+    case RE_OP_RANGE:
+        status = try_match_RANGE(state, test, text_pos);
+        break;
+    case RE_OP_RANGE_IGN:
+        status = try_match_RANGE_IGN(state, test, text_pos);
+        break;
+    case RE_OP_RANGE_IGN_REV:
+        status = try_match_RANGE_IGN_REV(state, test, text_pos);
+        break;
+    case RE_OP_RANGE_REV:
+        status = try_match_RANGE_REV(state, test, text_pos);
+        break;
+    case RE_OP_SEARCH_ANCHOR:
+        status = try_match_SEARCH_ANCHOR(state, test, text_pos);
+        break;
+    case RE_OP_SET_DIFF:
+    case RE_OP_SET_INTER:
+    case RE_OP_SET_SYM_DIFF:
+    case RE_OP_SET_UNION:
+        status = try_match_SET(state, test, text_pos);
+        break;
+    case RE_OP_SET_DIFF_IGN:
+    case RE_OP_SET_INTER_IGN:
+    case RE_OP_SET_SYM_DIFF_IGN:
+    case RE_OP_SET_UNION_IGN:
+        status = try_match_SET_IGN(state, test, text_pos);
+        break;
+    case RE_OP_SET_DIFF_IGN_REV:
+    case RE_OP_SET_INTER_IGN_REV:
+    case RE_OP_SET_SYM_DIFF_IGN_REV:
+    case RE_OP_SET_UNION_IGN_REV:
+        status = try_match_SET_IGN_REV(state, test, text_pos);
+        break;
+    case RE_OP_SET_DIFF_REV:
+    case RE_OP_SET_INTER_REV:
+    case RE_OP_SET_SYM_DIFF_REV:
+    case RE_OP_SET_UNION_REV:
+        status = try_match_SET_REV(state, test, text_pos);
+        break;
+    case RE_OP_START_OF_LINE:
+        status = try_match_START_OF_LINE(state, test, text_pos);
+        break;
+    case RE_OP_START_OF_LINE_U:
+        status = try_match_START_OF_LINE_U(state, test, text_pos);
+        break;
+    case RE_OP_START_OF_STRING:
+        status = try_match_START_OF_STRING(state, test, text_pos);
+        break;
+    case RE_OP_START_OF_WORD:
+        status = try_match_START_OF_WORD(state, test, text_pos);
+        break;
+    case RE_OP_STRING:
+        return try_match_STRING(state, next, test, text_pos, next_position);
+    case RE_OP_STRING_FLD:
+        return try_match_STRING_FLD(state, next, test, text_pos,
+          next_position);
+    case RE_OP_STRING_FLD_REV:
+        return try_match_STRING_FLD_REV(state, next, test, text_pos,
+          next_position);
+    case RE_OP_STRING_IGN:
+        return try_match_STRING_IGN(state, next, test, text_pos,
+          next_position);
+    case RE_OP_STRING_IGN_REV:
+        return try_match_STRING_IGN_REV(state, next, test, text_pos,
+          next_position);
+    case RE_OP_STRING_REV:
+        return try_match_STRING_REV(state, next, test, text_pos,
+          next_position);
+    default:
+        next_position->node = next->node;
+        next_position->text_pos = text_pos;
+        return RE_ERROR_SUCCESS;
+    }
+
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    next_position->node = next->match_next;
+    next_position->text_pos = text_pos + next->match_step;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Searches for a word boundary. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_BOUNDARY(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_boundary)(RE_State* state, Py_ssize_t text_pos);
+
+    at_boundary = state->encoding->at_boundary;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_boundary(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for a word boundary, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_BOUNDARY_rev(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_boundary)(RE_State* state, Py_ssize_t text_pos);
+
+    at_boundary = state->encoding->at_boundary;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_boundary(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for a default word boundary. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_DEFAULT_BOUNDARY(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_default_boundary)(RE_State* state, Py_ssize_t text_pos);
+
+    at_default_boundary = state->encoding->at_default_boundary;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_default_boundary(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for a default word boundary, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_DEFAULT_BOUNDARY_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_default_boundary)(RE_State* state, Py_ssize_t text_pos);
+
+    at_default_boundary = state->encoding->at_default_boundary;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_default_boundary(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for the default end of a word. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_DEFAULT_END_OF_WORD(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_default_word_end)(RE_State* state, Py_ssize_t text_pos);
+
+    at_default_word_end = state->encoding->at_default_word_end;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_default_word_end(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for the default end of a word, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_DEFAULT_END_OF_WORD_rev(RE_State*
+  state, RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_default_word_end)(RE_State* state, Py_ssize_t text_pos);
+
+    at_default_word_end = state->encoding->at_default_word_end;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_default_word_end(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for the default start of a word. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_DEFAULT_START_OF_WORD(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_default_word_start)(RE_State* state, Py_ssize_t text_pos);
+
+    at_default_word_start = state->encoding->at_default_word_start;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_default_word_start(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for the default start of a word, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_DEFAULT_START_OF_WORD_rev(RE_State*
+  state, RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_default_word_start)(RE_State* state, Py_ssize_t text_pos);
+
+    at_default_word_start = state->encoding->at_default_word_start;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_default_word_start(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for the end of line. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_END_OF_LINE(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (text_pos >= state->text_length || state->char_at(state->text,
+          text_pos) == '\n')
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for the end of line, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_END_OF_LINE_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (text_pos >= state->text_length || state->char_at(state->text,
+          text_pos) == '\n')
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for the end of the string. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_END_OF_STRING(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    if (state->slice_end >= state->text_length)
+        return state->text_length;
+
+    return -1;
+}
+
+/* Searches for the end of the string, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_END_OF_STRING_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    if (text_pos >= state->text_length)
+        return text_pos;
+
+    return -1;
+}
+
+/* Searches for the end of the string or line. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_END_OF_STRING_LINE(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    if (text_pos <= state->final_newline)
+        text_pos = state->final_newline;
+    else if (text_pos <= state->text_length)
+        text_pos = state->text_length;
+
+    if (text_pos > state->slice_end)
+        return -1;
+
+    if (text_pos >= state->text_length)
+        return text_pos;
+
+    return text_pos;
+}
+
+/* Searches for the end of the string or line, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_END_OF_STRING_LINE_rev(RE_State*
+  state, RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    if (text_pos >= state->text_length)
+        text_pos = state->text_length;
+    else if (text_pos >= state->final_newline)
+        text_pos = state->final_newline;
+    else
+        return -1;
+
+    if (text_pos < state->slice_start)
+        return -1;
+
+    if (text_pos <= 0)
+        return text_pos;
+
+    return text_pos;
+}
+
+/* Searches for the end of a word. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_END_OF_WORD(RE_State* state, RE_Node*
+  node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_word_end)(RE_State* state, Py_ssize_t text_pos);
+
+    at_word_end = state->encoding->at_word_end;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_word_end(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for the end of a word, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_END_OF_WORD_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_word_end)(RE_State* state, Py_ssize_t text_pos);
+
+    at_word_end = state->encoding->at_word_end;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_word_end(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for a grapheme boundary. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_GRAPHEME_BOUNDARY(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_grapheme_boundary)(RE_State* state, Py_ssize_t text_pos);
+
+    at_grapheme_boundary = state->encoding->at_grapheme_boundary;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_grapheme_boundary(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for a grapheme boundary, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_GRAPHEME_BOUNDARY_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_grapheme_boundary)(RE_State* state, Py_ssize_t text_pos);
+
+    at_grapheme_boundary = state->encoding->at_grapheme_boundary;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_grapheme_boundary(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for the start of line. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_START_OF_LINE(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (text_pos <= 0 || state->char_at(state->text, text_pos - 1) == '\n')
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for the start of line, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_START_OF_LINE_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (text_pos <= 0 || state->char_at(state->text, text_pos - 1) == '\n')
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for the start of the string. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_START_OF_STRING(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    if (text_pos <= 0)
+        return text_pos;
+
+    return -1;
+}
+
+/* Searches for the start of the string, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_START_OF_STRING_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    *is_partial = FALSE;
+
+    if (state->slice_start <= 0)
+        return 0;
+
+    return -1;
+}
+
+/* Searches for the start of a word. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_START_OF_WORD(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_word_start)(RE_State* state, Py_ssize_t text_pos);
+
+    at_word_start = state->encoding->at_word_start;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_word_start(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos >= state->slice_end)
+            return -1;
+
+        ++text_pos;
+    }
+}
+
+/* Searches for the start of a word, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_START_OF_WORD_rev(RE_State* state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    BOOL (*at_word_start)(RE_State* state, Py_ssize_t text_pos);
+
+    at_word_start = state->encoding->at_word_start;
+
+    *is_partial = FALSE;
+
+    for (;;) {
+        if (at_word_start(state, text_pos) == node->match)
+            return text_pos;
+
+        if (text_pos <= state->slice_start)
+            return -1;
+
+        --text_pos;
+    }
+}
+
+/* Searches for a string. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_STRING(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    RE_State* state;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    if ((node->status & RE_STATUS_REQUIRED) && text_pos == state->req_pos)
+        return text_pos;
+
+    return string_search(safe_state, node, text_pos, state->slice_end,
+      is_partial);
+}
+
+/* Searches for a string, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_STRING_FLD(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, Py_ssize_t* new_pos, BOOL* is_partial) {
+    RE_State* state;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    if ((node->status & RE_STATUS_REQUIRED) && text_pos == state->req_pos) {
+        *new_pos = state->req_end;
+        return text_pos;
+    }
+
+    return string_search_fld(safe_state, node, text_pos, state->slice_end,
+      new_pos, is_partial);
+}
+
+/* Searches for a string, ignoring case, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_STRING_FLD_REV(RE_SafeState*
+  safe_state, RE_Node* node, Py_ssize_t text_pos, Py_ssize_t* new_pos, BOOL*
+  is_partial) {
+    RE_State* state;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    if ((node->status & RE_STATUS_REQUIRED) && text_pos == state->req_pos) {
+        *new_pos = state->req_end;
+        return text_pos;
+    }
+
+    return string_search_fld_rev(safe_state, node, text_pos,
+      state->slice_start, new_pos, is_partial);
+}
+
+/* Searches for a string, ignoring case. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_STRING_IGN(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    RE_State* state;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    if ((node->status & RE_STATUS_REQUIRED) && text_pos == state->req_pos)
+        return text_pos;
+
+    return string_search_ign(safe_state, node, text_pos, state->slice_end,
+      is_partial);
+}
+
+/* Searches for a string, ignoring case, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_STRING_IGN_REV(RE_SafeState*
+  safe_state, RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    RE_State* state;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    if ((node->status & RE_STATUS_REQUIRED) && text_pos == state->req_pos)
+        return text_pos;
+
+    return string_search_ign_rev(safe_state, node, text_pos,
+      state->slice_start, is_partial);
+}
+
+/* Searches for a string, backwards. */
+Py_LOCAL_INLINE(Py_ssize_t) search_start_STRING_REV(RE_SafeState* safe_state,
+  RE_Node* node, Py_ssize_t text_pos, BOOL* is_partial) {
+    RE_State* state;
+
+    state = safe_state->re_state;
+
+    *is_partial = FALSE;
+
+    if ((node->status & RE_STATUS_REQUIRED) && text_pos == state->req_pos)
+        return text_pos;
+
+    return string_search_rev(safe_state, node, text_pos, state->slice_start,
+      is_partial);
+}
+
+/* Searches for the start of a match. */
+Py_LOCAL_INLINE(int) search_start(RE_SafeState* safe_state, RE_NextNode* next,
+  RE_Position* new_position, int search_index) {
+    RE_State* state;
+    Py_ssize_t start_pos;
+    RE_Node* test;
+    RE_Node* node;
+    RE_SearchPosition* info;
+    Py_ssize_t text_pos;
+
+    state = safe_state->re_state;
+
+    start_pos = state->text_pos;
+    TRACE(("<<search_start>> at %d\n", start_pos))
+
+    test = next->test;
+    node = next->node;
+
+    if (state->reverse) {
+        if (start_pos < state->slice_start) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = state->slice_start;
+                return RE_ERROR_PARTIAL;
+            }
+
+            return RE_ERROR_FAILURE;
+        }
+    } else {
+        if (start_pos > state->slice_end) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = state->slice_end;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+    }
+
+    if (test->status & RE_STATUS_FUZZY) {
+        /* Don't call 'search_start' again. */
+        state->pattern->do_search_start = FALSE;
+
+        state->match_pos = start_pos;
+        new_position->node = node;
+        new_position->text_pos = start_pos;
+
+        return RE_ERROR_SUCCESS;
+    }
+
+again:
+    if (!state->pattern->is_fuzzy && state->partial_side == RE_PARTIAL_NONE) {
+        if (state->reverse) {
+            if (start_pos - state->min_width < state->slice_start)
+                return RE_ERROR_FAILURE;
+        } else {
+            if (start_pos + state->min_width > state->slice_end)
+                return RE_ERROR_FAILURE;
+        }
+    }
+
+    if (search_index < MAX_SEARCH_POSITIONS) {
+        info = &state->search_positions[search_index];
+        if (state->reverse) {
+            if (info->start_pos >= 0 && info->start_pos >= start_pos &&
+              start_pos >= info->match_pos) {
+                state->match_pos = info->match_pos;
+
+                new_position->text_pos = state->match_pos;
+                new_position->node = node;
+
+                return RE_ERROR_SUCCESS;
+            }
+        } else {
+            if (info->start_pos >= 0 && info->start_pos <= start_pos &&
+              start_pos <= info->match_pos) {
+                state->match_pos = info->match_pos;
+
+                new_position->text_pos = state->match_pos;
+                new_position->node = node;
+
+                return RE_ERROR_SUCCESS;
+            }
+        }
+    } else
+        info = NULL;
+
+    switch (test->op) {
+    case RE_OP_ANY:
+        start_pos = match_many_ANY(state, test, start_pos, state->slice_end,
+          FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_ANY_ALL:
+    case RE_OP_ANY_ALL_REV:
+        break;
+    case RE_OP_ANY_REV:
+        start_pos = match_many_ANY_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_ANY_U:
+        start_pos = match_many_ANY_U(state, test, start_pos, state->slice_end,
+          FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_ANY_U_REV:
+        start_pos = match_many_ANY_U_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_BOUNDARY:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_BOUNDARY_rev(state, test, start_pos,
+              &is_partial);
+        else
+            start_pos = search_start_BOUNDARY(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_CHARACTER:
+        start_pos = match_many_CHARACTER(state, test, start_pos,
+          state->slice_end, FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_CHARACTER_IGN:
+        start_pos = match_many_CHARACTER_IGN(state, test, start_pos,
+          state->slice_end, FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_CHARACTER_IGN_REV:
+        start_pos = match_many_CHARACTER_IGN_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_CHARACTER_REV:
+        start_pos = match_many_CHARACTER_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_DEFAULT_BOUNDARY:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_DEFAULT_BOUNDARY_rev(state, test,
+              start_pos, &is_partial);
+        else
+            start_pos = search_start_DEFAULT_BOUNDARY(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_DEFAULT_END_OF_WORD:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_DEFAULT_END_OF_WORD_rev(state, test,
+              start_pos, &is_partial);
+        else
+            start_pos = search_start_DEFAULT_END_OF_WORD(state, test,
+              start_pos, &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_DEFAULT_START_OF_WORD:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_DEFAULT_START_OF_WORD_rev(state, test,
+              start_pos, &is_partial);
+        else
+            start_pos = search_start_DEFAULT_START_OF_WORD(state, test,
+              start_pos, &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_END_OF_LINE:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_END_OF_LINE_rev(state, test, start_pos,
+              &is_partial);
+        else
+            start_pos = search_start_END_OF_LINE(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_END_OF_STRING:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_END_OF_STRING_rev(state, test, start_pos,
+              &is_partial);
+        else
+            start_pos = search_start_END_OF_STRING(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_END_OF_STRING_LINE:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_END_OF_STRING_LINE_rev(state, test,
+              start_pos, &is_partial);
+        else
+            start_pos = search_start_END_OF_STRING_LINE(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_END_OF_WORD:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_END_OF_WORD_rev(state, test, start_pos,
+              &is_partial);
+        else
+            start_pos = search_start_END_OF_WORD(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_GRAPHEME_BOUNDARY:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_GRAPHEME_BOUNDARY_rev(state, test,
+              start_pos, &is_partial);
+        else
+            start_pos = search_start_GRAPHEME_BOUNDARY(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_PROPERTY:
+        start_pos = match_many_PROPERTY(state, test, start_pos,
+          state->slice_end, FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_PROPERTY_IGN:
+        start_pos = match_many_PROPERTY_IGN(state, test, start_pos,
+          state->slice_end, FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_PROPERTY_IGN_REV:
+        start_pos = match_many_PROPERTY_IGN_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_PROPERTY_REV:
+        start_pos = match_many_PROPERTY_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_RANGE:
+        start_pos = match_many_RANGE(state, test, start_pos, state->slice_end,
+          FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_RANGE_IGN:
+        start_pos = match_many_RANGE_IGN(state, test, start_pos,
+          state->slice_end, FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_RANGE_IGN_REV:
+        start_pos = match_many_RANGE_IGN_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_RANGE_REV:
+        start_pos = match_many_RANGE_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return RE_ERROR_FAILURE;
+        break;
+    case RE_OP_SEARCH_ANCHOR:
+        if (state->reverse) {
+            if (start_pos < state->search_anchor)
+                return RE_ERROR_FAILURE;
+        } else {
+            if (start_pos > state->search_anchor)
+                return RE_ERROR_FAILURE;
+        }
+
+        start_pos = state->search_anchor;
+        break;
+    case RE_OP_SET_DIFF:
+    case RE_OP_SET_INTER:
+    case RE_OP_SET_SYM_DIFF:
+    case RE_OP_SET_UNION:
+        start_pos = match_many_SET(state, test, start_pos, state->slice_end,
+          FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return FALSE;
+        break;
+    case RE_OP_SET_DIFF_IGN:
+    case RE_OP_SET_INTER_IGN:
+    case RE_OP_SET_SYM_DIFF_IGN:
+    case RE_OP_SET_UNION_IGN:
+        start_pos = match_many_SET_IGN(state, test, start_pos,
+          state->slice_end, FALSE);
+
+        if (start_pos >= state->text_length) {
+            if (state->partial_side == RE_PARTIAL_RIGHT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos >= state->slice_end)
+            return FALSE;
+        break;
+    case RE_OP_SET_DIFF_IGN_REV:
+    case RE_OP_SET_INTER_IGN_REV:
+    case RE_OP_SET_SYM_DIFF_IGN_REV:
+    case RE_OP_SET_UNION_IGN_REV:
+        start_pos = match_many_SET_IGN_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return FALSE;
+        break;
+    case RE_OP_SET_DIFF_REV:
+    case RE_OP_SET_INTER_REV:
+    case RE_OP_SET_SYM_DIFF_REV:
+    case RE_OP_SET_UNION_REV:
+        start_pos = match_many_SET_REV(state, test, start_pos,
+          state->slice_start, FALSE);
+
+        if (start_pos <= 0) {
+            if (state->partial_side == RE_PARTIAL_LEFT) {
+                new_position->text_pos = start_pos;
+                return RE_ERROR_PARTIAL;
+            }
+        }
+
+        if (start_pos <= state->slice_start)
+            return FALSE;
+        break;
+    case RE_OP_START_OF_LINE:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_START_OF_LINE_rev(state, test, start_pos,
+              &is_partial);
+        else
+            start_pos = search_start_START_OF_LINE(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_START_OF_STRING:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_START_OF_STRING_rev(state, test,
+              start_pos, &is_partial);
+        else
+            start_pos = search_start_START_OF_STRING(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_START_OF_WORD:
+    {
+        BOOL is_partial;
+
+        if (state->reverse)
+            start_pos = search_start_START_OF_WORD_rev(state, test, start_pos,
+              &is_partial);
+        else
+            start_pos = search_start_START_OF_WORD(state, test, start_pos,
+              &is_partial);
+
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_STRING:
+    {
+        BOOL is_partial;
+
+        start_pos = search_start_STRING(safe_state, test, start_pos,
+          &is_partial);
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_STRING_FLD:
+    {
+        Py_ssize_t new_pos;
+        BOOL is_partial;
+
+        start_pos = search_start_STRING_FLD(safe_state, test, start_pos,
+          &new_pos, &is_partial);
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+
+        /* Can we look further ahead? */
+        if (test == node) {
+            if (test->next_1.node) {
+                int status;
+
+                status = try_match(state, &test->next_1, new_pos,
+                  new_position);
+                if (status < 0)
+                    return status;
+
+                if (status == RE_ERROR_FAILURE) {
+                    ++start_pos;
+
+                    if (start_pos >= state->slice_end) {
+                        if (state->partial_side == RE_PARTIAL_RIGHT) {
+                            new_position->text_pos = state->slice_start;
+                            return RE_ERROR_PARTIAL;
+                        }
+
+                        return RE_ERROR_FAILURE;
+                    }
+
+                    goto again;
+                }
+            }
+
+            /* It's a possible match. */
+            state->match_pos = start_pos;
+
+            if (info) {
+                info->start_pos = state->text_pos;
+                info->match_pos = state->match_pos;
+            }
+
+            return RE_ERROR_SUCCESS;
+        }
+        break;
+    }
+    case RE_OP_STRING_FLD_REV:
+    {
+        Py_ssize_t new_pos;
+        BOOL is_partial;
+
+        start_pos = search_start_STRING_FLD_REV(safe_state, test, start_pos,
+          &new_pos, &is_partial);
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+
+        /* Can we look further ahead? */
+        if (test == node) {
+            if (test->next_1.node) {
+                int status;
+
+                status = try_match(state, &test->next_1, new_pos,
+                  new_position);
+                if (status < 0)
+                    return status;
+
+                if (status == RE_ERROR_FAILURE) {
+                    --start_pos;
+
+                    if (start_pos <= state->slice_start) {
+                        if (state->partial_side == RE_PARTIAL_LEFT) {
+                            new_position->text_pos = state->slice_start;
+                            return RE_ERROR_PARTIAL;
+                        }
+
+                        return RE_ERROR_FAILURE;
+                    }
+
+                    goto again;
+                }
+            }
+
+            /* It's a possible match. */
+            state->match_pos = start_pos;
+
+            if (info) {
+                info->start_pos = state->text_pos;
+                info->match_pos = state->match_pos;
+            }
+
+            return RE_ERROR_SUCCESS;
+        }
+        break;
+    }
+    case RE_OP_STRING_IGN:
+    {
+        BOOL is_partial;
+
+        start_pos = search_start_STRING_IGN(safe_state, test, start_pos,
+          &is_partial);
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_STRING_IGN_REV:
+    {
+        BOOL is_partial;
+
+        start_pos = search_start_STRING_IGN_REV(safe_state, test, start_pos,
+          &is_partial);
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    case RE_OP_STRING_REV:
+    {
+        BOOL is_partial;
+
+        start_pos = search_start_STRING_REV(safe_state, test, start_pos,
+          &is_partial);
+        if (start_pos < 0)
+            return RE_ERROR_FAILURE;
+
+        if (is_partial) {
+            new_position->text_pos = start_pos;
+            return RE_ERROR_PARTIAL;
+        }
+        break;
+    }
+    default:
+        /* Don't call 'search_start' again. */
+        state->pattern->do_search_start = FALSE;
+
+        state->match_pos = start_pos;
+        new_position->node = node;
+        new_position->text_pos = start_pos;
+        return RE_ERROR_SUCCESS;
+    }
+
+    /* Can we look further ahead? */
+    if (test == node) {
+        text_pos = start_pos + test->step;
+
+        if (test->next_1.node) {
+            int status;
+
+            status = try_match(state, &test->next_1, text_pos, new_position);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_FAILURE) {
+                if (state->reverse) {
+                    --start_pos;
+
+                    if (start_pos < state->slice_start) {
+                        if (state->partial_side == RE_PARTIAL_LEFT) {
+                            new_position->text_pos = state->slice_start;
+                            return RE_ERROR_PARTIAL;
+                        }
+
+                        return RE_ERROR_FAILURE;
+                    }
+                } else {
+                    ++start_pos;
+
+                    if (start_pos > state->slice_end) {
+                        if (state->partial_side == RE_PARTIAL_RIGHT) {
+                            new_position->text_pos = state->slice_end;
+                            return RE_ERROR_PARTIAL;
+                        }
+
+                        return RE_ERROR_FAILURE;
+                    }
+                }
+
+                goto again;
+            }
+        }
+    } else {
+        new_position->node = node;
+        new_position->text_pos = start_pos;
+    }
+
+    /* It's a possible match. */
+    state->match_pos = start_pos;
+
+    if (info) {
+        info->start_pos = state->text_pos;
+        info->match_pos = state->match_pos;
+    }
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Saves a capture group. */
+Py_LOCAL_INLINE(BOOL) save_capture(RE_SafeState* safe_state, size_t
+  private_index, size_t public_index) {
+    RE_State* state;
+    RE_GroupData* private_group;
+    RE_GroupData* public_group;
+
+    state = safe_state->re_state;
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    private_group = &state->groups[private_index - 1];
+    public_group = &state->groups[public_index - 1];
+
+    /* Will the repeated captures ever be visible? */
+    if (!state->visible_captures) {
+        public_group->captures[0] = private_group->span;
+        public_group->capture_count = 1;
+
+        return TRUE;
+    }
+
+    if (public_group->capture_count >= public_group->capture_capacity) {
+        size_t new_capacity;
+        RE_GroupSpan* new_captures;
+
+        new_capacity = public_group->capture_capacity * 2;
+        new_capacity = max_size_t(new_capacity, RE_INIT_CAPTURE_SIZE);
+        new_captures = (RE_GroupSpan*)safe_realloc(safe_state,
+          public_group->captures, new_capacity * sizeof(RE_GroupSpan));
+        if (!new_captures)
+            return FALSE;
+
+        public_group->captures = new_captures;
+        public_group->capture_capacity = new_capacity;
+    }
+
+    public_group->captures[public_group->capture_count++] =
+      private_group->span;
+
+    return TRUE;
+}
+
+/* Unsaves a capture group. */
+Py_LOCAL_INLINE(void) unsave_capture(RE_State* state, size_t private_index,
+  size_t public_index) {
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    if (state->groups[public_index - 1].capture_count > 0)
+        --state->groups[public_index - 1].capture_count;
+}
+
+/* Pushes the groups for backtracking. */
+Py_LOCAL_INLINE(BOOL) push_groups(RE_SafeState* safe_state) {
+    RE_State* state;
+    size_t group_count;
+    RE_SavedGroups* current;
+    size_t g;
+
+    state = safe_state->re_state;
+
+    group_count = state->pattern->true_group_count;
+    if (group_count == 0)
+        return TRUE;
+
+    current = state->current_saved_groups;
+
+    if (current && current->next)
+        current = current->next;
+    else if (!current && state->first_saved_groups)
+        current = state->first_saved_groups;
+    else {
+        RE_SavedGroups* new_block;
+
+        new_block = (RE_SavedGroups*)safe_alloc(safe_state,
+          sizeof(RE_SavedGroups));
+        if (!new_block)
+            return FALSE;
+
+        new_block->spans = (RE_GroupSpan*)safe_alloc(safe_state, group_count *
+          sizeof(RE_GroupSpan));
+        new_block->counts = (size_t*)safe_alloc(safe_state, group_count *
+          sizeof(Py_ssize_t));
+        if (!new_block->spans || !new_block->counts) {
+            safe_dealloc(safe_state, new_block->spans);
+            safe_dealloc(safe_state, new_block->counts);
+            safe_dealloc(safe_state, new_block);
+            return FALSE;
+        }
+
+        new_block->previous = current;
+        new_block->next = NULL;
+
+        if (new_block->previous)
+            new_block->previous->next = new_block;
+        else
+            state->first_saved_groups = new_block;
+
+        current = new_block;
+    }
+
+    for (g = 0; g < group_count; g++) {
+        current->spans[g] = state->groups[g].span;
+        current->counts[g] = state->groups[g].capture_count;
+    }
+
+    state->current_saved_groups = current;
+
+    return TRUE;
+}
+
+/* Pops the groups for backtracking. */
+Py_LOCAL_INLINE(void) pop_groups(RE_State* state) {
+    size_t group_count;
+    RE_SavedGroups* current;
+    size_t g;
+
+    group_count = state->pattern->true_group_count;
+    if (group_count == 0)
+        return;
+
+    current = state->current_saved_groups;
+
+    for (g = 0; g < group_count; g++) {
+        state->groups[g].span = current->spans[g];
+        state->groups[g].capture_count = current->counts[g];
+    }
+
+    state->current_saved_groups = current->previous;
+}
+
+/* Drops the groups for backtracking. */
+Py_LOCAL_INLINE(void) drop_groups(RE_State* state) {
+    if (state->pattern->true_group_count != 0)
+        state->current_saved_groups = state->current_saved_groups->previous;
+}
+
+/* Pushes the repeats for backtracking. */
+Py_LOCAL_INLINE(BOOL) push_repeats(RE_SafeState* safe_state) {
+    RE_State* state;
+    PatternObject* pattern;
+    size_t repeat_count;
+    RE_SavedRepeats* current;
+    size_t r;
+
+    state = safe_state->re_state;
+    pattern = state->pattern;
+
+    repeat_count = pattern->repeat_count;
+    if (repeat_count == 0)
+        return TRUE;
+
+    current = state->current_saved_repeats;
+
+    if (current && current->next)
+        current = current->next;
+    else if (!current && state->first_saved_repeats)
+        current = state->first_saved_repeats;
+    else {
+        RE_SavedRepeats* new_block;
+
+        new_block = (RE_SavedRepeats*)safe_alloc(safe_state,
+          sizeof(RE_SavedRepeats));
+        if (!new_block)
+            return FALSE;
+
+        new_block->repeats = (RE_RepeatData*)safe_alloc(safe_state,
+          repeat_count * sizeof(RE_RepeatData));
+        if (!new_block->repeats) {
+            safe_dealloc(safe_state, new_block);
+            return FALSE;
+        }
+
+        memset(new_block->repeats, 0, repeat_count * sizeof(RE_RepeatData));
+
+        new_block->previous = current;
+        new_block->next = NULL;
+
+        if (new_block->previous)
+            new_block->previous->next = new_block;
+        else
+            state->first_saved_repeats = new_block;
+
+        current = new_block;
+    }
+
+    for (r = 0; r < repeat_count; r++) {
+        if (!copy_repeat_data(safe_state, &current->repeats[r],
+          &state->repeats[r]))
+            return FALSE;
+    }
+
+    state->current_saved_repeats = current;
+
+    return TRUE;
+}
+
+/* Pops the repeats for backtracking. */
+Py_LOCAL_INLINE(void) pop_repeats(RE_State* state) {
+    PatternObject* pattern;
+    size_t repeat_count;
+    RE_SavedRepeats* current;
+    size_t r;
+
+    pattern = state->pattern;
+
+    repeat_count = pattern->repeat_count;
+    if (repeat_count == 0)
+        return;
+
+    current = state->current_saved_repeats;
+
+    for (r = 0; r < repeat_count; r++)
+        copy_repeat_data(NULL, &state->repeats[r], &current->repeats[r]);
+
+    state->current_saved_repeats = current->previous;
+}
+
+/* Drops the repeats for backtracking. */
+Py_LOCAL_INLINE(void) drop_repeats(RE_State* state) {
+    PatternObject* pattern;
+    size_t repeat_count;
+    RE_SavedRepeats* current;
+
+    pattern = state->pattern;
+
+    repeat_count = pattern->repeat_count;
+    if (repeat_count == 0)
+        return;
+
+    current = state->current_saved_repeats;
+    state->current_saved_repeats = current->previous;
+}
+
+/* Inserts a new span in a guard list. */
+Py_LOCAL_INLINE(BOOL) insert_guard_span(RE_SafeState* safe_state, RE_GuardList*
+  guard_list, size_t index) {
+    size_t n;
+
+    if (guard_list->count >= guard_list->capacity) {
+        size_t new_capacity;
+        RE_GuardSpan* new_spans;
+
+        new_capacity = guard_list->capacity * 2;
+        if (new_capacity == 0)
+            new_capacity = RE_INIT_GUARDS_BLOCK_SIZE;
+        new_spans = (RE_GuardSpan*)safe_realloc(safe_state, guard_list->spans,
+          new_capacity * sizeof(RE_GuardSpan));
+        if (!new_spans)
+            return FALSE;
+
+        guard_list->capacity = new_capacity;
+        guard_list->spans = new_spans;
+    }
+
+    n = guard_list->count - index;
+    if (n > 0)
+        memmove(guard_list->spans + index + 1, guard_list->spans + index, n *
+          sizeof(RE_GuardSpan));
+    ++guard_list->count;
+
+    return TRUE;
+}
+
+/* Deletes a span in a guard list. */
+Py_LOCAL_INLINE(void) delete_guard_span(RE_GuardList* guard_list, size_t index)
+  {
+    size_t n;
+
+    n = guard_list->count - index - 1;
+    if (n > 0)
+        memmove(guard_list->spans + index, guard_list->spans + index + 1, n *
+          sizeof(RE_GuardSpan));
+    --guard_list->count;
+}
+
+/* Checks whether a position is guarded against further matching. */
+Py_LOCAL_INLINE(BOOL) is_guarded(RE_GuardList* guard_list, Py_ssize_t text_pos)
+  {
+    size_t low;
+    size_t high;
+
+    /* Is this position in the guard list? */
+    if (guard_list->count == 0 || text_pos < guard_list->spans[0].low)
+        guard_list->last_low = 0;
+    else if (text_pos > guard_list->spans[guard_list->count - 1].high)
+        guard_list->last_low = guard_list->count;
+    else {
+        low = 0;
+        high = guard_list->count;
+        while (low < high) {
+            size_t mid;
+            RE_GuardSpan* span;
+
+            mid = (low + high) / 2;
+            span = &guard_list->spans[mid];
+            if (text_pos < span->low)
+                high = mid;
+            else if (text_pos > span->high)
+                low = mid + 1;
+            else
+                return span->protect;
+        }
+
+        guard_list->last_low = low;
+    }
+
+    guard_list->last_text_pos = text_pos;
+
+    return FALSE;
+}
+
+/* Guards a position against further matching. */
+Py_LOCAL_INLINE(BOOL) guard(RE_SafeState* safe_state, RE_GuardList* guard_list,
+  Py_ssize_t text_pos, BOOL protect) {
+    size_t low;
+    size_t high;
+
+    /* Where should be new position be added? */
+    if (text_pos == guard_list->last_text_pos)
+        low = guard_list->last_low;
+    else {
+        low = 0;
+        high = guard_list->count;
+        while (low < high) {
+            size_t mid;
+            RE_GuardSpan* span;
+
+            mid = (low + high) / 2;
+            span = &guard_list->spans[mid];
+            if (text_pos < span->low)
+                high = mid;
+            else if (text_pos > span->high)
+                low = mid + 1;
+            else
+                return TRUE;
+        }
+    }
+
+    /* Add the position to the guard list. */
+    if (low > 0 && guard_list->spans[low - 1].high + 1 == text_pos &&
+      guard_list->spans[low - 1].protect == protect) {
+        /* The new position is just above this span. */
+        if (low < guard_list->count && guard_list->spans[low].low - 1 ==
+          text_pos && guard_list->spans[low].protect == protect) {
+            /* The new position joins 2 spans */
+            guard_list->spans[low - 1].high = guard_list->spans[low].high;
+            delete_guard_span(guard_list, low);
+        } else
+            /* Extend the span. */
+            guard_list->spans[low - 1].high = text_pos;
+    } else if (low < guard_list->count && guard_list->spans[low].low - 1 ==
+      text_pos && guard_list->spans[low].protect == protect)
+        /* The new position is just below this span. */
+        /* Extend the span. */
+        guard_list->spans[low].low = text_pos;
+    else {
+        /* Insert a new span. */
+        if (!insert_guard_span(safe_state, guard_list, low))
+            return FALSE;
+        guard_list->spans[low].low = text_pos;
+        guard_list->spans[low].high = text_pos;
+        guard_list->spans[low].protect = protect;
+    }
+
+    guard_list->last_text_pos = -1;
+
+    return TRUE;
+}
+
+/* Guards a position against further matching for a repeat. */
+Py_LOCAL_INLINE(BOOL) guard_repeat(RE_SafeState* safe_state, size_t index,
+  Py_ssize_t text_pos, RE_STATUS_T guard_type, BOOL protect) {
+    RE_State* state;
+    RE_GuardList* guard_list;
+
+    state = safe_state->re_state;
+
+    /* Is a guard active here? */
+    if (!(state->pattern->repeat_info[index].status & guard_type))
+        return TRUE;
+
+    /* Which guard list? */
+    if (guard_type & RE_STATUS_BODY)
+        guard_list = &state->repeats[index].body_guard_list;
+    else
+        guard_list = &state->repeats[index].tail_guard_list;
+
+    return guard(safe_state, guard_list, text_pos, protect);
+}
+
+/* Guards a range of positions against further matching for a repeat. */
+Py_LOCAL_INLINE(BOOL) guard_repeat_range(RE_SafeState* safe_state, size_t
+  index, Py_ssize_t lo_pos, Py_ssize_t hi_pos, RE_STATUS_T guard_type, BOOL
+  protect) {
+    RE_State* state;
+    RE_GuardList* guard_list;
+    Py_ssize_t pos;
+
+    state = safe_state->re_state;
+
+    /* Is a guard active here? */
+    if (!(state->pattern->repeat_info[index].status & guard_type))
+        return TRUE;
+
+    /* Which guard list? */
+    if (guard_type & RE_STATUS_BODY)
+        guard_list = &state->repeats[index].body_guard_list;
+    else
+        guard_list = &state->repeats[index].tail_guard_list;
+
+    for (pos = lo_pos; pos <= hi_pos; pos++) {
+        if (!guard(safe_state, guard_list, pos, protect))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+/* Checks whether a position is guarded against further matching for a repeat.
+ */
+Py_LOCAL_INLINE(BOOL) is_repeat_guarded(RE_SafeState* safe_state, size_t index,
+  Py_ssize_t text_pos, RE_STATUS_T guard_type) {
+    RE_State* state;
+    RE_GuardList* guard_list;
+
+    state = safe_state->re_state;
+
+    /* Is a guard active here? */
+    if (!(state->pattern->repeat_info[index].status & guard_type))
+        return FALSE;
+
+    /* Which guard list? */
+    if (guard_type == RE_STATUS_BODY)
+        guard_list = &state->repeats[index].body_guard_list;
+    else
+        guard_list = &state->repeats[index].tail_guard_list;
+
+    return is_guarded(guard_list, text_pos);
+}
+
+/* Builds a Unicode string. */
+Py_LOCAL_INLINE(PyObject*) build_unicode_value(void* buffer, Py_ssize_t len,
+  Py_ssize_t buffer_charsize) {
+    return PyUnicode_FromUnicode(buffer, len);
+}
+
+/* Builds a bytestring. Returns NULL if any member is too wide. */
+Py_LOCAL_INLINE(PyObject*) build_bytes_value(void* buffer, Py_ssize_t len,
+  Py_ssize_t buffer_charsize) {
+    Py_UCS1* byte_buffer;
+    Py_ssize_t i;
+    PyObject* result;
+
+    if (buffer_charsize == 1)
+        return Py_BuildValue("s#", buffer, len);
+
+    byte_buffer = re_alloc((size_t)len);
+    if (!byte_buffer)
+        return NULL;
+
+    for (i = 0; i < len; i++) {
+        Py_UCS2 c = ((Py_UCS2*)buffer)[i];
+        if (c > 0xFF)
+            goto too_wide;
+
+        byte_buffer[i] = (Py_UCS1)c;
+    }
+
+    result = Py_BuildValue("s#", byte_buffer, len);
+
+    re_dealloc(byte_buffer);
+
+    return result;
+
+too_wide:
+    re_dealloc(byte_buffer);
+
+    return NULL;
+}
+
+/* Looks for a string in a string set. */
+Py_LOCAL_INLINE(int) string_set_contains(RE_State* state, PyObject* string_set,
+  Py_ssize_t first, Py_ssize_t last) {
+    PyObject* string;
+    int status;
+
+    if (state->is_unicode)
+        string = build_unicode_value(state->point_to(state->text, first), last
+          - first, state->charsize);
+    else
+        string = build_bytes_value(state->point_to(state->text, first), last -
+          first, state->charsize);
+    if (!string)
+        return RE_ERROR_INTERNAL;
+
+    status = PySet_Contains(string_set, string);
+    Py_DECREF(string);
+
+    return status;
+}
+
+/* Looks for a string in a string set, ignoring case. */
+Py_LOCAL_INLINE(int) string_set_contains_ign(RE_State* state, PyObject*
+  string_set, void* buffer, Py_ssize_t index, Py_ssize_t len, Py_ssize_t
+  buffer_charsize) {
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    void (*set_char_at)(void* text, Py_ssize_t pos, Py_UCS4 ch);
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    BOOL (*possible_turkic)(RE_LocaleInfo* locale_info, Py_UCS4 ch);
+    Py_UCS4 codepoints[4];
+
+    switch (buffer_charsize) {
+    case 1:
+        char_at = bytes1_char_at;
+        set_char_at = bytes1_set_char_at;
+        break;
+    case 2:
+        char_at = bytes2_char_at;
+        set_char_at = bytes2_set_char_at;
+        break;
+    case 4:
+        char_at = bytes4_char_at;
+        set_char_at = bytes4_set_char_at;
+        break;
+    default:
+        char_at = bytes1_char_at;
+        set_char_at = bytes1_set_char_at;
+        break;
+    }
+
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    possible_turkic = encoding->possible_turkic;
+
+    /* Look for a possible Turkic 'I'. */
+    while (index < len && !possible_turkic(locale_info, char_at(buffer,
+      index)))
+        ++index;
+
+    if (index < len) {
+        /* Possible Turkic 'I'. */
+        int count;
+        int i;
+
+        /* Try all the alternatives to the 'I'. */
+        count = encoding->all_turkic_i(locale_info, char_at(buffer, index),
+          codepoints);
+
+        for (i = 0; i < count; i++) {
+            int status;
+
+            set_char_at(buffer, index, codepoints[i]);
+
+            /* Recurse for the remainder of the string. */
+            status = string_set_contains_ign(state, string_set, buffer, index +
+              1, len, buffer_charsize);
+            if (status != 0)
+                return status;
+        }
+
+        return 0;
+    } else {
+        /* No Turkic 'I'. */
+        PyObject* string;
+        int status;
+
+        if (state->is_unicode)
+            string = build_unicode_value(buffer, len, buffer_charsize);
+        else
+            string = build_bytes_value(buffer, len, buffer_charsize);
+        if (!string)
+            return RE_ERROR_MEMORY;
+
+        status = PySet_Contains(string_set, string);
+        Py_DECREF(string);
+
+        return status;
+    }
+}
+
+/* Creates a partial string set for truncation at the left or right side. */
+Py_LOCAL_INLINE(int) make_partial_string_set(RE_State* state, RE_Node* node) {
+    PatternObject* pattern;
+    int partial_side;
+    PyObject* string_set;
+    PyObject* partial_set;
+    PyObject* iter = NULL;
+    PyObject* item = NULL;
+    PyObject* slice = NULL;
+
+    pattern = state->pattern;
+    partial_side = state->partial_side;
+    if (partial_side != RE_PARTIAL_LEFT && partial_side != RE_PARTIAL_RIGHT)
+        return RE_ERROR_INTERNAL;
+
+    /* Fetch the full string set. PyList_GET_ITEM borrows a reference. */
+    string_set = PyList_GET_ITEM(pattern->named_list_indexes, node->values[0]);
+    if (!string_set)
+        return RE_ERROR_INTERNAL;
+
+    /* Gets the list of partial string sets. */
+    if (!pattern->partial_named_lists[partial_side]) {
+        size_t size;
+
+        size = pattern->named_lists_count * sizeof(PyObject*);
+        pattern->partial_named_lists[partial_side] = re_alloc(size);
+        if (!pattern->partial_named_lists[partial_side])
+            return RE_ERROR_INTERNAL;
+
+        memset(pattern->partial_named_lists[partial_side], 0, size);
+    }
+
+    /* Get the partial string set. */
+    partial_set = pattern->partial_named_lists[partial_side][node->values[0]];
+    if (partial_set)
+        return 1;
+
+    /* Build the partial string set. */
+    partial_set = PySet_New(NULL);
+    if (!partial_set)
+        return RE_ERROR_INTERNAL;
+
+    iter = PyObject_GetIter(string_set);
+    if (!iter)
+        goto error;
+
+    item = PyIter_Next(iter);
+
+    while (item) {
+        Py_ssize_t len;
+        Py_ssize_t first;
+        Py_ssize_t last;
+
+        len = PySequence_Length(item);
+        if (len == -1)
+            goto error;
+
+        first = 0;
+        last = len;
+
+        while (last - first > 1) {
+            int status;
+
+            /* Shorten the entry. */
+            if (partial_side == RE_PARTIAL_LEFT)
+                ++first;
+            else
+                --last;
+
+            slice = PySequence_GetSlice(item, first, last);
+            if (!slice)
+                goto error;
+
+            status = PySet_Add(partial_set, slice);
+            Py_DECREF(slice);
+            if (status < 0)
+                goto error;
+        }
+
+        Py_DECREF(item);
+        item = PyIter_Next(iter);
+    }
+
+    if (PyErr_Occurred())
+        goto error;
+
+    Py_DECREF(iter);
+
+    pattern->partial_named_lists[partial_side][node->values[0]] = partial_set;
+
+    return 1;
+
+error:
+    Py_XDECREF(item);
+    Py_XDECREF(iter);
+    Py_DECREF(partial_set);
+
+    return RE_ERROR_INTERNAL;
+}
+
+/* Tries to match a string at the current position with a member of a string
+ * set, forwards or backwards.
+ */
+Py_LOCAL_INLINE(int) string_set_match_fwdrev(RE_SafeState* safe_state, RE_Node*
+  node, BOOL reverse) {
+    RE_State* state;
+    Py_ssize_t min_len;
+    Py_ssize_t max_len;
+    Py_ssize_t text_available;
+    Py_ssize_t slice_available;
+    int partial_side;
+    Py_ssize_t len;
+    Py_ssize_t first;
+    Py_ssize_t last;
+    int status;
+    PyObject* string_set;
+
+    state = safe_state->re_state;
+
+    min_len = (Py_ssize_t)node->values[1];
+    max_len = (Py_ssize_t)node->values[2];
+
+    acquire_GIL(safe_state);
+
+    if (reverse) {
+        text_available = state->text_pos;
+        slice_available = state->text_pos - state->slice_start;
+        partial_side = RE_PARTIAL_LEFT;
+    } else {
+        text_available = state->text_length - state->text_pos;
+        slice_available = state->slice_end - state->text_pos;
+        partial_side = RE_PARTIAL_RIGHT;
+    }
+
+    /* Get as many characters as we need for the longest possible match. */
+    len = min_ssize_t(max_len, slice_available);
+
+    if (reverse) {
+        first = state->text_pos - len;
+        last = state->text_pos;
+    } else {
+        first = state->text_pos;
+        last = state->text_pos + len;
+    }
+
+    /* If we didn't get all of the characters we need, is a partial match
+     * allowed?
+     */
+    if (len < max_len && len == text_available && state->partial_side ==
+      partial_side) {
+        if (len == 0) {
+            /* An empty string is always a possible partial match. */
+            status = RE_ERROR_PARTIAL;
+            goto finished;
+        }
+
+        /* Make a set of the possible partial matches. */
+        status = make_partial_string_set(state, node);
+        if (status < 0)
+            goto finished;
+
+        /* Fetch the partial string set. */
+        string_set =
+          state->pattern->partial_named_lists[partial_side][node->values[0]];
+
+        /* Is the text we have a partial match? */
+        status = string_set_contains(state, string_set, first, last);
+        if (status < 0)
+            goto finished;
+
+        if (status == 1) {
+            /* Advance past the match. */
+            if (reverse)
+                state->text_pos -= len;
+            else
+                state->text_pos += len;
+
+            status = RE_ERROR_PARTIAL;
+            goto finished;
+        }
+    }
+
+    /* Fetch the string set. PyList_GET_ITEM borrows a reference. */
+    string_set = PyList_GET_ITEM(state->pattern->named_list_indexes,
+      node->values[0]);
+    if (!string_set) {
+        status = RE_ERROR_INTERNAL;
+        goto finished;
+    }
+
+    /* We've already looked for a partial match (if allowed), but what about a
+     * complete match?
+     */
+    while (len >= min_len) {
+        status = string_set_contains(state, string_set, first, last);
+
+        if (status == 1) {
+            /* Advance past the match. */
+            if (reverse)
+                state->text_pos -= len;
+            else
+                state->text_pos += len;
+
+            status = 1;
+            goto finished;
+        }
+
+        /* Look for a shorter match. */
+        --len;
+        if (reverse)
+            ++first;
+        else
+            --last;
+    }
+
+    /* No match. */
+    status = 0;
+
+finished:
+    release_GIL(safe_state);
+
+    return status;
+}
+
+/* Tries to match a string at the current position with a member of a string
+ * set, ignoring case, forwards or backwards.
+ */
+Py_LOCAL_INLINE(int) string_set_match_fld_fwdrev(RE_SafeState* safe_state,
+  RE_Node* node, BOOL reverse) {
+    RE_State* state;
+    int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+      folded);
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    Py_ssize_t folded_charsize;
+    void (*set_char_at)(void* text, Py_ssize_t pos, Py_UCS4 ch);
+    Py_ssize_t min_len;
+    Py_ssize_t max_len;
+    Py_ssize_t buf_len;
+    void* folded;
+    int status;
+    BOOL* end_of_fold = NULL;
+    Py_ssize_t text_available;
+    Py_ssize_t slice_available;
+    Py_ssize_t t_pos;
+    Py_ssize_t f_pos;
+    int step;
+    int partial_side;
+    Py_ssize_t len;
+    Py_ssize_t consumed;
+    Py_UCS4 codepoints[RE_MAX_FOLDED];
+    Py_ssize_t first;
+    Py_ssize_t last;
+    PyObject* string_set;
+
+    state = safe_state->re_state;
+    full_case_fold = state->encoding->full_case_fold;
+    char_at = state->char_at;
+
+    /* The folded string will have the same width as the original string. */
+    folded_charsize = state->charsize;
+
+    switch (folded_charsize) {
+    case 1:
+        set_char_at = bytes1_set_char_at;
+        break;
+    case 2:
+        set_char_at = bytes2_set_char_at;
+        break;
+    case 4:
+        set_char_at = bytes4_set_char_at;
+        break;
+    default:
+        return RE_ERROR_INTERNAL;
+    }
+
+    min_len = (Py_ssize_t)node->values[1];
+    max_len = (Py_ssize_t)node->values[2];
+
+    acquire_GIL(safe_state);
+
+    /* Allocate a buffer for the folded string. */
+    buf_len = max_len + RE_MAX_FOLDED;
+    folded = re_alloc((size_t)(buf_len * folded_charsize));
+    if (!folded) {
+        status = RE_ERROR_MEMORY;
+        goto finished;
+    }
+
+    end_of_fold = re_alloc((size_t)buf_len * sizeof(BOOL));
+    if (!end_of_fold) {
+        status = RE_ERROR_MEMORY;
+        goto finished;
+    }
+
+    memset(end_of_fold, 0, (size_t)buf_len * sizeof(BOOL));
+
+    if (reverse) {
+        text_available = state->text_pos;
+        slice_available = state->text_pos - state->slice_start;
+        t_pos = state->text_pos - 1;
+        f_pos = buf_len;
+        step = -1;
+        partial_side = RE_PARTIAL_LEFT;
+    } else {
+        text_available = state->text_length - state->text_pos;
+        slice_available = state->slice_end - state->text_pos;
+        t_pos = state->text_pos;
+        f_pos = 0;
+        step = 1;
+        partial_side = RE_PARTIAL_RIGHT;
+    }
+
+    /* We can stop getting characters as soon as the case-folded string is long
+     * enough (each codepoint from the text can expand to more than one folded
+     * codepoint).
+     */
+    len = 0;
+    end_of_fold[len] = TRUE;
+
+    consumed = 0;
+    while (len < max_len && consumed < slice_available) {
+        int count;
+        int j;
+
+        count = full_case_fold(state->locale_info, char_at(state->text, t_pos),
+          codepoints);
+
+        if (reverse)
+            f_pos -= count;
+
+        for (j = 0; j < count; j++)
+            set_char_at(folded, f_pos + j, codepoints[j]);
+
+        if (!reverse)
+            f_pos += count;
+
+        len += count;
+        end_of_fold[len] = TRUE;
+        ++consumed;
+        t_pos += step;
+    }
+
+    if (reverse) {
+        first = f_pos;
+        last = buf_len;
+    } else {
+        first = 0;
+        last = f_pos;
+    }
+
+    /* If we didn't get all of the characters we need, is a partial match
+     * allowed?
+     */
+    if (len < max_len && len == text_available && state->partial_side ==
+      partial_side) {
+        if (len == 0) {
+            /* An empty string is always a possible partial match. */
+            status = RE_ERROR_PARTIAL;
+            goto finished;
+        }
+
+        /* Make a set of the possible partial matches. */
+        status = make_partial_string_set(state, node);
+        if (status < 0)
+            goto finished;
+
+        /* Fetch the partial string set. */
+        string_set =
+          state->pattern->partial_named_lists[partial_side][node->values[0]];
+
+        /* Is the text we have a partial match? */
+        status = string_set_contains_ign(state, string_set, folded, first,
+          last, folded_charsize);
+        if (status < 0)
+            goto finished;
+
+        if (status == 1) {
+            /* Advance past the match. */
+            if (reverse)
+                state->text_pos -= consumed;
+            else
+                state->text_pos += consumed;
+
+            status = RE_ERROR_PARTIAL;
+            goto finished;
+        }
+    }
+
+    /* Fetch the string set. PyList_GET_ITEM borrows a reference. */
+    string_set = PyList_GET_ITEM(state->pattern->named_list_indexes,
+      node->values[0]);
+    if (!string_set) {
+        status = RE_ERROR_INTERNAL;
+        goto finished;
+    }
+
+    /* We've already looked for a partial match (if allowed), but what about a
+     * complete match?
+     */
+    while (len >= min_len) {
+        if (end_of_fold[len]) {
+            status = string_set_contains_ign(state, string_set, folded, first,
+              last, folded_charsize);
+
+            if (status == 1) {
+                /* Advance past the match. */
+                if (reverse)
+                    state->text_pos -= consumed;
+                else
+                    state->text_pos += consumed;
+
+                status = 1;
+                goto finished;
+            }
+
+            --consumed;
+        }
+
+        /* Look for a shorter match. */
+        --len;
+        if (reverse)
+            ++first;
+        else
+            --last;
+    }
+
+    /* No match. */
+    status = 0;
+
+finished:
+    re_dealloc(end_of_fold);
+    re_dealloc(folded);
+
+    release_GIL(safe_state);
+
+    return status;
+}
+
+/* Tries to match a string at the current position with a member of a string
+ * set, ignoring case, forwards or backwards.
+ */
+Py_LOCAL_INLINE(int) string_set_match_ign_fwdrev(RE_SafeState* safe_state,
+  RE_Node* node, BOOL reverse) {
+    RE_State* state;
+    Py_UCS4 (*simple_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch);
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    Py_ssize_t folded_charsize;
+    void (*set_char_at)(void* text, Py_ssize_t pos, Py_UCS4 ch);
+    Py_ssize_t min_len;
+    Py_ssize_t max_len;
+    void* folded;
+    int status;
+    Py_ssize_t text_available;
+    Py_ssize_t slice_available;
+    Py_ssize_t t_pos;
+    Py_ssize_t f_pos;
+    int step;
+    int partial_side;
+    Py_ssize_t len;
+    Py_ssize_t i;
+    Py_ssize_t first;
+    Py_ssize_t last;
+    PyObject* string_set;
+
+    state = safe_state->re_state;
+    simple_case_fold = state->encoding->simple_case_fold;
+    char_at = state->char_at;
+
+    /* The folded string will have the same width as the original string. */
+    folded_charsize = state->charsize;
+
+    switch (folded_charsize) {
+    case 1:
+        set_char_at = bytes1_set_char_at;
+        break;
+    case 2:
+        set_char_at = bytes2_set_char_at;
+        break;
+    case 4:
+        set_char_at = bytes4_set_char_at;
+        break;
+    default:
+        return RE_ERROR_INTERNAL;
+    }
+
+    min_len = (Py_ssize_t)node->values[1];
+    max_len = (Py_ssize_t)node->values[2];
+
+    acquire_GIL(safe_state);
+
+    /* Allocate a buffer for the folded string. */
+    folded = re_alloc((size_t)(max_len * folded_charsize));
+    if (!folded) {
+        status = RE_ERROR_MEMORY;
+        goto finished;
+    }
+
+    if (reverse) {
+        text_available = state->text_pos;
+        slice_available = state->text_pos - state->slice_start;
+        t_pos = state->text_pos - 1;
+        f_pos = max_len - 1;
+        step = -1;
+        partial_side = RE_PARTIAL_LEFT;
+    } else {
+        text_available = state->text_length - state->text_pos;
+        slice_available = state->slice_end - state->text_pos;
+        t_pos = state->text_pos;
+        f_pos = 0;
+        step = 1;
+        partial_side = RE_PARTIAL_RIGHT;
+    }
+
+    /* Get as many characters as we need for the longest possible match. */
+    len = min_ssize_t(max_len, slice_available);
+
+    for (i = 0; i < len; i ++) {
+        Py_UCS4 ch;
+
+        ch = simple_case_fold(state->locale_info, char_at(state->text, t_pos));
+        set_char_at(folded, f_pos, ch);
+        t_pos += step;
+        f_pos += step;
+    }
+
+    if (reverse) {
+        first = f_pos;
+        last = max_len;
+    } else {
+        first = 0;
+        last = f_pos;
+    }
+
+    /* If we didn't get all of the characters we need, is a partial match
+     * allowed?
+     */
+    if (len < max_len && len == text_available && state->partial_side ==
+      partial_side) {
+        if (len == 0) {
+            /* An empty string is always a possible partial match. */
+            status = RE_ERROR_PARTIAL;
+            goto finished;
+        }
+
+        /* Make a set of the possible partial matches. */
+        status = make_partial_string_set(state, node);
+        if (status < 0)
+            goto finished;
+
+        /* Fetch the partial string set. */
+        string_set =
+          state->pattern->partial_named_lists[partial_side][node->values[0]];
+
+        /* Is the text we have a partial match? */
+        status = string_set_contains_ign(state, string_set, folded, first,
+          last, folded_charsize);
+        if (status < 0)
+            goto finished;
+
+        if (status == 1) {
+            /* Advance past the match. */
+            if (reverse)
+                state->text_pos -= len;
+            else
+                state->text_pos += len;
+
+            status = RE_ERROR_PARTIAL;
+            goto finished;
+        }
+    }
+
+    /* Fetch the string set. PyList_GET_ITEM borrows a reference. */
+    string_set = PyList_GET_ITEM(state->pattern->named_list_indexes,
+      node->values[0]);
+    if (!string_set) {
+        status = RE_ERROR_INTERNAL;
+        goto finished;
+    }
+
+    /* We've already looked for a partial match (if allowed), but what about a
+     * complete match?
+     */
+    while (len >= min_len) {
+        status = string_set_contains_ign(state, string_set, folded, first,
+          last, folded_charsize);
+
+        if (status == 1) {
+            /* Advance past the match. */
+            if (reverse)
+                state->text_pos -= len;
+            else
+                state->text_pos += len;
+
+            status = 1;
+            goto finished;
+        }
+
+        /* Look for a shorter match. */
+        --len;
+        if (reverse)
+            ++first;
+        else
+            --last;
+    }
+
+    /* No match. */
+    status = 0;
+
+finished:
+    re_dealloc(folded);
+
+    release_GIL(safe_state);
+
+    return status;
+}
+
+/* Checks whether any additional fuzzy error is permitted. */
+Py_LOCAL_INLINE(BOOL) any_error_permitted(RE_State* state) {
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    return fuzzy_info->total_cost <= values[RE_FUZZY_VAL_MAX_COST] &&
+      fuzzy_info->counts[RE_FUZZY_ERR] < values[RE_FUZZY_VAL_MAX_ERR] &&
+      state->total_errors <= state->max_errors;
+}
+
+/* Checks whether this additional fuzzy error is permitted. */
+Py_LOCAL_INLINE(BOOL) this_error_permitted(RE_State* state, int fuzzy_type) {
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    return fuzzy_info->total_cost + values[RE_FUZZY_VAL_COST_BASE + fuzzy_type]
+      <= values[RE_FUZZY_VAL_MAX_COST] && fuzzy_info->counts[fuzzy_type] <
+      values[RE_FUZZY_VAL_MAX_BASE + fuzzy_type] && state->total_errors + 1 <=
+      state->max_errors;
+}
+
+/* Checks whether we've reachsd the end of the text during a fuzzy partial
+ * match.
+ */
+Py_LOCAL_INLINE(int) check_fuzzy_partial(RE_State* state, Py_ssize_t text_pos)
+  {
+    switch (state->partial_side) {
+    case RE_PARTIAL_LEFT:
+        if (text_pos < 0)
+            return RE_ERROR_PARTIAL;
+        break;
+    case RE_PARTIAL_RIGHT:
+        if (text_pos > state->text_length)
+            return RE_ERROR_PARTIAL;
+        break;
+    }
+
+    return RE_ERROR_FAILURE;
+}
+
+/* Checks a fuzzy match of an item. */
+Py_LOCAL_INLINE(int) next_fuzzy_match_item(RE_State* state, RE_FuzzyData* data,
+  BOOL is_string, int step) {
+    Py_ssize_t new_pos;
+
+    if (this_error_permitted(state, data->fuzzy_type)) {
+        switch (data->fuzzy_type) {
+        case RE_FUZZY_DEL:
+            /* Could a character at text_pos have been deleted? */
+            if (is_string)
+                data->new_string_pos += step;
+            else
+                data->new_node = data->new_node->next_1.node;
+            return RE_ERROR_SUCCESS;
+        case RE_FUZZY_INS:
+            /* Could the character at text_pos have been inserted? */
+            if (!data->permit_insertion)
+                return RE_ERROR_FAILURE;
+
+            new_pos = data->new_text_pos + step;
+            if (state->slice_start <= new_pos && new_pos <= state->slice_end) {
+                data->new_text_pos = new_pos;
+                return RE_ERROR_SUCCESS;
+            }
+
+            return check_fuzzy_partial(state, new_pos);
+        case RE_FUZZY_SUB:
+            /* Could the character at text_pos have been substituted? */
+            new_pos = data->new_text_pos + step;
+            if (state->slice_start <= new_pos && new_pos <= state->slice_end) {
+                data->new_text_pos = new_pos;
+                if (is_string)
+                    data->new_string_pos += step;
+                else
+                    data->new_node = data->new_node->next_1.node;
+                return RE_ERROR_SUCCESS;
+            }
+
+            return check_fuzzy_partial(state, new_pos);
+        }
+    }
+
+    return RE_ERROR_FAILURE;
+}
+
+/* Tries a fuzzy match of an item of width 0 or 1. */
+Py_LOCAL_INLINE(int) fuzzy_match_item(RE_SafeState* safe_state, BOOL search,
+  Py_ssize_t* text_pos, RE_Node** node, int step) {
+    RE_State* state;
+    RE_FuzzyData data;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+
+    state = safe_state->re_state;
+
+    if (!any_error_permitted(state)) {
+        *node = NULL;
+        return RE_ERROR_SUCCESS;
+    }
+
+    data.new_text_pos = *text_pos;
+    data.new_node = *node;
+
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    if (step == 0) {
+        if (data.new_node->status & RE_STATUS_REVERSE) {
+            data.step = -1;
+            data.limit = state->slice_start;
+        } else {
+            data.step = 1;
+            data.limit = state->slice_end;
+        }
+    } else
+        data.step = step;
+
+    /* Permit insertion except initially when searching (it's better just to
+     * start searching one character later).
+     */
+    data.permit_insertion = !search || data.new_text_pos !=
+      state->search_anchor;
+
+    for (data.fuzzy_type = 0; data.fuzzy_type < RE_FUZZY_COUNT;
+      data.fuzzy_type++) {
+        int status;
+
+        status = next_fuzzy_match_item(state, &data, FALSE, step);
+        if (status < 0)
+            return status;
+
+        if (status == RE_ERROR_SUCCESS)
+            goto found;
+    }
+
+    *node = NULL;
+    return RE_ERROR_SUCCESS;
+
+found:
+    if (!add_backtrack(safe_state, (*node)->op))
+        return RE_ERROR_FAILURE;
+    bt_data = state->backtrack;
+    bt_data->fuzzy_item.position.text_pos = *text_pos;
+    bt_data->fuzzy_item.position.node = *node;
+    bt_data->fuzzy_item.fuzzy_type = (RE_INT8)data.fuzzy_type;
+    bt_data->fuzzy_item.step = (RE_INT8)step;
+
+    ++fuzzy_info->counts[data.fuzzy_type];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    ++state->total_errors;
+
+    *text_pos = data.new_text_pos;
+    *node = data.new_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Retries a fuzzy match of a item of width 0 or 1. */
+Py_LOCAL_INLINE(int) retry_fuzzy_match_item(RE_SafeState* safe_state, BOOL
+  search, Py_ssize_t* text_pos, RE_Node** node, BOOL advance) {
+    RE_State* state;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+    RE_FuzzyData data;
+    int step;
+
+    state = safe_state->re_state;
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    bt_data = state->backtrack;
+    data.new_text_pos = bt_data->fuzzy_item.position.text_pos;
+    data.new_node = bt_data->fuzzy_item.position.node;
+    data.fuzzy_type = bt_data->fuzzy_item.fuzzy_type;
+    data.step = bt_data->fuzzy_item.step;
+
+    if (data.fuzzy_type >= 0) {
+        --fuzzy_info->counts[data.fuzzy_type];
+        --fuzzy_info->counts[RE_FUZZY_ERR];
+        fuzzy_info->total_cost -= values[RE_FUZZY_VAL_COST_BASE +
+          data.fuzzy_type];
+        --state->total_errors;
+    }
+
+    /* Permit insertion except initially when searching (it's better just to
+     * start searching one character later).
+     */
+    data.permit_insertion = !search || data.new_text_pos !=
+      state->search_anchor;
+
+    step = advance ? data.step : 0;
+
+    for (++data.fuzzy_type; data.fuzzy_type < RE_FUZZY_COUNT;
+      data.fuzzy_type++) {
+        int status;
+
+        status = next_fuzzy_match_item(state, &data, FALSE, step);
+        if (status < 0)
+            return status;
+
+        if (status == RE_ERROR_SUCCESS)
+            goto found;
+    }
+
+    discard_backtrack(state);
+    *node = NULL;
+    return RE_ERROR_SUCCESS;
+
+found:
+    bt_data->fuzzy_item.fuzzy_type = (RE_INT8)data.fuzzy_type;
+
+    ++fuzzy_info->counts[data.fuzzy_type];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    ++state->total_errors;
+
+    *text_pos = data.new_text_pos;
+    *node = data.new_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Tries a fuzzy insertion. */
+Py_LOCAL_INLINE(int) fuzzy_insert(RE_SafeState* safe_state, Py_ssize_t
+  text_pos, RE_Node* node) {
+    RE_State* state;
+    RE_BacktrackData* bt_data;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+
+    state = safe_state->re_state;
+
+    /* No insertion or deletion. */
+    if (!add_backtrack(safe_state, node->op))
+        return RE_ERROR_FAILURE;
+    bt_data = state->backtrack;
+    bt_data->fuzzy_insert.position.text_pos = text_pos;
+    bt_data->fuzzy_insert.position.node = node;
+    bt_data->fuzzy_insert.count = 0;
+    bt_data->fuzzy_insert.too_few_errors = state->too_few_errors;
+    bt_data->fuzzy_insert.fuzzy_node = node; /* END_FUZZY node. */
+
+    /* Check whether there are too few errors. */
+    fuzzy_info = &state->fuzzy_info;
+
+    /* The node in this case is the END_FUZZY node. */
+    values = node->values;
+
+    if (fuzzy_info->counts[RE_FUZZY_DEL] < values[RE_FUZZY_VAL_MIN_DEL] ||
+      fuzzy_info->counts[RE_FUZZY_INS] < values[RE_FUZZY_VAL_MIN_INS] ||
+      fuzzy_info->counts[RE_FUZZY_SUB] < values[RE_FUZZY_VAL_MIN_SUB] ||
+      fuzzy_info->counts[RE_FUZZY_ERR] < values[RE_FUZZY_VAL_MIN_ERR])
+      state->too_few_errors = RE_ERROR_SUCCESS;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Retries a fuzzy insertion. */
+Py_LOCAL_INLINE(int) retry_fuzzy_insert(RE_SafeState* safe_state, Py_ssize_t*
+  text_pos, RE_Node** node) {
+    RE_State* state;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+    Py_ssize_t new_text_pos;
+    RE_Node* new_node;
+    int step;
+    Py_ssize_t limit;
+    RE_Node* fuzzy_node;
+
+    state = safe_state->re_state;
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    bt_data = state->backtrack;
+    new_text_pos = bt_data->fuzzy_insert.position.text_pos;
+    new_node = bt_data->fuzzy_insert.position.node;
+
+    if (new_node->status & RE_STATUS_REVERSE) {
+        step = -1;
+        limit = state->slice_start;
+    } else {
+        step = 1;
+        limit = state->slice_end;
+    }
+
+    /* Could the character at text_pos have been inserted? */
+    if (!this_error_permitted(state, RE_FUZZY_INS) || new_text_pos == limit) {
+        size_t count;
+
+        count = bt_data->fuzzy_insert.count;
+
+        fuzzy_info->counts[RE_FUZZY_INS] -= count;
+        fuzzy_info->counts[RE_FUZZY_ERR] -= count;
+        fuzzy_info->total_cost -= values[RE_FUZZY_VAL_INS_COST] * count;
+        state->total_errors -= count;
+        state->too_few_errors = bt_data->fuzzy_insert.too_few_errors;
+
+        discard_backtrack(state);
+        *node = NULL;
+        return RE_ERROR_SUCCESS;
+    }
+
+    ++bt_data->fuzzy_insert.count;
+
+    ++fuzzy_info->counts[RE_FUZZY_INS];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_INS_COST];
+    ++state->total_errors;
+
+    /* Check whether there are too few errors. */
+    state->too_few_errors = bt_data->fuzzy_insert.too_few_errors;
+    fuzzy_node = bt_data->fuzzy_insert.fuzzy_node; /* END_FUZZY node. */
+    values = fuzzy_node->values;
+    if (fuzzy_info->counts[RE_FUZZY_DEL] < values[RE_FUZZY_VAL_MIN_DEL] ||
+      fuzzy_info->counts[RE_FUZZY_INS] < values[RE_FUZZY_VAL_MIN_INS] ||
+      fuzzy_info->counts[RE_FUZZY_SUB] < values[RE_FUZZY_VAL_MIN_SUB] ||
+      fuzzy_info->counts[RE_FUZZY_ERR] < values[RE_FUZZY_VAL_MIN_ERR])
+      state->too_few_errors = RE_ERROR_SUCCESS;
+
+    *text_pos = new_text_pos + step * (Py_ssize_t)bt_data->fuzzy_insert.count;
+    *node = new_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Tries a fuzzy match of a string. */
+Py_LOCAL_INLINE(int) fuzzy_match_string(RE_SafeState* safe_state, BOOL search,
+  Py_ssize_t* text_pos, RE_Node* node, Py_ssize_t* string_pos, BOOL* matched,
+  int step) {
+    RE_State* state;
+    RE_FuzzyData data;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+
+    state = safe_state->re_state;
+
+    if (!any_error_permitted(state)) {
+        *matched = FALSE;
+        return RE_ERROR_SUCCESS;
+    }
+
+    data.new_text_pos = *text_pos;
+    data.new_string_pos = *string_pos;
+    data.step = step;
+
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    /* Permit insertion except initially when searching (it's better just to
+     * start searching one character later).
+     */
+    data.permit_insertion = !search || data.new_text_pos !=
+      state->search_anchor;
+
+    for (data.fuzzy_type = 0; data.fuzzy_type < RE_FUZZY_COUNT;
+      data.fuzzy_type++) {
+        int status;
+
+        status = next_fuzzy_match_item(state, &data, TRUE, data.step);
+        if (status < 0)
+            return status;
+
+        if (status == RE_ERROR_SUCCESS)
+            goto found;
+    }
+
+    *matched = FALSE;
+    return RE_ERROR_SUCCESS;
+
+found:
+    if (!add_backtrack(safe_state, node->op))
+        return RE_ERROR_FAILURE;
+    bt_data = state->backtrack;
+    bt_data->fuzzy_string.position.text_pos = *text_pos;
+    bt_data->fuzzy_string.position.node = node;
+    bt_data->fuzzy_string.string_pos = *string_pos;
+    bt_data->fuzzy_string.fuzzy_type = (RE_INT8)data.fuzzy_type;
+    bt_data->fuzzy_string.step = (RE_INT8)step;
+
+    ++fuzzy_info->counts[data.fuzzy_type];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    ++state->total_errors;
+
+    *text_pos = data.new_text_pos;
+    *string_pos = data.new_string_pos;
+    *matched = TRUE;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Retries a fuzzy match of a string. */
+Py_LOCAL_INLINE(int) retry_fuzzy_match_string(RE_SafeState* safe_state, BOOL
+  search, Py_ssize_t* text_pos, RE_Node** node, Py_ssize_t* string_pos, BOOL*
+  matched) {
+    RE_State* state;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+    RE_FuzzyData data;
+    RE_Node* new_node;
+
+    state = safe_state->re_state;
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    bt_data = state->backtrack;
+    data.new_text_pos = bt_data->fuzzy_string.position.text_pos;
+    new_node = bt_data->fuzzy_string.position.node;
+    data.new_string_pos = bt_data->fuzzy_string.string_pos;
+    data.fuzzy_type = bt_data->fuzzy_string.fuzzy_type;
+    data.step = bt_data->fuzzy_string.step;
+
+    --fuzzy_info->counts[data.fuzzy_type];
+    --fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost -= values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    --state->total_errors;
+
+    /* Permit insertion except initially when searching (it's better just to
+     * start searching one character later).
+     */
+    data.permit_insertion = !search || data.new_text_pos !=
+      state->search_anchor;
+
+    for (++data.fuzzy_type; data.fuzzy_type < RE_FUZZY_COUNT;
+      data.fuzzy_type++) {
+        int status;
+
+        status = next_fuzzy_match_item(state, &data, TRUE, data.step);
+        if (status < 0)
+            return status;
+
+        if (status == RE_ERROR_SUCCESS)
+            goto found;
+    }
+
+    discard_backtrack(state);
+    *matched = FALSE;
+    return RE_ERROR_SUCCESS;
+
+found:
+    bt_data->fuzzy_string.fuzzy_type = (RE_INT8)data.fuzzy_type;
+
+    ++fuzzy_info->counts[data.fuzzy_type];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    ++state->total_errors;
+
+    *text_pos = data.new_text_pos;
+    *node = new_node;
+    *string_pos = data.new_string_pos;
+    *matched = TRUE;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Checks a fuzzy match of a atring. */
+Py_LOCAL_INLINE(int) next_fuzzy_match_string_fld(RE_State* state, RE_FuzzyData*
+  data) {
+    int new_pos;
+
+    if (this_error_permitted(state, data->fuzzy_type)) {
+        switch (data->fuzzy_type) {
+        case RE_FUZZY_DEL:
+            /* Could a character at text_pos have been deleted? */
+            data->new_string_pos += data->step;
+            return RE_ERROR_SUCCESS;
+        case RE_FUZZY_INS:
+            /* Could the character at text_pos have been inserted? */
+            if (!data->permit_insertion)
+                return RE_ERROR_FAILURE;
+
+            new_pos = data->new_folded_pos + data->step;
+            if (0 <= new_pos && new_pos <= data->folded_len) {
+                data->new_folded_pos = new_pos;
+                return RE_ERROR_SUCCESS;
+            }
+
+            return check_fuzzy_partial(state, new_pos);
+        case RE_FUZZY_SUB:
+            /* Could the character at text_pos have been substituted? */
+            new_pos = data->new_folded_pos + data->step;
+            if (0 <= new_pos && new_pos <= data->folded_len) {
+                data->new_folded_pos = new_pos;
+                data->new_string_pos += data->step;
+                return RE_ERROR_SUCCESS;
+            }
+
+            return check_fuzzy_partial(state, new_pos);
+        }
+    }
+
+    return RE_ERROR_FAILURE;
+}
+
+/* Tries a fuzzy match of a string, ignoring case. */
+Py_LOCAL_INLINE(int) fuzzy_match_string_fld(RE_SafeState* safe_state, BOOL
+  search, Py_ssize_t* text_pos, RE_Node* node, Py_ssize_t* string_pos, int*
+  folded_pos, int folded_len, BOOL* matched, int step) {
+    RE_State* state;
+    Py_ssize_t new_text_pos;
+    RE_FuzzyData data;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+
+    state = safe_state->re_state;
+
+    if (!any_error_permitted(state)) {
+        *matched = FALSE;
+        return RE_ERROR_SUCCESS;
+    }
+
+    new_text_pos = *text_pos;
+    data.new_string_pos = *string_pos;
+    data.new_folded_pos = *folded_pos;
+    data.folded_len = folded_len;
+    data.step = step;
+
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    /* Permit insertion except initially when searching (it's better just to
+     * start searching one character later).
+     */
+    data.permit_insertion = !search || new_text_pos != state->search_anchor;
+    if (step > 0) {
+        if (data.new_folded_pos != 0)
+            data.permit_insertion = RE_ERROR_SUCCESS;
+    } else {
+        if (data.new_folded_pos != folded_len)
+            data.permit_insertion = RE_ERROR_SUCCESS;
+    }
+
+    for (data.fuzzy_type = 0; data.fuzzy_type < RE_FUZZY_COUNT;
+      data.fuzzy_type++) {
+        int status;
+
+        status = next_fuzzy_match_string_fld(state, &data);
+        if (status < 0)
+            return status;
+
+        if (status == RE_ERROR_SUCCESS)
+            goto found;
+    }
+
+    *matched = FALSE;
+    return RE_ERROR_SUCCESS;
+
+found:
+    if (!add_backtrack(safe_state, node->op))
+        return RE_ERROR_FAILURE;
+    bt_data = state->backtrack;
+    bt_data->fuzzy_string.position.text_pos = *text_pos;
+    bt_data->fuzzy_string.position.node = node;
+    bt_data->fuzzy_string.string_pos = *string_pos;
+    bt_data->fuzzy_string.folded_pos = (RE_INT8)(*folded_pos);
+    bt_data->fuzzy_string.folded_len = (RE_INT8)folded_len;
+    bt_data->fuzzy_string.fuzzy_type = (RE_INT8)data.fuzzy_type;
+    bt_data->fuzzy_string.step = (RE_INT8)step;
+
+    ++fuzzy_info->counts[data.fuzzy_type];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    ++state->total_errors;
+
+    *text_pos = new_text_pos;
+    *string_pos = data.new_string_pos;
+    *folded_pos = data.new_folded_pos;
+    *matched = TRUE;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Retries a fuzzy match of a string, ignoring case. */
+Py_LOCAL_INLINE(int) retry_fuzzy_match_string_fld(RE_SafeState* safe_state,
+  BOOL search, Py_ssize_t* text_pos, RE_Node** node, Py_ssize_t* string_pos,
+  int* folded_pos, BOOL* matched) {
+    RE_State* state;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+    Py_ssize_t new_text_pos;
+    RE_Node* new_node;
+    RE_FuzzyData data;
+
+    state = safe_state->re_state;
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    bt_data = state->backtrack;
+    new_text_pos = bt_data->fuzzy_string.position.text_pos;
+    new_node = bt_data->fuzzy_string.position.node;
+    data.new_string_pos = bt_data->fuzzy_string.string_pos;
+    data.new_folded_pos = bt_data->fuzzy_string.folded_pos;
+    data.folded_len = bt_data->fuzzy_string.folded_len;
+    data.fuzzy_type = bt_data->fuzzy_string.fuzzy_type;
+    data.step = bt_data->fuzzy_string.step;
+
+    --fuzzy_info->counts[data.fuzzy_type];
+    --fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost -= values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    --state->total_errors;
+
+    /* Permit insertion except initially when searching (it's better just to
+     * start searching one character later).
+     */
+    data.permit_insertion = !search || new_text_pos != state->search_anchor;
+    if (data.step > 0) {
+        if (data.new_folded_pos != 0)
+            data.permit_insertion = RE_ERROR_SUCCESS;
+    } else {
+        if (data.new_folded_pos != bt_data->fuzzy_string.folded_len)
+            data.permit_insertion = RE_ERROR_SUCCESS;
+    }
+
+    for (++data.fuzzy_type; data.fuzzy_type < RE_FUZZY_COUNT;
+      data.fuzzy_type++) {
+        int status;
+
+        status = next_fuzzy_match_string_fld(state, &data);
+        if (status < 0)
+            return status;
+
+        if (status == RE_ERROR_SUCCESS)
+            goto found;
+    }
+
+    discard_backtrack(state);
+    *matched = FALSE;
+    return RE_ERROR_SUCCESS;
+
+found:
+    bt_data->fuzzy_string.fuzzy_type = (RE_INT8)data.fuzzy_type;
+
+    ++fuzzy_info->counts[data.fuzzy_type];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    ++state->total_errors;
+
+    *text_pos = new_text_pos;
+    *node = new_node;
+    *string_pos = data.new_string_pos;
+    *folded_pos = data.new_folded_pos;
+    *matched = TRUE;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Checks a fuzzy match of a atring. */
+Py_LOCAL_INLINE(int) next_fuzzy_match_group_fld(RE_State* state, RE_FuzzyData*
+  data) {
+    int new_pos;
+
+    if (this_error_permitted(state, data->fuzzy_type)) {
+        switch (data->fuzzy_type) {
+        case RE_FUZZY_DEL:
+            /* Could a character at text_pos have been deleted? */
+            data->new_gfolded_pos += data->step;
+            return RE_ERROR_SUCCESS;
+        case RE_FUZZY_INS:
+            /* Could the character at text_pos have been inserted? */
+            if (!data->permit_insertion)
+                return RE_ERROR_FAILURE;
+
+            new_pos = data->new_folded_pos + data->step;
+            if (0 <= new_pos && new_pos <= data->folded_len) {
+                data->new_folded_pos = new_pos;
+                return RE_ERROR_SUCCESS;
+            }
+
+            return check_fuzzy_partial(state, new_pos);
+        case RE_FUZZY_SUB:
+            /* Could the character at text_pos have been substituted? */
+            new_pos = data->new_folded_pos + data->step;
+            if (0 <= new_pos && new_pos <= data->folded_len) {
+                data->new_folded_pos = new_pos;
+                data->new_gfolded_pos += data->step;
+                return RE_ERROR_SUCCESS;
+            }
+
+            return check_fuzzy_partial(state, new_pos);
+        }
+    }
+
+    return RE_ERROR_FAILURE;
+}
+
+/* Tries a fuzzy match of a group reference, ignoring case. */
+Py_LOCAL_INLINE(int) fuzzy_match_group_fld(RE_SafeState* safe_state, BOOL
+  search, Py_ssize_t* text_pos, RE_Node* node, int* folded_pos, int folded_len,
+  Py_ssize_t* group_pos, int* gfolded_pos, int gfolded_len, BOOL* matched, int
+  step) {
+    RE_State* state;
+    Py_ssize_t new_text_pos;
+    RE_FuzzyData data;
+    Py_ssize_t new_group_pos;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+
+    state = safe_state->re_state;
+
+    if (!any_error_permitted(state)) {
+        *matched = FALSE;
+        return RE_ERROR_SUCCESS;
+    }
+
+    new_text_pos = *text_pos;
+    data.new_folded_pos = *folded_pos;
+    data.folded_len = folded_len;
+    new_group_pos = *group_pos;
+    data.new_gfolded_pos = *gfolded_pos;
+    data.step = step;
+
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    /* Permit insertion except initially when searching (it's better just to
+     * start searching one character later).
+     */
+    data.permit_insertion = !search || new_text_pos != state->search_anchor;
+    if (data.step > 0) {
+        if (data.new_folded_pos != 0)
+            data.permit_insertion = RE_ERROR_SUCCESS;
+    } else {
+        if (data.new_folded_pos != folded_len)
+            data.permit_insertion = RE_ERROR_SUCCESS;
+    }
+
+    for (data.fuzzy_type = 0; data.fuzzy_type < RE_FUZZY_COUNT;
+      data.fuzzy_type++) {
+        int status;
+
+        status = next_fuzzy_match_group_fld(state, &data);
+        if (status < 0)
+            return status;
+
+        if (status == RE_ERROR_SUCCESS)
+            goto found;
+    }
+
+    *matched = FALSE;
+    return RE_ERROR_SUCCESS;
+
+found:
+    if (!add_backtrack(safe_state, node->op))
+        return RE_ERROR_FAILURE;
+    bt_data = state->backtrack;
+    bt_data->fuzzy_string.position.text_pos = *text_pos;
+    bt_data->fuzzy_string.position.node = node;
+    bt_data->fuzzy_string.string_pos = *group_pos;
+    bt_data->fuzzy_string.folded_pos = (RE_INT8)(*folded_pos);
+    bt_data->fuzzy_string.folded_len = (RE_INT8)folded_len;
+    bt_data->fuzzy_string.gfolded_pos = (RE_INT8)(*gfolded_pos);
+    bt_data->fuzzy_string.gfolded_len = (RE_INT8)gfolded_len;
+    bt_data->fuzzy_string.fuzzy_type = (RE_INT8)data.fuzzy_type;
+    bt_data->fuzzy_string.step = (RE_INT8)step;
+
+    ++fuzzy_info->counts[data.fuzzy_type];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    ++state->total_errors;
+
+    *text_pos = new_text_pos;
+    *group_pos = new_group_pos;
+    *folded_pos = data.new_folded_pos;
+    *gfolded_pos = data.new_gfolded_pos;
+    *matched = TRUE;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Retries a fuzzy match of a group reference, ignoring case. */
+Py_LOCAL_INLINE(int) retry_fuzzy_match_group_fld(RE_SafeState* safe_state, BOOL
+  search, Py_ssize_t* text_pos, RE_Node** node, int* folded_pos, Py_ssize_t*
+  group_pos, int* gfolded_pos, BOOL* matched) {
+    RE_State* state;
+    RE_FuzzyInfo* fuzzy_info;
+    RE_CODE* values;
+    RE_BacktrackData* bt_data;
+    Py_ssize_t new_text_pos;
+    RE_Node* new_node;
+    Py_ssize_t new_group_pos;
+    RE_FuzzyData data;
+
+    state = safe_state->re_state;
+    fuzzy_info = &state->fuzzy_info;
+    values = fuzzy_info->node->values;
+
+    bt_data = state->backtrack;
+    new_text_pos = bt_data->fuzzy_string.position.text_pos;
+    new_node = bt_data->fuzzy_string.position.node;
+    new_group_pos = bt_data->fuzzy_string.string_pos;
+    data.new_folded_pos = bt_data->fuzzy_string.folded_pos;
+    data.folded_len = bt_data->fuzzy_string.folded_len;
+    data.new_gfolded_pos = bt_data->fuzzy_string.gfolded_pos;
+    data.fuzzy_type = bt_data->fuzzy_string.fuzzy_type;
+    data.step = bt_data->fuzzy_string.step;
+
+    --fuzzy_info->counts[data.fuzzy_type];
+    --fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost -= values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    --state->total_errors;
+
+    /* Permit insertion except initially when searching (it's better just to
+     * start searching one character later).
+     */
+    data.permit_insertion = !search || new_text_pos != state->search_anchor ||
+      data.new_folded_pos != bt_data->fuzzy_string.folded_len;
+
+    for (++data.fuzzy_type; data.fuzzy_type < RE_FUZZY_COUNT;
+      data.fuzzy_type++) {
+        int status;
+
+        status = next_fuzzy_match_group_fld(state, &data);
+        if (status < 0)
+            return status;
+
+        if (status == RE_ERROR_SUCCESS)
+            goto found;
+    }
+
+    discard_backtrack(state);
+    *matched = FALSE;
+    return RE_ERROR_SUCCESS;
+
+found:
+    bt_data->fuzzy_string.fuzzy_type = (RE_INT8)data.fuzzy_type;
+
+    ++fuzzy_info->counts[data.fuzzy_type];
+    ++fuzzy_info->counts[RE_FUZZY_ERR];
+    fuzzy_info->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type];
+    ++state->total_errors;
+
+    *text_pos = new_text_pos;
+    *node = new_node;
+    *group_pos = new_group_pos;
+    *folded_pos = data.new_folded_pos;
+    *gfolded_pos = data.new_gfolded_pos;
+    *matched = TRUE;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Locates the required string, if there's one. */
+Py_LOCAL_INLINE(Py_ssize_t) locate_required_string(RE_SafeState* safe_state,
+  BOOL search) {
+    RE_State* state;
+    PatternObject* pattern;
+    Py_ssize_t found_pos;
+    Py_ssize_t end_pos;
+
+    state = safe_state->re_state;
+    pattern = state->pattern;
+
+    if (!pattern->req_string)
+        /* There isn't a required string, so start matching from the current
+         * position.
+         */
+        return state->text_pos;
+
+    /* Search for the required string and calculate where to start matching. */
+    switch (pattern->req_string->op) {
+    case RE_OP_STRING:
+    {
+        BOOL is_partial;
+        Py_ssize_t limit;
+
+        if (search || pattern->req_offset < 0)
+            limit = state->slice_end;
+        else {
+            limit = state->slice_start + pattern->req_offset +
+              (Py_ssize_t)pattern->req_string->value_count;
+            if (limit > state->slice_end || limit < 0)
+                limit = state->slice_end;
+        }
+
+        if (state->req_pos < 0 || state->text_pos > state->req_pos)
+            /* First time or already passed it. */
+            found_pos = string_search(safe_state, pattern->req_string,
+              state->text_pos, limit, &is_partial);
+        else {
+            found_pos = state->req_pos;
+            is_partial = FALSE;
+        }
+
+        if (found_pos < 0)
+            /* The required string wasn't found. */
+            return -1;
+
+        if (!is_partial) {
+            /* Record where the required string matched. */
+            state->req_pos = found_pos;
+            state->req_end = found_pos +
+              (Py_ssize_t)pattern->req_string->value_count;
+        }
+
+        if (pattern->req_offset >= 0) {
+            /* Step back from the required string to where we should start
+             * matching.
+             */
+            found_pos -= pattern->req_offset;
+            if (found_pos >= state->text_pos)
+                return found_pos;
+        }
+        break;
+    }
+    case RE_OP_STRING_FLD:
+    {
+        BOOL is_partial;
+        Py_ssize_t limit;
+
+        if (search || pattern->req_offset < 0)
+            limit = state->slice_end;
+        else {
+            limit = state->slice_start + pattern->req_offset +
+              (Py_ssize_t)pattern->req_string->value_count;
+            if (limit > state->slice_end || limit < 0)
+                limit = state->slice_end;
+        }
+
+        if (state->req_pos < 0 || state->text_pos > state->req_pos)
+            /* First time or already passed it. */
+            found_pos = string_search_fld(safe_state, pattern->req_string,
+              state->text_pos, limit, &end_pos, &is_partial);
+        else {
+            found_pos = state->req_pos;
+            is_partial = FALSE;
+        }
+
+        if (found_pos < 0)
+            /* The required string wasn't found. */
+            return -1;
+
+        if (!is_partial) {
+            /* Record where the required string matched. */
+            state->req_pos = found_pos;
+            state->req_end = end_pos;
+        }
+
+        if (pattern->req_offset >= 0) {
+            /* Step back from the required string to where we should start
+             * matching.
+             */
+            found_pos -= pattern->req_offset;
+            if (found_pos >= state->text_pos)
+                return found_pos;
+        }
+        break;
+    }
+    case RE_OP_STRING_FLD_REV:
+    {
+        BOOL is_partial;
+        Py_ssize_t limit;
+
+        if (search || pattern->req_offset < 0)
+            limit = state->slice_start;
+        else {
+            limit = state->slice_end - pattern->req_offset -
+              (Py_ssize_t)pattern->req_string->value_count;
+            if (limit < state->slice_start)
+                limit = state->slice_start;
+        }
+
+        if (state->req_pos < 0 || state->text_pos < state->req_pos)
+            /* First time or already passed it. */
+            found_pos = string_search_fld_rev(safe_state, pattern->req_string,
+              state->text_pos, limit, &end_pos, &is_partial);
+        else {
+            found_pos = state->req_pos;
+            is_partial = FALSE;
+        }
+
+        if (found_pos < 0)
+            /* The required string wasn't found. */
+            return -1;
+
+        if (!is_partial) {
+            /* Record where the required string matched. */
+            state->req_pos = found_pos;
+            state->req_end = end_pos;
+        }
+
+        if (pattern->req_offset >= 0) {
+            /* Step back from the required string to where we should start
+             * matching.
+             */
+            found_pos += pattern->req_offset;
+            if (found_pos <= state->text_pos)
+                return found_pos;
+        }
+        break;
+    }
+    case RE_OP_STRING_IGN:
+    {
+        BOOL is_partial;
+        Py_ssize_t limit;
+
+        if (search || pattern->req_offset < 0)
+            limit = state->slice_end;
+        else {
+            limit = state->slice_start + pattern->req_offset +
+              (Py_ssize_t)pattern->req_string->value_count;
+            if (limit > state->slice_end || limit < 0)
+                limit = state->slice_end;
+        }
+
+        if (state->req_pos < 0 || state->text_pos > state->req_pos)
+            /* First time or already passed it. */
+            found_pos = string_search_ign(safe_state, pattern->req_string,
+              state->text_pos, limit, &is_partial);
+        else {
+            found_pos = state->req_pos;
+            is_partial = FALSE;
+        }
+
+        if (found_pos < 0)
+            /* The required string wasn't found. */
+            return -1;
+
+        if (!is_partial) {
+            /* Record where the required string matched. */
+            state->req_pos = found_pos;
+            state->req_end = found_pos +
+              (Py_ssize_t)pattern->req_string->value_count;
+        }
+
+        if (pattern->req_offset >= 0) {
+            /* Step back from the required string to where we should start
+             * matching.
+             */
+            found_pos -= pattern->req_offset;
+            if (found_pos >= state->text_pos)
+                return found_pos;
+        }
+        break;
+    }
+    case RE_OP_STRING_IGN_REV:
+    {
+        BOOL is_partial;
+        Py_ssize_t limit;
+
+        if (search || pattern->req_offset < 0)
+            limit = state->slice_start;
+        else {
+            limit = state->slice_end - pattern->req_offset -
+              (Py_ssize_t)pattern->req_string->value_count;
+            if (limit < state->slice_start)
+                limit = state->slice_start;
+        }
+
+        if (state->req_pos < 0 || state->text_pos < state->req_pos)
+            /* First time or already passed it. */
+            found_pos = string_search_ign_rev(safe_state, pattern->req_string,
+              state->text_pos, limit, &is_partial);
+        else {
+            found_pos = state->req_pos;
+            is_partial = FALSE;
+        }
+
+        if (found_pos < 0)
+            /* The required string wasn't found. */
+            return -1;
+
+        if (!is_partial) {
+            /* Record where the required string matched. */
+            state->req_pos = found_pos;
+            state->req_end = found_pos -
+              (Py_ssize_t)pattern->req_string->value_count;
+        }
+
+        if (pattern->req_offset >= 0) {
+            /* Step back from the required string to where we should start
+             * matching.
+             */
+            found_pos += pattern->req_offset;
+            if (found_pos <= state->text_pos)
+                return found_pos;
+        }
+        break;
+    }
+    case RE_OP_STRING_REV:
+    {
+        BOOL is_partial;
+        Py_ssize_t limit;
+
+        if (search || pattern->req_offset < 0)
+            limit = state->slice_start;
+        else {
+            limit = state->slice_end - pattern->req_offset -
+              (Py_ssize_t)pattern->req_string->value_count;
+            if (limit < state->slice_start)
+                limit = state->slice_start;
+        }
+
+        if (state->req_pos < 0 || state->text_pos < state->req_pos)
+            /* First time or already passed it. */
+            found_pos = string_search_rev(safe_state, pattern->req_string,
+              state->text_pos, limit, &is_partial);
+        else {
+            found_pos = state->req_pos;
+            is_partial = FALSE;
+        }
+
+        if (found_pos < 0)
+            /* The required string wasn't found. */
+            return -1;
+
+        if (!is_partial) {
+            /* Record where the required string matched. */
+            state->req_pos = found_pos;
+            state->req_end = found_pos -
+              (Py_ssize_t)pattern->req_string->value_count;
+        }
+
+        if (pattern->req_offset >= 0) {
+            /* Step back from the required string to where we should start
+             * matching.
+             */
+            found_pos += pattern->req_offset;
+            if (found_pos <= state->text_pos)
+                return found_pos;
+        }
+        break;
+    }
+    }
+
+    /* Start matching from the current position. */
+    return state->text_pos;
+}
+
+/* Tries to match a character pattern. */
+Py_LOCAL_INLINE(int) match_one(RE_State* state, RE_Node* node, Py_ssize_t
+  text_pos) {
+    switch (node->op) {
+    case RE_OP_ANY:
+        return try_match_ANY(state, node, text_pos);
+    case RE_OP_ANY_ALL:
+        return try_match_ANY_ALL(state, node, text_pos);
+    case RE_OP_ANY_ALL_REV:
+        return try_match_ANY_ALL_REV(state, node, text_pos);
+    case RE_OP_ANY_REV:
+        return try_match_ANY_REV(state, node, text_pos);
+    case RE_OP_ANY_U:
+        return try_match_ANY_U(state, node, text_pos);
+    case RE_OP_ANY_U_REV:
+        return try_match_ANY_U_REV(state, node, text_pos);
+    case RE_OP_CHARACTER:
+        return try_match_CHARACTER(state, node, text_pos);
+    case RE_OP_CHARACTER_IGN:
+        return try_match_CHARACTER_IGN(state, node, text_pos);
+    case RE_OP_CHARACTER_IGN_REV:
+        return try_match_CHARACTER_IGN_REV(state, node, text_pos);
+    case RE_OP_CHARACTER_REV:
+        return try_match_CHARACTER_REV(state, node, text_pos);
+    case RE_OP_PROPERTY:
+        return try_match_PROPERTY(state, node, text_pos);
+    case RE_OP_PROPERTY_IGN:
+        return try_match_PROPERTY_IGN(state, node, text_pos);
+    case RE_OP_PROPERTY_IGN_REV:
+        return try_match_PROPERTY_IGN_REV(state, node, text_pos);
+    case RE_OP_PROPERTY_REV:
+        return try_match_PROPERTY_REV(state, node, text_pos);
+    case RE_OP_RANGE:
+        return try_match_RANGE(state, node, text_pos);
+    case RE_OP_RANGE_IGN:
+        return try_match_RANGE_IGN(state, node, text_pos);
+    case RE_OP_RANGE_IGN_REV:
+        return try_match_RANGE_IGN_REV(state, node, text_pos);
+    case RE_OP_RANGE_REV:
+        return try_match_RANGE_REV(state, node, text_pos);
+    case RE_OP_SET_DIFF:
+    case RE_OP_SET_INTER:
+    case RE_OP_SET_SYM_DIFF:
+    case RE_OP_SET_UNION:
+        return try_match_SET(state, node, text_pos);
+    case RE_OP_SET_DIFF_IGN:
+    case RE_OP_SET_INTER_IGN:
+    case RE_OP_SET_SYM_DIFF_IGN:
+    case RE_OP_SET_UNION_IGN:
+        return try_match_SET_IGN(state, node, text_pos);
+    case RE_OP_SET_DIFF_IGN_REV:
+    case RE_OP_SET_INTER_IGN_REV:
+    case RE_OP_SET_SYM_DIFF_IGN_REV:
+    case RE_OP_SET_UNION_IGN_REV:
+        return try_match_SET_IGN_REV(state, node, text_pos);
+    case RE_OP_SET_DIFF_REV:
+    case RE_OP_SET_INTER_REV:
+    case RE_OP_SET_SYM_DIFF_REV:
+    case RE_OP_SET_UNION_REV:
+        return try_match_SET_REV(state, node, text_pos);
+    }
+
+    return FALSE;
+}
+
+/* Tests whether 2 nodes contains the same values. */
+Py_LOCAL_INLINE(BOOL) same_values(RE_Node* node_1, RE_Node* node_2) {
+    size_t i;
+
+    if (node_1->value_count != node_2->value_count)
+        return FALSE;
+
+    for (i = 0; i < node_1->value_count; i++) {
+        if (node_1->values[i] != node_2->values[i])
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+/* Tests whether 2 nodes are equivalent (both string-like in the same way). */
+Py_LOCAL_INLINE(BOOL) equivalent_nodes(RE_Node* node_1, RE_Node* node_2) {
+    switch (node_1->op) {
+    case RE_OP_CHARACTER:
+    case RE_OP_STRING:
+        switch (node_2->op) {
+        case RE_OP_CHARACTER:
+        case RE_OP_STRING:
+            return same_values(node_1, node_2);
+        }
+        break;
+    case RE_OP_CHARACTER_IGN:
+    case RE_OP_STRING_IGN:
+        switch (node_2->op) {
+        case RE_OP_CHARACTER_IGN:
+        case RE_OP_STRING_IGN:
+            return same_values(node_1, node_2);
+        }
+        break;
+    case RE_OP_CHARACTER_IGN_REV:
+    case RE_OP_STRING_IGN_REV:
+        switch (node_2->op) {
+        case RE_OP_CHARACTER_IGN_REV:
+        case RE_OP_STRING_IGN_REV:
+            return same_values(node_1, node_2);
+        }
+        break;
+    case RE_OP_CHARACTER_REV:
+    case RE_OP_STRING_REV:
+        switch (node_2->op) {
+        case RE_OP_CHARACTER_REV:
+        case RE_OP_STRING_REV:
+            return same_values(node_1, node_2);
+        }
+        break;
+    }
+
+    return FALSE;
+}
+
+/* Prunes the backtracking. */
+Py_LOCAL_INLINE(void) prune_backtracking(RE_State* state) {
+    RE_AtomicBlock* current;
+
+    current = state->current_atomic_block;
+    if (current && current->count > 0) {
+        /* In an atomic group or a lookaround. */
+        RE_AtomicData* atomic;
+
+        /* Discard any backtracking info from inside the atomic group or
+         * lookaround.
+         */
+        atomic = &current->items[current->count - 1];
+        state->current_backtrack_block = atomic->current_backtrack_block;
+        state->current_backtrack_block->count = atomic->backtrack_count;
+    } else {
+        /* In the outermost pattern. */
+        while (state->current_backtrack_block->previous)
+            state->current_backtrack_block =
+              state->current_backtrack_block->previous;
+
+        /* Keep the bottom FAILURE on the backtracking stack. */
+        state->current_backtrack_block->count = 1;
+    }
+}
+
+/* Saves the match as the best POSIX match (leftmost longest) found so far. */
+Py_LOCAL_INLINE(BOOL) save_best_match(RE_SafeState* safe_state) {
+    RE_State* state;
+    size_t group_count;
+    size_t g;
+
+    state = safe_state->re_state;
+
+    state->best_match_pos = state->match_pos;
+    state->best_text_pos = state->text_pos;
+    state->found_match = TRUE;
+
+    memmove(state->best_fuzzy_counts, state->total_fuzzy_counts,
+      sizeof(state->total_fuzzy_counts));
+
+    group_count = state->pattern->true_group_count;
+    if (group_count == 0)
+        return TRUE;
+
+    acquire_GIL(safe_state);
+
+    if (!state->best_match_groups) {
+        /* Allocate storage for the groups of the best match. */
+        state->best_match_groups = (RE_GroupData*)re_alloc(group_count *
+          sizeof(RE_GroupData));
+        if (!state->best_match_groups)
+            goto error;
+
+        memset(state->best_match_groups, 0, group_count *
+          sizeof(RE_GroupData));
+
+        for (g = 0; g < group_count; g++) {
+            RE_GroupData* best;
+            RE_GroupData* group;
+
+            best = &state->best_match_groups[g];
+            group = &state->groups[g];
+
+            best->capture_capacity = group->capture_capacity;
+            best->captures = (RE_GroupSpan*)re_alloc(best->capture_capacity *
+              sizeof(RE_GroupSpan));
+            if (!best->captures)
+               goto error;
+        }
+    }
+
+    /* Copy the group spans and captures. */
+    for (g = 0; g < group_count; g++) {
+        RE_GroupData* best;
+        RE_GroupData* group;
+
+        best = &state->best_match_groups[g];
+        group = &state->groups[g];
+
+        best->span = group->span;
+        best->capture_count = group->capture_count;
+
+        if (best->capture_count < best->capture_capacity) {
+            /* We need more space for the captures. */
+            re_dealloc(best->captures);
+            best->captures = (RE_GroupSpan*)re_alloc(best->capture_capacity *
+              sizeof(RE_GroupSpan));
+            if (!best->captures)
+                goto error;
+        }
+
+        /* Copy the captures for this group. */
+        memmove(best->captures, group->captures, group->capture_count *
+          sizeof(RE_GroupSpan));
+    }
+
+    release_GIL(safe_state);
+
+    return TRUE;
+
+error:
+    release_GIL(safe_state);
+
+    return FALSE;
+}
+
+/* Restores the best match for a POSIX match (leftmost longest). */
+Py_LOCAL_INLINE(void) restore_best_match(RE_SafeState* safe_state) {
+    RE_State* state;
+    size_t group_count;
+    size_t g;
+
+    state = safe_state->re_state;
+
+    if (!state->found_match)
+        return;
+
+    state->match_pos = state->best_match_pos;
+    state->text_pos = state->best_text_pos;
+
+    memmove(state->total_fuzzy_counts, state->best_fuzzy_counts,
+      sizeof(state->total_fuzzy_counts));
+
+    group_count = state->pattern->true_group_count;
+    if (group_count == 0)
+        return;
+
+    /* Copy the group spans and captures. */
+    for (g = 0; g < group_count; g++) {
+        RE_GroupData* group;
+        RE_GroupData* best;
+
+        group = &state->groups[g];
+        best = &state->best_match_groups[g];
+
+        group->span = best->span;
+        group->capture_count = best->capture_count;
+
+        /* Copy the captures for this group. */
+        memmove(group->captures, best->captures, best->capture_count *
+          sizeof(RE_GroupSpan));
+    }
+}
+
+/* Checks whether the new match is better than the current match for a POSIX
+ * match (leftmost longest) and saves it if it is.
+ */
+Py_LOCAL_INLINE(BOOL) check_posix_match(RE_SafeState* safe_state) {
+    RE_State* state;
+    Py_ssize_t best_length;
+    Py_ssize_t new_length;
+
+    state = safe_state->re_state;
+
+    if (!state->found_match)
+        return save_best_match(safe_state);
+
+    /* Check the overall match. */
+    if (state->reverse) {
+        /* We're searching backwards. */
+        best_length = state->match_pos - state->best_text_pos;
+        new_length = state->match_pos - state->text_pos;
+    } else {
+        /* We're searching forwards. */
+        best_length = state->best_text_pos - state->match_pos;
+        new_length = state->text_pos - state->match_pos;
+    }
+
+    if (new_length > best_length)
+        /* It's a longer match. */
+        return save_best_match(safe_state);
+
+    return TRUE;
+}
+
+/* Performs a depth-first match or search from the context. */
+Py_LOCAL_INLINE(int) basic_match(RE_SafeState* safe_state, BOOL search) {
+    RE_State* state;
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo* locale_info;
+    PatternObject* pattern;
+    RE_Node* start_node;
+    RE_NextNode start_pair;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    Py_ssize_t pattern_step; /* The overall step of the pattern (forwards or backwards). */
+    Py_ssize_t string_pos;
+    BOOL do_search_start;
+    Py_ssize_t found_pos;
+    int status;
+    RE_Node* node;
+    int folded_pos;
+    int gfolded_pos;
+    TRACE(("<<basic_match>>\n"))
+
+    state = safe_state->re_state;
+    encoding = state->encoding;
+    locale_info = state->locale_info;
+    pattern = state->pattern;
+    start_node = pattern->start_node;
+
+    /* Look beyond any initial group node. */
+    start_pair.node = start_node;
+    start_pair.test = pattern->start_test;
+
+    /* Is the pattern anchored to the start or end of the string? */
+    switch (start_pair.test->op) {
+    case RE_OP_END_OF_STRING:
+        if (state->reverse) {
+            /* Searching backwards. */
+            if (state->text_pos != state->text_length)
+                return RE_ERROR_FAILURE;
+
+            /* Don't bother to search further because it's anchored. */
+            search = FALSE;
+        }
+        break;
+    case RE_OP_START_OF_STRING:
+        if (!state->reverse) {
+            /* Searching forwards. */
+            if (state->text_pos != 0)
+                return RE_ERROR_FAILURE;
+
+            /* Don't bother to search further because it's anchored. */
+            search = FALSE;
+        }
+        break;
+    }
+
+    char_at = state->char_at;
+    pattern_step = state->reverse ? -1 : 1;
+    string_pos = -1;
+    do_search_start = pattern->do_search_start;
+    state->fewest_errors = state->max_errors;
+
+    if (do_search_start && pattern->req_string &&
+      equivalent_nodes(start_pair.test, pattern->req_string))
+        do_search_start = FALSE;
+
+    /* Add a backtrack entry for failure. */
+    if (!add_backtrack(safe_state, RE_OP_FAILURE))
+        return RE_ERROR_BACKTRACKING;
+
+start_match:
+    /* If we're searching, advance along the string until there could be a
+     * match.
+     */
+    if (pattern->pattern_call_ref >= 0) {
+        RE_GuardList* guard_list;
+
+        guard_list = &state->group_call_guard_list[pattern->pattern_call_ref];
+        guard_list->count = 0;
+        guard_list->last_text_pos = -1;
+    }
+
+    /* Locate the required string, if there's one, unless this is a recursive
+     * call of 'basic_match'.
+     */
+    if (!pattern->req_string)
+        found_pos = state->text_pos;
+    else {
+        found_pos = locate_required_string(safe_state, search);
+        if (found_pos < 0)
+            return RE_ERROR_FAILURE;
+    }
+
+    if (search) {
+        state->text_pos = found_pos;
+
+        if (do_search_start) {
+            RE_Position new_position;
+
+next_match_1:
+            /* 'search_start' will clear 'do_search_start' if it can't perform
+             * a fast search for the next possible match. This enables us to
+             * avoid the overhead of the call subsequently.
+             */
+            status = search_start(safe_state, &start_pair, &new_position, 0);
+            if (status == RE_ERROR_PARTIAL) {
+                state->match_pos = state->text_pos;
+                return status;
+            } else if (status != RE_ERROR_SUCCESS)
+                return status;
+
+            node = new_position.node;
+            state->text_pos = new_position.text_pos;
+
+            if (node->op == RE_OP_SUCCESS) {
+                /* Must the match advance past its start? */
+                if (state->text_pos != state->search_anchor ||
+                  !state->must_advance)
+                    return RE_ERROR_SUCCESS;
+
+                state->text_pos = state->match_pos + pattern_step;
+                goto next_match_1;
+            }
+
+            /* 'do_search_start' may have been cleared. */
+            do_search_start = pattern->do_search_start;
+        } else {
+            /* Avoiding 'search_start', which we've found can't perform a fast
+             * search for the next possible match.
+             */
+            node = start_node;
+
+next_match_2:
+            if (state->reverse) {
+                if (state->text_pos < state->slice_start) {
+                    if (state->partial_side == RE_PARTIAL_LEFT)
+                        return RE_ERROR_PARTIAL;
+
+                    return RE_ERROR_FAILURE;
+                }
+            } else {
+                if (state->text_pos > state->slice_end) {
+                    if (state-> partial_side == RE_PARTIAL_RIGHT)
+                        return RE_ERROR_PARTIAL;
+
+                    return RE_ERROR_FAILURE;
+                }
+            }
+
+            state->match_pos = state->text_pos;
+
+            if (node->op == RE_OP_SUCCESS) {
+                /* Must the match advance past its start? */
+                if (state->text_pos != state->search_anchor ||
+                  !state->must_advance) {
+                    BOOL success;
+
+                    if (state->match_all) {
+                        /* We want to match all of the slice. */
+                        if (state->reverse)
+                            success = state->text_pos == state->slice_start;
+                        else
+                            success = state->text_pos == state->slice_end;
+                    } else
+                        success = TRUE;
+
+                    if (success)
+                        return RE_ERROR_SUCCESS;
+                }
+
+                state->text_pos = state->match_pos + pattern_step;
+                goto next_match_2;
+            }
+        }
+    } else {
+        /* The start position is anchored to the current position. */
+        if (found_pos != state->text_pos)
+            return RE_ERROR_FAILURE;
+
+        node = start_node;
+    }
+
+advance:
+    /* The main matching loop. */
+    for (;;) {
+        TRACE(("%d|", state->text_pos))
+
+        /* Should we abort the matching? */
+        ++state->iterations;
+
+        if (state->iterations == 0 && safe_check_signals(safe_state))
+            return RE_ERROR_INTERRUPTED;
+
+        switch (node->op) {
+        case RE_OP_ANY: /* Any character except a newline. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_ANY(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS) {
+                ++state->text_pos;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_ANY_ALL: /* Any character at all. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_ANY_ALL(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS) {
+                ++state->text_pos;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_ANY_ALL_REV: /* Any character at all, backwards. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_ANY_ALL_REV(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS) {
+                --state->text_pos;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_ANY_REV: /* Any character except a newline, backwards. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_ANY_REV(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS) {
+                --state->text_pos;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_ANY_U: /* Any character except a line separator. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_ANY_U(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS) {
+                ++state->text_pos;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_ANY_U_REV: /* Any character except a line separator, backwards. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_ANY_U_REV(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS) {
+                --state->text_pos;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_ATOMIC: /* Start of an atomic group. */
+        {
+            RE_AtomicData* atomic;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            if (!add_backtrack(safe_state, RE_OP_ATOMIC))
+                return RE_ERROR_BACKTRACKING;
+            state->backtrack->atomic.too_few_errors = state->too_few_errors;
+            state->backtrack->atomic.capture_change = state->capture_change;
+
+            atomic = push_atomic(safe_state);
+            if (!atomic)
+                return RE_ERROR_MEMORY;
+            atomic->backtrack_count = state->current_backtrack_block->count;
+            atomic->current_backtrack_block = state->current_backtrack_block;
+            atomic->is_lookaround = FALSE;
+            atomic->has_groups = (node->status & RE_STATUS_HAS_GROUPS) != 0;
+            atomic->has_repeats = (node->status & RE_STATUS_HAS_REPEATS) != 0;
+
+            /* Save the groups and repeats. */
+            if (atomic->has_groups && !push_groups(safe_state))
+                return RE_ERROR_MEMORY;
+
+            if (atomic->has_repeats && !push_repeats(safe_state))
+                return RE_ERROR_MEMORY;
+
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_BOUNDARY: /* On a word boundary. */
+            TRACE(("%s %d\n", re_op_text[node->op], node->match))
+
+            status = try_match_BOUNDARY(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_BRANCH: /* 2-way branch. */
+        {
+            RE_Position next_position;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match(state, &node->next_1, state->text_pos,
+              &next_position);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS) {
+                if (!add_backtrack(safe_state, RE_OP_BRANCH))
+                    return RE_ERROR_BACKTRACKING;
+                state->backtrack->branch.position.node =
+                  node->nonstring.next_2.node;
+                state->backtrack->branch.position.text_pos = state->text_pos;
+
+                node = next_position.node;
+                state->text_pos = next_position.text_pos;
+            } else
+                node = node->nonstring.next_2.node;
+            break;
+        }
+        case RE_OP_CALL_REF: /* A group call reference. */
+        {
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            if (!push_group_return(safe_state, NULL))
+                return RE_ERROR_MEMORY;
+
+            if (!add_backtrack(safe_state, RE_OP_CALL_REF))
+                return RE_ERROR_BACKTRACKING;
+
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_CHARACTER: /* A character. */
+            TRACE(("%s %d %d\n", re_op_text[node->op], node->match,
+              node->values[0]))
+
+            if (state->text_pos >= state->text_length && state->partial_side ==
+              RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos < state->slice_end &&
+              matches_CHARACTER(encoding, locale_info, node,
+              char_at(state->text, state->text_pos)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_CHARACTER_IGN: /* A character, ignoring case. */
+            TRACE(("%s %d %d\n", re_op_text[node->op], node->match,
+              node->values[0]))
+
+            if (state->text_pos >= state->text_length && state->partial_side ==
+              RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos < state->slice_end &&
+              matches_CHARACTER_IGN(encoding, locale_info, node,
+              char_at(state->text, state->text_pos)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_CHARACTER_IGN_REV: /* A character, backwards, ignoring case. */
+            TRACE(("%s %d %d\n", re_op_text[node->op], node->match,
+              node->values[0]))
+
+            if (state->text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos > state->slice_start &&
+              matches_CHARACTER_IGN(encoding, locale_info, node,
+              char_at(state->text, state->text_pos - 1)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_CHARACTER_REV: /* A character, backwards. */
+            TRACE(("%s %d %d\n", re_op_text[node->op], node->match,
+              node->values[0]))
+
+            if (state->text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos > state->slice_start &&
+              matches_CHARACTER(encoding, locale_info, node,
+              char_at(state->text, state->text_pos - 1)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_CONDITIONAL: /* Start of a conditional subpattern. */
+        {
+            RE_AtomicData* conditional;
+            TRACE(("%s %d\n", re_op_text[node->op], node->match))
+
+            if (!add_backtrack(safe_state, RE_OP_CONDITIONAL))
+                return RE_ERROR_BACKTRACKING;
+            state->backtrack->lookaround.too_few_errors =
+              state->too_few_errors;
+            state->backtrack->lookaround.capture_change =
+              state->capture_change;
+            state->backtrack->lookaround.inside = TRUE;
+            state->backtrack->lookaround.node = node;
+
+            conditional = push_atomic(safe_state);
+            if (!conditional)
+                return RE_ERROR_MEMORY;
+            conditional->backtrack_count =
+              state->current_backtrack_block->count;
+            conditional->current_backtrack_block =
+              state->current_backtrack_block;
+            conditional->slice_start = state->slice_start;
+            conditional->slice_end = state->slice_end;
+            conditional->text_pos = state->text_pos;
+            conditional->node = node;
+            conditional->backtrack = state->backtrack;
+            conditional->is_lookaround = TRUE;
+            conditional->has_groups = (node->status & RE_STATUS_HAS_GROUPS) !=
+              0;
+            conditional->has_repeats = (node->status & RE_STATUS_HAS_REPEATS)
+              != 0;
+
+            /* Save the groups and repeats. */
+            if (conditional->has_groups && !push_groups(safe_state))
+                return RE_ERROR_MEMORY;
+
+            if (conditional->has_repeats && !push_repeats(safe_state))
+                return RE_ERROR_MEMORY;
+
+            conditional->saved_groups = state->current_saved_groups;
+            conditional->saved_repeats = state->current_saved_repeats;
+
+            state->slice_start = 0;
+            state->slice_end = state->text_length;
+
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_DEFAULT_BOUNDARY: /* On a default word boundary. */
+            TRACE(("%s %d\n", re_op_text[node->op], node->match))
+
+            status = try_match_DEFAULT_BOUNDARY(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_DEFAULT_END_OF_WORD: /* At the default end of a word. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_DEFAULT_END_OF_WORD(state, node,
+              state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_DEFAULT_START_OF_WORD: /* At the default start of a word. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_DEFAULT_START_OF_WORD(state, node,
+              state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_END_ATOMIC: /* End of an atomic group. */
+        {
+            RE_AtomicData* atomic;
+
+            /* Discard any backtracking info from inside the atomic group. */
+            atomic = top_atomic(safe_state);
+            state->current_backtrack_block = atomic->current_backtrack_block;
+            state->current_backtrack_block->count = atomic->backtrack_count;
+
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_END_CONDITIONAL: /* End of a conditional subpattern. */
+        {
+            RE_AtomicData* conditional;
+
+            conditional = pop_atomic(safe_state);
+            while (!conditional->is_lookaround) {
+                if (conditional->has_repeats)
+                    drop_repeats(state);
+
+                if (conditional->has_groups)
+                    drop_groups(state);
+
+                conditional = pop_atomic(safe_state);
+            }
+            state->text_pos = conditional->text_pos;
+            state->slice_end = conditional->slice_end;
+            state->slice_start = conditional->slice_start;
+
+            /* Discard any backtracking info from inside the lookaround. */
+            state->current_backtrack_block =
+              conditional->current_backtrack_block;
+            state->current_backtrack_block->count =
+              conditional->backtrack_count;
+            state->current_saved_groups = conditional->saved_groups;
+            state->current_saved_repeats = conditional->saved_repeats;
+
+            /* It's a positive lookaround that's succeeded. We're now going to
+             * leave the lookaround.
+             */
+            conditional->backtrack->lookaround.inside = FALSE;
+
+            if (conditional->node->match) {
+                /* It's a positive lookaround that's succeeded.
+                 *
+                 * Go to the 'true' branch.
+                 */
+                node = node->next_1.node;
+            } else {
+                /* It's a negative lookaround that's succeeded.
+                 *
+                 * Go to the 'false' branch.
+                 */
+                node = node->nonstring.next_2.node;
+            }
+            break;
+        }
+        case RE_OP_END_FUZZY: /* End of fuzzy matching. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            if (!fuzzy_insert(safe_state, state->text_pos, node))
+                return RE_ERROR_BACKTRACKING;
+
+            /* If there were too few errors, in the fuzzy section, try again.
+             */
+            if (state->too_few_errors) {
+                state->too_few_errors = FALSE;
+                goto backtrack;
+            }
+
+            state->total_fuzzy_counts[RE_FUZZY_SUB] +=
+              state->fuzzy_info.counts[RE_FUZZY_SUB];
+            state->total_fuzzy_counts[RE_FUZZY_INS] +=
+              state->fuzzy_info.counts[RE_FUZZY_INS];
+            state->total_fuzzy_counts[RE_FUZZY_DEL] +=
+              state->fuzzy_info.counts[RE_FUZZY_DEL];
+
+            node = node->next_1.node;
+            break;
+        case RE_OP_END_GREEDY_REPEAT: /* End of a greedy repeat. */
+        {
+            RE_CODE index;
+            RE_RepeatData* rp_data;
+            BOOL changed;
+            BOOL try_body;
+            int body_status;
+            RE_Position next_body_position;
+            BOOL try_tail;
+            int tail_status;
+            RE_Position next_tail_position;
+            RE_BacktrackData* bt_data;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Repeat indexes are 0-based. */
+            index = node->values[0];
+            rp_data = &state->repeats[index];
+
+            /* The body has matched successfully at this position. */
+            if (!guard_repeat(safe_state, index, rp_data->start,
+              RE_STATUS_BODY, FALSE))
+                return RE_ERROR_MEMORY;
+
+            ++rp_data->count;
+
+            /* Have we advanced through the text or has a capture group change?
+             */
+            changed = rp_data->capture_change != state->capture_change ||
+              state->text_pos != rp_data->start;
+
+            /* The counts are of type size_t, so the format needs to specify
+             * that.
+             */
+            TRACE(("min is %" PY_FORMAT_SIZE_T "u, max is %" PY_FORMAT_SIZE_T
+              "u, count is %" PY_FORMAT_SIZE_T "u\n", node->values[1],
+              node->values[2], rp_data->count))
+
+            /* Could the body or tail match? */
+            try_body = changed && (rp_data->count < node->values[2] ||
+              ~node->values[2] == 0) && !is_repeat_guarded(safe_state, index,
+              state->text_pos, RE_STATUS_BODY);
+            if (try_body) {
+                body_status = try_match(state, &node->next_1, state->text_pos,
+                  &next_body_position);
+                if (body_status < 0)
+                    return body_status;
+
+                if (body_status == RE_ERROR_FAILURE)
+                    try_body = FALSE;
+            } else
+                body_status = RE_ERROR_FAILURE;
+
+            try_tail = (!changed || rp_data->count >= node->values[1]) &&
+              !is_repeat_guarded(safe_state, index, state->text_pos,
+              RE_STATUS_TAIL);
+            if (try_tail) {
+                tail_status = try_match(state, &node->nonstring.next_2,
+                  state->text_pos, &next_tail_position);
+                if (tail_status < 0)
+                    return tail_status;
+
+                if (tail_status == RE_ERROR_FAILURE)
+                    try_tail = FALSE;
+            } else
+                tail_status = RE_ERROR_FAILURE;
+
+            if (!try_body && !try_tail) {
+                /* Neither the body nor the tail could match. */
+                --rp_data->count;
+                goto backtrack;
+            }
+
+            if (body_status < 0 || (body_status == 0 && tail_status < 0))
+                return RE_ERROR_PARTIAL;
+
+            /* Record info in case we backtrack into the body. */
+            if (!add_backtrack(safe_state, RE_OP_BODY_END))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            bt_data->repeat.index = index;
+            bt_data->repeat.count = rp_data->count - 1;
+            bt_data->repeat.start = rp_data->start;
+            bt_data->repeat.capture_change = rp_data->capture_change;
+
+            if (try_body) {
+                /* Both the body and the tail could match. */
+                if (try_tail) {
+                    /* The body takes precedence. If the body fails to match
+                     * then we want to try the tail before backtracking
+                     * further.
+                     */
+
+                    /* Record backtracking info for matching the tail. */
+                    if (!add_backtrack(safe_state, RE_OP_MATCH_TAIL))
+                        return RE_ERROR_BACKTRACKING;
+                    bt_data = state->backtrack;
+                    bt_data->repeat.position = next_tail_position;
+                    bt_data->repeat.index = index;
+                    bt_data->repeat.count = rp_data->count;
+                    bt_data->repeat.start = rp_data->start;
+                    bt_data->repeat.capture_change = rp_data->capture_change;
+                    bt_data->repeat.text_pos = state->text_pos;
+                }
+
+                /* Record backtracking info in case the body fails to match. */
+                if (!add_backtrack(safe_state, RE_OP_BODY_START))
+                    return RE_ERROR_BACKTRACKING;
+                bt_data = state->backtrack;
+                bt_data->repeat.index = index;
+                bt_data->repeat.text_pos = state->text_pos;
+
+                rp_data->capture_change = state->capture_change;
+                rp_data->start = state->text_pos;
+
+                /* Advance into the body. */
+                node = next_body_position.node;
+                state->text_pos = next_body_position.text_pos;
+            } else {
+                /* Only the tail could match. */
+
+                /* Advance into the tail. */
+                node = next_tail_position.node;
+                state->text_pos = next_tail_position.text_pos;
+            }
+            break;
+        }
+        case RE_OP_END_GROUP: /* End of a capture group. */
+        {
+            RE_CODE private_index;
+            RE_CODE public_index;
+            RE_GroupData* group;
+            RE_BacktrackData* bt_data;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[1]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             */
+            private_index = node->values[0];
+            public_index = node->values[1];
+            group = &state->groups[private_index - 1];
+
+            if (!add_backtrack(safe_state, RE_OP_END_GROUP))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            bt_data->group.private_index = private_index;
+            bt_data->group.public_index = public_index;
+            bt_data->group.text_pos = group->span.end;
+            bt_data->group.capture = (BOOL)node->values[2];
+            bt_data->group.current_capture = group->current_capture;
+
+            if (pattern->group_info[private_index - 1].referenced &&
+              group->span.end != state->text_pos)
+                ++state->capture_change;
+            group->span.end = state->text_pos;
+
+            /* Save the capture? */
+            if (node->values[2]) {
+                group->current_capture = (Py_ssize_t)group->capture_count;
+                if (!save_capture(safe_state, private_index, public_index))
+                    return RE_ERROR_MEMORY;
+            }
+
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_END_LAZY_REPEAT: /* End of a lazy repeat. */
+        {
+            RE_CODE index;
+            RE_RepeatData* rp_data;
+            BOOL changed;
+            BOOL try_body;
+            int body_status;
+            RE_Position next_body_position;
+            BOOL try_tail;
+            int tail_status;
+            RE_Position next_tail_position;
+            RE_BacktrackData* bt_data;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Repeat indexes are 0-based. */
+            index = node->values[0];
+            rp_data = &state->repeats[index];
+
+            /* The body has matched successfully at this position. */
+            if (!guard_repeat(safe_state, index, rp_data->start,
+              RE_STATUS_BODY, FALSE))
+                return RE_ERROR_MEMORY;
+
+            ++rp_data->count;
+
+            /* Have we advanced through the text or has a capture group change?
+             */
+            changed = rp_data->capture_change != state->capture_change ||
+              state->text_pos != rp_data->start;
+
+            /* The counts are of type size_t, so the format needs to specify
+             * that.
+             */
+            TRACE(("min is %" PY_FORMAT_SIZE_T "u, max is %" PY_FORMAT_SIZE_T
+              "u, count is %" PY_FORMAT_SIZE_T "u\n", node->values[1],
+              node->values[2], rp_data->count))
+
+            /* Could the body or tail match? */
+            try_body = changed && (rp_data->count < node->values[2] ||
+              ~node->values[2] == 0) && !is_repeat_guarded(safe_state, index,
+              state->text_pos, RE_STATUS_BODY);
+            if (try_body) {
+                body_status = try_match(state, &node->next_1, state->text_pos,
+                  &next_body_position);
+                if (body_status < 0)
+                    return body_status;
+
+                if (body_status == RE_ERROR_FAILURE)
+                    try_body = FALSE;
+            } else
+                body_status = RE_ERROR_FAILURE;
+
+            try_tail = (!changed || rp_data->count >= node->values[1]);
+            if (try_tail) {
+                tail_status = try_match(state, &node->nonstring.next_2,
+                  state->text_pos, &next_tail_position);
+                if (tail_status < 0)
+                    return tail_status;
+
+                if (tail_status == RE_ERROR_FAILURE)
+                    try_tail = FALSE;
+            } else
+                tail_status = RE_ERROR_FAILURE;
+
+            if (!try_body && !try_tail) {
+                /* Neither the body nor the tail could match. */
+                --rp_data->count;
+                goto backtrack;
+            }
+
+            if (body_status < 0 || (body_status == 0 && tail_status < 0))
+                return RE_ERROR_PARTIAL;
+
+            /* Record info in case we backtrack into the body. */
+            if (!add_backtrack(safe_state, RE_OP_BODY_END))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            bt_data->repeat.index = index;
+            bt_data->repeat.count = rp_data->count - 1;
+            bt_data->repeat.start = rp_data->start;
+            bt_data->repeat.capture_change = rp_data->capture_change;
+
+            if (try_body) {
+                /* Both the body and the tail could match. */
+                if (try_tail) {
+                    /* The tail takes precedence. If the tail fails to match
+                     * then we want to try the body before backtracking
+                     * further.
+                     */
+
+                    /* Record backtracking info for matching the body. */
+                    if (!add_backtrack(safe_state, RE_OP_MATCH_BODY))
+                        return RE_ERROR_BACKTRACKING;
+                    bt_data = state->backtrack;
+                    bt_data->repeat.position = next_body_position;
+                    bt_data->repeat.index = index;
+                    bt_data->repeat.count = rp_data->count;
+                    bt_data->repeat.start = rp_data->start;
+                    bt_data->repeat.capture_change = rp_data->capture_change;
+                    bt_data->repeat.text_pos = state->text_pos;
+
+                    /* Advance into the tail. */
+                    node = next_tail_position.node;
+                    state->text_pos = next_tail_position.text_pos;
+                } else {
+                    /* Only the body could match. */
+
+                    /* Record backtracking info in case the body fails to
+                     * match.
+                     */
+                    if (!add_backtrack(safe_state, RE_OP_BODY_START))
+                        return RE_ERROR_BACKTRACKING;
+                    bt_data = state->backtrack;
+                    bt_data->repeat.index = index;
+                    bt_data->repeat.text_pos = state->text_pos;
+
+                    rp_data->capture_change = state->capture_change;
+                    rp_data->start = state->text_pos;
+
+                    /* Advance into the body. */
+                    node = next_body_position.node;
+                    state->text_pos = next_body_position.text_pos;
+                }
+            } else {
+                /* Only the tail could match. */
+
+                /* Advance into the tail. */
+                node = next_tail_position.node;
+                state->text_pos = next_tail_position.text_pos;
+            }
+            break;
+        }
+        case RE_OP_END_LOOKAROUND: /* End of a lookaround subpattern. */
+        {
+            RE_AtomicData* lookaround;
+
+            lookaround = pop_atomic(safe_state);
+            while (!lookaround->is_lookaround) {
+                if (lookaround->has_repeats)
+                    drop_repeats(state);
+
+                if (lookaround->has_groups)
+                    drop_groups(state);
+
+                lookaround = pop_atomic(safe_state);
+            }
+            state->text_pos = lookaround->text_pos;
+            state->slice_end = lookaround->slice_end;
+            state->slice_start = lookaround->slice_start;
+
+            /* Discard any backtracking info from inside the lookaround. */
+            state->current_backtrack_block =
+              lookaround->current_backtrack_block;
+            state->current_backtrack_block->count =
+              lookaround->backtrack_count;
+            state->current_saved_groups = lookaround->saved_groups;
+            state->current_saved_repeats = lookaround->saved_repeats;
+
+            if (lookaround->node->match) {
+                /* It's a positive lookaround that's succeeded. We're now going
+                 * to leave the lookaround.
+                 */
+                lookaround->backtrack->lookaround.inside = FALSE;
+
+                node = node->next_1.node;
+            } else {
+                /* It's a negative lookaround that's succeeded. The groups and
+                 * certain flags may have changed. We need to restore them and
+                 * then backtrack.
+                 */
+                if (lookaround->has_repeats)
+                    pop_repeats(state);
+
+                if (lookaround->has_groups)
+                    pop_groups(state);
+
+                state->too_few_errors =
+                  lookaround->backtrack->lookaround.too_few_errors;
+                state->capture_change =
+                  lookaround->backtrack->lookaround.capture_change;
+
+                discard_backtrack(state);
+                goto backtrack;
+            }
+            break;
+        }
+        case RE_OP_END_OF_LINE: /* At the end of a line. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_END_OF_LINE(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_END_OF_LINE_U: /* At the end of a line. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_END_OF_LINE_U(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_END_OF_STRING: /* At the end of the string. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_END_OF_STRING(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_END_OF_STRING_LINE: /* At end of string or final newline. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_END_OF_STRING_LINE(state, node,
+              state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_END_OF_STRING_LINE_U: /* At end of string or final newline. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_END_OF_STRING_LINE_U(state, node,
+              state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_END_OF_WORD: /* At the end of a word. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_END_OF_WORD(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_FAILURE: /* Failure. */
+            goto backtrack;
+        case RE_OP_FUZZY: /* Fuzzy matching. */
+        {
+            RE_FuzzyInfo* fuzzy_info;
+            RE_BacktrackData* bt_data;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            fuzzy_info = &state->fuzzy_info;
+
+            /* Save the current fuzzy info. */
+            if (!add_backtrack(safe_state, RE_OP_FUZZY))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            memmove(&bt_data->fuzzy.fuzzy_info, fuzzy_info,
+              sizeof(RE_FuzzyInfo));
+            bt_data->fuzzy.index = node->values[0];
+            bt_data->fuzzy.text_pos = state->text_pos;
+
+            /* Initialise the new fuzzy info. */
+            memset(fuzzy_info->counts, 0, 4 * sizeof(fuzzy_info->counts[0]));
+            fuzzy_info->total_cost = 0;
+            fuzzy_info->node = node;
+
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_GRAPHEME_BOUNDARY: /* On a grapheme boundary. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_GRAPHEME_BOUNDARY(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_GREEDY_REPEAT: /* Greedy repeat. */
+        {
+            RE_CODE index;
+            RE_RepeatData* rp_data;
+            RE_BacktrackData* bt_data;
+            BOOL try_body;
+            int body_status;
+            RE_Position next_body_position;
+            BOOL try_tail;
+            int tail_status;
+            RE_Position next_tail_position;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Repeat indexes are 0-based. */
+            index = node->values[0];
+            rp_data = &state->repeats[index];
+
+            /* We might need to backtrack into the head, so save the current
+             * repeat.
+             */
+            if (!add_backtrack(safe_state, RE_OP_GREEDY_REPEAT))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            bt_data->repeat.index = index;
+            bt_data->repeat.count = rp_data->count;
+            bt_data->repeat.start = rp_data->start;
+            bt_data->repeat.capture_change = rp_data->capture_change;
+            bt_data->repeat.text_pos = state->text_pos;
+
+            /* Initialise the new repeat. */
+            rp_data->count = 0;
+            rp_data->start = state->text_pos;
+            rp_data->capture_change = state->capture_change;
+
+            /* Could the body or tail match? */
+            try_body = node->values[2] > 0 && !is_repeat_guarded(safe_state,
+              index, state->text_pos, RE_STATUS_BODY);
+            if (try_body) {
+                body_status = try_match(state, &node->next_1, state->text_pos,
+                  &next_body_position);
+                if (body_status < 0)
+                    return body_status;
+
+                if (body_status == RE_ERROR_FAILURE)
+                    try_body = FALSE;
+            } else
+                body_status = RE_ERROR_FAILURE;
+
+            try_tail = node->values[1] == 0;
+            if (try_tail) {
+                tail_status = try_match(state, &node->nonstring.next_2,
+                  state->text_pos, &next_tail_position);
+                if (tail_status < 0)
+                    return tail_status;
+
+                if (tail_status == RE_ERROR_FAILURE)
+                    try_tail = FALSE;
+            } else
+                tail_status = RE_ERROR_FAILURE;
+            if (!try_body && !try_tail)
+                /* Neither the body nor the tail could match. */
+                goto backtrack;
+
+            if (body_status < 0 || (body_status == 0 && tail_status < 0))
+                return RE_ERROR_PARTIAL;
+
+            if (try_body) {
+                if (try_tail) {
+                    /* Both the body and the tail could match, but the body
+                     * takes precedence. If the body fails to match then we
+                     * want to try the tail before backtracking further.
+                     */
+
+                    /* Record backtracking info for matching the tail. */
+                    if (!add_backtrack(safe_state, RE_OP_MATCH_TAIL))
+                        return RE_ERROR_BACKTRACKING;
+                    bt_data = state->backtrack;
+                    bt_data->repeat.position = next_tail_position;
+                    bt_data->repeat.index = index;
+                    bt_data->repeat.count = rp_data->count;
+                    bt_data->repeat.start = rp_data->start;
+                    bt_data->repeat.capture_change = rp_data->capture_change;
+                    bt_data->repeat.text_pos = state->text_pos;
+                }
+
+                /* Advance into the body. */
+                node = next_body_position.node;
+                state->text_pos = next_body_position.text_pos;
+            } else {
+                /* Only the tail could match. */
+
+                /* Advance into the tail. */
+                node = next_tail_position.node;
+                state->text_pos = next_tail_position.text_pos;
+            }
+            break;
+        }
+        case RE_OP_GREEDY_REPEAT_ONE: /* Greedy repeat for one character. */
+        {
+            RE_CODE index;
+            RE_RepeatData* rp_data;
+            size_t count;
+            BOOL is_partial;
+            BOOL match;
+            RE_BacktrackData* bt_data;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Repeat indexes are 0-based. */
+            index = node->values[0];
+            rp_data = &state->repeats[index];
+
+            if (is_repeat_guarded(safe_state, index, state->text_pos,
+              RE_STATUS_BODY))
+                goto backtrack;
+
+            /* Count how many times the character repeats, up to the maximum.
+             */
+            count = count_one(state, node->nonstring.next_2.node,
+              state->text_pos, node->values[2], &is_partial);
+            if (is_partial) {
+                state->text_pos += (Py_ssize_t)count * node->step;
+                return RE_ERROR_PARTIAL;
+            }
+
+            /* Unmatch until it's not guarded. */
+            match = FALSE;
+            for (;;) {
+                if (count < node->values[1])
+                    /* The number of repeats is below the minimum. */
+                    break;
+
+                if (!is_repeat_guarded(safe_state, index, state->text_pos +
+                  (Py_ssize_t)count * node->step, RE_STATUS_TAIL)) {
+                    /* It's not guarded at this position. */
+                    match = TRUE;
+                    break;
+                }
+
+                if (count == 0)
+                    break;
+
+                --count;
+            }
+
+            if (!match) {
+                /* The repeat has failed to match at this position. */
+                if (!guard_repeat(safe_state, index, state->text_pos,
+                  RE_STATUS_BODY, TRUE))
+                    return RE_ERROR_MEMORY;
+                goto backtrack;
+            }
+
+            if (count > node->values[1]) {
+                /* Record the backtracking info. */
+                if (!add_backtrack(safe_state, RE_OP_GREEDY_REPEAT_ONE))
+                    return RE_ERROR_BACKTRACKING;
+                bt_data = state->backtrack;
+                bt_data->repeat.position.node = node;
+                bt_data->repeat.index = index;
+                bt_data->repeat.text_pos = rp_data->start;
+                bt_data->repeat.count = rp_data->count;
+
+                rp_data->start = state->text_pos;
+                rp_data->count = count;
+            }
+
+            /* Advance into the tail. */
+            state->text_pos += (Py_ssize_t)count * node->step;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_GROUP_CALL: /* Group call. */
+        {
+            size_t index;
+            size_t g;
+            size_t r;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            index = node->values[0];
+
+            /* Save the capture groups and repeat guards. */
+            if (!push_group_return(safe_state, node->next_1.node))
+                return RE_ERROR_MEMORY;
+
+            /* Clear the capture groups for the group call. They'll be restored
+             * on return.
+             */
+            for (g = 0; g < state->pattern->true_group_count; g++) {
+                RE_GroupData* group;
+
+                group = &state->groups[g];
+                group->span.start = -1;
+                group->span.end = -1;
+                group->current_capture = -1;
+            }
+
+            /* Clear the repeat guards for the group call. They'll be restored
+             * on return.
+             */
+            for (r = 0; r < state->pattern->repeat_count; r++) {
+                RE_RepeatData* repeat;
+
+                repeat = &state->repeats[r];
+                repeat->body_guard_list.count = 0;
+                repeat->body_guard_list.last_text_pos = -1;
+                repeat->tail_guard_list.count = 0;
+                repeat->tail_guard_list.last_text_pos = -1;
+            }
+
+            /* Call a group, skipping its CALL_REF node. */
+            node = pattern->call_ref_info[index].node->next_1.node;
+
+            if (!add_backtrack(safe_state, RE_OP_GROUP_CALL))
+                return RE_ERROR_BACKTRACKING;
+            break;
+        }
+        case RE_OP_GROUP_EXISTS: /* Capture group exists. */
+        {
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             *
+             * Check whether the captured text, if any, exists at this position
+             * in the string.
+             *
+             * A group index of 0, however, means that it's a DEFINE, which we
+             * should skip.
+             */
+            if (node->values[0] == 0)
+                /* Skip past the body. */
+                node = node->nonstring.next_2.node;
+            else {
+                RE_GroupData* group;
+
+                group = &state->groups[node->values[0] - 1];
+                if (group->current_capture >= 0)
+                    /* The 'true' branch. */
+                    node = node->next_1.node;
+                else
+                    /* The 'false' branch. */
+                    node = node->nonstring.next_2.node;
+            }
+            break;
+        }
+        case RE_OP_GROUP_RETURN: /* Group return. */
+        {
+            RE_Node* return_node;
+            RE_BacktrackData* bt_data;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            return_node = top_group_return(state);
+
+            if (!add_backtrack(safe_state, RE_OP_GROUP_RETURN))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            bt_data->group_call.node = return_node;
+            bt_data->group_call.capture_change = state->capture_change;
+
+            if (return_node) {
+                /* The group was called. */
+                node = return_node;
+
+                /* Save the groups. */
+                if (!push_groups(safe_state))
+                    return RE_ERROR_MEMORY;
+
+                /* Save the repeats. */
+                if (!push_repeats(safe_state))
+                    return RE_ERROR_MEMORY;
+            } else
+                /* The group was not called. */
+                node = node->next_1.node;
+
+            pop_group_return(state);
+            break;
+        }
+        case RE_OP_KEEP: /* Keep. */
+        {
+            RE_BacktrackData* bt_data;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            if (!add_backtrack(safe_state, RE_OP_KEEP))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            bt_data->keep.match_pos = state->match_pos;
+            state->match_pos = state->text_pos;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_LAZY_REPEAT: /* Lazy repeat. */
+        {
+            RE_CODE index;
+            RE_RepeatData* rp_data;
+            RE_BacktrackData* bt_data;
+            BOOL try_body;
+            int body_status;
+            RE_Position next_body_position;
+            BOOL try_tail;
+            int tail_status;
+            RE_Position next_tail_position;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Repeat indexes are 0-based. */
+            index = node->values[0];
+            rp_data = &state->repeats[index];
+
+            /* We might need to backtrack into the head, so save the current
+             * repeat.
+             */
+            if (!add_backtrack(safe_state, RE_OP_LAZY_REPEAT))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            bt_data->repeat.index = index;
+            bt_data->repeat.count = rp_data->count;
+            bt_data->repeat.start = rp_data->start;
+            bt_data->repeat.capture_change = rp_data->capture_change;
+            bt_data->repeat.text_pos = state->text_pos;
+
+            /* Initialise the new repeat. */
+            rp_data->count = 0;
+            rp_data->start = state->text_pos;
+            rp_data->capture_change = state->capture_change;
+
+            /* Could the body or tail match? */
+            try_body = node->values[2] > 0 && !is_repeat_guarded(safe_state,
+              index, state->text_pos, RE_STATUS_BODY);
+            if (try_body) {
+                body_status = try_match(state, &node->next_1, state->text_pos,
+                  &next_body_position);
+                if (body_status < 0)
+                    return body_status;
+
+                if (body_status == RE_ERROR_FAILURE)
+                    try_body = FALSE;
+            } else
+                body_status = RE_ERROR_FAILURE;
+
+            try_tail = node->values[1] == 0;
+            if (try_tail) {
+                tail_status = try_match(state, &node->nonstring.next_2,
+                  state->text_pos, &next_tail_position);
+                if (tail_status < 0)
+                    return tail_status;
+
+                if (tail_status == RE_ERROR_FAILURE)
+                    try_tail = FALSE;
+            } else
+                tail_status = RE_ERROR_FAILURE;
+
+            if (!try_body && !try_tail)
+                /* Neither the body nor the tail could match. */
+                goto backtrack;
+
+            if (body_status < 0 || (body_status == 0 && tail_status < 0))
+                return RE_ERROR_PARTIAL;
+
+            if (try_body) {
+                if (try_tail) {
+                    /* Both the body and the tail could match, but the tail
+                     * takes precedence. If the tail fails to match then we
+                     * want to try the body before backtracking further.
+                     */
+
+                    /* Record backtracking info for matching the tail. */
+                    if (!add_backtrack(safe_state, RE_OP_MATCH_BODY))
+                        return RE_ERROR_BACKTRACKING;
+                    bt_data = state->backtrack;
+                    bt_data->repeat.position = next_body_position;
+                    bt_data->repeat.index = index;
+                    bt_data->repeat.count = rp_data->count;
+                    bt_data->repeat.start = rp_data->start;
+                    bt_data->repeat.capture_change = rp_data->capture_change;
+                    bt_data->repeat.text_pos = state->text_pos;
+
+                    /* Advance into the tail. */
+                    node = next_tail_position.node;
+                    state->text_pos = next_tail_position.text_pos;
+                } else {
+                    /* Advance into the body. */
+                    node = next_body_position.node;
+                    state->text_pos = next_body_position.text_pos;
+                }
+            } else {
+                /* Only the tail could match. */
+
+                /* Advance into the tail. */
+                node = next_tail_position.node;
+                state->text_pos = next_tail_position.text_pos;
+            }
+            break;
+        }
+        case RE_OP_LAZY_REPEAT_ONE: /* Lazy repeat for one character. */
+        {
+            RE_CODE index;
+            RE_RepeatData* rp_data;
+            size_t count;
+            BOOL is_partial;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Repeat indexes are 0-based. */
+            index = node->values[0];
+            rp_data = &state->repeats[index];
+
+            if (is_repeat_guarded(safe_state, index, state->text_pos,
+              RE_STATUS_BODY))
+                goto backtrack;
+
+            /* Count how many times the character repeats, up to the minimum.
+             */
+            count = count_one(state, node->nonstring.next_2.node,
+              state->text_pos, node->values[1], &is_partial);
+            if (is_partial) {
+                state->text_pos += (Py_ssize_t)count * node->step;
+                return RE_ERROR_PARTIAL;
+            }
+
+            /* Have we matched at least the minimum? */
+            if (count < node->values[1]) {
+                /* The repeat has failed to match at this position. */
+                if (!guard_repeat(safe_state, index, state->text_pos,
+                  RE_STATUS_BODY, TRUE))
+                    return RE_ERROR_MEMORY;
+                goto backtrack;
+            }
+
+            if (count < node->values[2]) {
+                /* The match is shorter than the maximum, so we might need to
+                 * backtrack the repeat to consume more.
+                 */
+                RE_BacktrackData* bt_data;
+
+                /* Get the offset to the repeat values in the context. */
+                rp_data = &state->repeats[index];
+                if (!add_backtrack(safe_state, RE_OP_LAZY_REPEAT_ONE))
+                    return RE_ERROR_BACKTRACKING;
+                bt_data = state->backtrack;
+                bt_data->repeat.position.node = node;
+                bt_data->repeat.index = index;
+                bt_data->repeat.text_pos = rp_data->start;
+                bt_data->repeat.count = rp_data->count;
+
+                rp_data->start = state->text_pos;
+                rp_data->count = count;
+            }
+
+            /* Advance into the tail. */
+            state->text_pos += (Py_ssize_t)count * node->step;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_LOOKAROUND: /* Start of a lookaround subpattern. */
+        {
+            RE_AtomicData* lookaround;
+            TRACE(("%s %d\n", re_op_text[node->op], node->match))
+
+            if (!add_backtrack(safe_state, RE_OP_LOOKAROUND))
+                return RE_ERROR_BACKTRACKING;
+            state->backtrack->lookaround.too_few_errors =
+              state->too_few_errors;
+            state->backtrack->lookaround.capture_change =
+              state->capture_change;
+            state->backtrack->lookaround.inside = TRUE;
+            state->backtrack->lookaround.node = node;
+
+            lookaround = push_atomic(safe_state);
+            if (!lookaround)
+                return RE_ERROR_MEMORY;
+            lookaround->backtrack_count =
+              state->current_backtrack_block->count;
+            lookaround->current_backtrack_block =
+              state->current_backtrack_block;
+            lookaround->slice_start = state->slice_start;
+            lookaround->slice_end = state->slice_end;
+            lookaround->text_pos = state->text_pos;
+            lookaround->node = node;
+            lookaround->backtrack = state->backtrack;
+            lookaround->is_lookaround = TRUE;
+            lookaround->has_groups = (node->status & RE_STATUS_HAS_GROUPS) !=
+              0;
+            lookaround->has_repeats = (node->status & RE_STATUS_HAS_REPEATS) !=
+              0;
+
+            /* Save the groups and repeats. */
+            if (lookaround->has_groups && !push_groups(safe_state))
+                return RE_ERROR_MEMORY;
+
+            if (lookaround->has_repeats && !push_repeats(safe_state))
+                return RE_ERROR_MEMORY;
+
+            lookaround->saved_groups = state->current_saved_groups;
+            lookaround->saved_repeats = state->current_saved_repeats;
+
+            state->slice_start = 0;
+            state->slice_end = state->text_length;
+
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_PROPERTY: /* A property. */
+            TRACE(("%s %d %d\n", re_op_text[node->op], node->match,
+              node->values[0]))
+
+            if (state->text_pos >= state->text_length && state->partial_side ==
+              RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos < state->slice_end &&
+              matches_PROPERTY(encoding, locale_info, node,
+              char_at(state->text, state->text_pos)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_PROPERTY_IGN: /* A property, ignoring case. */
+            TRACE(("%s %d %d\n", re_op_text[node->op], node->match,
+              node->values[0]))
+
+            if (state->text_pos >= state->text_length && state->partial_side ==
+              RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos < state->slice_end &&
+              matches_PROPERTY_IGN(encoding, locale_info, node,
+              char_at(state->text, state->text_pos)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_PROPERTY_IGN_REV: /* A property, backwards, ignoring case. */
+            TRACE(("%s %d %d\n", re_op_text[node->op], node->match,
+              node->values[0]))
+
+            if (state->text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos > state->slice_start &&
+              matches_PROPERTY_IGN(encoding, locale_info, node,
+              char_at(state->text, state->text_pos - 1)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_PROPERTY_REV: /* A property, backwards. */
+            TRACE(("%s %d %d\n", re_op_text[node->op], node->match,
+              node->values[0]))
+
+            if (state->text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos > state->slice_start &&
+              matches_PROPERTY(encoding, locale_info, node,
+              char_at(state->text, state->text_pos - 1)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_PRUNE: /* Prune the backtracking. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            prune_backtracking(state);
+
+            node = node->next_1.node;
+            break;
+        case RE_OP_RANGE: /* A range. */
+            TRACE(("%s %d %d %d\n", re_op_text[node->op], node->match,
+              node->values[0], node->values[1]))
+
+            if (state->text_pos >= state->text_length && state->partial_side ==
+              RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos < state->slice_end && matches_RANGE(encoding,
+              locale_info, node, char_at(state->text, state->text_pos)) ==
+              node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_RANGE_IGN: /* A range, ignoring case. */
+            TRACE(("%s %d %d %d\n", re_op_text[node->op], node->match,
+              node->values[0], node->values[1]))
+
+            if (state->text_pos >= state->text_length && state->partial_side ==
+              RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos < state->slice_end &&
+              matches_RANGE_IGN(encoding, locale_info, node,
+              char_at(state->text, state->text_pos)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_RANGE_IGN_REV: /* A range, backwards, ignoring case. */
+            TRACE(("%s %d %d %d\n", re_op_text[node->op], node->match,
+              node->values[0], node->values[1]))
+
+            if (state->text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos > state->slice_start &&
+              matches_RANGE_IGN(encoding, locale_info, node,
+              char_at(state->text, state->text_pos - 1)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_RANGE_REV: /* A range, backwards. */
+            TRACE(("%s %d %d %d\n", re_op_text[node->op], node->match,
+              node->values[0], node->values[1]))
+
+            if (state->text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos > state->slice_start && matches_RANGE(encoding,
+              locale_info, node, char_at(state->text, state->text_pos - 1)) ==
+              node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_REF_GROUP: /* Reference to a capture group. */
+        {
+            RE_GroupData* group;
+            RE_GroupSpan* span;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             *
+             * Check whether the captured text, if any, exists at this position
+             * in the string.
+             */
+
+            /* Did the group capture anything? */
+            group = &state->groups[node->values[0] - 1];
+            if (group->current_capture < 0)
+                goto backtrack;
+
+            span = &group->captures[group->current_capture];
+
+            if (string_pos < 0)
+                string_pos = span->start;
+
+            /* Try comparing. */
+            while (string_pos < span->end) {
+                if (state->text_pos >= state->text_length &&
+                  state->partial_side == RE_PARTIAL_RIGHT)
+                    return RE_ERROR_PARTIAL;
+
+                if (state->text_pos < state->slice_end &&
+                  same_char(char_at(state->text, state->text_pos),
+                  char_at(state->text, string_pos))) {
+                    ++string_pos;
+                    ++state->text_pos;
+                } else if (node->status & RE_STATUS_FUZZY) {
+                    BOOL matched;
+
+                    status = fuzzy_match_string(safe_state, search,
+                      &state->text_pos, node, &string_pos, &matched, 1);
+                    if (status < 0)
+                        return RE_ERROR_PARTIAL;
+
+                    if (!matched) {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                } else {
+                    string_pos = -1;
+                    goto backtrack;
+                }
+            }
+
+            string_pos = -1;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_REF_GROUP_FLD: /* Reference to a capture group, ignoring case. */
+        {
+            RE_GroupData* group;
+            RE_GroupSpan* span;
+            int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch,
+              Py_UCS4* folded);
+            int folded_len;
+            int gfolded_len;
+            Py_UCS4 folded[RE_MAX_FOLDED];
+            Py_UCS4 gfolded[RE_MAX_FOLDED];
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             *
+             * Check whether the captured text, if any, exists at this position
+             * in the string.
+             */
+
+            /* Did the group capture anything? */
+            group = &state->groups[node->values[0] - 1];
+            if (group->current_capture < 0)
+                goto backtrack;
+
+            span = &group->captures[group->current_capture];
+
+            full_case_fold = encoding->full_case_fold;
+
+            if (string_pos < 0) {
+                string_pos = span->start;
+                folded_pos = 0;
+                folded_len = 0;
+                gfolded_pos = 0;
+                gfolded_len = 0;
+            } else {
+                folded_len = full_case_fold(locale_info, char_at(state->text,
+                  state->text_pos), folded);
+                gfolded_len = full_case_fold(locale_info, char_at(state->text,
+                  string_pos), gfolded);
+            }
+
+            /* Try comparing. */
+            while (string_pos < span->end) {
+                /* Case-fold at current position in text. */
+                if (folded_pos >= folded_len) {
+                    if (state->text_pos >= state->text_length &&
+                      state->partial_side == RE_PARTIAL_RIGHT)
+                        return RE_ERROR_PARTIAL;
+
+                    if (state->text_pos < state->slice_end)
+                        folded_len = full_case_fold(locale_info,
+                          char_at(state->text, state->text_pos), folded);
+                    else
+                        folded_len = 0;
+
+                    folded_pos = 0;
+                }
+
+                /* Case-fold at current position in group. */
+                if (gfolded_pos >= gfolded_len) {
+                    gfolded_len = full_case_fold(locale_info,
+                      char_at(state->text, string_pos), gfolded);
+                    gfolded_pos = 0;
+                }
+
+                if (folded_pos < folded_len && folded[folded_pos] ==
+                  gfolded[gfolded_pos]) {
+                    ++folded_pos;
+                    ++gfolded_pos;
+                } else if (node->status & RE_STATUS_FUZZY) {
+                    BOOL matched;
+
+                    status = fuzzy_match_group_fld(safe_state, search,
+                      &state->text_pos, node, &folded_pos, folded_len,
+                      &string_pos, &gfolded_pos, gfolded_len, &matched, 1);
+                    if (status < 0)
+                        return RE_ERROR_PARTIAL;
+
+                    if (!matched) {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                } else {
+                    string_pos = -1;
+                    goto backtrack;
+                }
+
+                if (folded_pos >= folded_len && folded_len > 0)
+                    ++state->text_pos;
+
+                if (gfolded_pos >= gfolded_len)
+                    ++string_pos;
+            }
+
+            string_pos = -1;
+
+            if (folded_pos < folded_len || gfolded_pos < gfolded_len)
+                goto backtrack;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_REF_GROUP_FLD_REV: /* Reference to a capture group, ignoring case. */
+        {
+            RE_GroupData* group;
+            RE_GroupSpan* span;
+            int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch,
+              Py_UCS4* folded);
+            int folded_len;
+            int gfolded_len;
+            Py_UCS4 folded[RE_MAX_FOLDED];
+            Py_UCS4 gfolded[RE_MAX_FOLDED];
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             *
+             * Check whether the captured text, if any, exists at this position
+             * in the string.
+             */
+
+            /* Did the group capture anything? */
+            group = &state->groups[node->values[0] - 1];
+            if (group->current_capture < 0)
+                goto backtrack;
+
+            span = &group->captures[group->current_capture];
+
+            full_case_fold = encoding->full_case_fold;
+
+            if (string_pos < 0) {
+                string_pos = span->end;
+                folded_pos = 0;
+                folded_len = 0;
+                gfolded_pos = 0;
+                gfolded_len = 0;
+            } else {
+                folded_len = full_case_fold(locale_info, char_at(state->text,
+                  state->text_pos - 1), folded);
+                gfolded_len = full_case_fold(locale_info, char_at(state->text,
+                  string_pos - 1), gfolded);
+            }
+
+            /* Try comparing. */
+            while (string_pos > span->start) {
+                /* Case-fold at current position in text. */
+                if (folded_pos <= 0) {
+                    if (state->text_pos <= 0 && state->partial_side ==
+                      RE_PARTIAL_LEFT)
+                        return RE_ERROR_PARTIAL;
+
+                    if (state->text_pos > state->slice_start)
+                        folded_len = full_case_fold(locale_info,
+                          char_at(state->text, state->text_pos - 1), folded);
+                    else
+                        folded_len = 0;
+
+                    folded_pos = folded_len;
+                }
+
+                /* Case-fold at current position in group. */
+                if (gfolded_pos <= 0) {
+                    gfolded_len = full_case_fold(locale_info,
+                      char_at(state->text, string_pos - 1), gfolded);
+                    gfolded_pos = gfolded_len;
+                }
+
+                if (folded_pos > 0 && folded[folded_pos - 1] ==
+                  gfolded[gfolded_pos - 1]) {
+                    --folded_pos;
+                    --gfolded_pos;
+                } else if (node->status & RE_STATUS_FUZZY) {
+                    BOOL matched;
+
+                    status = fuzzy_match_group_fld(safe_state, search,
+                      &state->text_pos, node, &folded_pos, folded_len,
+                      &string_pos, &gfolded_pos, gfolded_len, &matched, -1);
+                    if (status < 0)
+                        return RE_ERROR_PARTIAL;
+
+                    if (!matched) {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                } else {
+                    string_pos = -1;
+                    goto backtrack;
+                }
+
+                if (folded_pos <= 0 && folded_len > 0)
+                    --state->text_pos;
+
+                if (gfolded_pos <= 0)
+                    --string_pos;
+            }
+
+            string_pos = -1;
+
+            if (folded_pos > 0 || gfolded_pos > 0)
+                goto backtrack;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_REF_GROUP_IGN: /* Reference to a capture group, ignoring case. */
+        {
+            RE_GroupData* group;
+            RE_GroupSpan* span;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             *
+             * Check whether the captured text, if any, exists at this position
+             * in the string.
+             */
+
+            /* Did the group capture anything? */
+            group = &state->groups[node->values[0] - 1];
+            if (group->current_capture < 0)
+                goto backtrack;
+
+            span = &group->captures[group->current_capture];
+
+            if (string_pos < 0)
+                string_pos = span->start;
+
+            /* Try comparing. */
+            while (string_pos < span->end) {
+                if (state->text_pos >= state->text_length &&
+                  state->partial_side == RE_PARTIAL_RIGHT)
+                    return RE_ERROR_PARTIAL;
+
+                if (state->text_pos < state->slice_end &&
+                  same_char_ign(encoding, locale_info, char_at(state->text,
+                  state->text_pos), char_at(state->text, string_pos))) {
+                    ++string_pos;
+                    ++state->text_pos;
+                } else if (node->status & RE_STATUS_FUZZY) {
+                    BOOL matched;
+
+                    status = fuzzy_match_string(safe_state, search,
+                      &state->text_pos, node, &string_pos, &matched, 1);
+                    if (status < 0)
+                        return RE_ERROR_PARTIAL;
+
+                    if (!matched) {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                } else {
+                    string_pos = -1;
+                    goto backtrack;
+                }
+            }
+
+            string_pos = -1;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_REF_GROUP_IGN_REV: /* Reference to a capture group, ignoring case. */
+        {
+            RE_GroupData* group;
+            RE_GroupSpan* span;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             *
+             * Check whether the captured text, if any, exists at this position
+             * in the string.
+             */
+
+            /* Did the group capture anything? */
+            group = &state->groups[node->values[0] - 1];
+            if (group->current_capture < 0)
+                goto backtrack;
+
+            span = &group->captures[group->current_capture];
+
+            if (string_pos < 0)
+                string_pos = span->end;
+
+            /* Try comparing. */
+            while (string_pos > span->start) {
+                if (state->text_pos <= 0 && state->partial_side ==
+                  RE_PARTIAL_LEFT)
+                    return RE_ERROR_PARTIAL;
+
+                if (state->text_pos > state->slice_start &&
+                  same_char_ign(encoding, locale_info, char_at(state->text,
+                  state->text_pos - 1), char_at(state->text, string_pos - 1)))
+                  {
+                    --string_pos;
+                    --state->text_pos;
+                } else if (node->status & RE_STATUS_FUZZY) {
+                    BOOL matched;
+
+                    status = fuzzy_match_string(safe_state, search,
+                      &state->text_pos, node, &string_pos, &matched, -1);
+                    if (status < 0)
+                        return RE_ERROR_PARTIAL;
+
+                    if (!matched) {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                } else {
+                    string_pos = -1;
+                    goto backtrack;
+                }
+            }
+
+            string_pos = -1;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_REF_GROUP_REV: /* Reference to a capture group. */
+        {
+            RE_GroupData* group;
+            RE_GroupSpan* span;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             *
+             * Check whether the captured text, if any, exists at this position
+             * in the string.
+             */
+
+            /* Did the group capture anything? */
+            group = &state->groups[node->values[0] - 1];
+            if (group->current_capture < 0)
+                goto backtrack;
+
+            span = &group->captures[group->current_capture];
+
+            if (string_pos < 0)
+                string_pos = span->end;
+
+            /* Try comparing. */
+            while (string_pos > span->start) {
+                if (state->text_pos <= 0 && state->partial_side ==
+                  RE_PARTIAL_LEFT)
+                    return RE_ERROR_PARTIAL;
+
+                if (state->text_pos > state->slice_start &&
+                  same_char(char_at(state->text, state->text_pos - 1),
+                  char_at(state->text, string_pos - 1))) {
+                    --string_pos;
+                    --state->text_pos;
+                } else if (node->status & RE_STATUS_FUZZY) {
+                    BOOL matched;
+
+                    status = fuzzy_match_string(safe_state, search,
+                      &state->text_pos, node, &string_pos, &matched, -1);
+                    if (status < 0)
+                        return RE_ERROR_PARTIAL;
+
+                    if (!matched) {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                } else {
+                    string_pos = -1;
+                    goto backtrack;
+                }
+            }
+
+            string_pos = -1;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_SEARCH_ANCHOR: /* At the start of the search. */
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[0]))
+
+            if (state->text_pos == state->search_anchor)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_SET_DIFF: /* Character set. */
+        case RE_OP_SET_INTER:
+        case RE_OP_SET_SYM_DIFF:
+        case RE_OP_SET_UNION:
+            TRACE(("%s %d\n", re_op_text[node->op], node->match))
+
+            if (state->text_pos >= state->text_length && state->partial_side ==
+              RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos < state->slice_end && matches_SET(encoding,
+              locale_info, node, char_at(state->text, state->text_pos)) ==
+              node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_SET_DIFF_IGN: /* Character set, ignoring case. */
+        case RE_OP_SET_INTER_IGN:
+        case RE_OP_SET_SYM_DIFF_IGN:
+        case RE_OP_SET_UNION_IGN:
+            TRACE(("%s %d\n", re_op_text[node->op], node->match))
+
+            if (state->text_pos >= state->text_length && state->partial_side ==
+              RE_PARTIAL_RIGHT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos < state->slice_end && matches_SET_IGN(encoding,
+              locale_info, node, char_at(state->text, state->text_pos)) ==
+              node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_SET_DIFF_IGN_REV: /* Character set, ignoring case. */
+        case RE_OP_SET_INTER_IGN_REV:
+        case RE_OP_SET_SYM_DIFF_IGN_REV:
+        case RE_OP_SET_UNION_IGN_REV:
+            TRACE(("%s %d\n", re_op_text[node->op], node->match))
+
+            if (state->text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos > state->slice_start &&
+              matches_SET_IGN(encoding, locale_info, node, char_at(state->text,
+              state->text_pos - 1)) == node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_SET_DIFF_REV: /* Character set. */
+        case RE_OP_SET_INTER_REV:
+        case RE_OP_SET_SYM_DIFF_REV:
+        case RE_OP_SET_UNION_REV:
+            TRACE(("%s %d\n", re_op_text[node->op], node->match))
+
+            if (state->text_pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                return RE_ERROR_PARTIAL;
+
+            if (state->text_pos > state->slice_start && matches_SET(encoding,
+              locale_info, node, char_at(state->text, state->text_pos - 1)) ==
+              node->match) {
+                state->text_pos += node->step;
+                node = node->next_1.node;
+            } else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, -1);
+                if (status < 0)
+                    return RE_ERROR_PARTIAL;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_SKIP: /* Skip the part of the text already matched. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            if (node->status & RE_STATUS_REVERSE)
+                state->slice_end = state->text_pos;
+            else
+                state->slice_start = state->text_pos;
+
+            prune_backtracking(state);
+            node = node->next_1.node;
+            break;
+        case RE_OP_START_GROUP: /* Start of a capture group. */
+        {
+            RE_CODE private_index;
+            RE_CODE public_index;
+            RE_GroupData* group;
+            RE_BacktrackData* bt_data;
+            TRACE(("%s %d\n", re_op_text[node->op], node->values[1]))
+
+            /* Capture group indexes are 1-based (excluding group 0, which is
+             * the entire matched string).
+             */
+            private_index = node->values[0];
+            public_index = node->values[1];
+            group = &state->groups[private_index - 1];
+
+            if (!add_backtrack(safe_state, RE_OP_START_GROUP))
+                return RE_ERROR_BACKTRACKING;
+            bt_data = state->backtrack;
+            bt_data->group.private_index = private_index;
+            bt_data->group.public_index = public_index;
+            bt_data->group.text_pos = group->span.start;
+            bt_data->group.capture = (BOOL)node->values[2];
+            bt_data->group.current_capture = group->current_capture;
+
+            if (pattern->group_info[private_index - 1].referenced &&
+              group->span.start != state->text_pos)
+                ++state->capture_change;
+            group->span.start = state->text_pos;
+
+            /* Save the capture? */
+            if (node->values[2]) {
+                group->current_capture = (Py_ssize_t)group->capture_count;
+                if (!save_capture(safe_state, private_index, public_index))
+                    return RE_ERROR_MEMORY;
+            }
+
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_START_OF_LINE: /* At the start of a line. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_START_OF_LINE(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_START_OF_LINE_U: /* At the start of a line. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_START_OF_LINE_U(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_START_OF_STRING: /* At the start of the string. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_START_OF_STRING(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_START_OF_WORD: /* At the start of a word. */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = try_match_START_OF_WORD(state, node, state->text_pos);
+            if (status < 0)
+                return status;
+
+            if (status == RE_ERROR_SUCCESS)
+                node = node->next_1.node;
+            else if (node->status & RE_STATUS_FUZZY) {
+                status = fuzzy_match_item(safe_state, search, &state->text_pos,
+                  &node, 0);
+                if (status < 0)
+                    return status;
+
+                if (!node)
+                    goto backtrack;
+            } else
+                goto backtrack;
+            break;
+        case RE_OP_STRING: /* A string. */
+        {
+            Py_ssize_t length;
+            RE_CODE* values;
+            TRACE(("%s %d\n", re_op_text[node->op], node->value_count))
+
+            if ((node->status & RE_STATUS_REQUIRED) && state->text_pos ==
+              state->req_pos && string_pos < 0)
+                state->text_pos = state->req_end;
+            else {
+                length = (Py_ssize_t)node->value_count;
+
+                if (string_pos < 0)
+                    string_pos = 0;
+
+                values = node->values;
+
+                /* Try comparing. */
+                while (string_pos < length) {
+                    if (state->text_pos >= state->text_length &&
+                      state->partial_side == RE_PARTIAL_RIGHT)
+                        return RE_ERROR_PARTIAL;
+
+                    if (state->text_pos < state->slice_end &&
+                      same_char(char_at(state->text, state->text_pos),
+                      values[string_pos])) {
+                        ++string_pos;
+                        ++state->text_pos;
+                    } else if (node->status & RE_STATUS_FUZZY) {
+                        BOOL matched;
+
+                        status = fuzzy_match_string(safe_state, search,
+                          &state->text_pos, node, &string_pos, &matched, 1);
+                        if (status < 0)
+                            return RE_ERROR_PARTIAL;
+
+                        if (!matched) {
+                            string_pos = -1;
+                            goto backtrack;
+                        }
+                    } else {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                }
+            }
+
+            string_pos = -1;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_FLD: /* A string, ignoring case. */
+        {
+            Py_ssize_t length;
+            int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch,
+              Py_UCS4* folded);
+            RE_CODE* values;
+            int folded_len;
+            Py_UCS4 folded[RE_MAX_FOLDED];
+            TRACE(("%s %d\n", re_op_text[node->op], node->value_count))
+
+            if ((node->status & RE_STATUS_REQUIRED) && state->text_pos ==
+              state->req_pos && string_pos < 0)
+                state->text_pos = state->req_end;
+            else {
+                length = (Py_ssize_t)node->value_count;
+
+                full_case_fold = encoding->full_case_fold;
+
+                if (string_pos < 0) {
+                    string_pos = 0;
+                    folded_pos = 0;
+                    folded_len = 0;
+                } else {
+                    folded_len = full_case_fold(locale_info,
+                      char_at(state->text, state->text_pos), folded);
+                    if (folded_pos >= folded_len) {
+                        if (state->text_pos >= state->slice_end)
+                            goto backtrack;
+
+                        ++state->text_pos;
+                        folded_pos = 0;
+                        folded_len = 0;
+                    }
+                }
+
+                values = node->values;
+
+                /* Try comparing. */
+                while (string_pos < length) {
+                    if (folded_pos >= folded_len) {
+                        if (state->text_pos >= state->text_length &&
+                          state->partial_side == RE_PARTIAL_RIGHT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (state->text_pos < state->slice_end)
+                            folded_len = full_case_fold(locale_info,
+                              char_at(state->text, state->text_pos), folded);
+                        else
+                            folded_len = 0;
+
+                        folded_pos = 0;
+                    }
+
+                    if (folded_pos < folded_len && same_char_ign(encoding,
+                      locale_info, folded[folded_pos], values[string_pos])) {
+                        ++string_pos;
+                        ++folded_pos;
+
+                        if (folded_pos >= folded_len)
+                            ++state->text_pos;
+                    } else if (node->status & RE_STATUS_FUZZY) {
+                        BOOL matched;
+
+                        status = fuzzy_match_string_fld(safe_state, search,
+                          &state->text_pos, node, &string_pos, &folded_pos,
+                          folded_len, &matched, 1);
+                        if (status < 0)
+                            return RE_ERROR_PARTIAL;
+
+                        if (!matched) {
+                            string_pos = -1;
+                            goto backtrack;
+                        }
+
+                        if (folded_pos >= folded_len && folded_len > 0)
+                            ++state->text_pos;
+                    } else {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                }
+
+                if (node->status & RE_STATUS_FUZZY) {
+                    while (folded_pos < folded_len) {
+                        BOOL matched;
+
+                        if (!fuzzy_match_string_fld(safe_state, search,
+                          &state->text_pos, node, &string_pos, &folded_pos,
+                          folded_len, &matched, 1))
+                            return RE_ERROR_BACKTRACKING;
+
+                        if (!matched) {
+                            string_pos = -1;
+                            goto backtrack;
+                        }
+
+                        if (folded_pos >= folded_len && folded_len > 0)
+                            ++state->text_pos;
+                    }
+                }
+
+                string_pos = -1;
+
+                if (folded_pos < folded_len)
+                    goto backtrack;
+            }
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_FLD_REV: /* A string, ignoring case. */
+        {
+            Py_ssize_t length;
+            int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch,
+              Py_UCS4* folded);
+            RE_CODE* values;
+            int folded_len;
+            Py_UCS4 folded[RE_MAX_FOLDED];
+            TRACE(("%s %d\n", re_op_text[node->op], node->value_count))
+
+            if ((node->status & RE_STATUS_REQUIRED) && state->text_pos ==
+              state->req_pos && string_pos < 0)
+                state->text_pos = state->req_end;
+            else {
+                length = (Py_ssize_t)node->value_count;
+
+                full_case_fold = encoding->full_case_fold;
+
+                if (string_pos < 0) {
+                    string_pos = length;
+                    folded_pos = 0;
+                    folded_len = 0;
+                } else {
+                    folded_len = full_case_fold(locale_info,
+                      char_at(state->text, state->text_pos - 1), folded);
+                    if (folded_pos <= 0) {
+                        if (state->text_pos <= state->slice_start)
+                            goto backtrack;
+
+                        --state->text_pos;
+                        folded_pos = 0;
+                        folded_len = 0;
+                    }
+                }
+
+                values = node->values;
+
+                /* Try comparing. */
+                while (string_pos > 0) {
+                    if (folded_pos <= 0) {
+                        if (state->text_pos <= 0 && state->partial_side ==
+                          RE_PARTIAL_LEFT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (state->text_pos > state->slice_start)
+                            folded_len = full_case_fold(locale_info,
+                              char_at(state->text, state->text_pos - 1),
+                              folded);
+                        else
+                            folded_len = 0;
+
+                        folded_pos = folded_len;
+                    }
+
+                    if (folded_pos > 0 && same_char_ign(encoding, locale_info,
+                      folded[folded_pos - 1], values[string_pos - 1])) {
+                        --string_pos;
+                        --folded_pos;
+
+                        if (folded_pos <= 0)
+                            --state->text_pos;
+                    } else if (node->status & RE_STATUS_FUZZY) {
+                        BOOL matched;
+
+                        status = fuzzy_match_string_fld(safe_state, search,
+                          &state->text_pos, node, &string_pos, &folded_pos,
+                          folded_len, &matched, -1);
+                        if (status < 0)
+                            return RE_ERROR_PARTIAL;
+
+                        if (!matched) {
+                            string_pos = -1;
+                            goto backtrack;
+                        }
+
+                        if (folded_pos <= 0 && folded_len > 0)
+                            --state->text_pos;
+                    } else {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                }
+
+                if (node->status & RE_STATUS_FUZZY) {
+                    while (folded_pos > 0) {
+                        BOOL matched;
+
+                        if (!fuzzy_match_string_fld(safe_state, search,
+                          &state->text_pos, node, &string_pos, &folded_pos,
+                          folded_len, &matched, -1))
+                            return RE_ERROR_BACKTRACKING;
+
+                        if (!matched) {
+                            string_pos = -1;
+                            goto backtrack;
+                        }
+
+                        if (folded_pos <= 0 && folded_len > 0)
+                            --state->text_pos;
+                    }
+                }
+
+                string_pos = -1;
+
+                if (folded_pos > 0)
+                    goto backtrack;
+            }
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_IGN: /* A string, ignoring case. */
+        {
+            Py_ssize_t length;
+            RE_CODE* values;
+            TRACE(("%s %d\n", re_op_text[node->op], node->value_count))
+
+            if ((node->status & RE_STATUS_REQUIRED) && state->text_pos ==
+              state->req_pos && string_pos < 0)
+                state->text_pos = state->req_end;
+            else {
+                length = (Py_ssize_t)node->value_count;
+
+                if (string_pos < 0)
+                    string_pos = 0;
+
+                values = node->values;
+
+                /* Try comparing. */
+                while (string_pos < length) {
+                    if (state->text_pos >= state->text_length &&
+                      state->partial_side == RE_PARTIAL_RIGHT)
+                        return RE_ERROR_PARTIAL;
+
+                    if (state->text_pos < state->slice_end &&
+                      same_char_ign(encoding, locale_info, char_at(state->text,
+                      state->text_pos), values[string_pos])) {
+                        ++string_pos;
+                        ++state->text_pos;
+                    } else if (node->status & RE_STATUS_FUZZY) {
+                        BOOL matched;
+
+                        status = fuzzy_match_string(safe_state, search,
+                          &state->text_pos, node, &string_pos, &matched, 1);
+                        if (status < 0)
+                            return RE_ERROR_PARTIAL;
+
+                        if (!matched) {
+                            string_pos = -1;
+                            goto backtrack;
+                        }
+                    } else {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                }
+            }
+
+            string_pos = -1;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_IGN_REV: /* A string, ignoring case. */
+        {
+            Py_ssize_t length;
+            RE_CODE* values;
+            TRACE(("%s %d\n", re_op_text[node->op], node->value_count))
+
+            if ((node->status & RE_STATUS_REQUIRED) && state->text_pos ==
+              state->req_pos && string_pos < 0)
+                state->text_pos = state->req_end;
+            else {
+                length = (Py_ssize_t)node->value_count;
+
+                if (string_pos < 0)
+                    string_pos = length;
+
+                values = node->values;
+
+                /* Try comparing. */
+                while (string_pos > 0) {
+                    if (state->text_pos <= 0 && state->partial_side ==
+                      RE_PARTIAL_LEFT)
+                        return RE_ERROR_PARTIAL;
+
+                    if (state->text_pos > state->slice_start &&
+                      same_char_ign(encoding, locale_info, char_at(state->text,
+                      state->text_pos - 1), values[string_pos - 1])) {
+                        --string_pos;
+                        --state->text_pos;
+                    } else if (node->status & RE_STATUS_FUZZY) {
+                        BOOL matched;
+
+                        status = fuzzy_match_string(safe_state, search,
+                          &state->text_pos, node, &string_pos, &matched, -1);
+                        if (status < 0)
+                            return RE_ERROR_PARTIAL;
+
+                        if (!matched) {
+                            string_pos = -1;
+                            goto backtrack;
+                        }
+                    } else {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                }
+            }
+
+            string_pos = -1;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_REV: /* A string. */
+        {
+            Py_ssize_t length;
+            RE_CODE* values;
+            TRACE(("%s %d\n", re_op_text[node->op], node->value_count))
+
+            if ((node->status & RE_STATUS_REQUIRED) && state->text_pos ==
+              state->req_pos && string_pos < 0)
+                state->text_pos = state->req_end;
+            else {
+                length = (Py_ssize_t)node->value_count;
+
+                if (string_pos < 0)
+                    string_pos = length;
+
+                values = node->values;
+
+                /* Try comparing. */
+                while (string_pos > 0) {
+                    if (state->text_pos <= 0 && state->partial_side ==
+                      RE_PARTIAL_LEFT)
+                        return RE_ERROR_PARTIAL;
+
+                    if (state->text_pos > state->slice_start &&
+                      same_char(char_at(state->text, state->text_pos - 1),
+                      values[string_pos - 1])) {
+                        --string_pos;
+                        --state->text_pos;
+                    } else if (node->status & RE_STATUS_FUZZY) {
+                        BOOL matched;
+
+                        status = fuzzy_match_string(safe_state, search,
+                          &state->text_pos, node, &string_pos, &matched, -1);
+                        if (status < 0)
+                            return RE_ERROR_PARTIAL;
+
+                        if (!matched) {
+                            string_pos = -1;
+                            goto backtrack;
+                        }
+                    } else {
+                        string_pos = -1;
+                        goto backtrack;
+                    }
+                }
+            }
+
+            string_pos = -1;
+
+            /* Successful match. */
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_SET: /* Member of a string set. */
+        {
+            int status;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = string_set_match_fwdrev(safe_state, node, FALSE);
+            if (status < 0)
+                return status;
+            if (status == 0)
+                goto backtrack;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_SET_FLD: /* Member of a string set, ignoring case. */
+        {
+            int status;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = string_set_match_fld_fwdrev(safe_state, node, FALSE);
+            if (status < 0)
+                return status;
+            if (status == 0)
+                goto backtrack;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_SET_FLD_REV: /* Member of a string set, ignoring case. */
+        {
+            int status;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = string_set_match_fld_fwdrev(safe_state, node, TRUE);
+            if (status < 0)
+                return status;
+            if (status == 0)
+                goto backtrack;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_SET_IGN: /* Member of a string set, ignoring case. */
+        {
+            int status;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = string_set_match_ign_fwdrev(safe_state, node, FALSE);
+            if (status < 0)
+                return status;
+            if (status == 0)
+                goto backtrack;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_SET_IGN_REV: /* Member of a string set, ignoring case. */
+        {
+            int status;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = string_set_match_ign_fwdrev(safe_state, node, TRUE);
+            if (status < 0)
+                return status;
+            if (status == 0)
+                goto backtrack;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_STRING_SET_REV: /* Member of a string set. */
+        {
+            int status;
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            status = string_set_match_fwdrev(safe_state, node, TRUE);
+            if (status < 0)
+                return status;
+            if (status == 0)
+                goto backtrack;
+            node = node->next_1.node;
+            break;
+        }
+        case RE_OP_SUCCESS: /* Success. */
+            /* Must the match advance past its start? */
+            TRACE(("%s\n", re_op_text[node->op]))
+
+            if (state->text_pos == state->search_anchor && state->must_advance)
+                goto backtrack;
+
+            if (state->match_all) {
+                /* We want to match all of the slice. */
+                if (state->reverse) {
+                    if (state->text_pos != state->slice_start)
+                        goto backtrack;
+                } else {
+                    if (state->text_pos != state->slice_end)
+                        goto backtrack;
+                }
+            }
+
+            if (state->pattern->flags & RE_FLAG_POSIX) {
+                /* If we're looking for a POSIX match, check whether this one
+                 * is better and then keep looking.
+                 */
+                if (!check_posix_match(safe_state))
+                    return RE_ERROR_MEMORY;
+
+                goto backtrack;
+            }
+
+            return RE_ERROR_SUCCESS;
+        default: /* Illegal opcode! */
+            TRACE(("UNKNOWN OP %d\n", node->op))
+            return RE_ERROR_ILLEGAL;
+        }
+    }
+
+backtrack:
+    for (;;) {
+        RE_BacktrackData* bt_data;
+        TRACE(("BACKTRACK "))
+
+        /* Should we abort the matching? */
+        ++state->iterations;
+
+        if (state->iterations == 0 && safe_check_signals(safe_state))
+            return RE_ERROR_INTERRUPTED;
+
+        bt_data = last_backtrack(state);
+
+        switch (bt_data->op) {
+        case RE_OP_ANY: /* Any character except a newline. */
+        case RE_OP_ANY_ALL: /* Any character at all. */
+        case RE_OP_ANY_ALL_REV: /* Any character at all, backwards. */
+        case RE_OP_ANY_REV: /* Any character except a newline, backwards. */
+        case RE_OP_ANY_U: /* Any character except a line separator. */
+        case RE_OP_ANY_U_REV: /* Any character except a line separator, backwards. */
+        case RE_OP_CHARACTER: /* A character. */
+        case RE_OP_CHARACTER_IGN: /* A character, ignoring case. */
+        case RE_OP_CHARACTER_IGN_REV: /* A character, ignoring case, backwards. */
+        case RE_OP_CHARACTER_REV: /* A character, backwards. */
+        case RE_OP_PROPERTY: /* A property. */
+        case RE_OP_PROPERTY_IGN: /* A property, ignoring case. */
+        case RE_OP_PROPERTY_IGN_REV: /* A property, ignoring case, backwards. */
+        case RE_OP_PROPERTY_REV: /* A property, backwards. */
+        case RE_OP_RANGE: /* A range. */
+        case RE_OP_RANGE_IGN: /* A range, ignoring case. */
+        case RE_OP_RANGE_IGN_REV: /* A range, ignoring case, backwards. */
+        case RE_OP_RANGE_REV: /* A range, backwards. */
+        case RE_OP_SET_DIFF: /* Set difference. */
+        case RE_OP_SET_DIFF_IGN: /* Set difference, ignoring case. */
+        case RE_OP_SET_DIFF_IGN_REV: /* Set difference, ignoring case, backwards. */
+        case RE_OP_SET_DIFF_REV: /* Set difference, backwards. */
+        case RE_OP_SET_INTER: /* Set intersection. */
+        case RE_OP_SET_INTER_IGN: /* Set intersection, ignoring case. */
+        case RE_OP_SET_INTER_IGN_REV: /* Set intersection, ignoring case, backwards. */
+        case RE_OP_SET_INTER_REV: /* Set intersection, backwards. */
+        case RE_OP_SET_SYM_DIFF: /* Set symmetric difference. */
+        case RE_OP_SET_SYM_DIFF_IGN: /* Set symmetric difference, ignoring case. */
+        case RE_OP_SET_SYM_DIFF_IGN_REV: /* Set symmetric difference, ignoring case, backwards. */
+        case RE_OP_SET_SYM_DIFF_REV: /* Set symmetric difference, backwards. */
+        case RE_OP_SET_UNION: /* Set union. */
+        case RE_OP_SET_UNION_IGN: /* Set union, ignoring case. */
+        case RE_OP_SET_UNION_IGN_REV: /* Set union, ignoring case, backwards. */
+        case RE_OP_SET_UNION_REV: /* Set union, backwards. */
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            status = retry_fuzzy_match_item(safe_state, search,
+              &state->text_pos, &node, TRUE);
+            if (status < 0)
+                return RE_ERROR_PARTIAL;
+
+            if (node)
+                goto advance;
+            break;
+        case RE_OP_ATOMIC: /* Start of an atomic group. */
+        {
+            RE_AtomicData* atomic;
+            /* backtrack to the start of an atomic group. */
+            atomic = pop_atomic(safe_state);
+
+            if (atomic->has_repeats)
+                pop_repeats(state);
+
+            if (atomic->has_groups)
+                pop_groups(state);
+
+            state->too_few_errors = bt_data->atomic.too_few_errors;
+            state->capture_change = bt_data->atomic.capture_change;
+
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_BODY_END:
+        {
+            RE_RepeatData* rp_data;
+            TRACE(("%s %d\n", re_op_text[bt_data->op], bt_data->repeat.index))
+
+            /* We're backtracking into the body. */
+            rp_data = &state->repeats[bt_data->repeat.index];
+
+            /* Restore the repeat info. */
+            rp_data->count = bt_data->repeat.count;
+            rp_data->start = bt_data->repeat.start;
+            rp_data->capture_change = bt_data->repeat.capture_change;
+
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_BODY_START:
+        {
+            TRACE(("%s %d\n", re_op_text[bt_data->op], bt_data->repeat.index))
+
+            /* The body may have failed to match at this position. */
+            if (!guard_repeat(safe_state, bt_data->repeat.index,
+              bt_data->repeat.text_pos, RE_STATUS_BODY, TRUE))
+                return RE_ERROR_MEMORY;
+
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_BOUNDARY: /* On a word boundary. */
+        case RE_OP_DEFAULT_BOUNDARY: /* On a default word boundary. */
+        case RE_OP_DEFAULT_END_OF_WORD: /* At a default end of a word. */
+        case RE_OP_DEFAULT_START_OF_WORD: /* At a default start of a word. */
+        case RE_OP_END_OF_LINE: /* At the end of a line. */
+        case RE_OP_END_OF_LINE_U: /* At the end of a line. */
+        case RE_OP_END_OF_STRING: /* At the end of the string. */
+        case RE_OP_END_OF_STRING_LINE: /* At end of string or final newline. */
+        case RE_OP_END_OF_STRING_LINE_U: /* At end of string or final newline. */
+        case RE_OP_END_OF_WORD: /* At end of a word. */
+        case RE_OP_GRAPHEME_BOUNDARY: /* On a grapheme boundary. */
+        case RE_OP_SEARCH_ANCHOR: /* At the start of the search. */
+        case RE_OP_START_OF_LINE: /* At the start of a line. */
+        case RE_OP_START_OF_LINE_U: /* At the start of a line. */
+        case RE_OP_START_OF_STRING: /* At the start of the string. */
+        case RE_OP_START_OF_WORD: /* At start of a word. */
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            status = retry_fuzzy_match_item(safe_state, search,
+              &state->text_pos, &node, FALSE);
+            if (status < 0)
+                return RE_ERROR_PARTIAL;
+
+            if (node)
+                goto advance;
+            break;
+        case RE_OP_BRANCH: /* 2-way branch. */
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            node = bt_data->branch.position.node;
+            state->text_pos = bt_data->branch.position.text_pos;
+            discard_backtrack(state);
+            goto advance;
+        case RE_OP_CALL_REF: /* A group call ref. */
+        case RE_OP_GROUP_CALL: /* Group call. */
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            pop_group_return(state);
+            discard_backtrack(state);
+            break;
+        case RE_OP_CONDITIONAL: /* Conditional subpattern. */
+        {
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            if (bt_data->lookaround.inside) {
+                /* Backtracked to the start of a lookaround. */
+                RE_AtomicData* conditional;
+
+                conditional = pop_atomic(safe_state);
+                state->text_pos = conditional->text_pos;
+                state->slice_end = conditional->slice_end;
+                state->slice_start = conditional->slice_start;
+                state->current_backtrack_block =
+                  conditional->current_backtrack_block;
+                state->current_backtrack_block->count =
+                  conditional->backtrack_count;
+
+                /* Restore the groups and repeats and certain flags. */
+                if (conditional->has_repeats)
+                    pop_repeats(state);
+
+                if (conditional->has_groups)
+                    pop_groups(state);
+
+                state->too_few_errors = bt_data->lookaround.too_few_errors;
+                state->capture_change = bt_data->lookaround.capture_change;
+
+                if (bt_data->lookaround.node->match) {
+                    /* It's a positive lookaround that's failed.
+                     *
+                     * Go to the 'false' branch.
+                     */
+                    node = bt_data->lookaround.node->nonstring.next_2.node;
+                } else {
+                    /* It's a negative lookaround that's failed.
+                     *
+                     * Go to the 'true' branch.
+                     */
+                    node = bt_data->lookaround.node->nonstring.next_2.node;
+                }
+
+                discard_backtrack(state);
+
+                goto advance;
+            } else {
+                /* Backtracked to a lookaround. If it's a positive lookaround
+                 * that succeeded, we need to restore the groups; if it's a
+                 * negative lookaround that failed, it would have completely
+                 * backtracked inside and already restored the groups. We also
+                 * need to restore certain flags.
+                 */
+                if (bt_data->lookaround.node->match)
+                    pop_groups(state);
+
+                state->too_few_errors = bt_data->lookaround.too_few_errors;
+                state->capture_change = bt_data->lookaround.capture_change;
+
+                discard_backtrack(state);
+            }
+            break;
+        }
+        case RE_OP_END_FUZZY: /* End of fuzzy matching. */
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            state->total_fuzzy_counts[RE_FUZZY_SUB] -=
+              state->fuzzy_info.counts[RE_FUZZY_SUB];
+            state->total_fuzzy_counts[RE_FUZZY_INS] -=
+              state->fuzzy_info.counts[RE_FUZZY_INS];
+            state->total_fuzzy_counts[RE_FUZZY_DEL] -=
+              state->fuzzy_info.counts[RE_FUZZY_DEL];
+
+            /* We need to retry the fuzzy match. */
+            status = retry_fuzzy_insert(safe_state, &state->text_pos, &node);
+            if (status < 0)
+                return RE_ERROR_PARTIAL;
+
+            /* If there were too few errors, in the fuzzy section, try again.
+             */
+            if (state->too_few_errors) {
+                state->too_few_errors = FALSE;
+                goto backtrack;
+            }
+
+            if (node) {
+                state->total_fuzzy_counts[RE_FUZZY_SUB] +=
+                  state->fuzzy_info.counts[RE_FUZZY_SUB];
+                state->total_fuzzy_counts[RE_FUZZY_INS] +=
+                  state->fuzzy_info.counts[RE_FUZZY_INS];
+                state->total_fuzzy_counts[RE_FUZZY_DEL] +=
+                  state->fuzzy_info.counts[RE_FUZZY_DEL];
+
+                node = node->next_1.node;
+                goto advance;
+            }
+            break;
+        case RE_OP_END_GROUP: /* End of a capture group. */
+        {
+            RE_CODE private_index;
+            RE_GroupData* group;
+            TRACE(("%s %d\n", re_op_text[bt_data->op],
+              bt_data->group.public_index))
+
+            private_index = bt_data->group.private_index;
+            group = &state->groups[private_index - 1];
+
+            /* Unsave the capture? */
+            if (bt_data->group.capture)
+                unsave_capture(state, bt_data->group.private_index,
+                  bt_data->group.public_index);
+
+            if (pattern->group_info[private_index - 1].referenced &&
+              group->span.end != bt_data->group.text_pos)
+                --state->capture_change;
+            group->span.end = bt_data->group.text_pos;
+            group->current_capture = bt_data->group.current_capture;
+
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_FAILURE:
+        {
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            /* Have we been looking for a POSIX match? */
+            if (state->found_match) {
+                restore_best_match(safe_state);
+                return RE_OP_SUCCESS;
+            }
+
+            /* Do we have to advance? */
+            if (!search)
+                return RE_ERROR_FAILURE;
+
+            /* Can we advance? */
+            state->text_pos = state->match_pos;
+
+            if (state->reverse) {
+                if (state->text_pos <= state->slice_start)
+                    return RE_ERROR_FAILURE;
+            } else {
+                if (state->text_pos >= state->slice_end)
+                    return RE_ERROR_FAILURE;
+            }
+
+            /* Skip over any repeated leading characters. */
+            switch (start_node->op) {
+            case RE_OP_GREEDY_REPEAT_ONE:
+            case RE_OP_LAZY_REPEAT_ONE:
+            {
+                size_t count;
+                BOOL is_partial;
+
+                /* How many characters did the repeat actually match? */
+                count = count_one(state, start_node->nonstring.next_2.node,
+                  state->text_pos, start_node->values[2], &is_partial);
+
+                /* If it's fewer than the maximum then skip over those
+                 * characters.
+                 */
+                if (count < start_node->values[2])
+                    state->text_pos += (Py_ssize_t)count * pattern_step;
+                break;
+            }
+            }
+
+            /* Advance and try to match again. e also need to check whether we
+             * need to skip.
+             */
+            if (state->reverse) {
+                if (state->text_pos > state->slice_end)
+                    state->text_pos = state->slice_end;
+                else
+                    --state->text_pos;
+            } else {
+                if (state->text_pos < state->slice_start)
+                    state->text_pos = state->slice_start;
+                else
+                    ++state->text_pos;
+            }
+
+            /* Clear the groups. */
+            clear_groups(state);
+
+            goto start_match;
+        }
+        case RE_OP_FUZZY: /* Fuzzy matching. */
+        {
+            RE_FuzzyInfo* fuzzy_info;
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            /* Restore the previous fuzzy info. */
+            fuzzy_info = &state->fuzzy_info;
+            memmove(fuzzy_info, &bt_data->fuzzy.fuzzy_info,
+               sizeof(RE_FuzzyInfo));
+
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_GREEDY_REPEAT: /* Greedy repeat. */
+        case RE_OP_LAZY_REPEAT: /* Lazy repeat. */
+        {
+            RE_RepeatData* rp_data;
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            /* The repeat failed to match. */
+            rp_data = &state->repeats[bt_data->repeat.index];
+
+            /* The body may have failed to match at this position. */
+            if (!guard_repeat(safe_state, bt_data->repeat.index,
+              bt_data->repeat.text_pos, RE_STATUS_BODY, TRUE))
+                return RE_ERROR_MEMORY;
+
+            /* Restore the previous repeat. */
+            rp_data->count = bt_data->repeat.count;
+            rp_data->start = bt_data->repeat.start;
+            rp_data->capture_change = bt_data->repeat.capture_change;
+
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_GREEDY_REPEAT_ONE: /* Greedy repeat for one character. */
+        {
+            RE_RepeatData* rp_data;
+            size_t count;
+            Py_ssize_t step;
+            Py_ssize_t pos;
+            Py_ssize_t limit;
+            RE_Node* test;
+            BOOL match;
+            BOOL m;
+            size_t index;
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            node = bt_data->repeat.position.node;
+
+            rp_data = &state->repeats[bt_data->repeat.index];
+
+            /* Unmatch one character at a time until the tail could match or we
+             * have reached the minimum.
+             */
+            state->text_pos = rp_data->start;
+
+            count = rp_data->count;
+            step = node->step;
+            pos = state->text_pos + (Py_ssize_t)count * step;
+            limit = state->text_pos + (Py_ssize_t)node->values[1] * step;
+
+            /* The tail failed to match at this position. */
+            if (!guard_repeat(safe_state, bt_data->repeat.index, pos,
+              RE_STATUS_TAIL, TRUE))
+                return RE_ERROR_MEMORY;
+
+            /* A (*SKIP) might have change the size of the slice. */
+            if (step > 0) {
+                if (limit < state->slice_start)
+                    limit = state->slice_start;
+            } else {
+                if (limit > state->slice_end)
+                    limit = state->slice_end;
+            }
+
+            if (pos == limit) {
+                /* We've backtracked the repeat as far as we can. */
+                rp_data->start = bt_data->repeat.text_pos;
+                rp_data->count = bt_data->repeat.count;
+                discard_backtrack(state);
+                break;
+            }
+
+            test = node->next_1.test;
+
+            m = test->match;
+            index = node->values[0];
+
+            match = FALSE;
+
+            if (test->status & RE_STATUS_FUZZY) {
+                for (;;) {
+                    int status;
+                    RE_Position next_position;
+
+                    pos -= step;
+
+                    status = try_match(state, &node->next_1, pos,
+                      &next_position);
+                    if (status < 0)
+                        return status;
+
+                    if (status != RE_ERROR_FAILURE &&
+                      !is_repeat_guarded(safe_state, index, pos,
+                      RE_STATUS_TAIL)) {
+                        match = TRUE;
+                        break;
+                    }
+
+                    if (pos == limit)
+                        break;
+                }
+            } else {
+                /* A repeated single-character match is often followed by a
+                 * literal, so checking specially for it can be a good
+                 * optimisation when working with long strings.
+                 */
+                switch (test->op) {
+                case RE_OP_CHARACTER:
+                {
+                    Py_UCS4 ch;
+
+                    ch = test->values[0];
+
+                    for (;;) {
+                        --pos;
+
+                        if (same_char(char_at(state->text, pos), ch) == m &&
+                          !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        if (pos == limit)
+                            break;
+
+                    }
+                    break;
+                }
+                case RE_OP_CHARACTER_IGN:
+                {
+                    Py_UCS4 ch;
+
+                    ch = test->values[0];
+
+                    for (;;) {
+                        --pos;
+
+                        if (same_char_ign(encoding, locale_info,
+                          char_at(state->text, pos), ch) == m &&
+                          !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        if (pos == limit)
+                            break;
+
+                    }
+                    break;
+                }
+                case RE_OP_CHARACTER_IGN_REV:
+                {
+                    Py_UCS4 ch;
+
+                    ch = test->values[0];
+
+                    for (;;) {
+                        ++pos;
+
+                        if (same_char_ign(encoding, locale_info,
+                          char_at(state->text, pos - 1), ch) == m &&
+                          !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        if (pos == limit)
+                            break;
+
+                    }
+                    break;
+                }
+                case RE_OP_CHARACTER_REV:
+                {
+                    Py_UCS4 ch;
+
+                    ch = test->values[0];
+
+                    for (;;) {
+                        ++pos;
+
+                        if (same_char(char_at(state->text, pos - 1), ch) == m
+                          && !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        if (pos == limit)
+                            break;
+
+                    }
+                    break;
+                }
+                case RE_OP_STRING:
+                {
+                    Py_ssize_t length;
+
+                    length = (Py_ssize_t)test->value_count;
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    pos = min_ssize_t(pos - 1, state->slice_end - length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        BOOL is_partial;
+
+                        if (pos < limit)
+                            break;
+
+                        found = string_search_rev(safe_state, test, pos +
+                          length, limit, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        pos = found - length;
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        --pos;
+                    }
+                    break;
+                }
+                case RE_OP_STRING_FLD:
+                {
+                    int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4
+                      ch, Py_UCS4* folded);
+                    Py_ssize_t folded_length;
+                    size_t i;
+                    Py_UCS4 folded[RE_MAX_FOLDED];
+
+                    full_case_fold = encoding->full_case_fold;
+
+                    folded_length = 0;
+                    for (i = 0; i < test->value_count; i++)
+                        folded_length += full_case_fold(locale_info,
+                          test->values[i], folded);
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    pos = min_ssize_t(pos - 1, state->slice_end -
+                      folded_length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        Py_ssize_t new_pos;
+                        BOOL is_partial;
+
+                        if (pos < limit)
+                            break;
+
+                        found = string_search_fld_rev(safe_state, test, pos +
+                          folded_length, limit, &new_pos, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        pos = found - folded_length;
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        --pos;
+                    }
+                    break;
+                }
+                case RE_OP_STRING_FLD_REV:
+                {
+                    int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4
+                      ch, Py_UCS4* folded);
+                    Py_ssize_t folded_length;
+                    size_t i;
+                    Py_UCS4 folded[RE_MAX_FOLDED];
+
+                    full_case_fold = encoding->full_case_fold;
+
+                    folded_length = 0;
+                    for (i = 0; i < test->value_count; i++)
+                        folded_length += full_case_fold(locale_info,
+                          test->values[i], folded);
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    pos = max_ssize_t(pos + 1, state->slice_start +
+                      folded_length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        Py_ssize_t new_pos;
+                        BOOL is_partial;
+
+                        if (pos > limit)
+                            break;
+
+                        found = string_search_fld(safe_state, test, pos -
+                          folded_length, limit, &new_pos, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        pos = found + folded_length;
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        ++pos;
+                    }
+                    break;
+                }
+                case RE_OP_STRING_IGN:
+                {
+                    Py_ssize_t length;
+
+                    length = (Py_ssize_t)test->value_count;
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    pos = min_ssize_t(pos - 1, state->slice_end - length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        BOOL is_partial;
+
+                        if (pos < limit)
+                            break;
+
+                        found = string_search_ign_rev(safe_state, test, pos +
+                          length, limit, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        pos = found - length;
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        --pos;
+                    }
+                    break;
+                }
+                case RE_OP_STRING_IGN_REV:
+                {
+                    Py_ssize_t length;
+
+                    length = (Py_ssize_t)test->value_count;
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    pos = max_ssize_t(pos + 1, state->slice_start + length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        BOOL is_partial;
+
+                        if (pos > limit)
+                            break;
+
+                        found = string_search_ign(safe_state, test, pos -
+                          length, limit, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        pos = found + length;
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        ++pos;
+                    }
+                    break;
+                }
+                case RE_OP_STRING_REV:
+                {
+                    Py_ssize_t length;
+
+                    length = (Py_ssize_t)test->value_count;
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    pos = max_ssize_t(pos + 1, state->slice_start + length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        BOOL is_partial;
+
+                        if (pos > limit)
+                            break;
+
+                        found = string_search(safe_state, test, pos - length,
+                          limit, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        pos = found + length;
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        ++pos;
+                    }
+                    break;
+                }
+                default:
+                    for (;;) {
+                        RE_Position next_position;
+
+                        pos -= step;
+
+                        status = try_match(state, &node->next_1, pos,
+                          &next_position);
+                        if (status < 0)
+                            return status;
+
+                        if (status == RE_ERROR_SUCCESS &&
+                          !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        if (pos == limit)
+                            break;
+                    }
+                    break;
+                }
+            }
+
+            if (match) {
+                count = (size_t)abs_ssize_t(pos - state->text_pos);
+
+                /* The tail could match. */
+                if (count > node->values[1])
+                    /* The match is longer than the minimum, so we might need
+                     * to backtrack the repeat again to consume less.
+                     */
+                    rp_data->count = count;
+                else {
+                    /* We've reached or passed the minimum, so we won't need to
+                     * backtrack the repeat again.
+                     */
+                    rp_data->start = bt_data->repeat.text_pos;
+                    rp_data->count = bt_data->repeat.count;
+                    discard_backtrack(state);
+
+                    /* Have we passed the minimum? */
+                    if (count < node->values[1])
+                        goto backtrack;
+                }
+
+                node = node->next_1.node;
+                state->text_pos = pos;
+                goto advance;
+            } else {
+                /* Don't try this repeated match again. */
+                if (step > 0) {
+                    if (!guard_repeat_range(safe_state, bt_data->repeat.index,
+                      limit, pos, RE_STATUS_BODY, TRUE))
+                        return RE_ERROR_MEMORY;
+                } else if (step < 0) {
+                    if (!guard_repeat_range(safe_state, bt_data->repeat.index,
+                      pos, limit, RE_STATUS_BODY, TRUE))
+                        return RE_ERROR_MEMORY;
+                }
+
+                /* We've backtracked the repeat as far as we can. */
+                rp_data->start = bt_data->repeat.text_pos;
+                rp_data->count = bt_data->repeat.count;
+                discard_backtrack(state);
+            }
+            break;
+        }
+        case RE_OP_GROUP_RETURN: /* Group return. */
+        {
+            RE_Node* return_node;
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            return_node = bt_data->group_call.node;
+
+            push_group_return(safe_state, return_node);
+
+            if (return_node) {
+                /* Restore the groups. */
+                pop_groups(state);
+                state->capture_change = bt_data->group_call.capture_change;
+
+                /* Restore the repeats. */
+                pop_repeats(state);
+            }
+
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_KEEP: /* Keep. */
+        {
+            state->match_pos = bt_data->keep.match_pos;
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_LAZY_REPEAT_ONE: /* Lazy repeat for one character. */
+        {
+            RE_RepeatData* rp_data;
+            size_t count;
+            Py_ssize_t step;
+            Py_ssize_t pos;
+            Py_ssize_t available;
+            size_t max_count;
+            Py_ssize_t limit;
+            RE_Node* repeated;
+            RE_Node* test;
+            BOOL match;
+            BOOL m;
+            size_t index;
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            node = bt_data->repeat.position.node;
+
+            rp_data = &state->repeats[bt_data->repeat.index];
+
+            /* Match one character at a time until the tail could match or we
+             * have reached the maximum.
+             */
+            state->text_pos = rp_data->start;
+            count = rp_data->count;
+
+            step = node->step;
+            pos = state->text_pos + (Py_ssize_t)count * step;
+            available = step > 0 ? state->slice_end - state->text_pos :
+              state->text_pos - state->slice_start;
+            max_count = min_size_t((size_t)available, node->values[2]);
+            limit = state->text_pos + (Py_ssize_t)max_count * step;
+
+            repeated = node->nonstring.next_2.node;
+
+            test = node->next_1.test;
+
+            m = test->match;
+            index = node->values[0];
+
+            match = FALSE;
+
+            if (test->status & RE_STATUS_FUZZY) {
+                for (;;) {
+                    RE_Position next_position;
+
+                    status = match_one(state, repeated, pos);
+                    if (status < 0)
+                        return status;
+
+                    if (status == RE_ERROR_FAILURE)
+                        break;
+
+                    pos += step;
+
+                    status = try_match(state, &node->next_1, pos,
+                      &next_position);
+                    if (status < 0)
+                        return status;
+
+                    if (status == RE_ERROR_SUCCESS &&
+                      !is_repeat_guarded(safe_state, index, pos,
+                      RE_STATUS_TAIL)) {
+                        match = TRUE;
+                        break;
+                    }
+
+                    if (pos == limit)
+                        break;
+                }
+            } else {
+                /* A repeated single-character match is often followed by a
+                 * literal, so checking specially for it can be a good
+                 * optimisation when working with long strings.
+                 */
+                switch (test->op) {
+                case RE_OP_CHARACTER:
+                {
+                    Py_UCS4 ch;
+
+                    ch = test->values[0];
+
+                    /* The tail is a character. We don't want to go off the end
+                     * of the slice.
+                     */
+                    limit = min_ssize_t(limit, state->slice_end - 1);
+
+                    for (;;) {
+                        if (pos >= state->text_length && state->partial_side ==
+                          RE_PARTIAL_RIGHT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos >= limit)
+                            break;
+
+                        status = match_one(state, repeated, pos);
+                        if (status < 0)
+                            return status;
+
+                        if (status == RE_ERROR_FAILURE)
+                            break;
+
+                        ++pos;
+
+                        if (same_char(char_at(state->text, pos), ch) == m &&
+                          !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_CHARACTER_IGN:
+                {
+                    Py_UCS4 ch;
+
+                    ch = test->values[0];
+
+                    /* The tail is a character. We don't want to go off the end
+                     * of the slice.
+                     */
+                    limit = min_ssize_t(limit, state->slice_end - 1);
+
+                    for (;;) {
+                        if (pos >= state->text_length && state->partial_side ==
+                          RE_PARTIAL_RIGHT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos >= limit)
+                            break;
+
+                        status = match_one(state, repeated, pos);
+                        if (status < 0)
+                            return status;
+
+                        if (status == RE_ERROR_FAILURE)
+                            break;
+
+                        ++pos;
+
+                        if (same_char_ign(encoding, locale_info,
+                          char_at(state->text, pos), ch) == m &&
+                          !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_CHARACTER_IGN_REV:
+                {
+                    Py_UCS4 ch;
+
+                    ch = test->values[0];
+
+                    /* The tail is a character. We don't want to go off the end
+                     * of the slice.
+                     */
+                    limit = max_ssize_t(limit, state->slice_start + 1);
+
+                    for (;;) {
+                        if (pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos <= limit)
+                            break;
+
+                        status = match_one(state, repeated, pos);
+                        if (status < 0)
+                            return status;
+
+                        if (status == RE_ERROR_FAILURE)
+                            break;
+
+                        --pos;
+
+                        if (same_char_ign(encoding, locale_info,
+                          char_at(state->text, pos - 1), ch) == m &&
+                          !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_CHARACTER_REV:
+                {
+                    Py_UCS4 ch;
+
+                    ch = test->values[0];
+
+                    /* The tail is a character. We don't want to go off the end
+                     * of the slice.
+                     */
+                    limit = max_ssize_t(limit, state->slice_start + 1);
+
+                    for (;;) {
+                        if (pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos <= limit)
+                            break;
+
+                        status = match_one(state, repeated, pos);
+                        if (status < 0)
+                            return status;
+
+                        if (status == RE_ERROR_FAILURE)
+                            break;
+
+                        --pos;
+
+                        if (same_char(char_at(state->text, pos - 1), ch) == m
+                          && !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_STRING:
+                {
+                    Py_ssize_t length;
+
+                    length = (Py_ssize_t)test->value_count;
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    limit = min_ssize_t(limit, state->slice_end - length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        BOOL is_partial;
+
+                        if (pos >= state->text_length && state->partial_side ==
+                          RE_PARTIAL_RIGHT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos >= limit)
+                            break;
+
+                        /* Look for the tail string. */
+                        found = string_search(safe_state, test, pos + 1, limit
+                          + length, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        if (repeated->op == RE_OP_ANY_ALL)
+                            /* Anything can precede the tail. */
+                            pos = found;
+                        else {
+                            /* Check that what precedes the tail will match. */
+                            while (pos != found) {
+                                status = match_one(state, repeated, pos);
+                                if (status < 0)
+                                    return status;
+
+                                if (status == RE_ERROR_FAILURE)
+                                    break;
+
+                                ++pos;
+                            }
+
+                            if (pos != found)
+                                /* Something preceding the tail didn't match.
+                                 */
+                                break;
+                        }
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_STRING_FLD:
+                {
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    limit = min_ssize_t(limit, state->slice_end);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        Py_ssize_t new_pos;
+                        BOOL is_partial;
+
+                        if (pos >= state->text_length && state->partial_side ==
+                          RE_PARTIAL_RIGHT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos >= limit)
+                            break;
+
+                        /* Look for the tail string. */
+                        found = string_search_fld(safe_state, test, pos + 1,
+                          limit, &new_pos, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        if (repeated->op == RE_OP_ANY_ALL)
+                            /* Anything can precede the tail. */
+                            pos = found;
+                        else {
+                            /* Check that what precedes the tail will match. */
+                            while (pos != found) {
+                                status = match_one(state, repeated, pos);
+                                if (status < 0)
+                                    return status;
+
+                                if (status == RE_ERROR_FAILURE)
+                                    break;
+
+                                ++pos;
+                            }
+
+                            if (pos != found)
+                                /* Something preceding the tail didn't match.
+                                 */
+                                break;
+                        }
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_STRING_FLD_REV:
+                {
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    limit = max_ssize_t(limit, state->slice_start);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        Py_ssize_t new_pos;
+                        BOOL is_partial;
+
+                        if (pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos <= limit)
+                            break;
+
+                        /* Look for the tail string. */
+                        found = string_search_fld_rev(safe_state, test, pos -
+                          1, limit, &new_pos, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        if (repeated->op == RE_OP_ANY_ALL)
+                            /* Anything can precede the tail. */
+                            pos = found;
+                        else {
+                            /* Check that what precedes the tail will match. */
+                            while (pos != found) {
+                                status = match_one(state, repeated, pos);
+                                if (status < 0)
+                                    return status;
+
+                                if (status == RE_ERROR_FAILURE)
+                                    break;
+
+                                --pos;
+                            }
+
+                            if (pos != found)
+                                /* Something preceding the tail didn't match.
+                                 */
+                                break;
+                        }
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_STRING_IGN:
+                {
+                    Py_ssize_t length;
+
+                    length = (Py_ssize_t)test->value_count;
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    limit = min_ssize_t(limit, state->slice_end - length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        BOOL is_partial;
+
+                        if (pos >= state->text_length && state->partial_side ==
+                          RE_PARTIAL_RIGHT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos >= limit)
+                            break;
+
+                        /* Look for the tail string. */
+                        found = string_search_ign(safe_state, test, pos + 1,
+                          limit + length, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        if (repeated->op == RE_OP_ANY_ALL)
+                            /* Anything can precede the tail. */
+                            pos = found;
+                        else {
+                            /* Check that what precedes the tail will match. */
+                            while (pos != found) {
+                                status = match_one(state, repeated, pos);
+                                if (status < 0)
+                                    return status;
+
+                                if (status == RE_ERROR_FAILURE)
+                                    break;
+
+                                ++pos;
+                            }
+
+                            if (pos != found)
+                                /* Something preceding the tail didn't match.
+                                 */
+                                break;
+                        }
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_STRING_IGN_REV:
+                {
+                    Py_ssize_t length;
+
+                    length = (Py_ssize_t)test->value_count;
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    limit = max_ssize_t(limit, state->slice_start + length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        BOOL is_partial;
+
+                        if (pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos <= limit)
+                            break;
+
+                        /* Look for the tail string. */
+                        found = string_search_ign_rev(safe_state, test, pos -
+                          1, limit - length, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        if (repeated->op == RE_OP_ANY_ALL)
+                            /* Anything can precede the tail. */
+                            pos = found;
+                        else {
+                            /* Check that what precedes the tail will match. */
+                            while (pos != found) {
+                                status = match_one(state, repeated, pos);
+                                if (status < 0)
+                                    return status;
+
+                                if (status == RE_ERROR_FAILURE)
+                                    break;
+
+                                --pos;
+                            }
+
+                            if (pos != found)
+                                /* Something preceding the tail didn't match.
+                                 */
+                                break;
+                        }
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case RE_OP_STRING_REV:
+                {
+                    Py_ssize_t length;
+
+                    length = (Py_ssize_t)test->value_count;
+
+                    /* The tail is a string. We don't want to go off the end of
+                     * the slice.
+                     */
+                    limit = max_ssize_t(limit, state->slice_start + length);
+
+                    for (;;) {
+                        Py_ssize_t found;
+                        BOOL is_partial;
+
+                        if (pos <= 0 && state->partial_side == RE_PARTIAL_LEFT)
+                            return RE_ERROR_PARTIAL;
+
+                        if (pos <= limit)
+                            break;
+
+                        /* Look for the tail string. */
+                        found = string_search_rev(safe_state, test, pos - 1,
+                          limit - length, &is_partial);
+                        if (is_partial)
+                            return RE_ERROR_PARTIAL;
+
+                        if (found < 0)
+                            break;
+
+                        if (repeated->op == RE_OP_ANY_ALL)
+                            /* Anything can precede the tail. */
+                            pos = found;
+                        else {
+                            /* Check that what precedes the tail will match. */
+                            while (pos != found) {
+                                status = match_one(state, repeated, pos);
+                                if (status < 0)
+                                    return status;
+
+                                if (status == RE_ERROR_FAILURE)
+                                    break;
+
+                                --pos;
+                            }
+
+                            if (pos != found)
+                                /* Something preceding the tail didn't match.
+                                 */
+                                break;
+                        }
+
+                        if (!is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+                    }
+                    break;
+                }
+                default:
+                    for (;;) {
+                        RE_Position next_position;
+
+                        status = match_one(state, repeated, pos);
+                        if (status < 0)
+                            return status;
+
+                        if (status == RE_ERROR_FAILURE)
+                            break;
+
+                        pos += step;
+
+                        status = try_match(state, &node->next_1, pos,
+                          &next_position);
+                        if (status < 0)
+                            return RE_ERROR_PARTIAL;
+
+                        if (status == RE_ERROR_SUCCESS &&
+                          !is_repeat_guarded(safe_state, index, pos,
+                          RE_STATUS_TAIL)) {
+                            match = TRUE;
+                            break;
+                        }
+
+                        if (pos == limit)
+                            break;
+                    }
+                    break;
+                }
+            }
+
+            if (match) {
+                /* The tail could match. */
+                count = (size_t)abs_ssize_t(pos - state->text_pos);
+                state->text_pos = pos;
+
+                if (count < max_count) {
+                    /* The match is shorter than the maximum, so we might need
+                     * to backtrack the repeat again to consume more.
+                     */
+                    rp_data->count = count;
+                } else {
+                    /* We've reached or passed the maximum, so we won't need to
+                     * backtrack the repeat again.
+                     */
+                    rp_data->start = bt_data->repeat.text_pos;
+                    rp_data->count = bt_data->repeat.count;
+                    discard_backtrack(state);
+
+                    /* Have we passed the maximum? */
+                    if (count > max_count)
+                        goto backtrack;
+                }
+
+                node = node->next_1.node;
+                goto advance;
+            } else {
+                /* The tail couldn't match. */
+                rp_data->start = bt_data->repeat.text_pos;
+                rp_data->count = bt_data->repeat.count;
+                discard_backtrack(state);
+            }
+            break;
+        }
+        case RE_OP_LOOKAROUND: /* Lookaround subpattern. */
+        {
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            if (bt_data->lookaround.inside) {
+                /* Backtracked to the start of a lookaround. */
+                RE_AtomicData* lookaround;
+
+                lookaround = pop_atomic(safe_state);
+                state->text_pos = lookaround->text_pos;
+                state->slice_end = lookaround->slice_end;
+                state->slice_start = lookaround->slice_start;
+                state->current_backtrack_block =
+                  lookaround->current_backtrack_block;
+                state->current_backtrack_block->count =
+                  lookaround->backtrack_count;
+
+                /* Restore the groups and repeats and certain flags. */
+                if (lookaround->has_repeats)
+                    pop_repeats(state);
+
+                if (lookaround->has_groups)
+                    pop_groups(state);
+
+                state->too_few_errors = bt_data->lookaround.too_few_errors;
+                state->capture_change = bt_data->lookaround.capture_change;
+
+                if (bt_data->lookaround.node->match) {
+                    /* It's a positive lookaround that's failed. */
+                    discard_backtrack(state);
+                } else {
+                    /* It's a negative lookaround that's failed. Record that
+                     * we've now left the lookaround and continue to the
+                     * following node.
+                     */
+                    bt_data->lookaround.inside = FALSE;
+                    node = bt_data->lookaround.node->nonstring.next_2.node;
+                    goto advance;
+                }
+            } else {
+                /* Backtracked to a lookaround. If it's a positive lookaround
+                 * that succeeded, we need to restore the groups; if it's a
+                 * negative lookaround that failed, it would have completely
+                 * backtracked inside and already restored the groups. We also
+                 * need to restore certain flags.
+                 */
+                if (bt_data->lookaround.node->match &&
+                  (bt_data->lookaround.node->status & RE_STATUS_HAS_GROUPS))
+                    pop_groups(state);
+
+                state->too_few_errors = bt_data->lookaround.too_few_errors;
+                state->capture_change = bt_data->lookaround.capture_change;
+
+                discard_backtrack(state);
+            }
+            break;
+        }
+        case RE_OP_MATCH_BODY:
+        {
+            RE_RepeatData* rp_data;
+            TRACE(("%s %d\n", re_op_text[bt_data->op], bt_data->repeat.index))
+
+            /* We want to match the body. */
+            rp_data = &state->repeats[bt_data->repeat.index];
+
+            /* Restore the repeat info. */
+            rp_data->count = bt_data->repeat.count;
+            rp_data->start = bt_data->repeat.start;
+            rp_data->capture_change = bt_data->repeat.capture_change;
+
+            /* Record backtracking info in case the body fails to match. */
+            bt_data->op = RE_OP_BODY_START;
+
+            /* Advance into the body. */
+            node = bt_data->repeat.position.node;
+            state->text_pos = bt_data->repeat.position.text_pos;
+            goto advance;
+        }
+        case RE_OP_MATCH_TAIL:
+        {
+            RE_RepeatData* rp_data;
+            TRACE(("%s %d\n", re_op_text[bt_data->op], bt_data->repeat.index))
+
+            /* We want to match the tail. */
+            rp_data = &state->repeats[bt_data->repeat.index];
+
+            /* Restore the repeat info. */
+            rp_data->count = bt_data->repeat.count;
+            rp_data->start = bt_data->repeat.start;
+            rp_data->capture_change = bt_data->repeat.capture_change;
+
+            /* Advance into the tail. */
+            node = bt_data->repeat.position.node;
+            state->text_pos = bt_data->repeat.position.text_pos;
+
+            discard_backtrack(state);
+            goto advance;
+        }
+        case RE_OP_REF_GROUP: /* Reference to a capture group. */
+        case RE_OP_REF_GROUP_IGN: /* Reference to a capture group, ignoring case. */
+        case RE_OP_REF_GROUP_IGN_REV: /* Reference to a capture group, backwards, ignoring case. */
+        case RE_OP_REF_GROUP_REV: /* Reference to a capture group, backwards. */
+        case RE_OP_STRING: /* A string. */
+        case RE_OP_STRING_IGN: /* A string, ignoring case. */
+        case RE_OP_STRING_IGN_REV: /* A string, backwards, ignoring case. */
+        case RE_OP_STRING_REV: /* A string, backwards. */
+        {
+            BOOL matched;
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            status = retry_fuzzy_match_string(safe_state, search,
+              &state->text_pos, &node, &string_pos, &matched);
+            if (status < 0)
+                return RE_ERROR_PARTIAL;
+
+            if (matched)
+                goto advance;
+
+            string_pos = -1;
+            break;
+        }
+        case RE_OP_REF_GROUP_FLD: /* Reference to a capture group, ignoring case. */
+        case RE_OP_REF_GROUP_FLD_REV: /* Reference to a capture group, backwards, ignoring case. */
+        {
+            BOOL matched;
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            status = retry_fuzzy_match_group_fld(safe_state, search,
+              &state->text_pos, &node, &folded_pos, &string_pos, &gfolded_pos,
+              &matched);
+            if (status < 0)
+                return RE_ERROR_PARTIAL;
+
+            if (matched)
+                goto advance;
+
+            string_pos = -1;
+            break;
+        }
+        case RE_OP_START_GROUP: /* Start of a capture group. */
+        {
+            RE_CODE private_index;
+            RE_GroupData* group;
+            TRACE(("%s %d\n", re_op_text[bt_data->op],
+              bt_data->group.public_index))
+
+            private_index = bt_data->group.private_index;
+            group = &state->groups[private_index - 1];
+
+            /* Unsave the capture? */
+            if (bt_data->group.capture)
+                unsave_capture(state, bt_data->group.private_index,
+                  bt_data->group.public_index);
+
+            if (pattern->group_info[private_index - 1].referenced &&
+              group->span.start != bt_data->group.text_pos)
+                --state->capture_change;
+            group->span.start = bt_data->group.text_pos;
+            group->current_capture = bt_data->group.current_capture;
+
+            discard_backtrack(state);
+            break;
+        }
+        case RE_OP_STRING_FLD: /* A string, ignoring case. */
+        case RE_OP_STRING_FLD_REV: /* A string, backwards, ignoring case. */
+        {
+            BOOL matched;
+            TRACE(("%s\n", re_op_text[bt_data->op]))
+
+            status = retry_fuzzy_match_string_fld(safe_state, search,
+              &state->text_pos, &node, &string_pos, &folded_pos, &matched);
+            if (status < 0)
+                return RE_ERROR_PARTIAL;
+
+            if (matched)
+                goto advance;
+
+            string_pos = -1;
+            break;
+        }
+        default:
+            TRACE(("UNKNOWN OP %d\n", bt_data->op))
+            return RE_ERROR_ILLEGAL;
+        }
+    }
+}
+
+/* Saves group data for fuzzy matching. */
+Py_LOCAL_INLINE(RE_GroupData*) save_groups(RE_SafeState* safe_state,
+  RE_GroupData* saved_groups) {
+    RE_State* state;
+    PatternObject* pattern;
+    size_t g;
+
+    /* Re-acquire the GIL. */
+    acquire_GIL(safe_state);
+
+    state = safe_state->re_state;
+    pattern = state->pattern;
+
+    if (!saved_groups) {
+        saved_groups = (RE_GroupData*)re_alloc(pattern->true_group_count *
+          sizeof(RE_GroupData));
+        if (!saved_groups)
+            goto error;
+
+        memset(saved_groups, 0, pattern->true_group_count *
+          sizeof(RE_GroupData));
+    }
+
+    for (g = 0; g < pattern->true_group_count; g++) {
+        RE_GroupData* orig;
+        RE_GroupData* copy;
+
+        orig = &state->groups[g];
+        copy = &saved_groups[g];
+
+        copy->span = orig->span;
+
+        if (orig->capture_count > copy->capture_capacity) {
+            RE_GroupSpan* cap_copy;
+
+            cap_copy = (RE_GroupSpan*)re_realloc(copy->captures,
+              orig->capture_count * sizeof(RE_GroupSpan));
+            if (!cap_copy)
+                goto error;
+
+            copy->capture_capacity = orig->capture_count;
+            copy->captures = cap_copy;
+        }
+
+        copy->capture_count = orig->capture_count;
+        Py_MEMCPY(copy->captures, orig->captures, orig->capture_count *
+          sizeof(RE_GroupSpan));
+    }
+
+    /* Release the GIL. */
+    release_GIL(safe_state);
+
+    return saved_groups;
+
+error:
+    if (saved_groups) {
+        for (g = 0; g < pattern->true_group_count; g++)
+            re_dealloc(saved_groups[g].captures);
+
+        re_dealloc(saved_groups);
+    }
+
+    /* Release the GIL. */
+    release_GIL(safe_state);
+
+    return NULL;
+}
+
+/* Restores group data for fuzzy matching. */
+Py_LOCAL_INLINE(void) restore_groups(RE_SafeState* safe_state, RE_GroupData*
+  saved_groups) {
+    RE_State* state;
+    PatternObject* pattern;
+    size_t g;
+
+    /* Re-acquire the GIL. */
+    acquire_GIL(safe_state);
+
+    state = safe_state->re_state;
+    pattern = state->pattern;
+
+    for (g = 0; g < pattern->true_group_count; g++)
+        re_dealloc(state->groups[g].captures);
+
+    Py_MEMCPY(state->groups, saved_groups, pattern->true_group_count *
+      sizeof(RE_GroupData));
+
+    re_dealloc(saved_groups);
+
+    /* Release the GIL. */
+    release_GIL(safe_state);
+}
+
+/* Discards group data for fuzzy matching. */
+Py_LOCAL_INLINE(void) discard_groups(RE_SafeState* safe_state, RE_GroupData*
+  saved_groups) {
+    RE_State* state;
+    PatternObject* pattern;
+    size_t g;
+
+    /* Re-acquire the GIL. */
+    acquire_GIL(safe_state);
+
+    state = safe_state->re_state;
+    pattern = state->pattern;
+
+    for (g = 0; g < pattern->true_group_count; g++)
+        re_dealloc(saved_groups[g].captures);
+
+    re_dealloc(saved_groups);
+
+    /* Release the GIL. */
+    release_GIL(safe_state);
+}
+
+/* Saves the fuzzy info. */
+Py_LOCAL_INLINE(void) save_fuzzy_counts(RE_State* state, size_t* fuzzy_counts)
+  {
+    Py_MEMCPY(fuzzy_counts, state->total_fuzzy_counts,
+      sizeof(state->total_fuzzy_counts));
+}
+
+/* Restores the fuzzy info. */
+Py_LOCAL_INLINE(void) restore_fuzzy_counts(RE_State* state, size_t*
+  fuzzy_counts) {
+    Py_MEMCPY(state->total_fuzzy_counts, fuzzy_counts,
+      sizeof(state->total_fuzzy_counts));
+}
+
+/* Makes the list of best matches found so far. */
+Py_LOCAL_INLINE(void) make_best_list(RE_BestList* best_list) {
+    best_list->capacity = 0;
+    best_list->count = 0;
+    best_list->entries = NULL;
+}
+
+/* Clears the list of best matches found so far. */
+Py_LOCAL_INLINE(void) clear_best_list(RE_BestList* best_list) {
+    best_list->count = 0;
+}
+
+/* Adds a new entry to the list of best matches found so far. */
+Py_LOCAL_INLINE(BOOL) add_to_best_list(RE_SafeState* safe_state, RE_BestList*
+  best_list, Py_ssize_t match_pos, Py_ssize_t text_pos) {
+    RE_BestEntry* entry;
+
+    if (best_list->count >= best_list->capacity) {
+        RE_BestEntry* new_entries;
+
+        best_list->capacity = best_list->capacity == 0 ? 16 :
+          best_list->capacity * 2;
+        new_entries = safe_realloc(safe_state, best_list->entries,
+          best_list->capacity * sizeof(RE_BestEntry));
+        if (!new_entries)
+            return FALSE;
+
+        best_list->entries = new_entries;
+    }
+
+    entry = &best_list->entries[best_list->count++];
+    entry->match_pos = match_pos;
+    entry->text_pos = text_pos;
+
+    return TRUE;
+}
+
+/* Destroy the list of best matches found so far. */
+Py_LOCAL_INLINE(void) destroy_best_list(RE_SafeState* safe_state, RE_BestList*
+  best_list) {
+    if (best_list->entries)
+        safe_dealloc(safe_state, best_list->entries);
+}
+
+/* Performs a match or search from the current text position for a best fuzzy
+ * match.
+ */
+Py_LOCAL_INLINE(int) do_best_fuzzy_match(RE_SafeState* safe_state, BOOL search)
+  {
+    RE_State* state;
+    Py_ssize_t available;
+    int step;
+    size_t fewest_errors;
+    BOOL must_advance;
+    BOOL found_match;
+    RE_BestList best_list;
+    Py_ssize_t start_pos;
+    int status;
+    TRACE(("<<do_best_fuzzy_match>>\n"))
+
+    state = safe_state->re_state;
+
+    if (state->reverse) {
+        available = state->text_pos - state->slice_start;
+        step = -1;
+    } else {
+        available = state->slice_end - state->text_pos;
+        step = 1;
+    }
+
+    /* The maximum permitted cost. */
+    state->max_errors = PY_SSIZE_T_MAX;
+    fewest_errors = PY_SSIZE_T_MAX;
+
+    state->best_text_pos = state->reverse ? state->slice_start :
+      state->slice_end;
+
+    must_advance = state->must_advance;
+    found_match = FALSE;
+
+    make_best_list(&best_list);
+
+    /* Search the text for the best match. */
+    start_pos = state->text_pos;
+    while (state->slice_start <= start_pos && start_pos <= state->slice_end) {
+        state->text_pos = start_pos;
+        state->must_advance = must_advance;
+
+        /* Initialise the state. */
+        init_match(state);
+
+        status = RE_ERROR_SUCCESS;
+        if (state->max_errors == 0 && state->partial_side == RE_PARTIAL_NONE) {
+            /* An exact match, and partial matches not permitted. */
+            if (available < state->min_width || (available == 0 &&
+              state->must_advance))
+                status = RE_ERROR_FAILURE;
+        }
+
+        if (status == RE_ERROR_SUCCESS)
+            status = basic_match(safe_state, search);
+
+        /* Has an error occurred, or is it a partial match? */
+        if (status < 0)
+            break;
+
+        if (status == RE_ERROR_SUCCESS) {
+            /* It was a successful match. */
+            found_match = TRUE;
+
+            if (state->total_errors < fewest_errors) {
+                /* This match was better than any of the previous ones. */
+                fewest_errors = state->total_errors;
+
+                if (state->total_errors == 0)
+                    /* It was a perfect match. */
+                    break;
+
+                /* Forget all the previous worse matches and remember this one.
+                 */
+                clear_best_list(&best_list);
+                if (!add_to_best_list(safe_state, &best_list, state->match_pos,
+                  state->text_pos))
+                    return RE_ERROR_MEMORY;
+            } else if (state->total_errors == fewest_errors)
+                /* This match was as good as the previous matches. Remember
+                 * this one.
+                 */
+                add_to_best_list(safe_state, &best_list, state->match_pos,
+                  state->text_pos);
+        }
+
+        /* Should we keep searching? */
+        if (!search)
+            break;
+
+        start_pos = state->match_pos + step;
+    }
+
+    if (found_match) {
+        /* We found a match. */
+        if (fewest_errors > 0) {
+            /* It doesn't look like a perfect match. */
+            int i;
+            Py_ssize_t slice_start;
+            Py_ssize_t slice_end;
+            size_t error_limit;
+            size_t best_fuzzy_counts[RE_FUZZY_COUNT];
+            RE_GroupData* best_groups;
+            Py_ssize_t best_match_pos;
+            Py_ssize_t best_text_pos;
+
+            slice_start = state->slice_start;
+            slice_end = state->slice_end;
+
+            error_limit = fewest_errors;
+
+            if (error_limit > RE_MAX_ERRORS)
+                error_limit = RE_MAX_ERRORS;
+
+            best_groups = NULL;
+
+            /* Look again at the best of the matches that we've seen. */
+            for (i = 0; i < best_list.count; i++) {
+                RE_BestEntry* entry;
+                Py_ssize_t max_offset;
+                Py_ssize_t offset;
+
+                /* Look for the best fit at this position. */
+                entry = &best_list.entries[i];
+
+                if (search) {
+                    max_offset = state->reverse ? entry->match_pos -
+                      state->slice_start : state->slice_end - entry->match_pos;
+
+                    if (max_offset > (Py_ssize_t)fewest_errors)
+                        max_offset = (Py_ssize_t)fewest_errors;
+
+                    if (max_offset > (Py_ssize_t)error_limit)
+                        max_offset = (Py_ssize_t)error_limit;
+                } else
+                    max_offset = 0;
+
+                start_pos = entry->match_pos;
+                offset = 0;
+
+                while (offset <= max_offset) {
+                    state->max_errors = 1;
+
+                    while (state->max_errors <= error_limit) {
+                        state->text_pos = start_pos;
+                        init_match(state);
+                        status = basic_match(safe_state, FALSE);
+
+                        if (status == RE_ERROR_SUCCESS) {
+                            BOOL better;
+
+                            if (state->total_errors < error_limit || i == 0 &&
+                              offset == 0)
+                                better = TRUE;
+                            else if (state->total_errors == error_limit)
+                                /* The cost is as low as the current best, but
+                                 * is it earlier?
+                                 */
+                                better = state->reverse ? state->match_pos >
+                                  best_match_pos : state->match_pos <
+                                  best_match_pos;
+
+                            if (better) {
+                                save_fuzzy_counts(state, best_fuzzy_counts);
+
+                                best_groups = save_groups(safe_state,
+                                  best_groups);
+                                if (!best_groups) {
+                                    destroy_best_list(safe_state, &best_list);
+                                    return RE_ERROR_MEMORY;
+                                }
+
+                                best_match_pos = state->match_pos;
+                                best_text_pos = state->text_pos;
+                                error_limit = state->total_errors;
+                            }
+
+                            break;
+                        }
+
+                        ++state->max_errors;
+                    }
+
+                    start_pos += step;
+                    ++offset;
+                }
+
+                if (status == RE_ERROR_SUCCESS && state->total_errors == 0)
+                    break;
+            }
+
+            if (best_groups) {
+                status = RE_ERROR_SUCCESS;
+                state->match_pos = best_match_pos;
+                state->text_pos = best_text_pos;
+
+                restore_groups(safe_state, best_groups);
+                restore_fuzzy_counts(state, best_fuzzy_counts);
+            } else {
+                /* None of the "best" matches could be improved on, so pick the
+                 * first.
+                 */
+                RE_BestEntry* entry;
+
+                /* Look at only the part of the string around the match. */
+                entry = &best_list.entries[0];
+
+                if (state->reverse) {
+                    state->slice_start = entry->text_pos;
+                    state->slice_end = entry->match_pos;
+                } else {
+                    state->slice_start = entry->match_pos;
+                    state->slice_end = entry->text_pos;
+                }
+
+                /* We'll expand the part that we're looking at to take to
+                 * compensate for any matching errors that have occurred.
+                 */
+                if (state->slice_start - slice_start >=
+                  (Py_ssize_t)fewest_errors)
+                    state->slice_start -= (Py_ssize_t)fewest_errors;
+                else
+                    state->slice_start = slice_start;
+
+                if (slice_end - state->slice_end >= (Py_ssize_t)fewest_errors)
+                    state->slice_end += (Py_ssize_t)fewest_errors;
+                else
+                    state->slice_end = slice_end;
+
+                state->max_errors = fewest_errors;
+                state->text_pos = entry->match_pos;
+                init_match(state);
+                status = basic_match(safe_state, search);
+            }
+
+            state->slice_start = slice_start;
+            state->slice_end = slice_end;
+        }
+    }
+
+    destroy_best_list(safe_state, &best_list);
+
+    return status;
+}
+
+/* Performs a match or search from the current text position for an enhanced
+ * fuzzy match.
+ */
+Py_LOCAL_INLINE(int) do_enhanced_fuzzy_match(RE_SafeState* safe_state, BOOL
+  search) {
+    RE_State* state;
+    PatternObject* pattern;
+    Py_ssize_t available;
+    size_t fewest_errors;
+    RE_GroupData* best_groups;
+    Py_ssize_t best_match_pos;
+    BOOL must_advance;
+    Py_ssize_t slice_start;
+    Py_ssize_t slice_end;
+    int status;
+    size_t best_fuzzy_counts[RE_FUZZY_COUNT];
+    Py_ssize_t best_text_pos = 0; /* Initialise to stop compiler warning. */
+    TRACE(("<<do_enhanced_fuzzy_match>>\n"))
+
+    state = safe_state->re_state;
+    pattern = state->pattern;
+
+    if (state->reverse)
+        available = state->text_pos - state->slice_start;
+    else
+        available = state->slice_end - state->text_pos;
+
+    /* The maximum permitted cost. */
+    state->max_errors = PY_SSIZE_T_MAX;
+    fewest_errors = PY_SSIZE_T_MAX;
+
+    best_groups = NULL;
+
+    state->best_match_pos = state->text_pos;
+    state->best_text_pos = state->reverse ? state->slice_start :
+      state->slice_end;
+
+    best_match_pos = state->text_pos;
+    must_advance = state->must_advance;
+
+    slice_start = state->slice_start;
+    slice_end = state->slice_end;
+
+    for (;;) {
+        /* If there's a better match, it won't start earlier in the string than
+         * the current best match, so there's no need to start earlier than
+         * that match.
+         */
+        state->must_advance = must_advance;
+
+        /* Initialise the state. */
+        init_match(state);
+
+        status = RE_ERROR_SUCCESS;
+        if (state->max_errors == 0 && state->partial_side == RE_PARTIAL_NONE) {
+            /* An exact match, and partial matches not permitted. */
+            if (available < state->min_width || (available == 0 &&
+              state->must_advance))
+                status = RE_ERROR_FAILURE;
+        }
+
+        if (status == RE_ERROR_SUCCESS)
+            status = basic_match(safe_state, search);
+
+        /* Has an error occurred, or is it a partial match? */
+        if (status < 0)
+            break;
+
+        if (status == RE_ERROR_SUCCESS) {
+            BOOL better;
+
+            better = state->total_errors < fewest_errors;
+
+            if (better) {
+                BOOL same_match;
+
+                fewest_errors = state->total_errors;
+                state->max_errors = fewest_errors;
+
+                save_fuzzy_counts(state, best_fuzzy_counts);
+
+                same_match = state->match_pos == best_match_pos &&
+                  state->text_pos == best_text_pos;
+                same_match = FALSE;
+
+                if (best_groups) {
+                    size_t g;
+
+                    /* Did we get the same match as the best so far? */
+                    for (g = 0; same_match && g < pattern->public_group_count;
+                      g++) {
+                        same_match = state->groups[g].span.start ==
+                          best_groups[g].span.start &&
+                          state->groups[g].span.end == best_groups[g].span.end;
+                    }
+                }
+
+                /* Save the best result so far. */
+                best_groups = save_groups(safe_state, best_groups);
+                if (!best_groups) {
+                    status = RE_ERROR_MEMORY;
+                    break;
+                }
+
+                best_match_pos = state->match_pos;
+                best_text_pos = state->text_pos;
+
+                if (same_match || state->total_errors == 0)
+                    break;
+
+                state->max_errors = state->total_errors;
+                if (state->max_errors < RE_MAX_ERRORS)
+                    --state->max_errors;
+            } else
+                break;
+
+            if (state->reverse) {
+                state->slice_start = state->text_pos;
+                state->slice_end = state->match_pos;
+            } else {
+                state->slice_start = state->match_pos;
+                state->slice_end = state->text_pos;
+            }
+
+            state->text_pos = state->match_pos;
+
+            if (state->max_errors == PY_SSIZE_T_MAX)
+                state->max_errors = 0;
+        } else
+            break;
+    }
+
+    state->slice_start = slice_start;
+    state->slice_end = slice_end;
+
+    if (best_groups) {
+        if (status == RE_ERROR_SUCCESS && state->total_errors == 0)
+            /* We have a perfect match, so the previous best match. */
+            discard_groups(safe_state, best_groups);
+        else {
+            /* Restore the previous best match. */
+            status = RE_ERROR_SUCCESS;
+
+            state->match_pos = best_match_pos;
+            state->text_pos = best_text_pos;
+
+            restore_groups(safe_state, best_groups);
+            restore_fuzzy_counts(state, best_fuzzy_counts);
+        }
+    }
+
+    return status;
+}
+
+/* Performs a match or search from the current text position for a simple fuzzy
+ * match.
+ */
+Py_LOCAL_INLINE(int) do_simple_fuzzy_match(RE_SafeState* safe_state, BOOL
+  search) {
+    RE_State* state;
+    Py_ssize_t available;
+    int status;
+    TRACE(("<<do_simple_fuzzy_match>>\n"))
+
+    state = safe_state->re_state;
+
+    if (state->reverse)
+        available = state->text_pos - state->slice_start;
+    else
+        available = state->slice_end - state->text_pos;
+
+    /* The maximum permitted cost. */
+    state->max_errors = PY_SSIZE_T_MAX;
+
+    state->best_match_pos = state->text_pos;
+    state->best_text_pos = state->reverse ? state->slice_start :
+      state->slice_end;
+
+    /* Initialise the state. */
+    init_match(state);
+
+    status = RE_ERROR_SUCCESS;
+    if (state->max_errors == 0 && state->partial_side == RE_PARTIAL_NONE) {
+        /* An exact match, and partial matches not permitted. */
+        if (available < state->min_width || (available == 0 &&
+          state->must_advance))
+            status = RE_ERROR_FAILURE;
+    }
+
+    if (status == RE_ERROR_SUCCESS)
+        status = basic_match(safe_state, search);
+
+    return status;
+}
+
+/* Performs a match or search from the current text position for an exact
+ * match.
+ */
+Py_LOCAL_INLINE(int) do_exact_match(RE_SafeState* safe_state, BOOL search) {
+    RE_State* state;
+    Py_ssize_t available;
+    int status;
+    TRACE(("<<do_exact_match>>\n"))
+
+    state = safe_state->re_state;
+
+    if (state->reverse)
+        available = state->text_pos - state->slice_start;
+    else
+        available = state->slice_end - state->text_pos;
+
+    /* The maximum permitted cost. */
+    state->max_errors = 0;
+
+    state->best_match_pos = state->text_pos;
+    state->best_text_pos = state->reverse ? state->slice_start :
+      state->slice_end;
+
+    /* Initialise the state. */
+    init_match(state);
+
+    status = RE_ERROR_SUCCESS;
+    if (state->max_errors == 0 && state->partial_side == RE_PARTIAL_NONE) {
+        /* An exact match, and partial matches not permitted. */
+        if (available < state->min_width || (available == 0 &&
+          state->must_advance))
+            status = RE_ERROR_FAILURE;
+    }
+
+    if (status == RE_ERROR_SUCCESS)
+        status = basic_match(safe_state, search);
+
+    return status;
+}
+
+/* Performs a match or search from the current text position.
+ *
+ * The state can sometimes be shared across threads. In such instances there's
+ * a lock (mutex) on it. The lock is held for the duration of matching.
+ */
+Py_LOCAL_INLINE(int) do_match(RE_SafeState* safe_state, BOOL search) {
+    RE_State* state;
+    PatternObject* pattern;
+    int status;
+    TRACE(("<<do_match>>\n"))
+
+    state = safe_state->re_state;
+    pattern = state->pattern;
+
+    /* Is there enough to search? */
+    if (state->reverse) {
+        if (state->text_pos < state->slice_start)
+            return FALSE;
+    } else {
+        if (state->text_pos > state->slice_end)
+            return FALSE;
+    }
+
+    /* Release the GIL. */
+    release_GIL(safe_state);
+
+    if (pattern->is_fuzzy) {
+        if (pattern->flags & RE_FLAG_BESTMATCH)
+            status = do_best_fuzzy_match(safe_state, search);
+        else if (pattern->flags & RE_FLAG_ENHANCEMATCH)
+            status = do_enhanced_fuzzy_match(safe_state, search);
+        else
+            status = do_simple_fuzzy_match(safe_state, search);
+    } else
+        status = do_exact_match(safe_state, search);
+
+    if (status == RE_ERROR_SUCCESS || status == RE_ERROR_PARTIAL) {
+        Py_ssize_t max_end_index;
+        RE_GroupInfo* group_info;
+        size_t g;
+
+        /* Store the results. */
+        state->lastindex = -1;
+        state->lastgroup = -1;
+        max_end_index = -1;
+
+        if (status == RE_ERROR_PARTIAL) {
+            /* We've matched up to the limit of the slice. */
+            if (state->reverse)
+                state->text_pos = state->slice_start;
+            else
+                state->text_pos = state->slice_end;
+        }
+
+        /* Store the capture groups. */
+        group_info = pattern->group_info;
+
+        for (g = 0; g < pattern->public_group_count; g++) {
+            RE_GroupSpan* span;
+
+            span = &state->groups[g].span;
+            /* The string positions are of type Py_ssize_t, so the format needs
+             * to specify that.
+             */
+            TRACE(("group %d from %" PY_FORMAT_SIZE_T "d to %" PY_FORMAT_SIZE_T
+              "d\n", g + 1, span->start, span->end))
+
+            if (span->start >= 0 && span->end >= 0 && group_info[g].end_index >
+              max_end_index) {
+                max_end_index = group_info[g].end_index;
+                state->lastindex = (Py_ssize_t)g + 1;
+                if (group_info[g].has_name)
+                    state->lastgroup = (Py_ssize_t)g + 1;
+            }
+        }
+    }
+
+    /* Re-acquire the GIL. */
+    acquire_GIL(safe_state);
+
+    if (status < 0 && status != RE_ERROR_PARTIAL && !PyErr_Occurred())
+        set_error(status, NULL);
+
+    return status;
+}
+
+/* Gets a string from a Python object.
+ *
+ * If the function returns true and str_info->should_release is true then it's
+ * the responsibility of the caller to release the buffer when it's no longer
+ * needed.
+ */
+Py_LOCAL_INLINE(BOOL) get_string(PyObject* string, RE_StringInfo* str_info) {
+    /* Given a Python object, return a data pointer, a length (in characters),
+     * and a character size. Return FALSE if the object is not a string (or not
+     * compatible).
+     */
+    PyBufferProcs* buffer;
+    Py_ssize_t bytes;
+    Py_ssize_t size;
+
+    /* Unicode objects do not support the buffer API. So, get the data directly
+     * instead.
+     */
+    if (PyUnicode_Check(string)) {
+        /* Unicode strings doesn't always support the buffer interface. */
+        str_info->characters = (void*)PyUnicode_AS_DATA(string);
+        str_info->length = PyUnicode_GET_SIZE(string);
+        str_info->charsize = sizeof(Py_UNICODE);
+        str_info->is_unicode = TRUE;
+        str_info->should_release = FALSE;
+        return TRUE;
+    }
+
+    /* Get pointer to string buffer. */
+#if PY_VERSION_HEX >= 0x02060000
+    buffer = Py_TYPE(string)->tp_as_buffer;
+    str_info->view.len = -1;
+#else
+    buffer = string->ob_type->tp_as_buffer;
+#endif
+
+    if (!buffer) {
+        PyErr_SetString(PyExc_TypeError, "expected string or buffer");
+        return FALSE;
+    }
+
+#if PY_VERSION_HEX >= 0x02060000
+    if (buffer->bf_getbuffer && (*buffer->bf_getbuffer)(string,
+      &str_info->view, PyBUF_SIMPLE) >= 0)
+        /* It's a new-style buffer. */
+        str_info->should_release = TRUE;
+    else
+#endif
+    if (buffer->bf_getreadbuffer && buffer->bf_getsegcount &&
+      buffer->bf_getsegcount(string, NULL) == 1)
+        /* It's an old-style buffer. */
+        str_info->should_release = FALSE;
+    else {
+        PyErr_SetString(PyExc_TypeError, "expected string or buffer");
+        return FALSE;
+    }
+
+    /* Determine buffer size. */
+#if PY_VERSION_HEX >= 0x02060000
+    if (str_info->should_release) {
+        /* It's a new-style buffer. */
+        bytes = str_info->view.len;
+        str_info->characters = str_info->view.buf;
+
+        if (str_info->characters == NULL) {
+            PyBuffer_Release(&str_info->view);
+            PyErr_SetString(PyExc_ValueError, "buffer is NULL");
+            return FALSE;
+        }
+    } else
+#endif
+        /* It's an old-style buffer. */
+        bytes = buffer->bf_getreadbuffer(string, 0, &str_info->characters);
+
+    if (bytes < 0) {
+#if PY_VERSION_HEX >= 0x02060000
+        if (str_info->should_release)
+            PyBuffer_Release(&str_info->view);
+#endif
+        PyErr_SetString(PyExc_TypeError, "buffer has negative size");
+        return FALSE;
+    }
+
+    /* Determine character size. */
+    size = PyObject_Size(string);
+
+    if (PyString_Check(string) || bytes == size)
+        str_info->charsize = 1;
+    else {
+#if PY_VERSION_HEX >= 0x02060000
+        if (str_info->should_release)
+            PyBuffer_Release(&str_info->view);
+#endif
+        PyErr_SetString(PyExc_TypeError, "buffer size mismatch");
+        return FALSE;
+    }
+
+    str_info->length = size;
+    str_info->is_unicode = FALSE;
+
+    return TRUE;
+}
+
+/* Deallocates the groups storage. */
+Py_LOCAL_INLINE(void) dealloc_groups(RE_GroupData* groups, size_t group_count)
+  {
+    size_t g;
+
+    if (!groups)
+        return;
+
+    for (g = 0; g < group_count; g++)
+        re_dealloc(groups[g].captures);
+
+    re_dealloc(groups);
+}
+
+/* Initialises a state object. */
+Py_LOCAL_INLINE(BOOL) state_init_2(RE_State* state, PatternObject* pattern,
+  PyObject* string, RE_StringInfo* str_info, Py_ssize_t start, Py_ssize_t end,
+  BOOL overlapped, int concurrent, BOOL partial, BOOL use_lock, BOOL
+  visible_captures, BOOL match_all) {
+    int i;
+    Py_ssize_t final_pos;
+
+    state->groups = NULL;
+    state->best_match_groups = NULL;
+    state->repeats = NULL;
+    state->visible_captures = visible_captures;
+    state->match_all = match_all;
+    state->backtrack_block.previous = NULL;
+    state->backtrack_block.next = NULL;
+    state->backtrack_block.capacity = RE_BACKTRACK_BLOCK_SIZE;
+    state->backtrack_allocated = RE_BACKTRACK_BLOCK_SIZE;
+    state->current_atomic_block = NULL;
+    state->first_saved_groups = NULL;
+    state->current_saved_groups = NULL;
+    state->first_saved_repeats = NULL;
+    state->current_saved_repeats = NULL;
+    state->lock = NULL;
+    state->fuzzy_guards = NULL;
+    state->first_group_call_frame = NULL;
+    state->current_group_call_frame = NULL;
+    state->group_call_guard_list = NULL;
+    state->req_pos = -1;
+
+    /* The call guards used by recursive patterns. */
+    if (pattern->call_ref_info_count > 0) {
+        state->group_call_guard_list =
+          (RE_GuardList*)re_alloc(pattern->call_ref_info_count *
+          sizeof(RE_GuardList));
+        if (!state->group_call_guard_list)
+            goto error;
+        memset(state->group_call_guard_list, 0, pattern->call_ref_info_count *
+          sizeof(RE_GuardList));
+    }
+
+    /* The capture groups. */
+    if (pattern->true_group_count) {
+        size_t g;
+
+        if (pattern->groups_storage) {
+            state->groups = pattern->groups_storage;
+            pattern->groups_storage = NULL;
+        } else {
+            state->groups = (RE_GroupData*)re_alloc(pattern->true_group_count *
+              sizeof(RE_GroupData));
+            if (!state->groups)
+                goto error;
+            memset(state->groups, 0, pattern->true_group_count *
+              sizeof(RE_GroupData));
+
+            for (g = 0; g < pattern->true_group_count; g++) {
+                RE_GroupSpan* captures;
+
+                captures = (RE_GroupSpan*)re_alloc(sizeof(RE_GroupSpan));
+                if (!captures) {
+                    size_t i;
+
+                    for (i = 0; i < g; i++)
+                        re_dealloc(state->groups[i].captures);
+
+                    goto error;
+                }
+
+                state->groups[g].captures = captures;
+                state->groups[g].capture_capacity = 1;
+            }
+        }
+    }
+
+    /* Adjust boundaries. */
+    if (start < 0)
+        start += str_info->length;
+    if (start < 0)
+        start = 0;
+    else if (start > str_info->length)
+        start = str_info->length;
+
+    if (end < 0)
+        end += str_info->length;
+    if (end < 0)
+        end = 0;
+    else if (end > str_info->length)
+        end = str_info->length;
+
+    state->overlapped = overlapped;
+    state->min_width = pattern->min_width;
+
+    /* Initialise the getters and setters for the character size. */
+    state->charsize = str_info->charsize;
+    state->is_unicode = str_info->is_unicode;
+
+#if PY_VERSION_HEX >= 0x02060000
+    /* Are we using a buffer object? If so, we need to copy the info. */
+    state->should_release = str_info->should_release;
+    if (state->should_release)
+        state->view = str_info->view;
+
+#endif
+    switch (state->charsize) {
+    case 1:
+        state->char_at = bytes1_char_at;
+        state->set_char_at = bytes1_set_char_at;
+        state->point_to = bytes1_point_to;
+        break;
+    case 2:
+        state->char_at = bytes2_char_at;
+        state->set_char_at = bytes2_set_char_at;
+        state->point_to = bytes2_point_to;
+        break;
+    case 4:
+        state->char_at = bytes4_char_at;
+        state->set_char_at = bytes4_set_char_at;
+        state->point_to = bytes4_point_to;
+        break;
+    default:
+        goto error;
+    }
+
+    state->encoding = pattern->encoding;
+    state->locale_info = pattern->locale_info;
+
+    /* The state object contains a reference to the string and also a pointer
+     * to its contents.
+     *
+     * The documentation says that the end of the slice behaves like the end of
+     * the string.
+     */
+    state->text = str_info->characters;
+    state->text_length = end;
+
+    state->reverse = (pattern->flags & RE_FLAG_REVERSE) != 0;
+    if (partial)
+        state->partial_side = state->reverse ? RE_PARTIAL_LEFT :
+          RE_PARTIAL_RIGHT;
+    else
+        state->partial_side = RE_PARTIAL_NONE;
+
+    state->slice_start = start;
+    state->slice_end = state->text_length;
+    state->text_pos = state->reverse ? state->slice_end : state->slice_start;
+
+    /* Point to the final newline and line separator if it's at the end of the
+     * string, otherwise just -1.
+     */
+    state->final_newline = -1;
+    state->final_line_sep = -1;
+    final_pos = state->text_length - 1;
+    if (final_pos >= 0) {
+        Py_UCS4 ch;
+
+        ch = state->char_at(state->text, final_pos);
+        if (ch == 0x0A) {
+            /* The string ends with LF. */
+            state->final_newline = final_pos;
+            state->final_line_sep = final_pos;
+
+            /* Does the string end with CR/LF? */
+            --final_pos;
+            if (final_pos >= 0 && state->char_at(state->text, final_pos) ==
+              0x0D)
+                state->final_line_sep = final_pos;
+        } else {
+            /* The string doesn't end with LF, but it could be another kind of
+             * line separator.
+             */
+            if (state->encoding->is_line_sep(ch))
+                state->final_line_sep = final_pos;
+        }
+    }
+
+    /* If the 'new' behaviour is enabled then split correctly on zero-width
+     * matches.
+     */
+    state->version_0 = (pattern->flags & RE_FLAG_VERSION1) == 0;
+    state->must_advance = FALSE;
+
+    state->pattern = pattern;
+    state->string = string;
+
+    if (pattern->repeat_count) {
+        if (pattern->repeats_storage) {
+            state->repeats = pattern->repeats_storage;
+            pattern->repeats_storage = NULL;
+        } else {
+            state->repeats = (RE_RepeatData*)re_alloc(pattern->repeat_count *
+              sizeof(RE_RepeatData));
+            if (!state->repeats)
+                goto error;
+            memset(state->repeats, 0, pattern->repeat_count *
+              sizeof(RE_RepeatData));
+        }
+    }
+
+    if (pattern->fuzzy_count) {
+        state->fuzzy_guards = (RE_FuzzyGuards*)re_alloc(pattern->fuzzy_count *
+          sizeof(RE_FuzzyGuards));
+        if (!state->fuzzy_guards)
+            goto error;
+        memset(state->fuzzy_guards, 0, pattern->fuzzy_count *
+          sizeof(RE_FuzzyGuards));
+    }
+
+    Py_INCREF(state->pattern);
+    Py_INCREF(state->string);
+
+    /* Multithreading is allowed during matching when explicitly enabled or on
+     * immutable strings.
+     */
+    switch (concurrent) {
+    case RE_CONC_NO:
+        state->is_multithreaded = FALSE;
+        break;
+    case RE_CONC_YES:
+        state->is_multithreaded = TRUE;
+        break;
+    default:
+        state->is_multithreaded = PyUnicode_Check(string) ||
+          PyString_Check(string);
+        break;
+    }
+
+    /* A state struct can sometimes be shared across threads. In such
+     * instances, if multithreading is enabled we need to protect the state
+     * with a lock (mutex) during matching.
+     */
+    if (state->is_multithreaded && use_lock)
+        state->lock = PyThread_allocate_lock();
+
+    for (i = 0; i < MAX_SEARCH_POSITIONS; i++)
+        state->search_positions[i].start_pos = -1;
+
+    return TRUE;
+
+error:
+    re_dealloc(state->group_call_guard_list);
+    re_dealloc(state->repeats);
+    dealloc_groups(state->groups, pattern->true_group_count);
+    re_dealloc(state->fuzzy_guards);
+    state->repeats = NULL;
+    state->groups = NULL;
+    state->fuzzy_guards = NULL;
+    return FALSE;
+}
+
+#if PY_VERSION_HEX >= 0x02060000
+/* Releases the string's buffer, if necessary. */
+Py_LOCAL_INLINE(void) release_buffer(RE_StringInfo* str_info) {
+    if (str_info->should_release)
+        PyBuffer_Release(&str_info->view);
+}
+
+#endif
+/* Initialises a state object. */
+Py_LOCAL_INLINE(BOOL) state_init(RE_State* state, PatternObject* pattern,
+  PyObject* string, Py_ssize_t start, Py_ssize_t end, BOOL overlapped, int
+  concurrent, BOOL partial, BOOL use_lock, BOOL visible_captures, BOOL
+  match_all) {
+    RE_StringInfo str_info;
+
+    /* Get the string to search or match. */
+    if (!get_string(string, &str_info))
+        return FALSE;
+
+    /* If we fail to initialise the state then we need to release the buffer if
+     * the string is a buffer object.
+     */
+    if (!state_init_2(state, pattern, string, &str_info, start, end,
+      overlapped, concurrent, partial, use_lock, visible_captures, match_all))
+      {
+#if PY_VERSION_HEX >= 0x02060000
+        release_buffer(&str_info);
+
+#endif
+        return FALSE;
+    }
+
+    /* The state has been initialised successfully, so now the state has the
+     * responsibility of releasing the buffer if the string is a buffer object.
+     */
+    return TRUE;
+}
+
+/* Deallocates repeat data. */
+Py_LOCAL_INLINE(void) dealloc_repeats(RE_RepeatData* repeats, size_t
+  repeat_count) {
+    size_t i;
+
+    if (!repeats)
+        return;
+
+    for (i = 0; i < repeat_count; i++) {
+        re_dealloc(repeats[i].body_guard_list.spans);
+        re_dealloc(repeats[i].tail_guard_list.spans);
+    }
+
+    re_dealloc(repeats);
+}
+
+/* Deallocates fuzzy guards. */
+Py_LOCAL_INLINE(void) dealloc_fuzzy_guards(RE_FuzzyGuards* guards, size_t
+  fuzzy_count) {
+    size_t i;
+
+    if (!guards)
+        return;
+
+    for (i = 0; i < fuzzy_count; i++) {
+        re_dealloc(guards[i].body_guard_list.spans);
+        re_dealloc(guards[i].tail_guard_list.spans);
+    }
+
+    re_dealloc(guards);
+}
+
+/* Finalises a state object, discarding its contents. */
+Py_LOCAL_INLINE(void) state_fini(RE_State* state) {
+    RE_BacktrackBlock* current_backtrack;
+    RE_AtomicBlock* current_atomic;
+    PatternObject* pattern;
+    RE_SavedGroups* saved_groups;
+    RE_SavedRepeats* saved_repeats;
+    RE_GroupCallFrame* frame;
+    size_t i;
+
+    /* Discard the lock (mutex) if there's one. */
+    if (state->lock)
+        PyThread_free_lock(state->lock);
+
+    /* Deallocate the backtrack blocks. */
+    current_backtrack = state->backtrack_block.next;
+    while (current_backtrack) {
+        RE_BacktrackBlock* next;
+
+        next = current_backtrack->next;
+        re_dealloc(current_backtrack);
+        state->backtrack_allocated -= RE_BACKTRACK_BLOCK_SIZE;
+        current_backtrack = next;
+    }
+
+    /* Deallocate the atomic blocks. */
+    current_atomic = state->current_atomic_block;
+    while (current_atomic) {
+        RE_AtomicBlock* next;
+
+        next = current_atomic->next;
+        re_dealloc(current_atomic);
+        current_atomic = next;
+    }
+
+    state->current_atomic_block = NULL;
+
+    pattern = state->pattern;
+
+    saved_groups = state->first_saved_groups;
+    while (saved_groups) {
+        RE_SavedGroups* next;
+
+        next = saved_groups->next;
+        re_dealloc(saved_groups->spans);
+        re_dealloc(saved_groups->counts);
+        re_dealloc(saved_groups);
+        saved_groups = next;
+    }
+
+    saved_repeats = state->first_saved_repeats;
+    while (saved_repeats) {
+        RE_SavedRepeats* next;
+
+        next = saved_repeats->next;
+
+        dealloc_repeats(saved_repeats->repeats, pattern->repeat_count);
+
+        re_dealloc(saved_repeats);
+        saved_repeats = next;
+    }
+
+    if (state->best_match_groups)
+        dealloc_groups(state->best_match_groups, pattern->true_group_count);
+
+    if (pattern->groups_storage)
+        dealloc_groups(state->groups, pattern->true_group_count);
+    else
+        pattern->groups_storage = state->groups;
+
+    if (pattern->repeats_storage)
+        dealloc_repeats(state->repeats, pattern->repeat_count);
+    else
+        pattern->repeats_storage = state->repeats;
+
+    frame = state->first_group_call_frame;
+    while (frame) {
+        RE_GroupCallFrame* next;
+
+        next = frame->next;
+
+        dealloc_groups(frame->groups, pattern->true_group_count);
+        dealloc_repeats(frame->repeats, pattern->repeat_count);
+
+        re_dealloc(frame);
+        frame = next;
+    }
+
+    for (i = 0; i < pattern->call_ref_info_count; i++)
+        re_dealloc(state->group_call_guard_list[i].spans);
+
+    if (state->group_call_guard_list)
+        re_dealloc(state->group_call_guard_list);
+
+    if (state->fuzzy_guards)
+        dealloc_fuzzy_guards(state->fuzzy_guards, pattern->fuzzy_count);
+
+    Py_DECREF(state->pattern);
+    Py_DECREF(state->string);
+#if PY_VERSION_HEX >= 0x02060000
+
+    if (state->should_release)
+        PyBuffer_Release(&state->view);
+#endif
+}
+
+/* Converts a string index to an integer.
+ *
+ * If the index is None then the default will be returned.
+ */
+Py_LOCAL_INLINE(Py_ssize_t) as_string_index(PyObject* obj, Py_ssize_t def) {
+    Py_ssize_t value;
+
+    if (obj == Py_None)
+        return def;
+
+    value = PyInt_AsSsize_t(obj);
+    if (value != -1 || !PyErr_Occurred())
+        return value;
+
+    PyErr_Clear();
+
+    value = PyLong_AsLong(obj);
+    if (value != -1 || !PyErr_Occurred())
+        return value;
+
+    set_error(RE_ERROR_INDEX, NULL);
+    return 0;
+}
+
+/* Deallocates a MatchObject. */
+static void match_dealloc(PyObject* self_) {
+    MatchObject* self;
+
+    self = (MatchObject*)self_;
+
+    Py_XDECREF(self->string);
+    Py_XDECREF(self->substring);
+    Py_DECREF(self->pattern);
+    if (self->groups)
+        re_dealloc(self->groups);
+    Py_XDECREF(self->regs);
+    PyObject_DEL(self);
+}
+
+/* Restricts a value to a range. */
+Py_LOCAL_INLINE(Py_ssize_t) limited_range(Py_ssize_t value, Py_ssize_t lower,
+  Py_ssize_t upper) {
+    if (value < lower)
+        return lower;
+
+    if (value > upper)
+        return upper;
+
+    return value;
+}
+
+/* Gets a slice from a Unicode string. */
+Py_LOCAL_INLINE(PyObject*) unicode_slice(PyObject* string, Py_ssize_t start,
+  Py_ssize_t end) {
+    Py_ssize_t length;
+    Py_UNICODE* buffer;
+
+    length = PyUnicode_GET_SIZE(string);
+    start = limited_range(start, 0, length);
+    end = limited_range(end, 0, length);
+
+    buffer = PyUnicode_AsUnicode(string);
+
+    return PyUnicode_FromUnicode(buffer + start, end - start);
+}
+
+/* Gets a slice from a bytestring. */
+Py_LOCAL_INLINE(PyObject*) bytes_slice(PyObject* string, Py_ssize_t start,
+  Py_ssize_t end) {
+    Py_ssize_t length;
+    char* buffer;
+
+    length = PyString_GET_SIZE(string);
+    start = limited_range(start, 0, length);
+    end = limited_range(end, 0, length);
+
+    buffer = PyString_AsString(string);
+
+    return PyString_FromStringAndSize(buffer + start, end - start);
+}
+
+/* Gets a slice from a string, returning either a Unicode string or a
+ * bytestring.
+ */
+Py_LOCAL_INLINE(PyObject*) get_slice(PyObject* string, Py_ssize_t start,
+  Py_ssize_t end) {
+    if (PyUnicode_Check(string))
+        return unicode_slice(string, start, end);
+
+    if (PyString_Check(string))
+        return bytes_slice(string, start, end);
+
+    return PySequence_GetSlice(string, start, end);
+}
+
+/* Gets a MatchObject's group by integer index. */
+static PyObject* match_get_group_by_index(MatchObject* self, Py_ssize_t index,
+  PyObject* def) {
+    RE_GroupSpan* span;
+
+    if (index < 0 || (size_t)index > self->group_count) {
+        /* Raise error if we were given a bad group number. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+
+    if (index == 0)
+        return get_slice(self->substring, self->match_start -
+          self->substring_offset, self->match_end - self->substring_offset);
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    span = &self->groups[index - 1].span;
+
+    if (span->start < 0 || span->end < 0) {
+        /* Return default value if the string or group is undefined. */
+        Py_INCREF(def);
+        return def;
+    }
+
+    return get_slice(self->substring, span->start - self->substring_offset,
+      span->end - self->substring_offset);
+}
+
+/* Gets a MatchObject's start by integer index. */
+static PyObject* match_get_start_by_index(MatchObject* self, Py_ssize_t index)
+  {
+    RE_GroupSpan* span;
+
+    if (index < 0 || (size_t)index > self->group_count) {
+        /* Raise error if we were given a bad group number. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+
+    if (index == 0)
+        return Py_BuildValue("n", self->match_start);
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    span = &self->groups[index - 1].span;
+    return Py_BuildValue("n", span->start);
+}
+
+/* Gets a MatchObject's starts by integer index. */
+static PyObject* match_get_starts_by_index(MatchObject* self, Py_ssize_t index)
+  {
+    RE_GroupData* group;
+    PyObject* result;
+    PyObject* item;
+    size_t i;
+
+    if (index < 0 || (size_t)index > self->group_count) {
+        /* Raise error if we were given a bad group number. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+
+    if (index == 0) {
+        result = PyList_New(1);
+        if (!result)
+            return NULL;
+
+        item = Py_BuildValue("n", self->match_start);
+        if (!item)
+            goto error;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(result, 0, item);
+
+        return result;
+    }
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    group = &self->groups[index - 1];
+
+    result = PyList_New((Py_ssize_t)group->capture_count);
+    if (!result)
+        return NULL;
+
+    for (i = 0; i < group->capture_count; i++) {
+        item = Py_BuildValue("n", group->captures[i].start);
+        if (!item)
+            goto error;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(result, i, item);
+    }
+
+    return result;
+
+error:
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* Gets a MatchObject's end by integer index. */
+static PyObject* match_get_end_by_index(MatchObject* self, Py_ssize_t index) {
+    RE_GroupSpan* span;
+
+    if (index < 0 || (size_t)index > self->group_count) {
+        /* Raise error if we were given a bad group number. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+
+    if (index == 0)
+        return Py_BuildValue("n", self->match_end);
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    span = &self->groups[index - 1].span;
+    return Py_BuildValue("n", span->end);
+}
+
+/* Gets a MatchObject's ends by integer index. */
+static PyObject* match_get_ends_by_index(MatchObject* self, Py_ssize_t index) {
+    RE_GroupData* group;
+    PyObject* result;
+    PyObject* item;
+    size_t i;
+
+    if (index < 0 || (size_t)index > self->group_count) {
+        /* Raise error if we were given a bad group number. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+
+    if (index == 0) {
+        result = PyList_New(1);
+        if (!result)
+            return NULL;
+
+        item = Py_BuildValue("n", self->match_end);
+        if (!item)
+            goto error;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(result, 0, item);
+
+        return result;
+    }
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    group = &self->groups[index - 1];
+
+    result = PyList_New((Py_ssize_t)group->capture_count);
+    if (!result)
+        return NULL;
+
+    for (i = 0; i < group->capture_count; i++) {
+        item = Py_BuildValue("n", group->captures[i].end);
+        if (!item)
+            goto error;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(result, i, item);
+    }
+
+    return result;
+
+error:
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* Gets a MatchObject's span by integer index. */
+static PyObject* match_get_span_by_index(MatchObject* self, Py_ssize_t index) {
+    RE_GroupSpan* span;
+
+    if (index < 0 || (size_t)index > self->group_count) {
+        /* Raise error if we were given a bad group number. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+
+    if (index == 0)
+        return Py_BuildValue("nn", self->match_start, self->match_end);
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    span = &self->groups[index - 1].span;
+    return Py_BuildValue("nn", span->start, span->end);
+}
+
+/* Gets a MatchObject's spans by integer index. */
+static PyObject* match_get_spans_by_index(MatchObject* self, Py_ssize_t index)
+  {
+    PyObject* result;
+    PyObject* item;
+    RE_GroupData* group;
+    size_t i;
+
+    if (index < 0 || (size_t)index > self->group_count) {
+        /* Raise error if we were given a bad group number. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+
+    if (index == 0) {
+        result = PyList_New(1);
+        if (!result)
+            return NULL;
+
+        item = Py_BuildValue("nn", self->match_start, self->match_end);
+        if (!item)
+            goto error;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(result, 0, item);
+
+        return result;
+    }
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    group = &self->groups[index - 1];
+
+    result = PyList_New((Py_ssize_t)group->capture_count);
+    if (!result)
+        return NULL;
+
+    for (i = 0; i < group->capture_count; i++) {
+        item = Py_BuildValue("nn", group->captures[i].start,
+          group->captures[i].end);
+        if (!item)
+            goto error;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(result, i, item);
+    }
+
+    return result;
+
+error:
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* Gets a MatchObject's captures by integer index. */
+static PyObject* match_get_captures_by_index(MatchObject* self, Py_ssize_t
+  index) {
+    PyObject* result;
+    PyObject* slice;
+    RE_GroupData* group;
+    size_t i;
+
+    if (index < 0 || (size_t)index > self->group_count) {
+        /* Raise error if we were given a bad group number. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+
+    if (index == 0) {
+        result = PyList_New(1);
+        if (!result)
+            return NULL;
+
+        slice = get_slice(self->substring, self->match_start -
+          self->substring_offset, self->match_end - self->substring_offset);
+        if (!slice)
+            goto error;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(result, 0, slice);
+
+        return result;
+    }
+
+    /* Capture group indexes are 1-based (excluding group 0, which is the
+     * entire matched string).
+     */
+    group = &self->groups[index - 1];
+
+    result = PyList_New((Py_ssize_t)group->capture_count);
+    if (!result)
+        return NULL;
+
+    for (i = 0; i < group->capture_count; i++) {
+        slice = get_slice(self->substring, group->captures[i].start -
+          self->substring_offset, group->captures[i].end -
+          self->substring_offset);
+        if (!slice)
+            goto error;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(result, i, slice);
+    }
+
+    return result;
+
+error:
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* Converts a group index to an integer. */
+Py_LOCAL_INLINE(Py_ssize_t) as_group_index(PyObject* obj) {
+    Py_ssize_t value;
+
+    value = PyInt_AsSsize_t(obj);
+    if (value != -1 || !PyErr_Occurred())
+        return value;
+
+    PyErr_Clear();
+
+    value = PyLong_AsLong(obj);
+    if (value != -1 || !PyErr_Occurred())
+        return value;
+
+    set_error(RE_ERROR_INDEX, NULL);
+    return -1;
+}
+
+/* Gets a MatchObject's group index.
+ *
+ * The supplied index can be an integer or a string (group name) object.
+ */
+Py_LOCAL_INLINE(Py_ssize_t) match_get_group_index(MatchObject* self, PyObject*
+  index, BOOL allow_neg) {
+    Py_ssize_t group;
+
+    /* Is the index an integer? */
+    group = as_group_index(index);
+    if (group != -1 || !PyErr_Occurred()) {
+        Py_ssize_t min_group = 0;
+
+        /* Adjust negative indices where valid and allowed. */
+        if (group < 0 && allow_neg) {
+            group += (Py_ssize_t)self->group_count + 1;
+            min_group = 1;
+        }
+
+        if (min_group <= group && (size_t)group <= self->group_count)
+            return group;
+
+        return -1;
+    }
+
+    /* The index might be a group name. */
+    if (self->pattern->groupindex) {
+        /* Look up the name. */
+        PyErr_Clear();
+
+        index = PyObject_GetItem(self->pattern->groupindex, index);
+        if (index) {
+            /* Check that we have an integer. */
+            group = as_group_index(index);
+            Py_DECREF(index);
+            if (group != -1 || !PyErr_Occurred())
+                return group;
+        }
+    }
+
+    PyErr_Clear();
+    return -1;
+}
+
+/* Gets a MatchObject's group by object index. */
+Py_LOCAL_INLINE(PyObject*) match_get_group(MatchObject* self, PyObject* index,
+  PyObject* def, BOOL allow_neg) {
+    /* Check that the index is an integer or a string. */
+    if (PyInt_Check(index) || PyLong_Check(index) || PyUnicode_Check(index) ||
+      PyString_Check(index))
+        return match_get_group_by_index(self, match_get_group_index(self,
+          index, allow_neg), def);
+
+    set_error(RE_ERROR_GROUP_INDEX_TYPE, index);
+    return NULL;
+}
+
+/* Gets info from a MatchObject by object index. */
+Py_LOCAL_INLINE(PyObject*) get_by_arg(MatchObject* self, PyObject* index,
+  RE_GetByIndexFunc get_by_index) {
+    /* Check that the index is an integer or a string. */
+    if (PyInt_Check(index) || PyLong_Check(index) || PyUnicode_Check(index) ||
+      PyString_Check(index))
+        return get_by_index(self, match_get_group_index(self, index, FALSE));
+
+    set_error(RE_ERROR_GROUP_INDEX_TYPE, index);
+    return NULL;
+}
+
+/* MatchObject's 'group' method. */
+static PyObject* match_group(MatchObject* self, PyObject* args) {
+    Py_ssize_t size;
+    PyObject* result;
+    Py_ssize_t i;
+
+    size = PyTuple_GET_SIZE(args);
+
+    switch (size) {
+    case 0:
+        /* group() */
+        result = match_get_group_by_index(self, 0, Py_None);
+        break;
+    case 1:
+        /* group(x). PyTuple_GET_ITEM borrows the reference. */
+        result = match_get_group(self, PyTuple_GET_ITEM(args, 0), Py_None,
+          FALSE);
+        break;
+    default:
+        /* group(x, y, z, ...) */
+        /* Fetch multiple items. */
+        result = PyTuple_New(size);
+        if (!result)
+            return NULL;
+
+        for (i = 0; i < size; i++) {
+            PyObject* item;
+
+            /* PyTuple_GET_ITEM borrows the reference. */
+            item = match_get_group(self, PyTuple_GET_ITEM(args, i), Py_None,
+              FALSE);
+            if (!item) {
+                Py_DECREF(result);
+                return NULL;
+            }
+
+            /* PyTuple_SET_ITEM borrows the reference. */
+            PyTuple_SET_ITEM(result, i, item);
+        }
+        break;
+    }
+
+    return result;
+}
+
+/* Generic method for getting info from a MatchObject. */
+Py_LOCAL_INLINE(PyObject*) get_from_match(MatchObject* self, PyObject* args,
+  RE_GetByIndexFunc get_by_index) {
+    Py_ssize_t size;
+    PyObject* result;
+    Py_ssize_t i;
+
+    size = PyTuple_GET_SIZE(args);
+
+    switch (size) {
+    case 0:
+        /* get() */
+        result = get_by_index(self, 0);
+        break;
+    case 1:
+        /* get(x). PyTuple_GET_ITEM borrows the reference. */
+        result = get_by_arg(self, PyTuple_GET_ITEM(args, 0), get_by_index);
+        break;
+    default:
+        /* get(x, y, z, ...) */
+        /* Fetch multiple items. */
+        result = PyTuple_New(size);
+        if (!result)
+            return NULL;
+
+        for (i = 0; i < size; i++) {
+            PyObject* item;
+
+            /* PyTuple_GET_ITEM borrows the reference. */
+            item = get_by_arg(self, PyTuple_GET_ITEM(args, i), get_by_index);
+            if (!item) {
+                Py_DECREF(result);
+                return NULL;
+            }
+
+            /* PyTuple_SET_ITEM borrows the reference. */
+            PyTuple_SET_ITEM(result, i, item);
+        }
+        break;
+    }
+
+    return result;
+}
+
+/* MatchObject's 'start' method. */
+static PyObject* match_start(MatchObject* self, PyObject* args) {
+    return get_from_match(self, args, match_get_start_by_index);
+}
+
+/* MatchObject's 'starts' method. */
+static PyObject* match_starts(MatchObject* self, PyObject* args) {
+    return get_from_match(self, args, match_get_starts_by_index);
+}
+
+/* MatchObject's 'end' method. */
+static PyObject* match_end(MatchObject* self, PyObject* args) {
+    return get_from_match(self, args, match_get_end_by_index);
+}
+
+/* MatchObject's 'ends' method. */
+static PyObject* match_ends(MatchObject* self, PyObject* args) {
+    return get_from_match(self, args, match_get_ends_by_index);
+}
+
+/* MatchObject's 'span' method. */
+static PyObject* match_span(MatchObject* self, PyObject* args) {
+    return get_from_match(self, args, match_get_span_by_index);
+}
+
+/* MatchObject's 'spans' method. */
+static PyObject* match_spans(MatchObject* self, PyObject* args) {
+    return get_from_match(self, args, match_get_spans_by_index);
+}
+
+/* MatchObject's 'captures' method. */
+static PyObject* match_captures(MatchObject* self, PyObject* args) {
+    return get_from_match(self, args, match_get_captures_by_index);
+}
+
+/* MatchObject's 'groups' method. */
+static PyObject* match_groups(MatchObject* self, PyObject* args, PyObject*
+  kwargs) {
+    PyObject* result;
+    size_t g;
+
+    PyObject* def = Py_None;
+    static char* kwlist[] = { "default", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:groups", kwlist, &def))
+        return NULL;
+
+    result = PyTuple_New((Py_ssize_t)self->group_count);
+    if (!result)
+        return NULL;
+
+    /* Group 0 is the entire matched portion of the string. */
+    for (g = 0; g < self->group_count; g++) {
+        PyObject* item;
+
+        item = match_get_group_by_index(self, (Py_ssize_t)g + 1, def);
+        if (!item)
+            goto error;
+
+        /* PyTuple_SET_ITEM borrows the reference. */
+        PyTuple_SET_ITEM(result, g, item);
+    }
+
+    return result;
+
+error:
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* MatchObject's 'groupdict' method. */
+static PyObject* match_groupdict(MatchObject* self, PyObject* args, PyObject*
+  kwargs) {
+    PyObject* result;
+    PyObject* keys;
+    Py_ssize_t g;
+
+    PyObject* def = Py_None;
+    static char* kwlist[] = { "default", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:groupdict", kwlist,
+      &def))
+        return NULL;
+
+    result = PyDict_New();
+    if (!result || !self->pattern->groupindex)
+        return result;
+
+    keys = PyMapping_Keys(self->pattern->groupindex);
+    if (!keys)
+        goto failed;
+
+    for (g = 0; g < PyList_GET_SIZE(keys); g++) {
+        PyObject* key;
+        PyObject* value;
+        int status;
+
+        /* PyList_GET_ITEM borrows a reference. */
+        key = PyList_GET_ITEM(keys, g);
+        if (!key)
+            goto failed;
+
+        value = match_get_group(self, key, def, FALSE);
+        if (!value)
+            goto failed;
+
+        status = PyDict_SetItem(result, key, value);
+        Py_DECREF(value);
+        if (status < 0)
+            goto failed;
+    }
+
+    Py_DECREF(keys);
+
+    return result;
+
+failed:
+    Py_XDECREF(keys);
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* MatchObject's 'capturesdict' method. */
+static PyObject* match_capturesdict(MatchObject* self) {
+    PyObject* result;
+    PyObject* keys;
+    Py_ssize_t g;
+
+    result = PyDict_New();
+    if (!result || !self->pattern->groupindex)
+        return result;
+
+    keys = PyMapping_Keys(self->pattern->groupindex);
+    if (!keys)
+        goto failed;
+
+    for (g = 0; g < PyList_GET_SIZE(keys); g++) {
+        PyObject* key;
+        Py_ssize_t group;
+        PyObject* captures;
+        int status;
+
+        /* PyList_GET_ITEM borrows a reference. */
+        key = PyList_GET_ITEM(keys, g);
+        if (!key)
+            goto failed;
+
+        group = match_get_group_index(self, key, FALSE);
+        if (group < 0)
+            goto failed;
+
+        captures = match_get_captures_by_index(self, group);
+        if (!captures)
+            goto failed;
+
+        status = PyDict_SetItem(result, key, captures);
+        Py_DECREF(captures);
+        if (status < 0)
+            goto failed;
+    }
+
+    Py_DECREF(keys);
+
+    return result;
+
+failed:
+    Py_XDECREF(keys);
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* Gets a Python object by name from a named module. */
+Py_LOCAL_INLINE(PyObject*) get_object(char* module_name, char* object_name) {
+    PyObject* module;
+    PyObject* object;
+
+    module = PyImport_ImportModule(module_name);
+    if (!module)
+        return NULL;
+
+    object = PyObject_GetAttrString(module, object_name);
+    Py_DECREF(module);
+
+    return object;
+}
+
+/* Calls a function in a module. */
+Py_LOCAL_INLINE(PyObject*) call(char* module_name, char* function_name,
+  PyObject* args) {
+    PyObject* function;
+    PyObject* result;
+
+    if (!args)
+        return NULL;
+
+    function = get_object(module_name, function_name);
+    if (!function)
+        return NULL;
+
+    result = PyObject_CallObject(function, args);
+    Py_DECREF(function);
+    Py_DECREF(args);
+
+    return result;
+}
+
+/* Gets a replacement item from the replacement list.
+ *
+ * The replacement item could be a string literal or a group.
+ */
+Py_LOCAL_INLINE(PyObject*) get_match_replacement(MatchObject* self, PyObject*
+  item, size_t group_count) {
+    Py_ssize_t index;
+
+    if (PyUnicode_Check(item) || PyString_Check(item)) {
+        /* It's a literal, which can be added directly to the list. */
+        Py_INCREF(item);
+        return item;
+    }
+
+    /* Is it a group reference? */
+    index = as_group_index(item);
+    if (index == -1 && PyErr_Occurred()) {
+        /* Not a group either! */
+        set_error(RE_ERROR_REPLACEMENT, NULL);
+        return NULL;
+    }
+
+    if (index == 0) {
+        /* The entire matched portion of the string. */
+        return get_slice(self->substring, self->match_start -
+          self->substring_offset, self->match_end - self->substring_offset);
+    } else if (index >= 1 && (size_t)index <= group_count) {
+        /* A group. If it didn't match then return None instead. */
+        RE_GroupData* group;
+
+        group = &self->groups[index - 1];
+
+        if (group->capture_count > 0)
+            return get_slice(self->substring, group->span.start -
+              self->substring_offset, group->span.end -
+              self->substring_offset);
+        else {
+            Py_INCREF(Py_None);
+            return Py_None;
+        }
+    } else {
+        /* No such group. */
+        set_error(RE_ERROR_NO_SUCH_GROUP, NULL);
+        return NULL;
+    }
+}
+
+/* Initialises the join list. */
+Py_LOCAL_INLINE(void) init_join_list(JoinInfo* join_info, BOOL reversed, BOOL
+  is_unicode) {
+    join_info->list = NULL;
+    join_info->item = NULL;
+    join_info->reversed = reversed;
+    join_info->is_unicode = is_unicode;
+}
+
+/* Adds an item to the join list. */
+Py_LOCAL_INLINE(int) add_to_join_list(JoinInfo* join_info, PyObject* item) {
+    PyObject* new_item;
+    int status;
+
+    if (join_info->is_unicode) {
+        if (PyUnicode_Check(item)) {
+            new_item = item;
+            Py_INCREF(new_item);
+        } else {
+            new_item = PyUnicode_FromObject(item);
+            if (!new_item) {
+                set_error(RE_ERROR_NOT_UNICODE, item);
+                return RE_ERROR_NOT_UNICODE;
+            }
+        }
+    } else {
+        if (PyString_Check(item)) {
+            new_item = item;
+            Py_INCREF(new_item);
+        } else {
+            new_item = PyUnicode_FromObject(item);
+            if (!new_item) {
+                set_error(RE_ERROR_NOT_STRING, item);
+                return RE_ERROR_NOT_STRING;
+            }
+        }
+    }
+
+    /* If the list already exists then just add the item to it. */
+    if (join_info->list) {
+        status = PyList_Append(join_info->list, new_item);
+        if (status < 0)
+            goto error;
+
+        Py_DECREF(new_item);
+        return status;
+    }
+
+    /* If we already have an item then we now have 2(!) and we need to put them
+     * into a list.
+     */
+    if (join_info->item) {
+        join_info->list = PyList_New(2);
+        if (!join_info->list) {
+            status = RE_ERROR_MEMORY;
+            goto error;
+        }
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(join_info->list, 0, join_info->item);
+        join_info->item = NULL;
+
+        /* PyList_SET_ITEM borrows the reference. */
+        PyList_SET_ITEM(join_info->list, 1, new_item);
+        return 0;
+    }
+
+    /* This is the first item. */
+    join_info->item = new_item;
+
+    return 0;
+
+error:
+    Py_DECREF(new_item);
+    set_error(status, NULL);
+    return status;
+}
+
+/* Clears the join list. */
+Py_LOCAL_INLINE(void) clear_join_list(JoinInfo* join_info) {
+    Py_XDECREF(join_info->list);
+    Py_XDECREF(join_info->item);
+}
+
+/* Joins together a list of strings for pattern_subx. */
+Py_LOCAL_INLINE(PyObject*) join_list_info(JoinInfo* join_info) {
+    /* If the list already exists then just do the join. */
+    if (join_info->list) {
+        PyObject* joiner;
+        PyObject* result;
+
+        if (join_info->reversed)
+            /* The list needs to be reversed before being joined. */
+            PyList_Reverse(join_info->list);
+
+        if (join_info->is_unicode) {
+            /* Concatenate the Unicode strings. */
+            joiner = PyUnicode_FromUnicode(NULL, 0);
+            if (!joiner) {
+                clear_join_list(join_info);
+                return NULL;
+            }
+
+            result = PyUnicode_Join(joiner, join_info->list);
+        } else {
+            joiner = PyString_FromString("");
+            if (!joiner) {
+                clear_join_list(join_info);
+                return NULL;
+            }
+
+            /* Concatenate the bytestrings. */
+            result = _PyString_Join(joiner, join_info->list);
+        }
+
+        Py_DECREF(joiner);
+        clear_join_list(join_info);
+
+        return result;
+    }
+
+    /* If we have only 1 item, so we'll just return it. */
+    if (join_info->item)
+        return join_info->item;
+
+    /* There are no items, so return an empty string. */
+    if (join_info->is_unicode)
+        return PyUnicode_FromUnicode(NULL, 0);
+    else
+        return PyString_FromString("");
+}
+
+/* Checks whether a string replacement is a literal.
+ *
+ * To keep it simple we'll say that a literal is a string which can be used
+ * as-is.
+ *
+ * Returns its length if it is a literal, otherwise -1.
+ */
+Py_LOCAL_INLINE(Py_ssize_t) check_replacement_string(PyObject* str_replacement,
+  unsigned char special_char) {
+    RE_StringInfo str_info;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    Py_ssize_t pos;
+
+    if (!get_string(str_replacement, &str_info))
+        return -1;
+
+    switch (str_info.charsize) {
+    case 1:
+        char_at = bytes1_char_at;
+        break;
+    case 2:
+        char_at = bytes2_char_at;
+        break;
+    case 4:
+        char_at = bytes4_char_at;
+        break;
+    default:
+#if PY_VERSION_HEX >= 0x02060000
+        release_buffer(&str_info);
+#endif
+        return -1;
+    }
+
+    for (pos = 0; pos < str_info.length; pos++) {
+        if (char_at(str_info.characters, pos) == special_char) {
+#if PY_VERSION_HEX >= 0x02060000
+            release_buffer(&str_info);
+
+#endif
+            return -1;
+        }
+    }
+
+#if PY_VERSION_HEX >= 0x02060000
+    release_buffer(&str_info);
+
+#endif
+    return str_info.length;
+}
+
+/* MatchObject's 'expand' method. */
+static PyObject* match_expand(MatchObject* self, PyObject* str_template) {
+    Py_ssize_t literal_length;
+    PyObject* replacement;
+    JoinInfo join_info;
+    Py_ssize_t size;
+    Py_ssize_t i;
+
+    /* Is the template just a literal? */
+    literal_length = check_replacement_string(str_template, '\\');
+    if (literal_length >= 0) {
+        /* It's a literal. */
+        Py_INCREF(str_template);
+        return str_template;
+    }
+
+    /* Hand the template to the template compiler. */
+    replacement = call(RE_MODULE, "_compile_replacement_helper",
+      PyTuple_Pack(2, self->pattern, str_template));
+    if (!replacement)
+        return NULL;
+
+    init_join_list(&join_info, FALSE, PyUnicode_Check(self->string));
+
+    /* Add each part of the template to the list. */
+    size = PyList_GET_SIZE(replacement);
+    for (i = 0; i < size; i++) {
+        PyObject* item;
+        PyObject* str_item;
+
+        /* PyList_GET_ITEM borrows a reference. */
+        item = PyList_GET_ITEM(replacement, i);
+        str_item = get_match_replacement(self, item, self->group_count);
+        if (!str_item)
+            goto error;
+
+        /* Add to the list. */
+        if (str_item == Py_None)
+            Py_DECREF(str_item);
+        else {
+            int status;
+
+            status = add_to_join_list(&join_info, str_item);
+            Py_DECREF(str_item);
+            if (status < 0)
+                goto error;
+        }
+    }
+
+    Py_DECREF(replacement);
+
+    /* Convert the list to a single string (also cleans up join_info). */
+    return join_list_info(&join_info);
+
+error:
+    clear_join_list(&join_info);
+    Py_DECREF(replacement);
+    return NULL;
+}
+
+#if PY_VERSION_HEX >= 0x02060000
+/* Gets a MatchObject's group dictionary. */
+Py_LOCAL_INLINE(PyObject*) match_get_group_dict(MatchObject* self) {
+    PyObject* result;
+    PyObject* keys;
+    Py_ssize_t g;
+
+    result = PyDict_New();
+    if (!result || !self->pattern->groupindex)
+        return result;
+
+    keys = PyMapping_Keys(self->pattern->groupindex);
+    if (!keys)
+        goto failed;
+
+    for (g = 0; g < PyList_GET_SIZE(keys); g++) {
+        PyObject* key;
+        PyObject* value;
+        int status;
+
+        /* PyList_GET_ITEM borrows a reference. */
+        key = PyList_GET_ITEM(keys, g);
+        if (!key)
+            goto failed;
+
+        value = match_get_group(self, key, Py_None, FALSE);
+        if (!value)
+            goto failed;
+
+        status = PyDict_SetItem(result, key, value);
+        Py_DECREF(value);
+        if (status < 0)
+            goto failed;
+    }
+
+    Py_DECREF(keys);
+
+    return result;
+
+failed:
+    Py_XDECREF(keys);
+    Py_DECREF(result);
+    return NULL;
+}
+
+static PyTypeObject Capture_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "_" RE_MODULE "." "Capture",
+    sizeof(MatchObject)
+};
+
+/* Creates a new CaptureObject. */
+Py_LOCAL_INLINE(PyObject*) make_capture_object(MatchObject** match_indirect,
+  Py_ssize_t index) {
+    CaptureObject* capture;
+
+    capture = PyObject_NEW(CaptureObject, &Capture_Type);
+    if (!capture)
+        return NULL;
+
+    capture->group_index = index;
+    capture->match_indirect = match_indirect;
+
+    return (PyObject*)capture;
+}
+
+#if PY_VERSION_HEX >= 0x02060000
+/* Makes a MatchObject's capture dictionary. */
+Py_LOCAL_INLINE(PyObject*) make_capture_dict(MatchObject* match, MatchObject**
+  match_indirect) {
+    PyObject* result;
+    PyObject* keys;
+    PyObject* values = NULL;
+    Py_ssize_t g;
+
+    result = PyDict_New();
+    if (!result)
+        return result;
+
+    keys = PyMapping_Keys(match->pattern->groupindex);
+    if (!keys)
+        goto failed;
+
+    values = PyMapping_Values(match->pattern->groupindex);
+    if (!values)
+        goto failed;
+
+    for (g = 0; g < PyList_GET_SIZE(keys); g++) {
+        PyObject* key;
+        PyObject* value;
+        Py_ssize_t v;
+        int status;
+
+        /* PyList_GET_ITEM borrows a reference. */
+        key = PyList_GET_ITEM(keys, g);
+        if (!key)
+            goto failed;
+
+        /* PyList_GET_ITEM borrows a reference. */
+        value = PyList_GET_ITEM(values, g);
+        if (!value)
+            goto failed;
+
+        v = PyLong_AsLong(value);
+        if (v == -1 && PyErr_Occurred())
+            goto failed;
+
+        value = make_capture_object(match_indirect, v);
+        if (!value)
+            goto failed;
+
+        status = PyDict_SetItem(result, key, value);
+        Py_DECREF(value);
+        if (status < 0)
+            goto failed;
+    }
+
+    Py_DECREF(values);
+    Py_DECREF(keys);
+
+    return result;
+
+failed:
+    Py_XDECREF(values);
+    Py_XDECREF(keys);
+    Py_DECREF(result);
+    return NULL;
+}
+#endif
+
+/* MatchObject's 'expandf' method. */
+static PyObject* match_expandf(MatchObject* self, PyObject* str_template) {
+    PyObject* format_func;
+    PyObject* args = NULL;
+    size_t g;
+    PyObject* kwargs = NULL;
+    PyObject* result;
+
+    format_func = PyObject_GetAttrString(str_template, "format");
+    if (!format_func)
+        return NULL;
+
+    args = PyTuple_New((Py_ssize_t)self->group_count + 1);
+    if (!args)
+        goto error;
+
+    for (g = 0; g < self->group_count + 1; g++)
+        /* PyTuple_SetItem borrows the reference. */
+        PyTuple_SetItem(args, (Py_ssize_t)g, make_capture_object(&self,
+          (Py_ssize_t)g));
+
+    kwargs = make_capture_dict(self, &self);
+    if (!kwargs)
+        goto error;
+
+    result = PyObject_Call(format_func, args, kwargs);
+
+    Py_DECREF(kwargs);
+    Py_DECREF(args);
+    Py_DECREF(format_func);
+
+    return result;
+
+error:
+    Py_XDECREF(args);
+    Py_DECREF(format_func);
+    return NULL;
+}
+
+#endif
+Py_LOCAL_INLINE(PyObject*) make_match_copy(MatchObject* self);
+
+/* MatchObject's '__copy__' method. */
+static PyObject* match_copy(MatchObject* self, PyObject *unused) {
+    return make_match_copy(self);
+}
+
+/* MatchObject's '__deepcopy__' method. */
+static PyObject* match_deepcopy(MatchObject* self, PyObject* memo) {
+    return make_match_copy(self);
+}
+
+/* MatchObject's 'regs' attribute. */
+static PyObject* match_regs(MatchObject* self) {
+    PyObject* regs;
+    PyObject* item;
+    size_t g;
+
+    regs = PyTuple_New((Py_ssize_t)self->group_count + 1);
+    if (!regs)
+        return NULL;
+
+    item = Py_BuildValue("nn", self->match_start, self->match_end);
+    if (!item)
+        goto error;
+
+    /* PyTuple_SET_ITEM borrows the reference. */
+    PyTuple_SET_ITEM(regs, 0, item);
+
+    for (g = 0; g < self->group_count; g++) {
+        RE_GroupSpan* span;
+
+        span = &self->groups[g].span;
+        item = Py_BuildValue("nn", span->start, span->end);
+        if (!item)
+            goto error;
+
+        /* PyTuple_SET_ITEM borrows the reference. */
+        PyTuple_SET_ITEM(regs, g + 1, item);
+    }
+
+    Py_INCREF(regs);
+    self->regs = regs;
+
+    return regs;
+
+error:
+    Py_DECREF(regs);
+    return NULL;
+}
+
+/* MatchObject's slice method. */
+Py_LOCAL_INLINE(PyObject*) match_get_group_slice(MatchObject* self, PyObject*
+  slice) {
+    Py_ssize_t start;
+    Py_ssize_t end;
+    Py_ssize_t step;
+    Py_ssize_t slice_length;
+
+    if (PySlice_GetIndicesEx((PySliceObject*)slice,
+      (Py_ssize_t)self->group_count + 1, &start, &end, &step, &slice_length) <
+      0)
+        return NULL;
+
+    if (slice_length <= 0)
+        return PyTuple_New(0);
+    else {
+        PyObject* result;
+        Py_ssize_t cur;
+        Py_ssize_t i;
+
+        result = PyTuple_New(slice_length);
+        if (!result)
+            return NULL;
+
+        cur = start;
+        for (i = 0; i < slice_length; i++) {
+            /* PyTuple_SetItem borrows the reference. */
+            PyTuple_SetItem(result, i, match_get_group_by_index(self, cur,
+              Py_None));
+            cur += step;
+        }
+
+        return result;
+    }
+}
+
+/* MatchObject's length method. */
+Py_LOCAL_INLINE(Py_ssize_t) match_length(MatchObject* self) {
+    return (Py_ssize_t)self->group_count + 1;
+}
+
+/* MatchObject's '__getitem__' method. */
+static PyObject* match_getitem(MatchObject* self, PyObject* item) {
+    if (PySlice_Check(item))
+        return match_get_group_slice(self, item);
+
+    return match_get_group(self, item, Py_None, TRUE);
+}
+
+/* Determines the portion of the target string which is covered by the group
+ * captures.
+ */
+Py_LOCAL_INLINE(void) determine_target_substring(MatchObject* match,
+  Py_ssize_t* slice_start, Py_ssize_t* slice_end) {
+    Py_ssize_t start;
+    Py_ssize_t end;
+    size_t g;
+
+    start = match->pos;
+    end = match->endpos;
+
+    for (g = 0; g < match->group_count; g++) {
+        RE_GroupSpan* span;
+        size_t c;
+
+        span = &match->groups[g].span;
+        if (span->start >= 0 && span->start < start)
+            start = span->start;
+        if (span->end >= 0 && span->end > end)
+            end = span->end;
+
+        for (c = 0; c < match->groups[g].capture_count; c++) {
+            RE_GroupSpan* span;
+
+            span = match->groups[g].captures;
+            if (span->start >= 0 && span->start < start)
+                start = span->start;
+            if (span->end >= 0 && span->end > end)
+                end = span->end;
+        }
+    }
+
+    *slice_start = start;
+    *slice_end = end;
+}
+
+/* MatchObject's 'detach_string' method. */
+static PyObject* match_detach_string(MatchObject* self, PyObject* unused) {
+    if (self->string) {
+        Py_ssize_t start;
+        Py_ssize_t end;
+        PyObject* substring;
+
+        determine_target_substring(self, &start, &end);
+
+        substring = get_slice(self->string, start, end);
+        if (substring) {
+            Py_XDECREF(self->substring);
+            self->substring = substring;
+            self->substring_offset = start;
+
+            Py_DECREF(self->string);
+            self->string = NULL;
+        }
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/* The documentation of a MatchObject. */
+PyDoc_STRVAR(match_group_doc,
+    "group([group1, ...]) --> string or tuple of strings.\n\
+    Return one or more subgroups of the match.  If there is a single argument,\n\
+    the result is a single string, or None if the group did not contribute to\n\
+    the match; if there are multiple arguments, the result is a tuple with one\n\
+    item per argument; if there are no arguments, the whole match is returned.\n\
+    Group 0 is the whole match.");
+
+PyDoc_STRVAR(match_start_doc,
+    "start([group1, ...]) --> int or tuple of ints.\n\
+    Return the index of the start of one or more subgroups of the match.  If\n\
+    there is a single argument, the result is an index, or -1 if the group did\n\
+    not contribute to the match; if there are multiple arguments, the result is\n\
+    a tuple with one item per argument; if there are no arguments, the index of\n\
+    the start of the whole match is returned.  Group 0 is the whole match.");
+
+PyDoc_STRVAR(match_end_doc,
+    "end([group1, ...]) --> int or tuple of ints.\n\
+    Return the index of the end of one or more subgroups of the match.  If there\n\
+    is a single argument, the result is an index, or -1 if the group did not\n\
+    contribute to the match; if there are multiple arguments, the result is a\n\
+    tuple with one item per argument; if there are no arguments, the index of\n\
+    the end of the whole match is returned.  Group 0 is the whole match.");
+
+PyDoc_STRVAR(match_span_doc,
+    "span([group1, ...]) --> 2-tuple of int or tuple of 2-tuple of ints.\n\
+    Return the span (a 2-tuple of the indices of the start and end) of one or\n\
+    more subgroups of the match.  If there is a single argument, the result is a\n\
+    span, or (-1, -1) if the group did not contribute to the match; if there are\n\
+    multiple arguments, the result is a tuple with one item per argument; if\n\
+    there are no arguments, the span of the whole match is returned.  Group 0 is\n\
+    the whole match.");
+
+PyDoc_STRVAR(match_groups_doc,
+    "groups(default=None) --> tuple of strings.\n\
+    Return a tuple containing all the subgroups of the match.  The argument is\n\
+    the default for groups that did not participate in the match.");
+
+PyDoc_STRVAR(match_groupdict_doc,
+    "groupdict(default=None) --> dict.\n\
+    Return a dictionary containing all the named subgroups of the match, keyed\n\
+    by the subgroup name.  The argument is the value to be given for groups that\n\
+    did not participate in the match.");
+
+PyDoc_STRVAR(match_capturesdict_doc,
+    "capturesdict() --> dict.\n\
+    Return a dictionary containing the captures of all the named subgroups of the\n\
+    match, keyed by the subgroup name.");
+
+PyDoc_STRVAR(match_expand_doc,
+    "expand(template) --> string.\n\
+    Return the string obtained by doing backslash substitution on the template,\n\
+    as done by the sub() method.");
+
+#if PY_VERSION_HEX >= 0x02060000
+PyDoc_STRVAR(match_expandf_doc,
+    "expandf(format) --> string.\n\
+    Return the string obtained by using the format, as done by the subf()\n\
+    method.");
+
+#endif
+PyDoc_STRVAR(match_captures_doc,
+    "captures([group1, ...]) --> list of strings or tuple of list of strings.\n\
+    Return the captures of one or more subgroups of the match.  If there is a\n\
+    single argument, the result is a list of strings; if there are multiple\n\
+    arguments, the result is a tuple of lists with one item per argument; if\n\
+    there are no arguments, the captures of the whole match is returned.  Group\n\
+    0 is the whole match.");
+
+PyDoc_STRVAR(match_starts_doc,
+    "starts([group1, ...]) --> list of ints or tuple of list of ints.\n\
+    Return the indices of the starts of the captures of one or more subgroups of\n\
+    the match.  If there is a single argument, the result is a list of indices;\n\
+    if there are multiple arguments, the result is a tuple of lists with one\n\
+    item per argument; if there are no arguments, the indices of the starts of\n\
+    the captures of the whole match is returned.  Group 0 is the whole match.");
+
+PyDoc_STRVAR(match_ends_doc,
+    "ends([group1, ...]) --> list of ints or tuple of list of ints.\n\
+    Return the indices of the ends of the captures of one or more subgroups of\n\
+    the match.  If there is a single argument, the result is a list of indices;\n\
+    if there are multiple arguments, the result is a tuple of lists with one\n\
+    item per argument; if there are no arguments, the indices of the ends of the\n\
+    captures of the whole match is returned.  Group 0 is the whole match.");
+
+PyDoc_STRVAR(match_spans_doc,
+    "spans([group1, ...]) --> list of 2-tuple of ints or tuple of list of 2-tuple of ints.\n\
+    Return the spans (a 2-tuple of the indices of the start and end) of the\n\
+    captures of one or more subgroups of the match.  If there is a single\n\
+    argument, the result is a list of spans; if there are multiple arguments,\n\
+    the result is a tuple of lists with one item per argument; if there are no\n\
+    arguments, the spans of the captures of the whole match is returned.  Group\n\
+    0 is the whole match.");
+
+PyDoc_STRVAR(match_detach_string_doc,
+    "detach_string()\n\
+    Detaches the target string from the match object. The 'string' attribute\n\
+    will become None.");
+
+/* MatchObject's methods. */
+static PyMethodDef match_methods[] = {
+    {"group", (PyCFunction)match_group, METH_VARARGS, match_group_doc},
+    {"start", (PyCFunction)match_start, METH_VARARGS, match_start_doc},
+    {"end", (PyCFunction)match_end, METH_VARARGS, match_end_doc},
+    {"span", (PyCFunction)match_span, METH_VARARGS, match_span_doc},
+    {"groups", (PyCFunction)match_groups, METH_VARARGS|METH_KEYWORDS,
+      match_groups_doc},
+    {"groupdict", (PyCFunction)match_groupdict, METH_VARARGS|METH_KEYWORDS,
+      match_groupdict_doc},
+    {"capturesdict", (PyCFunction)match_capturesdict, METH_NOARGS,
+      match_capturesdict_doc},
+    {"expand", (PyCFunction)match_expand, METH_O, match_expand_doc},
+#if PY_VERSION_HEX >= 0x02060000
+    {"expandf", (PyCFunction)match_expandf, METH_O, match_expandf_doc},
+#endif
+    {"captures", (PyCFunction)match_captures, METH_VARARGS,
+      match_captures_doc},
+    {"starts", (PyCFunction)match_starts, METH_VARARGS, match_starts_doc},
+    {"ends", (PyCFunction)match_ends, METH_VARARGS, match_ends_doc},
+    {"spans", (PyCFunction)match_spans, METH_VARARGS, match_spans_doc},
+    {"detach_string", (PyCFunction)match_detach_string, METH_NOARGS,
+      match_detach_string_doc},
+    {"__copy__", (PyCFunction)match_copy, METH_NOARGS},
+    {"__deepcopy__", (PyCFunction)match_deepcopy, METH_O},
+    {"__getitem__", (PyCFunction)match_getitem, METH_O|METH_COEXIST},
+    {NULL, NULL}
+};
+
+PyDoc_STRVAR(match_doc, "Match object");
+
+/* MatchObject's 'lastindex' attribute. */
+static PyObject* match_lastindex(PyObject* self_) {
+    MatchObject* self;
+
+    self = (MatchObject*)self_;
+
+    if (self->lastindex >= 0)
+        return Py_BuildValue("n", self->lastindex);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/* MatchObject's 'lastgroup' attribute. */
+static PyObject* match_lastgroup(PyObject* self_) {
+    MatchObject* self;
+
+    self = (MatchObject*)self_;
+
+    if (self->pattern->indexgroup && self->lastgroup >= 0) {
+        PyObject* index;
+        PyObject* result;
+
+        index = Py_BuildValue("n", self->lastgroup);
+
+        /* PyDict_GetItem returns borrows a reference. */
+        result = PyDict_GetItem(self->pattern->indexgroup, index);
+        Py_DECREF(index);
+        if (result) {
+            Py_INCREF(result);
+            return result;
+        }
+        PyErr_Clear();
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/* MatchObject's 'string' attribute. */
+static PyObject* match_string(PyObject* self_) {
+    MatchObject* self;
+
+    self = (MatchObject*)self_;
+
+    if (self->string) {
+        Py_INCREF(self->string);
+        return self->string;
+    } else {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+}
+#if PY_VERSION_HEX < 0x02060000
+
+/* MatchObject's 'partial' attribute. */
+static PyObject* match_partial(PyObject* self_) {
+    MatchObject* self;
+    PyObject* result;
+
+    self = (MatchObject*)self_;
+
+    result = self->partial ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+}
+#endif
+
+/* MatchObject's 'fuzzy_counts' attribute. */
+static PyObject* match_fuzzy_counts(PyObject* self_) {
+    MatchObject* self;
+
+    self = (MatchObject*)self_;
+
+    return Py_BuildValue("nnn", self->fuzzy_counts[RE_FUZZY_SUB],
+      self->fuzzy_counts[RE_FUZZY_INS], self->fuzzy_counts[RE_FUZZY_DEL]);
+}
+
+static PyGetSetDef match_getset[] = {
+    {"lastindex", (getter)match_lastindex, (setter)NULL,
+      "The group number of the last matched capturing group, or None."},
+    {"lastgroup", (getter)match_lastgroup, (setter)NULL,
+      "The name of the last matched capturing group, or None."},
+    {"regs", (getter)match_regs, (setter)NULL,
+      "A tuple of the spans of the capturing groups."},
+    {"string", (getter)match_string, (setter)NULL,
+      "The string that was searched, or None if it has been detached."},
+#if PY_VERSION_HEX < 0x02060000
+    {"partial", (getter)match_partial, (setter)NULL,
+      "Whether it's a partial match."},
+#endif
+    {"fuzzy_counts", (getter)match_fuzzy_counts, (setter)NULL,
+      "A tuple of the number of substitutions, insertions and deletions."},
+    {NULL} /* Sentinel */
+};
+
+static PyMemberDef match_members[] = {
+    {"re", T_OBJECT, offsetof(MatchObject, pattern), READONLY,
+      "The regex object that produced this match object."},
+    {"pos", T_PYSSIZET, offsetof(MatchObject, pos), READONLY,
+      "The position at which the regex engine starting searching."},
+    {"endpos", T_PYSSIZET, offsetof(MatchObject, endpos), READONLY,
+      "The final position beyond which the regex engine won't search."},
+#if PY_VERSION_HEX >= 0x02060000
+    {"partial", T_BOOL, offsetof(MatchObject, partial), READONLY,
+      "Whether it's a partial match."},
+#endif
+    {NULL} /* Sentinel */
+};
+
+static PyMappingMethods match_as_mapping = {
+    (lenfunc)match_length, /* mp_length */
+    (binaryfunc)match_getitem, /* mp_subscript */
+    0, /* mp_ass_subscript */
+};
+
+static PyTypeObject Match_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "_" RE_MODULE "." "Match",
+    sizeof(MatchObject)
+};
+
+/* Copies the groups. */
+Py_LOCAL_INLINE(RE_GroupData*) copy_groups(RE_GroupData* groups, size_t
+  group_count) {
+    size_t span_count;
+    size_t g;
+    RE_GroupData* groups_copy;
+    RE_GroupSpan* spans_copy;
+    size_t offset;
+
+    /* Calculate the total size of the group info. */
+    span_count = 0;
+    for (g = 0; g < group_count; g++)
+        span_count += groups[g].capture_count;
+
+    /* Allocate the storage for the group info in a single block. */
+    groups_copy = (RE_GroupData*)re_alloc(group_count * sizeof(RE_GroupData) +
+      span_count * sizeof(RE_GroupSpan));
+    if (!groups_copy)
+        return NULL;
+
+    /* The storage for the spans comes after the other group info. */
+    spans_copy = (RE_GroupSpan*)&groups_copy[group_count];
+
+    /* There's no need to initialise the spans info. */
+    memset(groups_copy, 0, group_count * sizeof(RE_GroupData));
+
+    offset = 0;
+    for (g = 0; g < group_count; g++) {
+        RE_GroupData* orig;
+        RE_GroupData* copy;
+
+        orig = &groups[g];
+        copy = &groups_copy[g];
+        copy->span = orig->span;
+
+        copy->captures = &spans_copy[offset];
+        offset += orig->capture_count;
+
+        if (orig->capture_count > 0) {
+            Py_MEMCPY(copy->captures, orig->captures, orig->capture_count *
+              sizeof(RE_GroupSpan));
+            copy->capture_capacity = orig->capture_count;
+            copy->capture_count = orig->capture_count;
+        }
+    }
+
+    return groups_copy;
+}
+
+/* Makes a copy of a MatchObject. */
+Py_LOCAL_INLINE(PyObject*) make_match_copy(MatchObject* self) {
+    MatchObject* match;
+
+    if (!self->string) {
+        /* The target string has been detached, so the MatchObject is now
+         * immutable.
+         */
+        Py_INCREF(self);
+        return (PyObject*)self;
+    }
+
+    /* Create a MatchObject. */
+    match = PyObject_NEW(MatchObject, &Match_Type);
+    if (!match)
+        return NULL;
+
+    Py_MEMCPY(match, self, sizeof(MatchObject));
+
+    Py_INCREF(match->string);
+    Py_INCREF(match->substring);
+    Py_INCREF(match->pattern);
+
+    /* Copy the groups to the MatchObject. */
+    if (self->group_count > 0) {
+        match->groups = copy_groups(self->groups, self->group_count);
+        if (!match->groups) {
+            Py_DECREF(match);
+            return NULL;
+        }
+    }
+
+    return (PyObject*)match;
+}
+
+/* Creates a new MatchObject. */
+Py_LOCAL_INLINE(PyObject*) pattern_new_match(PatternObject* pattern, RE_State*
+  state, int status) {
+    /* Create MatchObject (from state object). */
+    if (status > 0 || status == RE_ERROR_PARTIAL) {
+        MatchObject* match;
+
+        /* Create a MatchObject. */
+        match = PyObject_NEW(MatchObject, &Match_Type);
+        if (!match)
+            return NULL;
+
+        match->string = state->string;
+        match->substring = state->string;
+        match->substring_offset = 0;
+        match->pattern = pattern;
+        match->regs = NULL;
+
+        if (pattern->is_fuzzy) {
+            match->fuzzy_counts[RE_FUZZY_SUB] =
+              state->total_fuzzy_counts[RE_FUZZY_SUB];
+            match->fuzzy_counts[RE_FUZZY_INS] =
+              state->total_fuzzy_counts[RE_FUZZY_INS];
+            match->fuzzy_counts[RE_FUZZY_DEL] =
+              state->total_fuzzy_counts[RE_FUZZY_DEL];
+        } else
+            memset(match->fuzzy_counts, 0, sizeof(match->fuzzy_counts));
+
+        match->partial = status == RE_ERROR_PARTIAL;
+        Py_INCREF(match->string);
+        Py_INCREF(match->substring);
+        Py_INCREF(match->pattern);
+
+        /* Copy the groups to the MatchObject. */
+        if (pattern->public_group_count > 0) {
+            match->groups = copy_groups(state->groups,
+              pattern->public_group_count);
+            if (!match->groups) {
+                Py_DECREF(match);
+                return NULL;
+            }
+        } else
+            match->groups = NULL;
+
+        match->group_count = pattern->public_group_count;
+
+        match->pos = state->slice_start;
+        match->endpos = state->slice_end;
+
+        if (state->reverse) {
+            match->match_start = state->text_pos;
+            match->match_end = state->match_pos;
+        } else {
+            match->match_start = state->match_pos;
+            match->match_end = state->text_pos;
+        }
+
+        match->lastindex = state->lastindex;
+        match->lastgroup = state->lastgroup;
+
+        return (PyObject*)match;
+    } else if (status == 0) {
+        /* No match. */
+        Py_INCREF(Py_None);
+        return Py_None;
+    } else {
+        /* Internal error. */
+        set_error(status, NULL);
+        return NULL;
+    }
+}
+
+/* Gets the text of a capture group from a state. */
+Py_LOCAL_INLINE(PyObject*) state_get_group(RE_State* state, Py_ssize_t index,
+  PyObject* string, BOOL empty) {
+    RE_GroupData* group;
+    Py_ssize_t start;
+    Py_ssize_t end;
+
+    group = &state->groups[index - 1];
+
+    if (string != Py_None && index >= 1 && (size_t)index <=
+      state->pattern->public_group_count && group->capture_count > 0) {
+        start = group->span.start;
+        end = group->span.end;
+    } else {
+        if (empty)
+            /* Want an empty string. */
+            start = end = 0;
+        else {
+            Py_INCREF(Py_None);
+            return Py_None;
+        }
+    }
+
+    return get_slice(string, start, end);
+}
+
+/* Acquires the lock (mutex) on the state if there's one.
+ *
+ * It also increments the owner's refcount just to ensure that it won't be
+ * destroyed by another thread.
+ */
+Py_LOCAL_INLINE(void) acquire_state_lock(PyObject* owner, RE_SafeState*
+  safe_state) {
+    RE_State* state;
+
+    state = safe_state->re_state;
+
+    if (state->lock) {
+        /* In order to avoid deadlock we need to release the GIL while trying
+         * to acquire the lock.
+         */
+        Py_INCREF(owner);
+        if (!PyThread_acquire_lock(state->lock, 0)) {
+            release_GIL(safe_state);
+            PyThread_acquire_lock(state->lock, 1);
+            acquire_GIL(safe_state);
+        }
+    }
+}
+
+/* Releases the lock (mutex) on the state if there's one.
+ *
+ * It also decrements the owner's refcount, which was incremented when the lock
+ * was acquired.
+ */
+Py_LOCAL_INLINE(void) release_state_lock(PyObject* owner, RE_SafeState*
+  safe_state) {
+    RE_State* state;
+
+    state = safe_state->re_state;
+
+    if (state->lock) {
+        PyThread_release_lock(state->lock);
+        Py_DECREF(owner);
+    }
+}
+
+/* Implements the functionality of ScanObject's search and match methods. */
+Py_LOCAL_INLINE(PyObject*) scanner_search_or_match(ScannerObject* self, BOOL
+  search) {
+    RE_State* state;
+    RE_SafeState safe_state;
+    PyObject* match;
+
+    state = &self->state;
+
+    /* Initialise the "safe state" structure. */
+    safe_state.re_state = state;
+    safe_state.thread_state = NULL;
+
+    /* Acquire the state lock in case we're sharing the scanner object across
+     * threads.
+     */
+    acquire_state_lock((PyObject*)self, &safe_state);
+
+    if (self->status == RE_ERROR_FAILURE || self->status == RE_ERROR_PARTIAL) {
+        /* No or partial match. */
+        release_state_lock((PyObject*)self, &safe_state);
+        Py_INCREF(Py_None);
+        return Py_None;
+    } else if (self->status < 0) {
+        /* Internal error. */
+        release_state_lock((PyObject*)self, &safe_state);
+        set_error(self->status, NULL);
+        return NULL;
+    }
+
+    /* Look for another match. */
+    self->status = do_match(&safe_state, search);
+    if (self->status >= 0 || self->status == RE_ERROR_PARTIAL) {
+        /* Create the match object. */
+        match = pattern_new_match(self->pattern, state, self->status);
+
+        if (search && state->overlapped) {
+            /* Advance one character. */
+            Py_ssize_t step;
+
+            step = state->reverse ? -1 : 1;
+            state->text_pos = state->match_pos + step;
+            state->must_advance = FALSE;
+        } else
+            /* Continue from where we left off, but don't allow 2 contiguous
+             * zero-width matches.
+             */
+            state->must_advance = state->text_pos == state->match_pos;
+    } else
+        /* Internal error. */
+        match = NULL;
+
+    /* Release the state lock. */
+    release_state_lock((PyObject*)self, &safe_state);
+
+    return match;
+}
+
+/* ScannerObject's 'match' method. */
+static PyObject* scanner_match(ScannerObject* self, PyObject* unused) {
+    return scanner_search_or_match(self, FALSE);
+}
+
+/* ScannerObject's 'search' method. */
+static PyObject* scanner_search(ScannerObject* self, PyObject *unused) {
+    return scanner_search_or_match(self, TRUE);
+}
+
+/* ScannerObject's 'next' method. */
+static PyObject* scanner_next(PyObject* self) {
+    PyObject* match;
+
+    match = scanner_search((ScannerObject*)self, NULL);
+
+    if (match == Py_None) {
+        /* No match. */
+        Py_DECREF(Py_None);
+        PyErr_SetNone(PyExc_StopIteration);
+        return NULL;
+    }
+
+    return match;
+}
+
+/* Returns an iterator for a ScannerObject.
+ *
+ * The iterator is actually the ScannerObject itself.
+ */
+static PyObject* scanner_iter(PyObject* self) {
+    Py_INCREF(self);
+    return self;
+}
+
+/* Gets the next result from a scanner iterator. */
+static PyObject* scanner_iternext(PyObject* self) {
+    PyObject* match;
+
+    match = scanner_search((ScannerObject*)self, NULL);
+
+    if (match == Py_None) {
+        /* No match. */
+        Py_DECREF(match);
+        return NULL;
+    }
+
+    return match;
+}
+
+/* Makes a copy of a ScannerObject.
+ *
+ * It actually doesn't make a copy, just returns the original object.
+ */
+Py_LOCAL_INLINE(PyObject*) make_scanner_copy(ScannerObject* self) {
+    Py_INCREF(self);
+    return (PyObject*)self;
+}
+
+/* ScannerObject's '__copy__' method. */
+static PyObject* scanner_copy(ScannerObject* self, PyObject *unused) {
+    return make_scanner_copy(self);
+}
+
+/* ScannerObject's '__deepcopy__' method. */
+static PyObject* scanner_deepcopy(ScannerObject* self, PyObject* memo) {
+    return make_scanner_copy(self);
+}
+
+/* The documentation of a ScannerObject. */
+PyDoc_STRVAR(scanner_match_doc,
+    "match() --> MatchObject or None.\n\
+    Match at the current position in the string.");
+
+PyDoc_STRVAR(scanner_search_doc,
+    "search() --> MatchObject or None.\n\
+    Search from the current position in the string.");
+
+/* ScannerObject's methods. */
+static PyMethodDef scanner_methods[] = {
+    {"next", (PyCFunction)scanner_next, METH_NOARGS},
+    {"match", (PyCFunction)scanner_match, METH_NOARGS, scanner_match_doc},
+    {"search", (PyCFunction)scanner_search, METH_NOARGS, scanner_search_doc},
+    {"__copy__", (PyCFunction)scanner_copy, METH_NOARGS},
+    {"__deepcopy__", (PyCFunction)scanner_deepcopy, METH_O},
+    {NULL, NULL}
+};
+
+PyDoc_STRVAR(scanner_doc, "Scanner object");
+
+/* Deallocates a ScannerObject. */
+static void scanner_dealloc(PyObject* self_) {
+    ScannerObject* self;
+
+    self = (ScannerObject*)self_;
+
+    state_fini(&self->state);
+    Py_DECREF(self->pattern);
+    PyObject_DEL(self);
+}
+
+static PyMemberDef scanner_members[] = {
+    {"pattern", T_OBJECT, offsetof(ScannerObject, pattern), READONLY,
+      "The regex object that produced this scanner object."},
+    {NULL} /* Sentinel */
+};
+
+static PyTypeObject Scanner_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "_" RE_MODULE "." "Scanner",
+    sizeof(ScannerObject)
+};
+
+/* Decodes a 'concurrent' argument. */
+Py_LOCAL_INLINE(int) decode_concurrent(PyObject* concurrent) {
+    Py_ssize_t value;
+
+    if (concurrent == Py_None)
+        return RE_CONC_DEFAULT;
+
+    value = PyLong_AsLong(concurrent);
+    if (value == -1 && PyErr_Occurred()) {
+        set_error(RE_ERROR_CONCURRENT, NULL);
+        return -1;
+    }
+
+    return value ? RE_CONC_YES : RE_CONC_NO;
+}
+
+/* Decodes a 'partial' argument. */
+Py_LOCAL_INLINE(BOOL) decode_partial(PyObject* partial) {
+    Py_ssize_t value;
+
+    if (partial == Py_False)
+        return FALSE;
+
+    if (partial == Py_True)
+        return TRUE;
+
+    value = PyLong_AsLong(partial);
+    if (value == -1 && PyErr_Occurred()) {
+        PyErr_Clear();
+        return TRUE;
+    }
+
+    return value != 0;
+}
+
+/* Creates a new ScannerObject. */
+static PyObject* pattern_scanner(PatternObject* pattern, PyObject* args,
+  PyObject* kwargs) {
+    /* Create search state object. */
+    ScannerObject* self;
+    Py_ssize_t start;
+    Py_ssize_t end;
+    int conc;
+    BOOL part;
+
+    PyObject* string;
+    PyObject* pos = Py_None;
+    PyObject* endpos = Py_None;
+    Py_ssize_t overlapped = FALSE;
+    PyObject* concurrent = Py_None;
+    PyObject* partial = Py_False;
+    static char* kwlist[] = { "string", "pos", "endpos", "overlapped",
+      "concurrent", "partial", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOnOO:scanner", kwlist,
+      &string, &pos, &endpos, &overlapped, &concurrent, &partial))
+        return NULL;
+
+    start = as_string_index(pos, 0);
+    if (start == -1 && PyErr_Occurred())
+        return NULL;
+
+    end = as_string_index(endpos, PY_SSIZE_T_MAX);
+    if (end == -1 && PyErr_Occurred())
+        return NULL;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    part = decode_partial(partial);
+
+    /* Create a scanner object. */
+    self = PyObject_NEW(ScannerObject, &Scanner_Type);
+    if (!self)
+        return NULL;
+
+    self->pattern = pattern;
+    Py_INCREF(self->pattern);
+
+    /* The MatchObject, and therefore repeated captures, will be visible. */
+    if (!state_init(&self->state, pattern, string, start, end, overlapped != 0,
+      conc, part, TRUE, TRUE, FALSE)) {
+        PyObject_DEL(self);
+        return NULL;
+    }
+
+    self->status = RE_ERROR_SUCCESS;
+
+    return (PyObject*) self;
+}
+
+/* Performs the split for the SplitterObject. */
+Py_LOCAL_INLINE(PyObject*) next_split_part(SplitterObject* self) {
+    RE_State* state;
+    RE_SafeState safe_state;
+    PyObject* result = NULL; /* Initialise to stop compiler warning. */
+
+    state = &self->state;
+
+    /* Initialise the "safe state" structure. */
+    safe_state.re_state = state;
+    safe_state.thread_state = NULL;
+
+    /* Acquire the state lock in case we're sharing the splitter object across
+     * threads.
+     */
+    acquire_state_lock((PyObject*)self, &safe_state);
+
+    if (self->status == RE_ERROR_FAILURE || self->status == RE_ERROR_PARTIAL) {
+        /* Finished. */
+        release_state_lock((PyObject*)self, &safe_state);
+        result = Py_False;
+        Py_INCREF(result);
+        return result;
+    } else if (self->status < 0) {
+        /* Internal error. */
+        release_state_lock((PyObject*)self, &safe_state);
+        set_error(self->status, NULL);
+        return NULL;
+    }
+
+    if (self->index == 0) {
+        if (self->split_count < self->maxsplit) {
+            Py_ssize_t step;
+            Py_ssize_t end_pos;
+
+            if (state->reverse) {
+                step = -1;
+                end_pos = state->slice_start;
+            } else {
+                step = 1;
+                end_pos = state->slice_end;
+            }
+
+retry:
+            self->status = do_match(&safe_state, TRUE);
+            if (self->status < 0)
+                goto error;
+
+            if (self->status == RE_ERROR_SUCCESS) {
+                if (state->version_0) {
+                    /* Version 0 behaviour is to advance one character if the
+                     * split was zero-width. Unfortunately, this can give an
+                     * incorrect result. GvR wants this behaviour to be
+                     * retained so as not to break any existing software which
+                     * might rely on it.
+                     */
+                    if (state->text_pos == state->match_pos) {
+                        if (self->last_pos == end_pos)
+                            goto no_match;
+
+                        /* Advance one character. */
+                        state->text_pos += step;
+                        state->must_advance = FALSE;
+                        goto retry;
+                    }
+                }
+
+                ++self->split_count;
+
+                /* Get segment before this match. */
+                if (state->reverse)
+                    result = get_slice(state->string, state->match_pos,
+                      self->last_pos);
+                else
+                    result = get_slice(state->string, self->last_pos,
+                      state->match_pos);
+                if (!result)
+                    goto error;
+
+                self->last_pos = state->text_pos;
+
+                /* Version 0 behaviour is to advance one character if the match
+                 * was zero-width. Unfortunately, this can give an incorrect
+                 * result. GvR wants this behaviour to be retained so as not to
+                 * break any existing software which might rely on it.
+                 */
+                if (state->version_0) {
+                    if (state->text_pos == state->match_pos)
+                        /* Advance one character. */
+                        state->text_pos += step;
+
+                    state->must_advance = FALSE;
+                } else
+                    /* Continue from where we left off, but don't allow a
+                     * contiguous zero-width match.
+                     */
+                    state->must_advance = TRUE;
+            }
+        } else
+            goto no_match;
+
+        if (self->status == RE_ERROR_FAILURE || self->status ==
+          RE_ERROR_PARTIAL) {
+no_match:
+            /* Get segment following last match (even if empty). */
+            if (state->reverse)
+                result = get_slice(state->string, 0, self->last_pos);
+            else
+                result = get_slice(state->string, self->last_pos,
+                  state->text_length);
+            if (!result)
+                goto error;
+        }
+    } else {
+        /* Add group. */
+        result = state_get_group(state, self->index, state->string, FALSE);
+        if (!result)
+            goto error;
+    }
+
+    ++self->index;
+    if ((size_t)self->index > state->pattern->public_group_count)
+        self->index = 0;
+
+    /* Release the state lock. */
+    release_state_lock((PyObject*)self, &safe_state);
+
+    return result;
+
+error:
+    /* Release the state lock. */
+    release_state_lock((PyObject*)self, &safe_state);
+
+    return NULL;
+}
+
+/* SplitterObject's 'split' method. */
+static PyObject* splitter_split(SplitterObject* self, PyObject *unused) {
+    PyObject* result;
+
+    result = next_split_part(self);
+
+    if (result == Py_False) {
+        /* The sentinel. */
+        Py_DECREF(Py_False);
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+
+    return result;
+}
+
+/* SplitterObject's 'next' method. */
+static PyObject* splitter_next(PyObject* self) {
+    PyObject* result;
+
+    result = next_split_part((SplitterObject*)self);
+
+    if (result == Py_False) {
+        /* No match. */
+        Py_DECREF(Py_False);
+        PyErr_SetNone(PyExc_StopIteration);
+        return NULL;
+    }
+
+    return result;
+}
+
+/* Returns an iterator for a SplitterObject.
+ *
+ * The iterator is actually the SplitterObject itself.
+ */
+static PyObject* splitter_iter(PyObject* self) {
+    Py_INCREF(self);
+    return self;
+}
+
+/* Gets the next result from a splitter iterator. */
+static PyObject* splitter_iternext(PyObject* self) {
+    PyObject* result;
+
+    result = next_split_part((SplitterObject*)self);
+
+    if (result == Py_False) {
+        /* No match. */
+        Py_DECREF(result);
+        return NULL;
+    }
+
+    return result;
+}
+
+/* Makes a copy of a SplitterObject.
+ *
+ * It actually doesn't make a copy, just returns the original object.
+ */
+Py_LOCAL_INLINE(PyObject*) make_splitter_copy(SplitterObject* self) {
+    Py_INCREF(self);
+    return (PyObject*)self;
+}
+
+/* SplitterObject's '__copy__' method. */
+static PyObject* splitter_copy(SplitterObject* self, PyObject *unused) {
+    return make_splitter_copy(self);
+}
+
+/* SplitterObject's '__deepcopy__' method. */
+static PyObject* splitter_deepcopy(SplitterObject* self, PyObject* memo) {
+    return make_splitter_copy(self);
+}
+
+/* The documentation of a SplitterObject. */
+PyDoc_STRVAR(splitter_split_doc,
+    "split() --> string or None.\n\
+    Return the next part of the split string.");
+
+/* SplitterObject's methods. */
+static PyMethodDef splitter_methods[] = {
+    {"next", (PyCFunction)splitter_next, METH_NOARGS},
+    {"split", (PyCFunction)splitter_split, METH_NOARGS, splitter_split_doc},
+    {"__copy__", (PyCFunction)splitter_copy, METH_NOARGS},
+    {"__deepcopy__", (PyCFunction)splitter_deepcopy, METH_O},
+    {NULL, NULL}
+};
+
+PyDoc_STRVAR(splitter_doc, "Splitter object");
+
+/* Deallocates a SplitterObject. */
+static void splitter_dealloc(PyObject* self_) {
+    SplitterObject* self;
+
+    self = (SplitterObject*)self_;
+
+    state_fini(&self->state);
+    Py_DECREF(self->pattern);
+    PyObject_DEL(self);
+}
+#if PY_VERSION_HEX >= 0x02060000
+
+/* Converts a captures index to an integer.
+ *
+ * A negative capture index in 'expandf' and 'subf' is passed as a string
+ * because negative indexes are not supported by 'str.format'.
+ */
+Py_LOCAL_INLINE(Py_ssize_t) index_to_integer(PyObject* item) {
+    Py_ssize_t value;
+
+    value = PyInt_AsSsize_t(item);
+    if (value != -1 || !PyErr_Occurred())
+        return value;
+
+    PyErr_Clear();
+
+    value = PyLong_AsLong(item);
+    if (value != -1 || !PyErr_Occurred())
+        return value;
+
+    PyErr_Clear();
+
+    /* Is the index a string representation of an integer? */
+    if (PyUnicode_Check(item)) {
+        PyObject* int_obj;
+        Py_UNICODE* characters;
+        Py_ssize_t length;
+
+        characters = (Py_UNICODE*)PyUnicode_AS_DATA(item);
+        length = PyUnicode_GET_SIZE(item);
+        int_obj = PyLong_FromUnicode(characters, length, 0);
+        if (!int_obj)
+            goto error;
+
+        value = PyLong_AsLong(int_obj);
+        Py_DECREF(int_obj);
+        if (!PyErr_Occurred())
+            return value;
+    } else if (PyString_Check(item)) {
+        char* characters;
+        PyObject* int_obj;
+
+        characters = PyString_AsString(item);
+        int_obj = PyLong_FromString(characters, NULL, 0);
+        if (!int_obj)
+            goto error;
+
+        value = PyLong_AsLong(int_obj);
+        Py_DECREF(int_obj);
+        if (!PyErr_Occurred())
+            return value;
+    }
+
+error:
+    PyErr_Format(PyExc_TypeError, "list indices must be integers, not %.200s",
+      item->ob_type->tp_name);
+
+    return -1;
+}
+
+/* CaptureObject's length method. */
+Py_LOCAL_INLINE(Py_ssize_t) capture_length(CaptureObject* self) {
+    MatchObject* match;
+    RE_GroupData* group;
+
+    if (self->group_index == 0)
+        return 1;
+
+    match = *self->match_indirect;
+    group = &match->groups[self->group_index - 1];
+
+    return (Py_ssize_t)group->capture_count;
+}
+
+/* CaptureObject's '__getitem__' method. */
+static PyObject* capture_getitem(CaptureObject* self, PyObject* item) {
+    Py_ssize_t index;
+    MatchObject* match;
+    Py_ssize_t start;
+    Py_ssize_t end;
+
+    index = index_to_integer(item);
+    if (index == -1 && PyErr_Occurred())
+        return NULL;
+
+    match = *self->match_indirect;
+
+    if (self->group_index == 0) {
+        if (index < 0)
+            index += 1;
+
+        if (index != 0) {
+            PyErr_SetString(PyExc_IndexError, "list index out of range");
+            return NULL;
+        }
+
+        start = match->match_start;
+        end = match->match_end;
+    } else {
+        RE_GroupData* group;
+        RE_GroupSpan* span;
+
+        group = &match->groups[self->group_index - 1];
+
+        if (index < 0)
+            index += group->capture_count;
+
+        if (index < 0 || index >= (Py_ssize_t)group->capture_count) {
+            PyErr_SetString(PyExc_IndexError, "list index out of range");
+            return NULL;
+        }
+
+        span = &group->captures[index];
+
+        start = span->start;
+        end = span->end;
+    }
+
+    return get_slice(match->substring, start - match->substring_offset, end -
+      match->substring_offset);
+}
+
+static PyMappingMethods capture_as_mapping = {
+    (lenfunc)capture_length, /* mp_length */
+    (binaryfunc)capture_getitem, /* mp_subscript */
+    0, /* mp_ass_subscript */
+};
+
+/* CaptureObject's methods. */
+static PyMethodDef capture_methods[] = {
+    {"__getitem__", (PyCFunction)capture_getitem, METH_O|METH_COEXIST},
+    {NULL, NULL}
+};
+
+/* Deallocates a CaptureObject. */
+static void capture_dealloc(PyObject* self_) {
+    CaptureObject* self;
+
+    self = (CaptureObject*)self_;
+    PyObject_DEL(self);
+}
+
+/* CaptureObject's 'str' method. */
+static PyObject* capture_str(PyObject* self_) {
+    CaptureObject* self;
+    MatchObject* match;
+
+    self = (CaptureObject*)self_;
+    match = *self->match_indirect;
+
+    return match_get_group_by_index(match, self->group_index, Py_None);
+}
+#endif
+
+static PyMemberDef splitter_members[] = {
+    {"pattern", T_OBJECT, offsetof(SplitterObject, pattern), READONLY,
+      "The regex object that produced this splitter object."},
+    {NULL} /* Sentinel */
+};
+
+static PyTypeObject Splitter_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "_" RE_MODULE "." "Splitter",
+    sizeof(SplitterObject)
+};
+
+/* Creates a new SplitterObject. */
+Py_LOCAL_INLINE(PyObject*) pattern_splitter(PatternObject* pattern, PyObject*
+  args, PyObject* kwargs) {
+    /* Create split state object. */
+    int conc;
+    SplitterObject* self;
+    RE_State* state;
+
+    PyObject* string;
+    Py_ssize_t maxsplit = 0;
+    PyObject* concurrent = Py_None;
+    static char* kwlist[] = { "string", "maxsplit", "concurrent", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|nO:splitter", kwlist,
+      &string, &maxsplit, &concurrent))
+        return NULL;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    /* Create a splitter object. */
+    self = PyObject_NEW(SplitterObject, &Splitter_Type);
+    if (!self)
+        return NULL;
+
+    self->pattern = pattern;
+    Py_INCREF(self->pattern);
+
+    if (maxsplit == 0)
+        maxsplit = PY_SSIZE_T_MAX;
+
+    state = &self->state;
+
+    /* The MatchObject, and therefore repeated captures, will not be visible.
+     */
+    if (!state_init(state, pattern, string, 0, PY_SSIZE_T_MAX, FALSE, conc,
+      FALSE, TRUE, FALSE, FALSE)) {
+        PyObject_DEL(self);
+        return NULL;
+    }
+
+    self->maxsplit = maxsplit;
+    self->last_pos = state->reverse ? state->text_length : 0;
+    self->split_count = 0;
+    self->index = 0;
+    self->status = 1;
+
+    return (PyObject*) self;
+}
+
+/* Implements the functionality of PatternObject's search and match methods. */
+Py_LOCAL_INLINE(PyObject*) pattern_search_or_match(PatternObject* self,
+  PyObject* args, PyObject* kwargs, char* args_desc, BOOL search, BOOL
+  match_all) {
+    Py_ssize_t start;
+    Py_ssize_t end;
+    int conc;
+    BOOL part;
+    RE_State state;
+    RE_SafeState safe_state;
+    int status;
+    PyObject* match;
+
+    PyObject* string;
+    PyObject* pos = Py_None;
+    PyObject* endpos = Py_None;
+    PyObject* concurrent = Py_None;
+    PyObject* partial = Py_False;
+    static char* kwlist[] = { "string", "pos", "endpos", "concurrent",
+      "partial", NULL };
+    /* When working with a short string, such as a line from a file, the
+     * relative cost of PyArg_ParseTupleAndKeywords can be significant, and
+     * it's worth not using it when there are only positional arguments.
+     */
+    Py_ssize_t arg_count;
+    if (args && !kwargs && PyTuple_CheckExact(args))
+        arg_count = PyTuple_GET_SIZE(args);
+    else
+        arg_count = -1;
+
+    if (1 <= arg_count && arg_count <= 5) {
+        /* PyTuple_GET_ITEM borrows the reference. */
+        string = PyTuple_GET_ITEM(args, 0);
+        if (arg_count >= 2)
+            pos = PyTuple_GET_ITEM(args, 1);
+        if (arg_count >= 3)
+            endpos = PyTuple_GET_ITEM(args, 2);
+        if (arg_count >= 4)
+            concurrent = PyTuple_GET_ITEM(args, 3);
+        if (arg_count >= 5)
+            partial = PyTuple_GET_ITEM(args, 4);
+    } else if (!PyArg_ParseTupleAndKeywords(args, kwargs, args_desc, kwlist,
+      &string, &pos, &endpos, &concurrent, &partial))
+        return NULL;
+
+    start = as_string_index(pos, 0);
+    if (start == -1 && PyErr_Occurred())
+        return NULL;
+
+    end = as_string_index(endpos, PY_SSIZE_T_MAX);
+    if (end == -1 && PyErr_Occurred())
+        return NULL;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    part = decode_partial(partial);
+
+    /* The MatchObject, and therefore repeated captures, will be visible. */
+    if (!state_init(&state, self, string, start, end, FALSE, conc, part, FALSE,
+      TRUE, match_all))
+        return NULL;
+
+    /* Initialise the "safe state" structure. */
+    safe_state.re_state = &state;
+    safe_state.thread_state = NULL;
+
+    status = do_match(&safe_state, search);
+
+    if (status >= 0 || status == RE_ERROR_PARTIAL)
+        /* Create the match object. */
+        match = pattern_new_match(self, &state, status);
+    else
+        match = NULL;
+
+    state_fini(&state);
+
+    return match;
+}
+
+/* PatternObject's 'match' method. */
+static PyObject* pattern_match(PatternObject* self, PyObject* args, PyObject*
+  kwargs) {
+    return pattern_search_or_match(self, args, kwargs, "O|OOOO:match", FALSE,
+      FALSE);
+}
+
+/* PatternObject's 'fullmatch' method. */
+static PyObject* pattern_fullmatch(PatternObject* self, PyObject* args,
+  PyObject* kwargs) {
+    return pattern_search_or_match(self, args, kwargs, "O|OOOO:fullmatch",
+      FALSE, TRUE);
+}
+
+/* PatternObject's 'search' method. */
+static PyObject* pattern_search(PatternObject* self, PyObject* args, PyObject*
+  kwargs) {
+    return pattern_search_or_match(self, args, kwargs, "O|OOOO:search", TRUE,
+      FALSE);
+}
+
+/* Gets the limits of the matching. */
+Py_LOCAL_INLINE(BOOL) get_limits(PyObject* pos, PyObject* endpos, Py_ssize_t
+  length, Py_ssize_t* start, Py_ssize_t* end) {
+    Py_ssize_t s;
+    Py_ssize_t e;
+
+    s = as_string_index(pos, 0);
+    if (s == -1 && PyErr_Occurred())
+        return FALSE;
+
+    e = as_string_index(endpos, PY_SSIZE_T_MAX);
+    if (e == -1 && PyErr_Occurred())
+        return FALSE;
+
+    /* Adjust boundaries. */
+    if (s < 0)
+        s += length;
+    if (s < 0)
+        s = 0;
+    else if (s > length)
+        s = length;
+
+    if (e < 0)
+        e += length;
+    if (e < 0)
+        e = 0;
+    else if (e > length)
+        e = length;
+
+    *start = s;
+    *end = e;
+
+    return TRUE;
+}
+
+/* Gets a replacement item from the replacement list.
+ *
+ * The replacement item could be a string literal or a group.
+ *
+ * It can return None to represent an empty string.
+ */
+Py_LOCAL_INLINE(PyObject*) get_sub_replacement(PyObject* item, PyObject*
+  string, RE_State* state, size_t group_count) {
+    Py_ssize_t index;
+
+    if (PyUnicode_CheckExact(item) || PyString_CheckExact(item)) {
+        /* It's a literal, which can be added directly to the list. */
+        Py_INCREF(item);
+        return item;
+    }
+
+    /* Is it a group reference? */
+    index = as_group_index(item);
+    if (index == -1 && PyErr_Occurred()) {
+        /* Not a group either! */
+        set_error(RE_ERROR_REPLACEMENT, NULL);
+        return NULL;
+    }
+
+    if (index == 0) {
+        /* The entire matched portion of the string. */
+        if (state->match_pos == state->text_pos) {
+            /* Return None for "". */
+            Py_INCREF(Py_None);
+            return Py_None;
+        }
+
+        if (state->reverse)
+            return get_slice(string, state->text_pos, state->match_pos);
+        else
+            return get_slice(string, state->match_pos, state->text_pos);
+    } else if (1 <= index && (size_t)index <= group_count) {
+        /* A group. */
+        RE_GroupData* group;
+
+        group = &state->groups[index - 1];
+
+        if (group->capture_count == 0 && group->span.start != group->span.end)
+          {
+            /* The group didn't match or is "", so return None for "". */
+            Py_INCREF(Py_None);
+            return Py_None;
+        }
+
+        return get_slice(string, group->span.start, group->span.end);
+    } else {
+        /* No such group. */
+        set_error(RE_ERROR_INVALID_GROUP_REF, NULL);
+        return NULL;
+    }
+}
+
+/* PatternObject's 'subx' method. */
+Py_LOCAL_INLINE(PyObject*) pattern_subx(PatternObject* self, PyObject*
+  str_template, PyObject* string, Py_ssize_t maxsub, int sub_type, PyObject*
+  pos, PyObject* endpos, int concurrent) {
+    RE_StringInfo str_info;
+    Py_ssize_t start;
+    Py_ssize_t end;
+    BOOL is_callable = FALSE;
+    PyObject* replacement = NULL;
+    BOOL is_literal = FALSE;
+#if PY_VERSION_HEX >= 0x02060000
+    BOOL is_format = FALSE;
+#endif
+    BOOL is_template = FALSE;
+    RE_State state;
+    RE_SafeState safe_state;
+    JoinInfo join_info;
+    Py_ssize_t sub_count;
+    Py_ssize_t last_pos;
+    Py_ssize_t step;
+    PyObject* item;
+    MatchObject* match;
+#if PY_VERSION_HEX >= 0x02060000
+    BOOL built_capture = FALSE;
+#endif
+    PyObject* args;
+    PyObject* kwargs;
+    Py_ssize_t end_pos;
+
+    /* Get the string. */
+    if (!get_string(string, &str_info))
+        return NULL;
+
+    /* Get the limits of the search. */
+    if (!get_limits(pos, endpos, str_info.length, &start, &end)) {
+#if PY_VERSION_HEX >= 0x02060000
+        release_buffer(&str_info);
+
+#endif
+        return NULL;
+    }
+
+    /* If the pattern is too long for the string, then take a shortcut, unless
+     * it's a fuzzy pattern.
+     */
+    if (!self->is_fuzzy && self->min_width > end - start) {
+        PyObject* result;
+
+        Py_INCREF(string);
+
+        if (sub_type & RE_SUBN)
+            result = Py_BuildValue("Nn", string, 0);
+        else
+            result = string;
+
+#if PY_VERSION_HEX >= 0x02060000
+        release_buffer(&str_info);
+
+#endif
+        return result;
+    }
+
+    if (maxsub == 0)
+        maxsub = PY_SSIZE_T_MAX;
+
+    /* sub/subn takes either a function or a string template. */
+    if (PyCallable_Check(str_template)) {
+        /* It's callable. */
+        is_callable = TRUE;
+
+        replacement = str_template;
+        Py_INCREF(replacement);
+#if PY_VERSION_HEX >= 0x02060000
+    } else if (sub_type & RE_SUBF) {
+        /* Is it a literal format?
+         *
+         * To keep it simple we'll say that a literal is a string which can be
+         * used as-is, so no placeholders.
+         */
+        Py_ssize_t literal_length;
+
+        literal_length = check_replacement_string(str_template, '{');
+        if (literal_length > 0) {
+            /* It's a literal. */
+            is_literal = TRUE;
+
+            replacement = str_template;
+            Py_INCREF(replacement);
+        } else if (literal_length < 0) {
+            /* It isn't a literal, so get the 'format' method. */
+            is_format = TRUE;
+
+            replacement = PyObject_GetAttrString(str_template, "format");
+            if (!replacement) {
+                release_buffer(&str_info);
+                return NULL;
+            }
+        }
+#endif
+    } else {
+        /* Is it a literal template?
+         *
+         * To keep it simple we'll say that a literal is a string which can be
+         * used as-is, so no backslashes.
+         */
+        Py_ssize_t literal_length;
+
+        literal_length = check_replacement_string(str_template, '\\');
+        if (literal_length > 0) {
+            /* It's a literal. */
+            is_literal = TRUE;
+
+            replacement = str_template;
+            Py_INCREF(replacement);
+        } else if (literal_length < 0 ) {
+            /* It isn't a literal, so hand it over to the template compiler. */
+            is_template = TRUE;
+
+            replacement = call(RE_MODULE, "_compile_replacement_helper",
+              PyTuple_Pack(2, self, str_template));
+            if (!replacement) {
+#if PY_VERSION_HEX >= 0x02060000
+                release_buffer(&str_info);
+
+#endif
+                return NULL;
+            }
+        }
+    }
+
+    /* The MatchObject, and therefore repeated captures, will be visible only
+     * if the replacement is callable or subf is used.
+     */
+#if PY_VERSION_HEX >= 0x02060000
+    if (!state_init_2(&state, self, string, &str_info, start, end, FALSE,
+      concurrent, FALSE, FALSE, is_callable || (sub_type & RE_SUBF) != 0,
+      FALSE)) {
+        release_buffer(&str_info);
+
+#else
+    if (!state_init_2(&state, self, string, &str_info, start, end, FALSE,
+      concurrent, FALSE, FALSE, is_callable, FALSE)) {
+#endif
+        Py_XDECREF(replacement);
+        return NULL;
+    }
+
+    /* Initialise the "safe state" structure. */
+    safe_state.re_state = &state;
+    safe_state.thread_state = NULL;
+
+    init_join_list(&join_info, state.reverse, PyUnicode_Check(string));
+
+    sub_count = 0;
+    last_pos = state.reverse ? state.text_length : 0;
+    step = state.reverse ? -1 : 1;
+    while (sub_count < maxsub) {
+        int status;
+
+        status = do_match(&safe_state, TRUE);
+        if (status < 0)
+            goto error;
+
+        if (status == 0)
+            break;
+
+        /* Append the segment before this match. */
+        if (state.match_pos != last_pos) {
+            if (state.reverse)
+                item = get_slice(string, state.match_pos, last_pos);
+            else
+                item = get_slice(string, last_pos, state.match_pos);
+            if (!item)
+                goto error;
+
+            /* Add to the list. */
+            status = add_to_join_list(&join_info, item);
+            Py_DECREF(item);
+            if (status < 0)
+                goto error;
+        }
+
+        /* Add this match. */
+        if (is_literal) {
+            /* The replacement is a literal string. */
+            status = add_to_join_list(&join_info, replacement);
+            if (status < 0)
+                goto error;
+#if PY_VERSION_HEX >= 0x02060000
+        } else if (is_format) {
+            /* The replacement is a format string. */
+            size_t g;
+
+            /* We need to create the arguments for the 'format' method. We'll
+             * start by creating a MatchObject.
+             */
+            match = (MatchObject*)pattern_new_match(self, &state, 1);
+            if (!match)
+                goto error;
+
+            /* We'll build the args and kwargs the first time. They'll be using
+             * capture objects which refer to the match object indirectly; this
+             * means that args and kwargs can be reused with different match
+             * objects.
+             */
+            if (!built_capture) {
+                /* The args are a tuple of the capture group matches. */
+                args = PyTuple_New(match->group_count + 1);
+                if (!args) {
+                    Py_DECREF(match);
+                    goto error;
+                }
+
+                for (g = 0; g < match->group_count + 1; g++)
+                    /* PyTuple_SetItem borrows the reference. */
+                    PyTuple_SetItem(args, (Py_ssize_t)g,
+                      make_capture_object(&match, (Py_ssize_t)g));
+
+                /* The kwargs are a dict of the named capture group matches. */
+                kwargs = make_capture_dict(match, &match);
+                if (!kwargs) {
+                    Py_DECREF(args);
+                    Py_DECREF(match);
+                    goto error;
+                }
+
+                built_capture = TRUE;
+            }
+
+            /* Call the 'format' method. */
+            item = PyObject_Call(replacement, args, kwargs);
+
+            Py_DECREF(match);
+            if (!item)
+                goto error;
+
+            /* Add the result to the list. */
+            status = add_to_join_list(&join_info, item);
+            Py_DECREF(item);
+            if (status < 0)
+                goto error;
+#endif
+        } else if (is_template) {
+            /* The replacement is a list template. */
+            Py_ssize_t count;
+            Py_ssize_t index;
+            Py_ssize_t step;
+
+            /* Add each part of the template to the list. */
+            count = PyList_GET_SIZE(replacement);
+            if (join_info.reversed) {
+                /* We're searching backwards, so we'll be reversing the list
+                 * when it's complete. Therefore, we need to add the items of
+                 * the template in reverse order for them to be in the correct
+                 * order after the reversal.
+                 */
+                index = count - 1;
+                step = -1;
+            } else {
+                /* We're searching forwards. */
+                index = 0;
+                step = 1;
+            }
+
+            while (count > 0) {
+                PyObject* item;
+                PyObject* str_item;
+
+                /* PyList_GET_ITEM borrows a reference. */
+                item = PyList_GET_ITEM(replacement, index);
+                str_item = get_sub_replacement(item, string, &state,
+                  self->public_group_count);
+                if (!str_item)
+                    goto error;
+
+                /* Add the result to the list. */
+                if (str_item == Py_None)
+                    /* None for "". */
+                    Py_DECREF(str_item);
+                else {
+                    status = add_to_join_list(&join_info, str_item);
+                    Py_DECREF(str_item);
+                    if (status < 0)
+                        goto error;
+                }
+
+                --count;
+                index += step;
+            }
+        } else if (is_callable) {
+            /* Pass a MatchObject to the replacement function. */
+            PyObject* match;
+            PyObject* args;
+
+            /* We need to create a MatchObject to pass to the replacement
+             * function.
+             */
+            match = pattern_new_match(self, &state, 1);
+            if (!match)
+                goto error;
+
+            /* The args for the replacement function. */
+            args = PyTuple_Pack(1, match);
+            if (!args) {
+                Py_DECREF(match);
+                goto error;
+            }
+
+            /* Call the replacement function. */
+            item = PyObject_CallObject(replacement, args);
+            Py_DECREF(args);
+            Py_DECREF(match);
+            if (!item)
+                goto error;
+
+            /* Add the result to the list. */
+            status = add_to_join_list(&join_info, item);
+            Py_DECREF(item);
+            if (status < 0)
+                goto error;
+        }
+
+        ++sub_count;
+
+        last_pos = state.text_pos;
+
+        if (state.version_0) {
+            /* Always advance after a zero-width match. */
+            if (state.match_pos == state.text_pos) {
+                state.text_pos += step;
+                state.must_advance = FALSE;
+            } else
+                state.must_advance = TRUE;
+        } else
+            /* Continue from where we left off, but don't allow a contiguous
+             * zero-width match.
+             */
+            state.must_advance = state.match_pos == state.text_pos;
+    }
+
+    /* Get the segment following the last match. We use 'length' instead of
+     * 'text_length' because the latter is truncated to 'slice_end', a
+     * documented idiosyncracy of the 're' module.
+     */
+    end_pos = state.reverse ? 0 : str_info.length;
+    if (last_pos != end_pos) {
+        int status;
+
+        /* The segment is part of the original string. */
+        if (state.reverse)
+            item = get_slice(string, 0, last_pos);
+        else
+            item = get_slice(string, last_pos, str_info.length);
+        if (!item)
+            goto error;
+
+        status = add_to_join_list(&join_info, item);
+        Py_DECREF(item);
+        if (status < 0)
+            goto error;
+    }
+
+    Py_XDECREF(replacement);
+
+    /* Convert the list to a single string (also cleans up join_info). */
+    item = join_list_info(&join_info);
+
+    state_fini(&state);
+
+#if PY_VERSION_HEX >= 0x02060000
+    if (built_capture) {
+        Py_DECREF(kwargs);
+        Py_DECREF(args);
+    }
+
+#endif
+    if (!item)
+        return NULL;
+
+    if (sub_type & RE_SUBN)
+        return Py_BuildValue("Nn", item, sub_count);
+
+    return item;
+
+error:
+#if PY_VERSION_HEX >= 0x02060000
+    if (built_capture) {
+        Py_DECREF(kwargs);
+        Py_DECREF(args);
+    }
+
+#endif
+    clear_join_list(&join_info);
+    state_fini(&state);
+    Py_XDECREF(replacement);
+    return NULL;
+}
+
+/* PatternObject's 'sub' method. */
+static PyObject* pattern_sub(PatternObject* self, PyObject* args, PyObject*
+  kwargs) {
+    int conc;
+
+    PyObject* replacement;
+    PyObject* string;
+    Py_ssize_t count = 0;
+    PyObject* pos = Py_None;
+    PyObject* endpos = Py_None;
+    PyObject* concurrent = Py_None;
+    static char* kwlist[] = { "repl", "string", "count", "pos", "endpos",
+      "concurrent", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|nOOO:sub", kwlist,
+      &replacement, &string, &count, &pos, &endpos, &concurrent))
+        return NULL;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    return pattern_subx(self, replacement, string, count, RE_SUB, pos, endpos,
+      conc);
+}
+
+#if PY_VERSION_HEX >= 0x02060000
+/* PatternObject's 'subf' method. */
+static PyObject* pattern_subf(PatternObject* self, PyObject* args, PyObject*
+  kwargs) {
+    int conc;
+
+    PyObject* format;
+    PyObject* string;
+    Py_ssize_t count = 0;
+    PyObject* pos = Py_None;
+    PyObject* endpos = Py_None;
+    PyObject* concurrent = Py_None;
+    static char* kwlist[] = { "format", "string", "count", "pos", "endpos",
+      "concurrent", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|nOOO:sub", kwlist,
+      &format, &string, &count, &pos, &endpos, &concurrent))
+        return NULL;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    return pattern_subx(self, format, string, count, RE_SUBF, pos, endpos,
+      conc);
+}
+
+#endif
+/* PatternObject's 'subn' method. */
+static PyObject* pattern_subn(PatternObject* self, PyObject* args, PyObject*
+  kwargs) {
+    int conc;
+
+    PyObject* replacement;
+    PyObject* string;
+    Py_ssize_t count = 0;
+    PyObject* pos = Py_None;
+    PyObject* endpos = Py_None;
+    PyObject* concurrent = Py_None;
+    static char* kwlist[] = { "repl", "string", "count", "pos", "endpos",
+      "concurrent", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|nOOO:subn", kwlist,
+      &replacement, &string, &count, &pos, &endpos, &concurrent))
+        return NULL;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    return pattern_subx(self, replacement, string, count, RE_SUBN, pos, endpos,
+      conc);
+}
+
+#if PY_VERSION_HEX >= 0x02060000
+/* PatternObject's 'subfn' method. */
+static PyObject* pattern_subfn(PatternObject* self, PyObject* args, PyObject*
+  kwargs) {
+    int conc;
+
+    PyObject* format;
+    PyObject* string;
+    Py_ssize_t count = 0;
+    PyObject* pos = Py_None;
+    PyObject* endpos = Py_None;
+    PyObject* concurrent = Py_None;
+    static char* kwlist[] = { "format", "string", "count", "pos", "endpos",
+      "concurrent", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|nOOO:subn", kwlist,
+      &format, &string, &count, &pos, &endpos, &concurrent))
+        return NULL;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    return pattern_subx(self, format, string, count, RE_SUBF | RE_SUBN, pos,
+      endpos, conc);
+}
+
+#endif
+/* PatternObject's 'split' method. */
+static PyObject* pattern_split(PatternObject* self, PyObject* args, PyObject*
+  kwargs) {
+    int conc;
+
+    RE_State state;
+    RE_SafeState safe_state;
+    PyObject* list;
+    PyObject* item;
+    int status;
+    Py_ssize_t split_count;
+    size_t g;
+    Py_ssize_t start_pos;
+    Py_ssize_t end_pos;
+    Py_ssize_t step;
+    Py_ssize_t last_pos;
+
+    PyObject* string;
+    Py_ssize_t maxsplit = 0;
+    PyObject* concurrent = Py_None;
+    static char* kwlist[] = { "string", "maxsplit", "concurrent", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|nO:split", kwlist,
+      &string, &maxsplit, &concurrent))
+        return NULL;
+
+    if (maxsplit == 0)
+        maxsplit = PY_SSIZE_T_MAX;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    /* The MatchObject, and therefore repeated captures, will not be visible.
+     */
+    if (!state_init(&state, self, string, 0, PY_SSIZE_T_MAX, FALSE, conc,
+      FALSE, FALSE, FALSE, FALSE))
+        return NULL;
+
+    /* Initialise the "safe state" structure. */
+    safe_state.re_state = &state;
+    safe_state.thread_state = NULL;
+
+    list = PyList_New(0);
+    if (!list) {
+        state_fini(&state);
+        return NULL;
+    }
+
+    split_count = 0;
+    if (state.reverse) {
+        start_pos = state.text_length;
+        end_pos = 0;
+        step = -1;
+    } else {
+        start_pos = 0;
+        end_pos = state.text_length;
+        step = 1;
+    }
+
+    last_pos = start_pos;
+    while (split_count < maxsplit) {
+        status = do_match(&safe_state, TRUE);
+        if (status < 0)
+            goto error;
+
+        if (status == 0)
+            /* No more matches. */
+            break;
+
+        if (state.version_0) {
+            /* Version 0 behaviour is to advance one character if the split was
+             * zero-width. Unfortunately, this can give an incorrect result.
+             * GvR wants this behaviour to be retained so as not to break any
+             * existing software which might rely on it.
+             */
+            if (state.text_pos == state.match_pos) {
+                if (last_pos == end_pos)
+                    break;
+
+                /* Advance one character. */
+                state.text_pos += step;
+                state.must_advance = FALSE;
+                continue;
+            }
+        }
+
+        /* Get segment before this match. */
+        if (state.reverse)
+            item = get_slice(string, state.match_pos, last_pos);
+        else
+            item = get_slice(string, last_pos, state.match_pos);
+        if (!item)
+            goto error;
+
+        status = PyList_Append(list, item);
+        Py_DECREF(item);
+        if (status < 0)
+            goto error;
+
+        /* Add groups (if any). */
+        for (g = 1; g <= self->public_group_count; g++) {
+            item = state_get_group(&state, (Py_ssize_t)g, string, FALSE);
+            if (!item)
+                goto error;
+
+            status = PyList_Append(list, item);
+            Py_DECREF(item);
+            if (status < 0)
+                goto error;
+        }
+
+        ++split_count;
+        last_pos = state.text_pos;
+
+        /* Version 0 behaviour is to advance one character if the match was
+         * zero-width. Unfortunately, this can give an incorrect result. GvR
+         * wants this behaviour to be retained so as not to break any existing
+         * software which might rely on it.
+         */
+        if (state.version_0) {
+            if (state.text_pos == state.match_pos)
+                /* Advance one character. */
+                state.text_pos += step;
+
+            state.must_advance = FALSE;
+        } else
+            /* Continue from where we left off, but don't allow a contiguous
+             * zero-width match.
+             */
+            state.must_advance = TRUE;
+    }
+
+    /* Get segment following last match (even if empty). */
+    if (state.reverse)
+        item = get_slice(string, 0, last_pos);
+    else
+        item = get_slice(string, last_pos, state.text_length);
+    if (!item)
+        goto error;
+
+    status = PyList_Append(list, item);
+    Py_DECREF(item);
+    if (status < 0)
+        goto error;
+
+    state_fini(&state);
+
+    return list;
+
+error:
+    Py_DECREF(list);
+    state_fini(&state);
+    return NULL;
+}
+
+/* PatternObject's 'splititer' method. */
+static PyObject* pattern_splititer(PatternObject* pattern, PyObject* args,
+  PyObject* kwargs) {
+    return pattern_splitter(pattern, args, kwargs);
+}
+
+/* PatternObject's 'findall' method. */
+static PyObject* pattern_findall(PatternObject* self, PyObject* args, PyObject*
+  kwargs) {
+    Py_ssize_t start;
+    Py_ssize_t end;
+    int conc;
+    RE_State state;
+    RE_SafeState safe_state;
+    PyObject* list;
+    Py_ssize_t step;
+    int status;
+    Py_ssize_t b;
+    Py_ssize_t e;
+    size_t g;
+
+    PyObject* string;
+    PyObject* pos = Py_None;
+    PyObject* endpos = Py_None;
+    Py_ssize_t overlapped = FALSE;
+    PyObject* concurrent = Py_None;
+    static char* kwlist[] = { "string", "pos", "endpos", "overlapped",
+      "concurrent", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOnO:findall", kwlist,
+      &string, &pos, &endpos, &overlapped, &concurrent))
+        return NULL;
+
+    start = as_string_index(pos, 0);
+    if (start == -1 && PyErr_Occurred())
+        return NULL;
+
+    end = as_string_index(endpos, PY_SSIZE_T_MAX);
+    if (end == -1 && PyErr_Occurred())
+        return NULL;
+
+    conc = decode_concurrent(concurrent);
+    if (conc < 0)
+        return NULL;
+
+    /* The MatchObject, and therefore repeated captures, will not be visible.
+     */
+    if (!state_init(&state, self, string, start, end, overlapped != 0, conc,
+      FALSE, FALSE, FALSE, FALSE))
+        return NULL;
+
+    /* Initialise the "safe state" structure. */
+    safe_state.re_state = &state;
+    safe_state.thread_state = NULL;
+
+    list = PyList_New(0);
+    if (!list) {
+        state_fini(&state);
+        return NULL;
+    }
+
+    step = state.reverse ? -1 : 1;
+    while (state.slice_start <= state.text_pos && state.text_pos <=
+      state.slice_end) {
+        PyObject* item;
+
+        status = do_match(&safe_state, TRUE);
+        if (status < 0)
+            goto error;
+
+        if (status == 0)
+            break;
+
+        /* Don't bother to build a MatchObject. */
+        switch (self->public_group_count) {
+        case 0:
+            if (state.reverse) {
+                b = state.text_pos;
+                e = state.match_pos;
+            } else {
+                b = state.match_pos;
+                e = state.text_pos;
+            }
+            item = get_slice(string, b, e);
+            if (!item)
+                goto error;
+            break;
+        case 1:
+            item = state_get_group(&state, 1, string, TRUE);
+            if (!item)
+                goto error;
+            break;
+        default:
+            item = PyTuple_New((Py_ssize_t)self->public_group_count);
+            if (!item)
+                goto error;
+
+            for (g = 0; g < self->public_group_count; g++) {
+                PyObject* o;
+
+                o = state_get_group(&state, (Py_ssize_t)g + 1, string, TRUE);
+                if (!o) {
+                    Py_DECREF(item);
+                    goto error;
+                }
+
+                /* PyTuple_SET_ITEM borrows the reference. */
+                PyTuple_SET_ITEM(item, g, o);
+            }
+            break;
+        }
+
+        status = PyList_Append(list, item);
+        Py_DECREF(item);
+        if (status < 0)
+            goto error;
+
+        if (state.overlapped) {
+            /* Advance one character. */
+            state.text_pos = state.match_pos + step;
+            state.must_advance = FALSE;
+        } else
+            /* Continue from where we left off, but don't allow 2 contiguous
+             * zero-width matches.
+             */
+            state.must_advance = state.text_pos == state.match_pos;
+    }
+
+    state_fini(&state);
+
+    return list;
+
+error:
+    Py_DECREF(list);
+    state_fini(&state);
+    return NULL;
+}
+
+/* PatternObject's 'finditer' method. */
+static PyObject* pattern_finditer(PatternObject* pattern, PyObject* args,
+  PyObject* kwargs) {
+    return pattern_scanner(pattern, args, kwargs);
+}
+
+/* Makes a copy of a PatternObject. */
+Py_LOCAL_INLINE(PyObject*) make_pattern_copy(PatternObject* self) {
+    Py_INCREF(self);
+    return (PyObject*)self;
+}
+
+/* PatternObject's '__copy__' method. */
+static PyObject* pattern_copy(PatternObject* self, PyObject *unused) {
+    return make_pattern_copy(self);
+}
+
+/* PatternObject's '__deepcopy__' method. */
+static PyObject* pattern_deepcopy(PatternObject* self, PyObject* memo) {
+    return make_pattern_copy(self);
+}
+
+/* The documentation of a PatternObject. */
+PyDoc_STRVAR(pattern_match_doc,
+    "match(string, pos=None, endpos=None, concurrent=None) --> MatchObject or None.\n\
+    Match zero or more characters at the beginning of the string.");
+
+PyDoc_STRVAR(pattern_fullmatch_doc,
+    "fullmatch(string, pos=None, endpos=None, concurrent=None) --> MatchObject or None.\n\
+    Match zero or more characters against all of the string.");
+
+PyDoc_STRVAR(pattern_search_doc,
+    "search(string, pos=None, endpos=None, concurrent=None) --> MatchObject or None.\n\
+    Search through string looking for a match, and return a corresponding\n\
+    match object instance.  Return None if no match is found.");
+
+PyDoc_STRVAR(pattern_sub_doc,
+    "sub(repl, string, count=0, flags=0, pos=None, endpos=None, concurrent=None) --> newstring\n\
+    Return the string obtained by replacing the leftmost (or rightmost with a\n\
+    reverse pattern) non-overlapping occurrences of pattern in string by the\n\
+    replacement repl.");
+
+#if PY_VERSION_HEX >= 0x02060000
+PyDoc_STRVAR(pattern_subf_doc,
+    "subf(format, string, count=0, flags=0, pos=None, endpos=None, concurrent=None) --> newstring\n\
+    Return the string obtained by replacing the leftmost (or rightmost with a\n\
+    reverse pattern) non-overlapping occurrences of pattern in string by the\n\
+    replacement format.");
+
+#endif
+PyDoc_STRVAR(pattern_subn_doc,
+    "subn(repl, string, count=0, flags=0, pos=None, endpos=None, concurrent=None) --> (newstring, number of subs)\n\
+    Return the tuple (new_string, number_of_subs_made) found by replacing the\n\
+    leftmost (or rightmost with a reverse pattern) non-overlapping occurrences\n\
+    of pattern with the replacement repl.");
+
+#if PY_VERSION_HEX >= 0x02060000
+PyDoc_STRVAR(pattern_subfn_doc,
+    "subfn(format, string, count=0, flags=0, pos=None, endpos=None, concurrent=None) --> (newstring, number of subs)\n\
+    Return the tuple (new_string, number_of_subs_made) found by replacing the\n\
+    leftmost (or rightmost with a reverse pattern) non-overlapping occurrences\n\
+    of pattern with the replacement format.");
+
+#endif
+PyDoc_STRVAR(pattern_split_doc,
+    "split(string, string, maxsplit=0, concurrent=None) --> list.\n\
+    Split string by the occurrences of pattern.");
+
+PyDoc_STRVAR(pattern_splititer_doc,
+    "splititer(string, maxsplit=0, concurrent=None) --> iterator.\n\
+    Return an iterator yielding the parts of a split string.");
+
+PyDoc_STRVAR(pattern_findall_doc,
+    "findall(string, pos=None, endpos=None, overlapped=False, concurrent=None) --> list.\n\
+    Return a list of all matches of pattern in string.  The matches may be\n\
+    overlapped if overlapped is True.");
+
+PyDoc_STRVAR(pattern_finditer_doc,
+    "finditer(string, pos=None, endpos=None, overlapped=False, concurrent=None) --> iterator.\n\
+    Return an iterator over all matches for the RE pattern in string.  The\n\
+    matches may be overlapped if overlapped is True.  For each match, the\n\
+    iterator returns a MatchObject.");
+
+PyDoc_STRVAR(pattern_scanner_doc,
+    "scanner(string, pos=None, endpos=None, overlapped=False, concurrent=None) --> scanner.\n\
+    Return an scanner for the RE pattern in string.  The matches may be overlapped\n\
+    if overlapped is True.");
+
+/* The methods of a PatternObject. */
+static PyMethodDef pattern_methods[] = {
+    {"match", (PyCFunction)pattern_match, METH_VARARGS|METH_KEYWORDS,
+      pattern_match_doc},
+    {"fullmatch", (PyCFunction)pattern_fullmatch, METH_VARARGS|METH_KEYWORDS,
+      pattern_fullmatch_doc},
+    {"search", (PyCFunction)pattern_search, METH_VARARGS|METH_KEYWORDS,
+      pattern_search_doc},
+    {"sub", (PyCFunction)pattern_sub, METH_VARARGS|METH_KEYWORDS,
+      pattern_sub_doc},
+#if PY_VERSION_HEX >= 0x02060000
+    {"subf", (PyCFunction)pattern_subf, METH_VARARGS|METH_KEYWORDS,
+      pattern_subf_doc},
+#endif
+    {"subn", (PyCFunction)pattern_subn, METH_VARARGS|METH_KEYWORDS,
+      pattern_subn_doc},
+#if PY_VERSION_HEX >= 0x02060000
+    {"subfn", (PyCFunction)pattern_subfn, METH_VARARGS|METH_KEYWORDS,
+      pattern_subfn_doc},
+#endif
+    {"split", (PyCFunction)pattern_split, METH_VARARGS|METH_KEYWORDS,
+      pattern_split_doc},
+    {"splititer", (PyCFunction)pattern_splititer, METH_VARARGS|METH_KEYWORDS,
+      pattern_splititer_doc},
+    {"findall", (PyCFunction)pattern_findall, METH_VARARGS|METH_KEYWORDS,
+      pattern_findall_doc},
+    {"finditer", (PyCFunction)pattern_finditer, METH_VARARGS|METH_KEYWORDS,
+      pattern_finditer_doc},
+    {"scanner", (PyCFunction)pattern_scanner, METH_VARARGS|METH_KEYWORDS,
+      pattern_scanner_doc},
+    {"__copy__", (PyCFunction)pattern_copy, METH_NOARGS},
+    {"__deepcopy__", (PyCFunction)pattern_deepcopy, METH_O},
+    {NULL, NULL}
+};
+
+PyDoc_STRVAR(pattern_doc, "Compiled regex object");
+
+/* Deallocates a PatternObject. */
+static void pattern_dealloc(PyObject* self_) {
+    PatternObject* self;
+    size_t i;
+    int partial_side;
+
+    self = (PatternObject*)self_;
+
+    /* Discard the nodes. */
+    for (i = 0; i < self->node_count; i++) {
+        RE_Node* node;
+
+        node = self->node_list[i];
+        re_dealloc(node->values);
+        if (node->status & RE_STATUS_STRING) {
+            re_dealloc(node->string.bad_character_offset);
+            re_dealloc(node->string.good_suffix_offset);
+        }
+        re_dealloc(node);
+    }
+    re_dealloc(self->node_list);
+
+    /* Discard the group info. */
+    re_dealloc(self->group_info);
+
+    /* Discard the call_ref info. */
+    re_dealloc(self->call_ref_info);
+
+    /* Discard the repeat info. */
+    re_dealloc(self->repeat_info);
+
+    dealloc_groups(self->groups_storage, self->true_group_count);
+
+    dealloc_repeats(self->repeats_storage, self->repeat_count);
+
+    if (self->weakreflist)
+        PyObject_ClearWeakRefs((PyObject*)self);
+    Py_XDECREF(self->pattern);
+    Py_XDECREF(self->groupindex);
+    Py_XDECREF(self->indexgroup);
+
+    for (partial_side = 0; partial_side < 2; partial_side++) {
+        if (self->partial_named_lists[partial_side]) {
+            for (i = 0; i < self->named_lists_count; i++)
+                Py_XDECREF(self->partial_named_lists[partial_side][i]);
+
+            re_dealloc(self->partial_named_lists[partial_side]);
+        }
+    }
+
+    Py_DECREF(self->named_lists);
+    Py_DECREF(self->named_list_indexes);
+    re_dealloc(self->locale_info);
+    PyObject_DEL(self);
+}
+
+/* Info about the various flags that can be passed in. */
+typedef struct RE_FlagName {
+    char* name;
+    int value;
+} RE_FlagName;
+
+/* We won't bother about the A flag in Python 2. */
+static RE_FlagName flag_names[] = {
+    {"B", RE_FLAG_BESTMATCH},
+    {"D", RE_FLAG_DEBUG},
+    {"S", RE_FLAG_DOTALL},
+    {"F", RE_FLAG_FULLCASE},
+    {"I", RE_FLAG_IGNORECASE},
+    {"L", RE_FLAG_LOCALE},
+    {"M", RE_FLAG_MULTILINE},
+    {"P", RE_FLAG_POSIX},
+    {"R", RE_FLAG_REVERSE},
+    {"T", RE_FLAG_TEMPLATE},
+    {"U", RE_FLAG_UNICODE},
+    {"X", RE_FLAG_VERBOSE},
+    {"V0", RE_FLAG_VERSION0},
+    {"V1", RE_FLAG_VERSION1},
+    {"W", RE_FLAG_WORD},
+};
+
+/* Appends a string to a list. */
+Py_LOCAL_INLINE(BOOL) append_string(PyObject* list, char* string) {
+    PyObject* item;
+    int status;
+
+    item = Py_BuildValue("s", string);
+    if (!item)
+        return FALSE;
+
+    status = PyList_Append(list, item);
+    Py_DECREF(item);
+    if (status < 0)
+        return FALSE;
+
+    return TRUE;
+}
+
+/* Appends a (decimal) integer to a list. */
+Py_LOCAL_INLINE(BOOL) append_integer(PyObject* list, Py_ssize_t value) {
+    PyObject* int_obj;
+    PyObject* repr_obj;
+    int status;
+
+    int_obj = Py_BuildValue("n", value);
+    if (!int_obj)
+        return FALSE;
+
+    repr_obj = PyObject_Repr(int_obj);
+    Py_DECREF(int_obj);
+    if (!repr_obj)
+        return FALSE;
+
+    status = PyList_Append(list, repr_obj);
+    Py_DECREF(repr_obj);
+    if (status < 0)
+        return FALSE;
+
+    return TRUE;
+}
+
+/* MatchObject's '__repr__' method. */
+static PyObject* match_repr(PyObject* self_) {
+    MatchObject* self;
+    PyObject* list;
+    PyObject* matched_substring;
+    PyObject* matched_repr;
+    int status;
+    PyObject* separator;
+    PyObject* result;
+
+    self = (MatchObject*)self_;
+
+    list = PyList_New(0);
+    if (!list)
+        return NULL;
+
+    if (!append_string(list, "<regex.Match object; span=("))
+        goto error;
+
+    if (!append_integer(list, self->match_start))
+        goto error;
+
+    if (! append_string(list, ", "))
+        goto error;
+
+    if (!append_integer(list, self->match_end))
+        goto error;
+
+    if (!append_string(list, "), match="))
+        goto error;
+
+    matched_substring = get_slice(self->substring, self->match_start -
+      self->substring_offset, self->match_end - self->substring_offset);
+    if (!matched_substring)
+        goto error;
+
+    matched_repr = PyObject_Repr(matched_substring);
+    Py_DECREF(matched_substring);
+    if (!matched_repr)
+        goto error;
+
+    status = PyList_Append(list, matched_repr);
+    Py_DECREF(matched_repr);
+    if (status < 0)
+        goto error;
+
+    if (self->fuzzy_counts[RE_FUZZY_SUB] != 0 ||
+      self->fuzzy_counts[RE_FUZZY_INS] != 0 || self->fuzzy_counts[RE_FUZZY_DEL]
+      != 0) {
+        if (! append_string(list, ", fuzzy_counts=("))
+            goto error;
+
+        if (!append_integer(list,
+          (Py_ssize_t)self->fuzzy_counts[RE_FUZZY_SUB]))
+            goto error;
+
+        if (! append_string(list, ", "))
+            goto error;
+
+        if (!append_integer(list,
+          (Py_ssize_t)self->fuzzy_counts[RE_FUZZY_INS]))
+            goto error;
+
+        if (! append_string(list, ", "))
+            goto error;
+        if (!append_integer(list,
+          (Py_ssize_t)self->fuzzy_counts[RE_FUZZY_DEL]))
+            goto error;
+
+        if (! append_string(list, ")"))
+            goto error;
+    }
+
+    if (self->partial) {
+        if (!append_string(list, ", partial=True"))
+            goto error;
+    }
+
+    if (! append_string(list, ">"))
+        goto error;
+
+    separator = Py_BuildValue("s", "");
+    if (!separator)
+        goto error;
+
+    result = PyUnicode_Join(separator, list);
+    Py_DECREF(separator);
+    Py_DECREF(list);
+
+    return result;
+
+error:
+    Py_DECREF(list);
+    return NULL;
+}
+
+/* PatternObject's '__repr__' method. */
+static PyObject* pattern_repr(PyObject* self_) {
+    PatternObject* self;
+    PyObject* list;
+    PyObject* item;
+    int status;
+    int flag_count;
+    unsigned int i;
+    Py_ssize_t pos;
+    PyObject *key;
+    PyObject *value;
+    PyObject* separator;
+    PyObject* result;
+
+    self = (PatternObject*)self_;
+
+    list = PyList_New(0);
+    if (!list)
+        return NULL;
+
+    if (!append_string(list, "regex.Regex("))
+        goto error;
+
+    item = PyObject_Repr(self->pattern);
+    if (!item)
+        goto error;
+
+    status = PyList_Append(list, item);
+    Py_DECREF(item);
+    if (status < 0)
+        goto error;
+
+    flag_count = 0;
+    for (i = 0; i < sizeof(flag_names) / sizeof(flag_names[0]); i++) {
+        if (self->flags & flag_names[i].value) {
+            if (flag_count == 0) {
+                if (!append_string(list, ", flags="))
+                    goto error;
+            } else {
+                if (!append_string(list, " | "))
+                    goto error;
+            }
+
+            if (!append_string(list, "regex."))
+                goto error;
+
+            if (!append_string(list, flag_names[i].name))
+                goto error;
+
+            ++flag_count;
+        }
+    }
+
+    pos = 0;
+    /* PyDict_Next borrows references. */
+    while (PyDict_Next(self->named_lists, &pos, &key, &value)) {
+        if (!append_string(list, ", "))
+            goto error;
+
+        status = PyList_Append(list, key);
+        if (status < 0)
+            goto error;
+
+        if (!append_string(list, "="))
+            goto error;
+
+        item = PyObject_Repr(value);
+        if (!item)
+            goto error;
+
+        status = PyList_Append(list, item);
+        Py_DECREF(item);
+        if (status < 0)
+            goto error;
+    }
+
+    if (!append_string(list, ")"))
+        goto error;
+
+    separator = Py_BuildValue("s", "");
+    if (!separator)
+        goto error;
+
+    result = PyUnicode_Join(separator, list);
+    Py_DECREF(separator);
+    Py_DECREF(list);
+
+    return result;
+
+error:
+    Py_DECREF(list);
+    return NULL;
+}
+
+/* PatternObject's 'groupindex' method. */
+static PyObject* pattern_groupindex(PyObject* self_) {
+    PatternObject* self;
+
+    self = (PatternObject*)self_;
+
+    return PyDict_Copy(self->groupindex);
+}
+
+static PyGetSetDef pattern_getset[] = {
+    {"groupindex", (getter)pattern_groupindex, (setter)NULL,
+      "A dictionary mapping group names to group numbers."},
+    {NULL} /* Sentinel */
+};
+
+static PyMemberDef pattern_members[] = {
+    {"pattern", T_OBJECT, offsetof(PatternObject, pattern), READONLY,
+      "The pattern string from which the regex object was compiled."},
+    {"flags", T_PYSSIZET, offsetof(PatternObject, flags), READONLY,
+      "The regex matching flags."},
+    {"groups", T_PYSSIZET, offsetof(PatternObject, public_group_count),
+      READONLY, "The number of capturing groups in the pattern."},
+    {"named_lists", T_OBJECT, offsetof(PatternObject, named_lists), READONLY,
+      "The named lists used by the regex."},
+    {NULL} /* Sentinel */
+};
+
+static PyTypeObject Pattern_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "_" RE_MODULE "." "Pattern",
+    sizeof(PatternObject)
+};
+
+/* Building the nodes is made simpler by allowing branches to have a single
+ * exit. These need to be removed.
+ */
+Py_LOCAL_INLINE(void) skip_one_way_branches(PatternObject* pattern) {
+    BOOL modified;
+
+    /* If a node refers to a 1-way branch then make the former refer to the
+     * latter's destination. Repeat until they're all done.
+     */
+    do {
+        size_t i;
+
+        modified = FALSE;
+
+        for (i = 0; i < pattern->node_count; i++) {
+            RE_Node* node;
+            RE_Node* next;
+
+            node = pattern->node_list[i];
+
+            /* Check the first destination. */
+            next = node->next_1.node;
+            if (next && next->op == RE_OP_BRANCH &&
+              !next->nonstring.next_2.node) {
+                node->next_1.node = next->next_1.node;
+                modified = TRUE;
+            }
+
+            /* Check the second destination. */
+            next = node->nonstring.next_2.node;
+            if (next && next->op == RE_OP_BRANCH &&
+              !next->nonstring.next_2.node) {
+                node->nonstring.next_2.node = next->next_1.node;
+                modified = TRUE;
+            }
+        }
+    } while (modified);
+
+    /* The start node might be a 1-way branch. Skip over it because it'll be
+     * removed. It might even be the first in a chain.
+     */
+    while (pattern->start_node->op == RE_OP_BRANCH &&
+      !pattern->start_node->nonstring.next_2.node)
+        pattern->start_node = pattern->start_node->next_1.node;
+}
+
+/* Adds guards to repeats which are followed by a reference to a group.
+ *
+ * Returns whether a guard was added for a node at or after the given node.
+ */
+Py_LOCAL_INLINE(RE_STATUS_T) add_repeat_guards(PatternObject* pattern, RE_Node*
+  node) {
+    RE_STATUS_T result;
+
+    result = RE_STATUS_NEITHER;
+
+    for (;;) {
+        if (node->status & RE_STATUS_VISITED_AG)
+            return node->status & (RE_STATUS_REPEAT | RE_STATUS_REF);
+
+        switch (node->op) {
+        case RE_OP_BRANCH:
+        {
+            RE_STATUS_T branch_1_result;
+            RE_STATUS_T branch_2_result;
+            RE_STATUS_T status;
+
+            branch_1_result = add_repeat_guards(pattern, node->next_1.node);
+            branch_2_result = add_repeat_guards(pattern,
+              node->nonstring.next_2.node);
+            status = max_status_3(result, branch_1_result, branch_2_result);
+            node->status = RE_STATUS_VISITED_AG | status;
+            return status;
+        }
+        case RE_OP_END_GREEDY_REPEAT:
+        case RE_OP_END_LAZY_REPEAT:
+            node->status |= RE_STATUS_VISITED_AG;
+            return result;
+        case RE_OP_GREEDY_REPEAT:
+        case RE_OP_LAZY_REPEAT:
+        {
+            BOOL limited;
+            RE_STATUS_T body_result;
+            RE_STATUS_T tail_result;
+            RE_RepeatInfo* repeat_info;
+            RE_STATUS_T status;
+
+            limited = ~node->values[2] != 0;
+            if (limited)
+                body_result = RE_STATUS_LIMITED;
+            else
+                body_result = add_repeat_guards(pattern, node->next_1.node);
+            tail_result = add_repeat_guards(pattern,
+              node->nonstring.next_2.node);
+
+            repeat_info = &pattern->repeat_info[node->values[0]];
+            if (body_result != RE_STATUS_REF)
+                repeat_info->status |= RE_STATUS_BODY;
+            if (tail_result != RE_STATUS_REF)
+                repeat_info->status |= RE_STATUS_TAIL;
+            if (limited)
+                result = max_status_2(result, RE_STATUS_LIMITED);
+            else
+                result = max_status_2(result, RE_STATUS_REPEAT);
+            status = max_status_3(result, body_result, tail_result);
+            node->status |= RE_STATUS_VISITED_AG | status;
+            return status;
+        }
+        case RE_OP_GREEDY_REPEAT_ONE:
+        case RE_OP_LAZY_REPEAT_ONE:
+        {
+            BOOL limited;
+            RE_STATUS_T tail_result;
+            RE_RepeatInfo* repeat_info;
+            RE_STATUS_T status;
+
+            limited = ~node->values[2] != 0;
+            tail_result = add_repeat_guards(pattern, node->next_1.node);
+
+            repeat_info = &pattern->repeat_info[node->values[0]];
+            repeat_info->status |= RE_STATUS_BODY;
+            if (tail_result != RE_STATUS_REF)
+                repeat_info->status |= RE_STATUS_TAIL;
+            if (limited)
+                result = max_status_2(result, RE_STATUS_LIMITED);
+            else
+                result = max_status_2(result, RE_STATUS_REPEAT);
+            status = max_status_3(result, RE_STATUS_REPEAT, tail_result);
+            node->status = RE_STATUS_VISITED_AG | status;
+            return status;
+        }
+        case RE_OP_GROUP_CALL:
+        case RE_OP_REF_GROUP:
+        case RE_OP_REF_GROUP_FLD:
+        case RE_OP_REF_GROUP_FLD_REV:
+        case RE_OP_REF_GROUP_IGN:
+        case RE_OP_REF_GROUP_IGN_REV:
+        case RE_OP_REF_GROUP_REV:
+            result = RE_STATUS_REF;
+            node = node->next_1.node;
+            break;
+        case RE_OP_GROUP_EXISTS:
+        {
+            RE_STATUS_T branch_1_result;
+            RE_STATUS_T branch_2_result;
+            RE_STATUS_T status;
+
+            branch_1_result = add_repeat_guards(pattern, node->next_1.node);
+            branch_2_result = add_repeat_guards(pattern,
+              node->nonstring.next_2.node);
+            status = max_status_4(result, branch_1_result, branch_2_result,
+              RE_STATUS_REF);
+            node->status = RE_STATUS_VISITED_AG | status;
+            return status;
+        }
+        case RE_OP_SUCCESS:
+            node->status = RE_STATUS_VISITED_AG | result;
+            return result;
+        default:
+            node = node->next_1.node;
+            break;
+        }
+    }
+}
+
+/* Adds an index to a node's values unless it's already present.
+ *
+ * 'offset' is the offset of the index count within the values.
+ */
+Py_LOCAL_INLINE(BOOL) add_index(RE_Node* node, size_t offset, size_t index) {
+    size_t index_count;
+    size_t first_index;
+    size_t i;
+    RE_CODE* new_values;
+
+    if (!node)
+        return TRUE;
+
+    index_count = node->values[offset];
+    first_index = offset + 1;
+
+    /* Is the index already present? */
+    for (i = 0; i < index_count; i++) {
+        if (node->values[first_index + i] == index)
+            return TRUE;
+    }
+
+    /* Allocate more space for the new index. */
+    new_values = re_realloc(node->values, (node->value_count + 1) *
+      sizeof(RE_CODE));
+    if (!new_values)
+        return FALSE;
+
+    ++node->value_count;
+    node->values = new_values;
+
+    node->values[first_index + node->values[offset]++] = (RE_CODE)index;
+
+    return TRUE;
+}
+
+/* Records the index of every repeat and fuzzy section within atomic
+ * subpatterns and lookarounds.
+ */
+Py_LOCAL_INLINE(BOOL) record_subpattern_repeats_and_fuzzy_sections(RE_Node*
+  parent_node, size_t offset, size_t repeat_count, RE_Node* node) {
+    while (node) {
+        if (node->status & RE_STATUS_VISITED_REP)
+            return TRUE;
+
+        node->status |= RE_STATUS_VISITED_REP;
+
+        switch (node->op) {
+        case RE_OP_BRANCH:
+        case RE_OP_GROUP_EXISTS:
+            if (!record_subpattern_repeats_and_fuzzy_sections(parent_node,
+              offset, repeat_count, node->next_1.node))
+                return FALSE;
+            node = node->nonstring.next_2.node;
+            break;
+        case RE_OP_END_FUZZY:
+            node = node->next_1.node;
+            break;
+        case RE_OP_END_GREEDY_REPEAT:
+        case RE_OP_END_LAZY_REPEAT:
+            return TRUE;
+        case RE_OP_FUZZY:
+            /* Record the fuzzy index. */
+            if (!add_index(parent_node, offset, repeat_count +
+              node->values[0]))
+                return FALSE;
+            node = node->next_1.node;
+            break;
+        case RE_OP_GREEDY_REPEAT:
+        case RE_OP_LAZY_REPEAT:
+            /* Record the repeat index. */
+            if (!add_index(parent_node, offset, node->values[0]))
+                return FALSE;
+            if (!record_subpattern_repeats_and_fuzzy_sections(parent_node,
+              offset, repeat_count, node->next_1.node))
+                return FALSE;
+            node = node->nonstring.next_2.node;
+            break;
+        case RE_OP_GREEDY_REPEAT_ONE:
+        case RE_OP_LAZY_REPEAT_ONE:
+            /* Record the repeat index. */
+            if (!add_index(parent_node, offset, node->values[0]))
+                return FALSE;
+            node = node->next_1.node;
+            break;
+        default:
+            node = node->next_1.node;
+            break;
+        }
+    }
+
+    return TRUE;
+}
+
+/* Marks nodes which are being used as used. */
+Py_LOCAL_INLINE(void) use_nodes(RE_Node* node) {
+    while (node && !(node->status & RE_STATUS_USED)) {
+        node->status |= RE_STATUS_USED;
+        if (!(node->status & RE_STATUS_STRING)) {
+            if (node->nonstring.next_2.node)
+                use_nodes(node->nonstring.next_2.node);
+        }
+        node = node->next_1.node;
+    }
+}
+
+/* Discards any unused nodes.
+ *
+ * Optimising the nodes might result in some nodes no longer being used.
+ */
+Py_LOCAL_INLINE(void) discard_unused_nodes(PatternObject* pattern) {
+    size_t i;
+    size_t new_count;
+
+    /* Mark the nodes which are being used. */
+    use_nodes(pattern->start_node);
+
+    for (i = 0; i < pattern->call_ref_info_capacity; i++)
+        use_nodes(pattern->call_ref_info[i].node);
+
+    new_count = 0;
+    for (i = 0; i < pattern->node_count; i++) {
+        RE_Node* node;
+
+        node = pattern->node_list[i];
+        if (node->status & RE_STATUS_USED)
+            pattern->node_list[new_count++] = node;
+        else {
+            re_dealloc(node->values);
+            if (node->status & RE_STATUS_STRING) {
+                re_dealloc(node->string.bad_character_offset);
+                re_dealloc(node->string.good_suffix_offset);
+            }
+            re_dealloc(node);
+        }
+    }
+
+    pattern->node_count = new_count;
+}
+
+/* Marks all the group which are named. Returns FALSE if there's an error. */
+Py_LOCAL_INLINE(BOOL) mark_named_groups(PatternObject* pattern) {
+    size_t i;
+
+    for (i = 0; i < pattern->public_group_count; i++) {
+        RE_GroupInfo* group_info;
+        PyObject* index;
+        int status;
+
+        group_info = &pattern->group_info[i];
+        index = Py_BuildValue("n", i + 1);
+        if (!index)
+            return FALSE;
+
+        status = PyDict_Contains(pattern->indexgroup, index);
+        Py_DECREF(index);
+        if (status < 0)
+            return FALSE;
+
+        group_info->has_name = status == 1;
+    }
+
+    return TRUE;
+}
+
+/* Gets the test node.
+ *
+ * The test node lets the matcher look ahead in the pattern, allowing it to
+ * avoid the cost of housekeeping, only to find that what follows doesn't match
+ * anyway.
+ */
+Py_LOCAL_INLINE(void) set_test_node(RE_NextNode* next) {
+    RE_Node* node = next->node;
+    RE_Node* test;
+
+    next->test = node;
+    next->match_next = node;
+    next->match_step = 0;
+
+    if (!node)
+        return;
+
+    test = node;
+    while (test->op == RE_OP_END_GROUP || test->op == RE_OP_START_GROUP)
+        test = test->next_1.node;
+
+    next->test = test;
+
+    if (test != node)
+        return;
+
+    switch (test->op) {
+    case RE_OP_ANY:
+    case RE_OP_ANY_ALL:
+    case RE_OP_ANY_ALL_REV:
+    case RE_OP_ANY_REV:
+    case RE_OP_ANY_U:
+    case RE_OP_ANY_U_REV:
+    case RE_OP_BOUNDARY:
+    case RE_OP_CHARACTER:
+    case RE_OP_CHARACTER_IGN:
+    case RE_OP_CHARACTER_IGN_REV:
+    case RE_OP_CHARACTER_REV:
+    case RE_OP_DEFAULT_BOUNDARY:
+    case RE_OP_DEFAULT_END_OF_WORD:
+    case RE_OP_DEFAULT_START_OF_WORD:
+    case RE_OP_END_OF_LINE:
+    case RE_OP_END_OF_LINE_U:
+    case RE_OP_END_OF_STRING:
+    case RE_OP_END_OF_STRING_LINE:
+    case RE_OP_END_OF_STRING_LINE_U:
+    case RE_OP_END_OF_WORD:
+    case RE_OP_GRAPHEME_BOUNDARY:
+    case RE_OP_PROPERTY:
+    case RE_OP_PROPERTY_IGN:
+    case RE_OP_PROPERTY_IGN_REV:
+    case RE_OP_PROPERTY_REV:
+    case RE_OP_RANGE:
+    case RE_OP_RANGE_IGN:
+    case RE_OP_RANGE_IGN_REV:
+    case RE_OP_RANGE_REV:
+    case RE_OP_SEARCH_ANCHOR:
+    case RE_OP_SET_DIFF:
+    case RE_OP_SET_DIFF_IGN:
+    case RE_OP_SET_DIFF_IGN_REV:
+    case RE_OP_SET_DIFF_REV:
+    case RE_OP_SET_INTER:
+    case RE_OP_SET_INTER_IGN:
+    case RE_OP_SET_INTER_IGN_REV:
+    case RE_OP_SET_INTER_REV:
+    case RE_OP_SET_SYM_DIFF:
+    case RE_OP_SET_SYM_DIFF_IGN:
+    case RE_OP_SET_SYM_DIFF_IGN_REV:
+    case RE_OP_SET_SYM_DIFF_REV:
+    case RE_OP_SET_UNION:
+    case RE_OP_SET_UNION_IGN:
+    case RE_OP_SET_UNION_IGN_REV:
+    case RE_OP_SET_UNION_REV:
+    case RE_OP_START_OF_LINE:
+    case RE_OP_START_OF_LINE_U:
+    case RE_OP_START_OF_STRING:
+    case RE_OP_START_OF_WORD:
+    case RE_OP_STRING:
+    case RE_OP_STRING_FLD:
+    case RE_OP_STRING_FLD_REV:
+    case RE_OP_STRING_IGN:
+    case RE_OP_STRING_IGN_REV:
+    case RE_OP_STRING_REV:
+        next->match_next = test->next_1.node;
+        next->match_step = test->step;
+        break;
+    case RE_OP_GREEDY_REPEAT_ONE:
+    case RE_OP_LAZY_REPEAT_ONE:
+        if (test->values[1] > 0)
+            next->test = test;
+        break;
+    }
+}
+
+/* Sets the test nodes. */
+Py_LOCAL_INLINE(void) set_test_nodes(PatternObject* pattern) {
+    RE_Node** node_list;
+    size_t i;
+
+    node_list = pattern->node_list;
+    for (i = 0; i < pattern->node_count; i++) {
+        RE_Node* node;
+
+        node = node_list[i];
+        set_test_node(&node->next_1);
+        if (!(node->status & RE_STATUS_STRING))
+            set_test_node(&node->nonstring.next_2);
+    }
+}
+
+/* Optimises the pattern. */
+Py_LOCAL_INLINE(BOOL) optimise_pattern(PatternObject* pattern) {
+    size_t i;
+
+    /* Building the nodes is made simpler by allowing branches to have a single
+     * exit. These need to be removed.
+     */
+    skip_one_way_branches(pattern);
+
+    /* Add position guards for repeat bodies containing a reference to a group
+     * or repeat tails followed at some point by a reference to a group.
+     */
+    add_repeat_guards(pattern, pattern->start_node);
+
+    /* Record the index of repeats and fuzzy sections within the body of atomic
+     * and lookaround nodes.
+     */
+    if (!record_subpattern_repeats_and_fuzzy_sections(NULL, 0,
+      pattern->repeat_count, pattern->start_node))
+        return FALSE;
+
+    for (i = 0; i < pattern->call_ref_info_count; i++) {
+        RE_Node* node;
+
+        node = pattern->call_ref_info[i].node;
+        if (!record_subpattern_repeats_and_fuzzy_sections(NULL, 0,
+          pattern->repeat_count, node))
+            return FALSE;
+    }
+
+    /* Discard any unused nodes. */
+    discard_unused_nodes(pattern);
+
+    /* Set the test nodes. */
+    set_test_nodes(pattern);
+
+    /* Mark all the group that are named. */
+    if (!mark_named_groups(pattern))
+        return FALSE;
+
+    return TRUE;
+}
+
+/* Creates a new pattern node. */
+Py_LOCAL_INLINE(RE_Node*) create_node(PatternObject* pattern, RE_UINT8 op,
+  RE_CODE flags, Py_ssize_t step, size_t value_count) {
+    RE_Node* node;
+
+    node = (RE_Node*)re_alloc(sizeof(*node));
+    if (!node)
+        return NULL;
+    memset(node, 0, sizeof(RE_Node));
+
+    node->value_count = value_count;
+    if (node->value_count > 0) {
+        node->values = (RE_CODE*)re_alloc(node->value_count * sizeof(RE_CODE));
+        if (!node->values)
+            goto error;
+    } else
+        node->values = NULL;
+
+    node->op = op;
+    node->match = (flags & RE_POSITIVE_OP) != 0;
+    node->status = (RE_STATUS_T)(flags << RE_STATUS_SHIFT);
+    node->step = step;
+
+    /* Ensure that there's enough storage to record the new node. */
+    if (pattern->node_count >= pattern->node_capacity) {
+        RE_Node** new_node_list;
+
+        pattern->node_capacity *= 2;
+        if (pattern->node_capacity == 0)
+            pattern->node_capacity = RE_INIT_NODE_LIST_SIZE;
+        new_node_list = (RE_Node**)re_realloc(pattern->node_list,
+          pattern->node_capacity * sizeof(RE_Node*));
+        if (!new_node_list)
+            goto error;
+        pattern->node_list = new_node_list;
+    }
+
+    /* Record the new node. */
+    pattern->node_list[pattern->node_count++] = node;
+
+    return node;
+
+error:
+    re_dealloc(node->values);
+    re_dealloc(node);
+    return NULL;
+}
+
+/* Adds a node as a next node for another node. */
+Py_LOCAL_INLINE(void) add_node(RE_Node* node_1, RE_Node* node_2) {
+    if (!node_1->next_1.node)
+        node_1->next_1.node = node_2;
+    else
+        node_1->nonstring.next_2.node = node_2;
+}
+
+/* Ensures that the entry for a group's details actually exists. */
+Py_LOCAL_INLINE(BOOL) ensure_group(PatternObject* pattern, size_t group) {
+    size_t old_capacity;
+    size_t new_capacity;
+    RE_GroupInfo* new_group_info;
+
+    if (group <= pattern->true_group_count)
+        /* We already have an entry for the group. */
+        return TRUE;
+
+    /* Increase the storage capacity to include the new entry if it's
+     * insufficient.
+     */
+    old_capacity = pattern->group_info_capacity;
+    new_capacity = pattern->group_info_capacity;
+    while (group > new_capacity)
+        new_capacity += RE_LIST_SIZE_INC;
+
+    if (new_capacity > old_capacity) {
+        new_group_info = (RE_GroupInfo*)re_realloc(pattern->group_info,
+          new_capacity * sizeof(RE_GroupInfo));
+        if (!new_group_info)
+            return FALSE;
+        memset(new_group_info + old_capacity, 0, (new_capacity - old_capacity)
+          * sizeof(RE_GroupInfo));
+
+        pattern->group_info = new_group_info;
+        pattern->group_info_capacity = new_capacity;
+    }
+
+    pattern->true_group_count = group;
+
+    return TRUE;
+}
+
+/* Records that there's a reference to a group. */
+Py_LOCAL_INLINE(BOOL) record_ref_group(PatternObject* pattern, size_t group) {
+    if (!ensure_group(pattern, group))
+        return FALSE;
+
+    pattern->group_info[group - 1].referenced = TRUE;
+
+    return TRUE;
+}
+
+/* Records that there's a new group. */
+Py_LOCAL_INLINE(BOOL) record_group(PatternObject* pattern, size_t group,
+  RE_Node* node) {
+    if (!ensure_group(pattern, group))
+        return FALSE;
+
+    if (group >= 1) {
+        RE_GroupInfo* info;
+
+        info = &pattern->group_info[group - 1];
+        info->end_index = (Py_ssize_t)pattern->true_group_count;
+        info->node = node;
+    }
+
+    return TRUE;
+}
+
+/* Records that a group has closed. */
+Py_LOCAL_INLINE(void) record_group_end(PatternObject* pattern, size_t group) {
+    if (group >= 1)
+        pattern->group_info[group - 1].end_index = ++pattern->group_end_index;
+}
+
+/* Ensures that the entry for a call_ref's details actually exists. */
+Py_LOCAL_INLINE(BOOL) ensure_call_ref(PatternObject* pattern, size_t call_ref)
+  {
+    size_t old_capacity;
+    size_t new_capacity;
+    RE_CallRefInfo* new_call_ref_info;
+
+    if (call_ref < pattern->call_ref_info_count)
+        /* We already have an entry for the call_ref. */
+        return TRUE;
+
+    /* Increase the storage capacity to include the new entry if it's
+     * insufficient.
+     */
+    old_capacity = pattern->call_ref_info_capacity;
+    new_capacity = pattern->call_ref_info_capacity;
+    while (call_ref >= new_capacity)
+        new_capacity += RE_LIST_SIZE_INC;
+
+    if (new_capacity > old_capacity) {
+        new_call_ref_info = (RE_CallRefInfo*)re_realloc(pattern->call_ref_info,
+          new_capacity * sizeof(RE_CallRefInfo));
+        if (!new_call_ref_info)
+            return FALSE;
+        memset(new_call_ref_info + old_capacity, 0, (new_capacity -
+          old_capacity) * sizeof(RE_CallRefInfo));
+
+        pattern->call_ref_info = new_call_ref_info;
+        pattern->call_ref_info_capacity = new_capacity;
+    }
+
+    pattern->call_ref_info_count = 1 + call_ref;
+
+    return TRUE;
+}
+
+/* Records that a call_ref is defined. */
+Py_LOCAL_INLINE(BOOL) record_call_ref_defined(PatternObject* pattern, size_t
+  call_ref, RE_Node* node) {
+    if (!ensure_call_ref(pattern, call_ref))
+        return FALSE;
+
+    pattern->call_ref_info[call_ref].defined = TRUE;
+    pattern->call_ref_info[call_ref].node = node;
+
+    return TRUE;
+}
+
+/* Records that a call_ref is used. */
+Py_LOCAL_INLINE(BOOL) record_call_ref_used(PatternObject* pattern, size_t
+  call_ref) {
+    if (!ensure_call_ref(pattern, call_ref))
+        return FALSE;
+
+    pattern->call_ref_info[call_ref].used = TRUE;
+
+    return TRUE;
+}
+
+/* Checks whether a node matches one and only one character. */
+Py_LOCAL_INLINE(BOOL) sequence_matches_one(RE_Node* node) {
+    while (node->op == RE_OP_BRANCH && !node->nonstring.next_2.node)
+        node = node->next_1.node;
+
+    if (node->next_1.node || (node->status & RE_STATUS_FUZZY))
+        return FALSE;
+
+    return node_matches_one_character(node);
+}
+
+/* Records a repeat. */
+Py_LOCAL_INLINE(BOOL) record_repeat(PatternObject* pattern, size_t index,
+  size_t repeat_depth) {
+    size_t old_capacity;
+    size_t new_capacity;
+
+    /* Increase the storage capacity to include the new entry if it's
+     * insufficient.
+     */
+    old_capacity = pattern->repeat_info_capacity;
+    new_capacity = pattern->repeat_info_capacity;
+    while (index >= new_capacity)
+        new_capacity += RE_LIST_SIZE_INC;
+
+    if (new_capacity > old_capacity) {
+        RE_RepeatInfo* new_repeat_info;
+
+        new_repeat_info = (RE_RepeatInfo*)re_realloc(pattern->repeat_info,
+          new_capacity * sizeof(RE_RepeatInfo));
+        if (!new_repeat_info)
+            return FALSE;
+        memset(new_repeat_info + old_capacity, 0, (new_capacity - old_capacity)
+          * sizeof(RE_RepeatInfo));
+
+        pattern->repeat_info = new_repeat_info;
+        pattern->repeat_info_capacity = new_capacity;
+    }
+
+    if (index >= pattern->repeat_count)
+        pattern->repeat_count = index + 1;
+
+    if (repeat_depth > 0)
+        pattern->repeat_info[index].status |= RE_STATUS_INNER;
+
+    return TRUE;
+}
+
+Py_LOCAL_INLINE(Py_ssize_t) get_step(RE_CODE op) {
+    switch (op) {
+    case RE_OP_ANY:
+    case RE_OP_ANY_ALL:
+    case RE_OP_ANY_U:
+    case RE_OP_CHARACTER:
+    case RE_OP_CHARACTER_IGN:
+    case RE_OP_PROPERTY:
+    case RE_OP_PROPERTY_IGN:
+    case RE_OP_RANGE:
+    case RE_OP_RANGE_IGN:
+    case RE_OP_SET_DIFF:
+    case RE_OP_SET_DIFF_IGN:
+    case RE_OP_SET_INTER:
+    case RE_OP_SET_INTER_IGN:
+    case RE_OP_SET_SYM_DIFF:
+    case RE_OP_SET_SYM_DIFF_IGN:
+    case RE_OP_SET_UNION:
+    case RE_OP_SET_UNION_IGN:
+    case RE_OP_STRING:
+    case RE_OP_STRING_FLD:
+    case RE_OP_STRING_IGN:
+        return 1;
+    case RE_OP_ANY_ALL_REV:
+    case RE_OP_ANY_REV:
+    case RE_OP_ANY_U_REV:
+    case RE_OP_CHARACTER_IGN_REV:
+    case RE_OP_CHARACTER_REV:
+    case RE_OP_PROPERTY_IGN_REV:
+    case RE_OP_PROPERTY_REV:
+    case RE_OP_RANGE_IGN_REV:
+    case RE_OP_RANGE_REV:
+    case RE_OP_SET_DIFF_IGN_REV:
+    case RE_OP_SET_DIFF_REV:
+    case RE_OP_SET_INTER_IGN_REV:
+    case RE_OP_SET_INTER_REV:
+    case RE_OP_SET_SYM_DIFF_IGN_REV:
+    case RE_OP_SET_SYM_DIFF_REV:
+    case RE_OP_SET_UNION_IGN_REV:
+    case RE_OP_SET_UNION_REV:
+    case RE_OP_STRING_FLD_REV:
+    case RE_OP_STRING_IGN_REV:
+    case RE_OP_STRING_REV:
+        return -1;
+    }
+
+    return 0;
+}
+
+Py_LOCAL_INLINE(int) build_sequence(RE_CompileArgs* args);
+
+/* Builds an ANY node. */
+Py_LOCAL_INLINE(int) build_ANY(RE_CompileArgs* args) {
+    RE_UINT8 op;
+    RE_CODE flags;
+    Py_ssize_t step;
+    RE_Node* node;
+
+    /* codes: opcode, flags. */
+    if (args->code + 1 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    op = (RE_UINT8)args->code[0];
+    flags = args->code[1];
+
+    step = get_step(op);
+
+    /* Create the node. */
+    node = create_node(args->pattern, op, flags, step, 0);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    args->code += 2;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    ++args->min_width;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a FUZZY node. */
+Py_LOCAL_INLINE(int) build_FUZZY(RE_CompileArgs* args) {
+    RE_CODE flags;
+    RE_Node* start_node;
+    RE_Node* end_node;
+    RE_CODE index;
+    RE_CompileArgs subargs;
+    int status;
+
+    /* codes: opcode, flags, constraints, sequence, end. */
+    if (args->code + 13 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    flags = args->code[1];
+
+    /* Create nodes for the start and end of the fuzzy sequence. */
+    start_node = create_node(args->pattern, RE_OP_FUZZY, flags, 0, 9);
+    end_node = create_node(args->pattern, RE_OP_END_FUZZY, flags, 0, 5);
+    if (!start_node || !end_node)
+        return RE_ERROR_MEMORY;
+
+    index = (RE_CODE)args->pattern->fuzzy_count++;
+    start_node->values[0] = index;
+    end_node->values[0] = index;
+
+    /* The constraints consist of 4 pairs of limits and the cost equation. */
+    end_node->values[RE_FUZZY_VAL_MIN_DEL] = args->code[2]; /* Deletion minimum. */
+    end_node->values[RE_FUZZY_VAL_MIN_INS] = args->code[4]; /* Insertion minimum. */
+    end_node->values[RE_FUZZY_VAL_MIN_SUB] = args->code[6]; /* Substitution minimum. */
+    end_node->values[RE_FUZZY_VAL_MIN_ERR] = args->code[8]; /* Error minimum. */
+
+    start_node->values[RE_FUZZY_VAL_MAX_DEL] = args->code[3]; /* Deletion maximum. */
+    start_node->values[RE_FUZZY_VAL_MAX_INS] = args->code[5]; /* Insertion maximum. */
+    start_node->values[RE_FUZZY_VAL_MAX_SUB] = args->code[7]; /* Substitution maximum. */
+    start_node->values[RE_FUZZY_VAL_MAX_ERR] = args->code[9]; /* Error maximum. */
+
+    start_node->values[RE_FUZZY_VAL_DEL_COST] = args->code[10]; /* Deletion cost. */
+    start_node->values[RE_FUZZY_VAL_INS_COST] = args->code[11]; /* Insertion cost. */
+    start_node->values[RE_FUZZY_VAL_SUB_COST] = args->code[12]; /* Substitution cost. */
+    start_node->values[RE_FUZZY_VAL_MAX_COST] = args->code[13]; /* Total cost. */
+
+    args->code += 14;
+
+    subargs = *args;
+    subargs.within_fuzzy = TRUE;
+
+    /* Compile the sequence and check that we've reached the end of the
+     * subpattern.
+     */
+    status = build_sequence(&subargs);
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    if (subargs.code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    args->code = subargs.code;
+    args->min_width += subargs.min_width;
+    args->has_captures |= subargs.has_captures;
+    args->is_fuzzy = TRUE;
+    args->has_groups |= subargs.has_groups;
+    args->has_repeats |= subargs.has_repeats;
+
+    ++args->code;
+
+    /* Append the fuzzy sequence. */
+    add_node(args->end, start_node);
+    add_node(start_node, subargs.start);
+    add_node(subargs.end, end_node);
+    args->end = end_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds an ATOMIC node. */
+Py_LOCAL_INLINE(int) build_ATOMIC(RE_CompileArgs* args) {
+    RE_Node* atomic_node;
+    RE_CompileArgs subargs;
+    int status;
+    RE_Node* end_node;
+
+    /* codes: opcode, sequence, end. */
+    if (args->code + 1 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    atomic_node = create_node(args->pattern, RE_OP_ATOMIC, 0, 0, 0);
+    if (!atomic_node)
+        return RE_ERROR_MEMORY;
+
+    ++args->code;
+
+    /* Compile the sequence and check that we've reached the end of it. */
+    subargs = *args;
+
+    status = build_sequence(&subargs);
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    if (subargs.code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    args->code = subargs.code;
+    ++args->code;
+
+    /* Check the subpattern. */
+    args->min_width += subargs.min_width;
+    args->has_captures |= subargs.has_captures;
+    args->is_fuzzy |= subargs.is_fuzzy;
+    args->has_groups |= subargs.has_groups;
+    args->has_repeats |= subargs.has_repeats;
+
+    if (subargs.has_groups)
+        atomic_node->status |= RE_STATUS_HAS_GROUPS;
+
+    if (subargs.has_repeats)
+        atomic_node->status |= RE_STATUS_HAS_REPEATS;
+
+    /* Create the node to terminate the subpattern. */
+    end_node = create_node(subargs.pattern, RE_OP_END_ATOMIC, 0, 0, 0);
+    if (!end_node)
+        return RE_ERROR_MEMORY;
+
+    /* Append the new sequence. */
+    add_node(args->end, atomic_node);
+    add_node(atomic_node, subargs.start);
+    add_node(subargs.end, end_node);
+    args->end = end_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a BOUNDARY node. */
+Py_LOCAL_INLINE(int) build_BOUNDARY(RE_CompileArgs* args) {
+    RE_UINT8 op;
+    RE_CODE flags;
+    RE_Node* node;
+
+    /* codes: opcode, flags. */
+    if (args->code + 1 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    op = (RE_UINT8)args->code[0];
+    flags = args->code[1];
+
+    args->code += 2;
+
+    /* Create the node. */
+    node = create_node(args->pattern, op, flags, 0, 0);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a BRANCH node. */
+Py_LOCAL_INLINE(int) build_BRANCH(RE_CompileArgs* args) {
+    RE_Node* branch_node;
+    RE_Node* join_node;
+    Py_ssize_t min_width;
+    RE_CompileArgs subargs;
+    int status;
+
+    /* codes: opcode, branch, next, branch, end. */
+    if (args->code + 2 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    /* Create nodes for the start and end of the branch sequence. */
+    branch_node = create_node(args->pattern, RE_OP_BRANCH, 0, 0, 0);
+    join_node = create_node(args->pattern, RE_OP_BRANCH, 0, 0, 0);
+    if (!branch_node || !join_node)
+        return RE_ERROR_MEMORY;
+
+    /* Append the node. */
+    add_node(args->end, branch_node);
+    args->end = join_node;
+
+    min_width = PY_SSIZE_T_MAX;
+
+    subargs = *args;
+
+    /* A branch in the regular expression is compiled into a series of 2-way
+     * branches.
+     */
+    do {
+        RE_Node* next_branch_node;
+
+        /* Skip over the 'BRANCH' or 'NEXT' opcode. */
+        ++subargs.code;
+
+        /* Compile the sequence until the next 'BRANCH' or 'NEXT' opcode. */
+        status = build_sequence(&subargs);
+        if (status != RE_ERROR_SUCCESS)
+            return status;
+
+        min_width = min_ssize_t(min_width, subargs.min_width);
+
+        args->has_captures |= subargs.has_captures;
+        args->is_fuzzy |= subargs.is_fuzzy;
+        args->has_groups |= subargs.has_groups;
+        args->has_repeats |= subargs.has_repeats;
+
+        /* Append the sequence. */
+        add_node(branch_node, subargs.start);
+        add_node(subargs.end, join_node);
+
+        /* Create a start node for the next sequence and append it. */
+        next_branch_node = create_node(subargs.pattern, RE_OP_BRANCH, 0, 0, 0);
+        if (!next_branch_node)
+            return RE_ERROR_MEMORY;
+
+        add_node(branch_node, next_branch_node);
+        branch_node = next_branch_node;
+    } while (subargs.code < subargs.end_code && subargs.code[0] == RE_OP_NEXT);
+
+    /* We should have reached the end of the branch. */
+    if (subargs.code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    args->code = subargs.code;
+
+    ++args->code;
+    args->min_width += min_width;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a CALL_REF node. */
+Py_LOCAL_INLINE(int) build_CALL_REF(RE_CompileArgs* args) {
+    RE_CODE call_ref;
+    RE_Node* start_node;
+    RE_Node* end_node;
+    RE_CompileArgs subargs;
+    int status;
+
+    /* codes: opcode, call_ref. */
+    if (args->code + 1 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    call_ref = args->code[1];
+
+    args->code += 2;
+
+    /* Create nodes for the start and end of the subpattern. */
+    start_node = create_node(args->pattern, RE_OP_CALL_REF, 0, 0, 1);
+    end_node = create_node(args->pattern, RE_OP_GROUP_RETURN, 0, 0, 0);
+    if (!start_node || !end_node)
+        return RE_ERROR_MEMORY;
+
+    start_node->values[0] = call_ref;
+
+    /* Compile the sequence and check that we've reached the end of the
+     * subpattern.
+     */
+    subargs = *args;
+    status = build_sequence(&subargs);
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    if (subargs.code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    args->code = subargs.code;
+    args->min_width += subargs.min_width;
+    args->has_captures |= subargs.has_captures;
+    args->is_fuzzy |= subargs.is_fuzzy;
+    args->has_groups |= subargs.has_groups;
+    args->has_repeats |= subargs.has_repeats;
+
+    ++args->code;
+
+    /* Record that we defined a call_ref. */
+    if (!record_call_ref_defined(args->pattern, call_ref, start_node))
+        return RE_ERROR_MEMORY;
+
+    /* Append the node. */
+    add_node(args->end, start_node);
+    add_node(start_node, subargs.start);
+    add_node(subargs.end, end_node);
+    args->end = end_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a CHARACTER or PROPERTY node. */
+Py_LOCAL_INLINE(int) build_CHARACTER_or_PROPERTY(RE_CompileArgs* args) {
+    RE_UINT8 op;
+    RE_CODE flags;
+    Py_ssize_t step;
+    RE_Node* node;
+
+    /* codes: opcode, flags, value. */
+    if (args->code + 2 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    op = (RE_UINT8)args->code[0];
+    flags = args->code[1];
+
+    step = get_step(op);
+
+    if (flags & RE_ZEROWIDTH_OP)
+        step = 0;
+
+    /* Create the node. */
+    node = create_node(args->pattern, op, flags, step, 1);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    node->values[0] = args->code[2];
+
+    args->code += 3;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    if (step != 0)
+        ++args->min_width;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a CONDITIONAL node. */
+Py_LOCAL_INLINE(int) build_CONDITIONAL(RE_CompileArgs* args) {
+    RE_CODE flags;
+    BOOL forward;
+    RE_Node* test_node;
+    RE_CompileArgs subargs;
+    int status;
+    RE_Node* end_test_node;
+    RE_Node* end_node;
+    Py_ssize_t min_width;
+
+    /* codes: opcode, flags, forward, sequence, next, sequence, next, sequence,
+     * end.
+     */
+    if (args->code + 4 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    flags = args->code[1];
+    forward = (BOOL)args->code[2];
+
+    /* Create a node for the lookaround. */
+    test_node = create_node(args->pattern, RE_OP_CONDITIONAL, flags, 0, 0);
+    if (!test_node)
+        return RE_ERROR_MEMORY;
+
+    args->code += 3;
+
+    add_node(args->end, test_node);
+
+    /* Compile the lookaround test and check that we've reached the end of the
+     * subpattern.
+     */
+    subargs = *args;
+    subargs.forward = forward;
+    status = build_sequence(&subargs);
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    if (subargs.code[0] != RE_OP_NEXT)
+        return RE_ERROR_ILLEGAL;
+
+    args->code = subargs.code;
+    ++args->code;
+
+    /* Check the lookaround subpattern. */
+    args->has_captures |= subargs.has_captures;
+    args->is_fuzzy |= subargs.is_fuzzy;
+    args->has_groups |= subargs.has_groups;
+    args->has_repeats |= subargs.has_repeats;
+
+    if (subargs.has_groups)
+        test_node->status |= RE_STATUS_HAS_GROUPS;
+
+    if (subargs.has_repeats)
+        test_node->status |= RE_STATUS_HAS_REPEATS;
+
+    /* Create the node to terminate the test. */
+    end_test_node = create_node(args->pattern, RE_OP_END_CONDITIONAL, 0, 0, 0);
+    if (!end_test_node)
+        return RE_ERROR_MEMORY;
+
+    /* test node -> test -> end test node */
+    add_node(test_node, subargs.start);
+    add_node(subargs.end, end_test_node);
+
+    /* Compile the true branch. */
+    subargs = *args;
+    status = build_sequence(&subargs);
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    /* Check the true branch. */
+    args->code = subargs.code;
+    args->has_captures |= subargs.has_captures;
+    args->is_fuzzy |= subargs.is_fuzzy;
+    args->has_groups |= subargs.has_groups;
+    args->has_repeats |= subargs.has_repeats;
+
+    min_width = subargs.min_width;
+
+    /* Create the terminating node. */
+    end_node = create_node(args->pattern, RE_OP_BRANCH, 0, 0, 0);
+    if (!end_node)
+        return RE_ERROR_MEMORY;
+
+    /* end test node -> true branch -> end node */
+    add_node(end_test_node, subargs.start);
+    add_node(subargs.end, end_node);
+
+    if (args->code[0] == RE_OP_NEXT) {
+        /* There's a false branch. */
+        ++args->code;
+
+        /* Compile the false branch. */
+        subargs.code = args->code;
+        status = build_sequence(&subargs);
+        if (status != RE_ERROR_SUCCESS)
+            return status;
+
+        /* Check the false branch. */
+        args->code = subargs.code;
+        args->has_captures |= subargs.has_captures;
+        args->is_fuzzy |= subargs.is_fuzzy;
+        args->has_groups |= subargs.has_groups;
+        args->has_repeats |= subargs.has_repeats;
+
+        min_width = min_ssize_t(min_width, subargs.min_width);
+
+        /* test node -> false branch -> end node */
+        add_node(test_node, subargs.start);
+        add_node(subargs.end, end_node);
+    } else
+        /* end test node -> end node */
+        add_node(end_test_node, end_node);
+
+    if (args->code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    args->min_width += min_width;
+
+    ++args->code;
+
+    args->end = end_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a GROUP node. */
+Py_LOCAL_INLINE(int) build_GROUP(RE_CompileArgs* args) {
+    RE_CODE private_group;
+    RE_CODE public_group;
+    RE_Node* start_node;
+    RE_Node* end_node;
+    RE_CompileArgs subargs;
+    int status;
+
+    /* codes: opcode, private_group, public_group. */
+    if (args->code + 2 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    private_group = args->code[1];
+    public_group = args->code[2];
+
+    args->code += 3;
+
+    /* Create nodes for the start and end of the capture group. */
+    start_node = create_node(args->pattern, args->forward ? RE_OP_START_GROUP :
+      RE_OP_END_GROUP, 0, 0, 3);
+    end_node = create_node(args->pattern, args->forward ? RE_OP_END_GROUP :
+      RE_OP_START_GROUP, 0, 0, 3);
+    if (!start_node || !end_node)
+        return RE_ERROR_MEMORY;
+
+    start_node->values[0] = private_group;
+    end_node->values[0] = private_group;
+    start_node->values[1] = public_group;
+    end_node->values[1] = public_group;
+
+    /* Signal that the capture should be saved when it's complete. */
+    start_node->values[2] = 0;
+    end_node->values[2] = 1;
+
+    /* Record that we have a new capture group. */
+    if (!record_group(args->pattern, private_group, start_node))
+        return RE_ERROR_MEMORY;
+
+    /* Compile the sequence and check that we've reached the end of the capture
+     * group.
+     */
+    subargs = *args;
+    status = build_sequence(&subargs);
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    if (subargs.code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    args->code = subargs.code;
+    args->min_width += subargs.min_width;
+    args->has_captures |= subargs.has_captures | subargs.visible_captures;
+    args->is_fuzzy |= subargs.is_fuzzy;
+    args->has_groups |= TRUE;
+    args->has_repeats |= subargs.has_repeats;
+
+    ++args->code;
+
+    /* Record that the capture group has closed. */
+    record_group_end(args->pattern, private_group);
+
+    /* Append the capture group. */
+    add_node(args->end, start_node);
+    add_node(start_node, subargs.start);
+    add_node(subargs.end, end_node);
+    args->end = end_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a GROUP_CALL node. */
+Py_LOCAL_INLINE(int) build_GROUP_CALL(RE_CompileArgs* args) {
+    RE_CODE call_ref;
+    RE_Node* node;
+
+    /* codes: opcode, call_ref. */
+    if (args->code + 1 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    call_ref = args->code[1];
+
+    /* Create the node. */
+    node = create_node(args->pattern, RE_OP_GROUP_CALL, 0, 0, 1);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    node->values[0] = call_ref;
+
+    node->status |= RE_STATUS_HAS_GROUPS;
+    node->status |= RE_STATUS_HAS_REPEATS;
+
+    args->code += 2;
+
+    /* Record that we used a call_ref. */
+    if (!record_call_ref_used(args->pattern, call_ref))
+        return RE_ERROR_MEMORY;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a GROUP_EXISTS node. */
+Py_LOCAL_INLINE(int) build_GROUP_EXISTS(RE_CompileArgs* args) {
+    RE_CODE group;
+    RE_Node* start_node;
+    RE_Node* end_node;
+    RE_CompileArgs subargs;
+    int status;
+    Py_ssize_t min_width;
+
+    /* codes: opcode, sequence, next, sequence, end. */
+    if (args->code + 2 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    group = args->code[1];
+
+    args->code += 2;
+
+    /* Record that we have a reference to a group. If group is 0, then we have
+     * a DEFINE and not a true group.
+     */
+    if (group > 0 && !record_ref_group(args->pattern, group))
+        return RE_ERROR_MEMORY;
+
+    /* Create nodes for the start and end of the structure. */
+    start_node = create_node(args->pattern, RE_OP_GROUP_EXISTS, 0, 0, 1);
+    end_node = create_node(args->pattern, RE_OP_BRANCH, 0, 0, 0);
+    if (!start_node || !end_node)
+        return RE_ERROR_MEMORY;
+
+    start_node->values[0] = group;
+
+    subargs = *args;
+    status = build_sequence(&subargs);
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    args->code = subargs.code;
+    args->has_captures |= subargs.has_captures;
+    args->is_fuzzy |= subargs.is_fuzzy;
+    args->has_groups |= subargs.has_groups;
+    args->has_repeats |= subargs.has_repeats;
+
+    min_width = subargs.min_width;
+
+    /* Append the start node. */
+    add_node(args->end, start_node);
+    add_node(start_node, subargs.start);
+
+    if (args->code[0] == RE_OP_NEXT) {
+        RE_Node* true_branch_end;
+
+        ++args->code;
+
+        true_branch_end = subargs.end;
+
+        subargs.code = args->code;
+
+        status = build_sequence(&subargs);
+        if (status != RE_ERROR_SUCCESS)
+            return status;
+
+        args->code = subargs.code;
+        args->has_captures |= subargs.has_captures;
+        args->is_fuzzy |= subargs.is_fuzzy;
+
+        if (group == 0) {
+            /* Join the 2 branches end-to-end and bypass it. The sequence
+             * itself will never be matched as a whole, so it doesn't matter.
+             */
+            min_width = 0;
+
+            add_node(start_node, end_node);
+            add_node(true_branch_end, subargs.start);
+        } else {
+            args->has_groups |= subargs.has_groups;
+            args->has_repeats |= subargs.has_repeats;
+
+            min_width = min_ssize_t(min_width, subargs.min_width);
+
+            add_node(start_node, subargs.start);
+            add_node(true_branch_end, end_node);
+        }
+
+        add_node(subargs.end, end_node);
+    } else {
+        add_node(start_node, end_node);
+        add_node(subargs.end, end_node);
+
+        min_width = 0;
+    }
+
+    args->min_width += min_width;
+
+    if (args->code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    ++args->code;
+
+    args->end = end_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a LOOKAROUND node. */
+Py_LOCAL_INLINE(int) build_LOOKAROUND(RE_CompileArgs* args) {
+    RE_CODE flags;
+    BOOL forward;
+    RE_Node* lookaround_node;
+    RE_CompileArgs subargs;
+    int status;
+    RE_Node* end_node;
+    RE_Node* next_node;
+
+    /* codes: opcode, flags, forward, sequence, end. */
+    if (args->code + 3 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    flags = args->code[1];
+    forward = (BOOL)args->code[2];
+
+    /* Create a node for the lookaround. */
+    lookaround_node = create_node(args->pattern, RE_OP_LOOKAROUND, flags, 0,
+      0);
+    if (!lookaround_node)
+        return RE_ERROR_MEMORY;
+
+    args->code += 3;
+
+    /* Compile the sequence and check that we've reached the end of the
+     * subpattern.
+     */
+    subargs = *args;
+    subargs.forward = forward;
+    status = build_sequence(&subargs);
+    if (status != RE_ERROR_SUCCESS)
+        return status;
+
+    if (subargs.code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    args->code = subargs.code;
+    ++args->code;
+
+    /* Check the subpattern. */
+    args->has_captures |= subargs.has_captures;
+    args->is_fuzzy |= subargs.is_fuzzy;
+    args->has_groups |= subargs.has_groups;
+    args->has_repeats |= subargs.has_repeats;
+
+    if (subargs.has_groups)
+        lookaround_node->status |= RE_STATUS_HAS_GROUPS;
+
+    if (subargs.has_repeats)
+        lookaround_node->status |= RE_STATUS_HAS_REPEATS;
+
+    /* Create the node to terminate the subpattern. */
+    end_node = create_node(args->pattern, RE_OP_END_LOOKAROUND, 0, 0, 0);
+    if (!end_node)
+        return RE_ERROR_MEMORY;
+
+    /* Make a continuation node. */
+    next_node = create_node(args->pattern, RE_OP_BRANCH, 0, 0, 0);
+    if (!next_node)
+        return RE_ERROR_MEMORY;
+
+    /* Append the new sequence. */
+    add_node(args->end, lookaround_node);
+    add_node(lookaround_node, subargs.start);
+    add_node(lookaround_node, next_node);
+    add_node(subargs.end, end_node);
+    add_node(end_node, next_node);
+
+    args->end = next_node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a RANGE node. */
+Py_LOCAL_INLINE(int) build_RANGE(RE_CompileArgs* args) {
+    RE_UINT8 op;
+    RE_CODE flags;
+    Py_ssize_t step;
+    RE_Node* node;
+
+    /* codes: opcode, flags, lower, upper. */
+    if (args->code + 3 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    op = (RE_UINT8)args->code[0];
+    flags = args->code[1];
+
+    step = get_step(op);
+
+    if (flags & RE_ZEROWIDTH_OP)
+        step = 0;
+
+    /* Create the node. */
+    node = create_node(args->pattern, op, flags, step, 2);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    node->values[0] = args->code[2];
+    node->values[1] = args->code[3];
+
+    args->code += 4;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    if (step != 0)
+        ++args->min_width;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a REF_GROUP node. */
+Py_LOCAL_INLINE(int) build_REF_GROUP(RE_CompileArgs* args) {
+    RE_CODE flags;
+    RE_CODE group;
+    RE_Node* node;
+
+    /* codes: opcode, flags, group. */
+    if (args->code + 2 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    flags = args->code[1];
+    group = args->code[2];
+    node = create_node(args->pattern, (RE_UINT8)args->code[0], flags, 0, 1);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    node->values[0] = group;
+
+    args->code += 3;
+
+    /* Record that we have a reference to a group. */
+    if (!record_ref_group(args->pattern, group))
+        return RE_ERROR_MEMORY;
+
+    /* Append the reference. */
+    add_node(args->end, node);
+    args->end = node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a REPEAT node. */
+Py_LOCAL_INLINE(int) build_REPEAT(RE_CompileArgs* args) {
+    BOOL greedy;
+    RE_CODE min_count;
+    RE_CODE max_count;
+    int status;
+
+    /* codes: opcode, min_count, max_count, sequence, end. */
+    if (args->code + 3 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    greedy = args->code[0] == RE_OP_GREEDY_REPEAT;
+    min_count = args->code[1];
+    max_count = args->code[2];
+    if (args->code[1] > args->code[2])
+        return RE_ERROR_ILLEGAL;
+
+    args->code += 3;
+
+    if (min_count == 1 && max_count == 1) {
+        /* Singly-repeated sequence. */
+        RE_CompileArgs subargs;
+
+        subargs = *args;
+        status = build_sequence(&subargs);
+        if (status != RE_ERROR_SUCCESS)
+            return status;
+
+        if (subargs.code[0] != RE_OP_END)
+            return RE_ERROR_ILLEGAL;
+
+        args->code = subargs.code;
+        args->min_width += subargs.min_width;
+        args->has_captures |= subargs.has_captures;
+        args->is_fuzzy |= subargs.is_fuzzy;
+        args->has_groups |= subargs.has_groups;
+        args->has_repeats |= subargs.has_repeats;
+
+        ++args->code;
+
+        /* Append the sequence. */
+        add_node(args->end, subargs.start);
+        args->end = subargs.end;
+    } else {
+        size_t index;
+        RE_Node* repeat_node;
+        RE_CompileArgs subargs;
+
+        index = args->pattern->repeat_count;
+
+        /* Create the nodes for the repeat. */
+        repeat_node = create_node(args->pattern, greedy ? RE_OP_GREEDY_REPEAT :
+          RE_OP_LAZY_REPEAT, 0, args->forward ? 1 : -1, 4);
+        if (!repeat_node || !record_repeat(args->pattern, index,
+          args->repeat_depth))
+            return RE_ERROR_MEMORY;
+
+        repeat_node->values[0] = (RE_CODE)index;
+        repeat_node->values[1] = min_count;
+        repeat_node->values[2] = max_count;
+        repeat_node->values[3] = args->forward;
+
+        if (args->within_fuzzy)
+            args->pattern->repeat_info[index].status |= RE_STATUS_BODY;
+
+        /* Compile the 'body' and check that we've reached the end of it. */
+        subargs = *args;
+        subargs.visible_captures = TRUE;
+        ++subargs.repeat_depth;
+        status = build_sequence(&subargs);
+        if (status != RE_ERROR_SUCCESS)
+            return status;
+
+        if (subargs.code[0] != RE_OP_END)
+            return RE_ERROR_ILLEGAL;
+
+        args->code = subargs.code;
+        args->min_width += (Py_ssize_t)min_count * subargs.min_width;
+        args->has_captures |= subargs.has_captures;
+        args->is_fuzzy |= subargs.is_fuzzy;
+        args->has_groups |= subargs.has_groups;
+        args->has_repeats = TRUE;
+
+        ++args->code;
+
+        /* Is it a repeat of something which will match a single character?
+         *
+         * If it's in a fuzzy section then it won't be optimised as a
+         * single-character repeat.
+         */
+        if (sequence_matches_one(subargs.start)) {
+            repeat_node->op = greedy ? RE_OP_GREEDY_REPEAT_ONE :
+              RE_OP_LAZY_REPEAT_ONE;
+
+            /* Append the new sequence. */
+            add_node(args->end, repeat_node);
+            repeat_node->nonstring.next_2.node = subargs.start;
+            args->end = repeat_node;
+        } else {
+            RE_Node* end_repeat_node;
+            RE_Node* end_node;
+
+            end_repeat_node = create_node(args->pattern, greedy ?
+              RE_OP_END_GREEDY_REPEAT : RE_OP_END_LAZY_REPEAT, 0, args->forward
+              ? 1 : -1, 4);
+            if (!end_repeat_node)
+                return RE_ERROR_MEMORY;
+
+            end_repeat_node->values[0] = repeat_node->values[0];
+            end_repeat_node->values[1] = repeat_node->values[1];
+            end_repeat_node->values[2] = repeat_node->values[2];
+            end_repeat_node->values[3] = args->forward;
+
+            end_node = create_node(args->pattern, RE_OP_BRANCH, 0, 0, 0);
+            if (!end_node)
+                return RE_ERROR_MEMORY;
+
+            /* Append the new sequence. */
+            add_node(args->end, repeat_node);
+            add_node(repeat_node, subargs.start);
+            add_node(repeat_node, end_node);
+            add_node(subargs.end, end_repeat_node);
+            add_node(end_repeat_node, subargs.start);
+            add_node(end_repeat_node, end_node);
+            args->end = end_node;
+        }
+    }
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a STRING node. */
+Py_LOCAL_INLINE(int) build_STRING(RE_CompileArgs* args, BOOL is_charset) {
+    RE_CODE flags;
+    RE_CODE length;
+    RE_UINT8 op;
+    Py_ssize_t step;
+    RE_Node* node;
+    size_t i;
+
+    /* codes: opcode, flags, length, characters. */
+    flags = args->code[1];
+    length = args->code[2];
+    if (args->code + 3 + length > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    op = (RE_UINT8)args->code[0];
+
+    step = get_step(op);
+
+    /* Create the node. */
+    node = create_node(args->pattern, op, flags, step * (Py_ssize_t)length,
+      length);
+    if (!node)
+        return RE_ERROR_MEMORY;
+    if (!is_charset)
+        node->status |= RE_STATUS_STRING;
+
+    for (i = 0; i < length; i++)
+        node->values[i] = args->code[3 + i];
+
+    args->code += 3 + length;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    /* Because of full case-folding, one character in the text could match
+     * multiple characters in the pattern.
+     */
+    if (op == RE_OP_STRING_FLD || op == RE_OP_STRING_FLD_REV)
+        args->min_width += possible_unfolded_length((Py_ssize_t)length);
+    else
+        args->min_width += (Py_ssize_t)length;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a SET node. */
+Py_LOCAL_INLINE(int) build_SET(RE_CompileArgs* args) {
+    RE_UINT8 op;
+    RE_CODE flags;
+    Py_ssize_t step;
+    RE_Node* node;
+    Py_ssize_t min_width;
+    int status;
+
+    /* codes: opcode, flags, members. */
+    op = (RE_UINT8)args->code[0];
+    flags = args->code[1];
+
+    step = get_step(op);
+
+    if (flags & RE_ZEROWIDTH_OP)
+        step = 0;
+
+    node = create_node(args->pattern, op, flags, step, 0);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    args->code += 2;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    min_width = args->min_width;
+
+    /* Compile the character set. */
+    do {
+        switch (args->code[0]) {
+        case RE_OP_CHARACTER:
+        case RE_OP_PROPERTY:
+            status = build_CHARACTER_or_PROPERTY(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_RANGE:
+            status = build_RANGE(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_SET_DIFF:
+        case RE_OP_SET_INTER:
+        case RE_OP_SET_SYM_DIFF:
+        case RE_OP_SET_UNION:
+            status = build_SET(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_STRING:
+            /* A set of characters. */
+            if (!build_STRING(args, TRUE))
+                return FALSE;
+            break;
+        default:
+            /* Illegal opcode for a character set. */
+            return RE_ERROR_ILLEGAL;
+        }
+    } while (args->code < args->end_code && args->code[0] != RE_OP_END);
+
+    /* Check that we've reached the end correctly. (The last opcode should be
+     * 'END'.)
+     */
+    if (args->code >= args->end_code || args->code[0] != RE_OP_END)
+        return RE_ERROR_ILLEGAL;
+
+    ++args->code;
+
+    /* At this point the set's members are in the main sequence. They need to
+     * be moved out-of-line.
+     */
+    node->nonstring.next_2.node = node->next_1.node;
+    node->next_1.node = NULL;
+    args->end = node;
+
+    args->min_width = min_width;
+
+    if (step != 0)
+        ++args->min_width;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a STRING_SET node. */
+Py_LOCAL_INLINE(int) build_STRING_SET(RE_CompileArgs* args) {
+    RE_CODE index;
+    RE_CODE min_len;
+    RE_CODE max_len;
+    RE_Node* node;
+
+    /* codes: opcode, index, min_len, max_len. */
+    if (args->code + 3 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    index = args->code[1];
+    min_len = args->code[2];
+    max_len = args->code[3];
+    node = create_node(args->pattern, (RE_UINT8)args->code[0], 0, 0, 3);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    node->values[0] = index;
+    node->values[1] = min_len;
+    node->values[2] = max_len;
+
+    args->code += 4;
+
+    /* Append the reference. */
+    add_node(args->end, node);
+    args->end = node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a SUCCESS node . */
+Py_LOCAL_INLINE(int) build_SUCCESS(RE_CompileArgs* args) {
+    RE_Node* node;
+    /* code: opcode. */
+
+    /* Create the node. */
+    node = create_node(args->pattern, (RE_UINT8)args->code[0], 0, 0, 0);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    ++args->code;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a zero-width node. */
+Py_LOCAL_INLINE(int) build_zerowidth(RE_CompileArgs* args) {
+    RE_CODE flags;
+    RE_Node* node;
+
+    /* codes: opcode, flags. */
+    if (args->code + 1 > args->end_code)
+        return RE_ERROR_ILLEGAL;
+
+    flags = args->code[1];
+
+    /* Create the node. */
+    node = create_node(args->pattern, (RE_UINT8)args->code[0], flags, 0, 0);
+    if (!node)
+        return RE_ERROR_MEMORY;
+
+    args->code += 2;
+
+    /* Append the node. */
+    add_node(args->end, node);
+    args->end = node;
+
+    return RE_ERROR_SUCCESS;
+}
+
+/* Builds a sequence of nodes from regular expression code. */
+Py_LOCAL_INLINE(int) build_sequence(RE_CompileArgs* args) {
+    int status;
+
+    /* Guarantee that there's something to attach to. */
+    args->start = create_node(args->pattern, RE_OP_BRANCH, 0, 0, 0);
+    args->end = args->start;
+
+    args->min_width = 0;
+    args->has_captures = FALSE;
+    args->is_fuzzy = FALSE;
+    args->has_groups = FALSE;
+    args->has_repeats = FALSE;
+
+    /* The sequence should end with an opcode we don't understand. If it
+     * doesn't then the code is illegal.
+     */
+    while (args->code < args->end_code) {
+        /* The following code groups opcodes by format, not function. */
+        switch (args->code[0]) {
+        case RE_OP_ANY:
+        case RE_OP_ANY_ALL:
+        case RE_OP_ANY_ALL_REV:
+        case RE_OP_ANY_REV:
+        case RE_OP_ANY_U:
+        case RE_OP_ANY_U_REV:
+            /* A simple opcode with no trailing codewords and width of 1. */
+            status = build_ANY(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_ATOMIC:
+            /* An atomic sequence. */
+            status = build_ATOMIC(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_BOUNDARY:
+        case RE_OP_DEFAULT_BOUNDARY:
+        case RE_OP_DEFAULT_END_OF_WORD:
+        case RE_OP_DEFAULT_START_OF_WORD:
+        case RE_OP_END_OF_WORD:
+        case RE_OP_GRAPHEME_BOUNDARY:
+        case RE_OP_KEEP:
+        case RE_OP_SKIP:
+        case RE_OP_START_OF_WORD:
+            /* A word or grapheme boundary. */
+            status = build_BOUNDARY(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_BRANCH:
+            /* A 2-way branch. */
+            status = build_BRANCH(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_CALL_REF:
+            /* A group call ref. */
+            status = build_CALL_REF(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_CHARACTER:
+        case RE_OP_CHARACTER_IGN:
+        case RE_OP_CHARACTER_IGN_REV:
+        case RE_OP_CHARACTER_REV:
+        case RE_OP_PROPERTY:
+        case RE_OP_PROPERTY_IGN:
+        case RE_OP_PROPERTY_IGN_REV:
+        case RE_OP_PROPERTY_REV:
+            /* A character literal or a property. */
+            status = build_CHARACTER_or_PROPERTY(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_CONDITIONAL:
+            /* A lookaround conditional. */
+            status = build_CONDITIONAL(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_END_OF_LINE:
+        case RE_OP_END_OF_LINE_U:
+        case RE_OP_END_OF_STRING:
+        case RE_OP_END_OF_STRING_LINE:
+        case RE_OP_END_OF_STRING_LINE_U:
+        case RE_OP_SEARCH_ANCHOR:
+        case RE_OP_START_OF_LINE:
+        case RE_OP_START_OF_LINE_U:
+        case RE_OP_START_OF_STRING:
+            /* A simple opcode with no trailing codewords and width of 0. */
+            status = build_zerowidth(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_FAILURE:
+        case RE_OP_PRUNE:
+        case RE_OP_SUCCESS:
+            status = build_SUCCESS(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_FUZZY:
+            /* A fuzzy sequence. */
+            status = build_FUZZY(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_GREEDY_REPEAT:
+        case RE_OP_LAZY_REPEAT:
+            /* A repeated sequence. */
+            status = build_REPEAT(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_GROUP:
+            /* A capture group. */
+            status = build_GROUP(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_GROUP_CALL:
+            /* A group call. */
+            status = build_GROUP_CALL(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_GROUP_EXISTS:
+            /* A conditional sequence. */
+            status = build_GROUP_EXISTS(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_LOOKAROUND:
+            /* A lookaround. */
+            status = build_LOOKAROUND(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_RANGE:
+        case RE_OP_RANGE_IGN:
+        case RE_OP_RANGE_IGN_REV:
+        case RE_OP_RANGE_REV:
+            /* A range. */
+            status = build_RANGE(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_REF_GROUP:
+        case RE_OP_REF_GROUP_FLD:
+        case RE_OP_REF_GROUP_FLD_REV:
+        case RE_OP_REF_GROUP_IGN:
+        case RE_OP_REF_GROUP_IGN_REV:
+        case RE_OP_REF_GROUP_REV:
+            /* A reference to a group. */
+            status = build_REF_GROUP(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_SET_DIFF:
+        case RE_OP_SET_DIFF_IGN:
+        case RE_OP_SET_DIFF_IGN_REV:
+        case RE_OP_SET_DIFF_REV:
+        case RE_OP_SET_INTER:
+        case RE_OP_SET_INTER_IGN:
+        case RE_OP_SET_INTER_IGN_REV:
+        case RE_OP_SET_INTER_REV:
+        case RE_OP_SET_SYM_DIFF:
+        case RE_OP_SET_SYM_DIFF_IGN:
+        case RE_OP_SET_SYM_DIFF_IGN_REV:
+        case RE_OP_SET_SYM_DIFF_REV:
+        case RE_OP_SET_UNION:
+        case RE_OP_SET_UNION_IGN:
+        case RE_OP_SET_UNION_IGN_REV:
+        case RE_OP_SET_UNION_REV:
+            /* A set. */
+            status = build_SET(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        case RE_OP_STRING:
+        case RE_OP_STRING_FLD:
+        case RE_OP_STRING_FLD_REV:
+        case RE_OP_STRING_IGN:
+        case RE_OP_STRING_IGN_REV:
+        case RE_OP_STRING_REV:
+            /* A string literal. */
+            if (!build_STRING(args, FALSE))
+                return FALSE;
+            break;
+        case RE_OP_STRING_SET:
+        case RE_OP_STRING_SET_FLD:
+        case RE_OP_STRING_SET_FLD_REV:
+        case RE_OP_STRING_SET_IGN:
+        case RE_OP_STRING_SET_IGN_REV:
+        case RE_OP_STRING_SET_REV:
+            /* A reference to a list. */
+            status = build_STRING_SET(args);
+            if (status != RE_ERROR_SUCCESS)
+                return status;
+            break;
+        default:
+            /* We've found an opcode which we don't recognise. We'll leave it
+             * for the caller.
+             */
+            return RE_ERROR_SUCCESS;
+        }
+    }
+
+    /* If we're here then we should be at the end of the code, otherwise we
+     * have an error.
+     */
+    return args->code == args->end_code;
+}
+
+/* Compiles the regular expression code to 'nodes'.
+ *
+ * Various details about the regular expression are discovered during
+ * compilation and stored in the PatternObject.
+ */
+Py_LOCAL_INLINE(BOOL) compile_to_nodes(RE_CODE* code, RE_CODE* end_code,
+  PatternObject* pattern) {
+    RE_CompileArgs args;
+    int status;
+
+    /* Compile a regex sequence and then check that we've reached the end
+     * correctly. (The last opcode should be 'SUCCESS'.)
+     *
+     * If successful, 'start' and 'end' will point to the start and end nodes
+     * of the compiled sequence.
+     */
+    args.code = code;
+    args.end_code = end_code;
+    args.pattern = pattern;
+    args.forward = (pattern->flags & RE_FLAG_REVERSE) == 0;
+    args.visible_captures = FALSE;
+    args.has_captures = FALSE;
+    args.repeat_depth = 0;
+    args.is_fuzzy = FALSE;
+    args.within_fuzzy = FALSE;
+    status = build_sequence(&args);
+    if (status == RE_ERROR_ILLEGAL)
+        set_error(RE_ERROR_ILLEGAL, NULL);
+
+    if (status != RE_ERROR_SUCCESS)
+        return FALSE;
+
+    pattern->min_width = args.min_width;
+    pattern->is_fuzzy = args.is_fuzzy;
+    pattern->do_search_start = TRUE;
+    pattern->start_node = args.start;
+
+    /* Optimise the pattern. */
+    if (!optimise_pattern(pattern))
+        return FALSE;
+
+    pattern->start_test = locate_test_start(pattern->start_node);
+
+    /* Get the call_ref for the entire pattern, if any. */
+    if (pattern->start_node->op == RE_OP_CALL_REF)
+        pattern->pattern_call_ref = (Py_ssize_t)pattern->start_node->values[0];
+    else
+        pattern->pattern_call_ref = -1;
+
+    return TRUE;
+}
+
+/* Gets the required characters for a regex.
+ *
+ * In the event of an error, it just pretends that there are no required
+ * characters.
+ */
+Py_LOCAL_INLINE(void) get_required_chars(PyObject* required_chars, RE_CODE**
+  req_chars, size_t* req_length) {
+    Py_ssize_t len;
+    RE_CODE* chars;
+    Py_ssize_t i;
+
+    *req_chars = NULL;
+    *req_length = 0;
+
+    len = PyTuple_GET_SIZE(required_chars);
+    if (len < 1 || PyErr_Occurred()) {
+        PyErr_Clear();
+        return;
+    }
+
+    chars = (RE_CODE*)re_alloc((size_t)len * sizeof(RE_CODE));
+    if (!chars)
+        goto error;
+
+    for (i = 0; i < len; i++) {
+        PyObject* o;
+        size_t value;
+
+        /* PyTuple_SET_ITEM borrows the reference. */
+        o = PyTuple_GET_ITEM(required_chars, i);
+
+        value = PyLong_AsUnsignedLong(o);
+        if ((Py_ssize_t)value == -1 && PyErr_Occurred())
+            goto error;
+
+        chars[i] = (RE_CODE)value;
+        if (chars[i] != value)
+            goto error;
+    }
+
+    *req_chars = chars;
+    *req_length = (size_t)len;
+
+    return;
+
+error:
+    PyErr_Clear();
+    re_dealloc(chars);
+}
+
+/* Makes a STRING node. */
+Py_LOCAL_INLINE(RE_Node*) make_STRING_node(PatternObject* pattern, RE_UINT8 op,
+  size_t length, RE_CODE* chars) {
+    Py_ssize_t step;
+    RE_Node* node;
+    size_t i;
+
+    step = get_step(op);
+
+    /* Create the node. */
+    node = create_node(pattern, op, 0, step * (Py_ssize_t)length, length);
+    if (!node)
+        return NULL;
+
+    node->status |= RE_STATUS_STRING;
+
+    for (i = 0; i < length; i++)
+        node->values[i] = chars[i];
+
+    return node;
+}
+
+/* Scans all of the characters in the current locale for their properties. */
+Py_LOCAL_INLINE(void) scan_locale_chars(RE_LocaleInfo* locale_info) {
+    int c;
+
+    for (c = 0; c < 0x100; c++) {
+        unsigned short props = 0;
+
+        if (isalnum(c))
+            props |= RE_LOCALE_ALNUM;
+        if (isalpha(c))
+            props |= RE_LOCALE_ALPHA;
+        if (iscntrl(c))
+            props |= RE_LOCALE_CNTRL;
+        if (isdigit(c))
+            props |= RE_LOCALE_DIGIT;
+        if (isgraph(c))
+            props |= RE_LOCALE_GRAPH;
+        if (islower(c))
+            props |= RE_LOCALE_LOWER;
+        if (isprint(c))
+            props |= RE_LOCALE_PRINT;
+        if (ispunct(c))
+            props |= RE_LOCALE_PUNCT;
+        if (isspace(c))
+            props |= RE_LOCALE_SPACE;
+        if (isupper(c))
+            props |= RE_LOCALE_UPPER;
+
+        locale_info->properties[c] = props;
+        locale_info->uppercase[c] = (unsigned char)toupper(c);
+        locale_info->lowercase[c] = (unsigned char)tolower(c);
+    }
+}
+
+/* Compiles regular expression code to a PatternObject.
+ *
+ * The regular expression code is provided as a list and is then compiled to
+ * 'nodes'. Various details about the regular expression are discovered during
+ * compilation and stored in the PatternObject.
+ */
+static PyObject* re_compile(PyObject* self_, PyObject* args) {
+    PyObject* pattern;
+    Py_ssize_t flags = 0;
+    PyObject* code_list;
+    PyObject* groupindex;
+    PyObject* indexgroup;
+    PyObject* named_lists;
+    PyObject* named_list_indexes;
+    Py_ssize_t req_offset;
+    PyObject* required_chars;
+    Py_ssize_t req_flags;
+    size_t public_group_count;
+    Py_ssize_t code_len;
+    RE_CODE* code;
+    Py_ssize_t i;
+    RE_CODE* req_chars;
+    size_t req_length;
+    PatternObject* self;
+    BOOL unicode;
+    BOOL locale;
+    BOOL ascii;
+    BOOL ok;
+
+    if (!PyArg_ParseTuple(args, "OnOOOOOnOnn:re_compile", &pattern, &flags,
+      &code_list, &groupindex, &indexgroup, &named_lists, &named_list_indexes,
+      &req_offset, &required_chars, &req_flags, &public_group_count))
+        return NULL;
+
+    /* Read the regex code. */
+    code_len = PyList_GET_SIZE(code_list);
+    code = (RE_CODE*)re_alloc((size_t)code_len * sizeof(RE_CODE));
+    if (!code)
+        return NULL;
+
+    for (i = 0; i < code_len; i++) {
+        PyObject* o;
+        size_t value;
+
+        /* PyList_GET_ITEM borrows a reference. */
+        o = PyList_GET_ITEM(code_list, i);
+
+        value = PyLong_AsUnsignedLong(o);
+        if ((Py_ssize_t)value == -1 && PyErr_Occurred())
+            goto error;
+
+        code[i] = (RE_CODE)value;
+        if (code[i] != value)
+            goto error;
+    }
+
+    /* Get the required characters. */
+    get_required_chars(required_chars, &req_chars, &req_length);
+
+    /* Create the PatternObject. */
+    self = PyObject_NEW(PatternObject, &Pattern_Type);
+    if (!self) {
+        set_error(RE_ERROR_MEMORY, NULL);
+        re_dealloc(req_chars);
+        re_dealloc(code);
+        return NULL;
+    }
+
+    /* Initialise the PatternObject. */
+    self->pattern = pattern;
+    self->flags = flags;
+    self->weakreflist = NULL;
+    self->start_node = NULL;
+    self->repeat_count = 0;
+    self->true_group_count = 0;
+    self->public_group_count = public_group_count;
+    self->group_end_index = 0;
+    self->groupindex = groupindex;
+    self->indexgroup = indexgroup;
+    self->named_lists = named_lists;
+    self->named_lists_count = (size_t)PyDict_Size(named_lists);
+    self->partial_named_lists[0] = NULL;
+    self->partial_named_lists[1] = NULL;
+    self->named_list_indexes = named_list_indexes;
+    self->node_capacity = 0;
+    self->node_count = 0;
+    self->node_list = NULL;
+    self->group_info_capacity = 0;
+    self->group_info = NULL;
+    self->call_ref_info_capacity = 0;
+    self->call_ref_info_count = 0;
+    self->call_ref_info = NULL;
+    self->repeat_info_capacity = 0;
+    self->repeat_info = NULL;
+    self->groups_storage = NULL;
+    self->repeats_storage = NULL;
+    self->fuzzy_count = 0;
+    self->recursive = FALSE;
+    self->req_offset = req_offset;
+    self->req_string = NULL;
+    self->locale_info = NULL;
+    Py_INCREF(self->pattern);
+    Py_INCREF(self->groupindex);
+    Py_INCREF(self->indexgroup);
+    Py_INCREF(self->named_lists);
+    Py_INCREF(self->named_list_indexes);
+
+    /* Initialise the character encoding. */
+    unicode = (flags & RE_FLAG_UNICODE) != 0;
+    locale = (flags & RE_FLAG_LOCALE) != 0;
+    ascii = (flags & RE_FLAG_ASCII) != 0;
+    if (!unicode && !locale && !ascii) {
+        if (PyString_Check(self->pattern))
+            ascii = RE_FLAG_ASCII;
+        else
+            unicode = RE_FLAG_UNICODE;
+    }
+    if (unicode)
+        self->encoding = &unicode_encoding;
+    else if (locale)
+        self->encoding = &locale_encoding;
+    else if (ascii)
+        self->encoding = &ascii_encoding;
+
+    /* Compile the regular expression code to nodes. */
+    ok = compile_to_nodes(code, code + code_len, self);
+
+    /* We no longer need the regular expression code. */
+    re_dealloc(code);
+
+    if (!ok) {
+        Py_DECREF(self);
+        re_dealloc(req_chars);
+        return NULL;
+    }
+
+    /* Make a node for the required string, if there's one. */
+    if (req_chars) {
+        /* Remove the FULLCASE flag if it's not a Unicode pattern or not
+         * ignoring case.
+         */
+        if (!(self->flags & RE_FLAG_UNICODE) || !(self->flags &
+          RE_FLAG_IGNORECASE))
+            req_flags &= ~RE_FLAG_FULLCASE;
+
+        if (self->flags & RE_FLAG_REVERSE) {
+            switch (req_flags) {
+            case 0:
+                self->req_string = make_STRING_node(self, RE_OP_STRING_REV,
+                  req_length, req_chars);
+                break;
+            case RE_FLAG_IGNORECASE | RE_FLAG_FULLCASE:
+                self->req_string = make_STRING_node(self, RE_OP_STRING_FLD_REV,
+                  req_length, req_chars);
+                break;
+            case RE_FLAG_IGNORECASE:
+                self->req_string = make_STRING_node(self, RE_OP_STRING_IGN_REV,
+                  req_length, req_chars);
+                break;
+            }
+        } else {
+            switch (req_flags) {
+            case 0:
+                self->req_string = make_STRING_node(self, RE_OP_STRING,
+                  req_length, req_chars);
+                break;
+            case RE_FLAG_IGNORECASE | RE_FLAG_FULLCASE:
+                self->req_string = make_STRING_node(self, RE_OP_STRING_FLD,
+                  req_length, req_chars);
+                break;
+            case RE_FLAG_IGNORECASE:
+                self->req_string = make_STRING_node(self, RE_OP_STRING_IGN,
+                  req_length, req_chars);
+                break;
+            }
+        }
+
+        re_dealloc(req_chars);
+    }
+
+    if (locale) {
+        /* Store info about the characters in the locale for locale-sensitive
+         * matching.
+         */
+        self->locale_info = re_alloc(sizeof(RE_LocaleInfo));
+        if (!self->locale_info) {
+            Py_DECREF(self);
+            return NULL;
+        }
+
+        scan_locale_chars(self->locale_info);
+    }
+
+    return (PyObject*)self;
+
+error:
+    re_dealloc(code);
+    set_error(RE_ERROR_ILLEGAL, NULL);
+    return NULL;
+}
+
+/* Gets the size of the codewords. */
+static PyObject* get_code_size(PyObject* self, PyObject* unused) {
+    return Py_BuildValue("n", sizeof(RE_CODE));
+}
+
+/* Gets the property dict. */
+static PyObject* get_properties(PyObject* self_, PyObject* args) {
+    Py_INCREF(property_dict);
+
+    return property_dict;
+}
+
+/* Folds the case of a string. */
+static PyObject* fold_case(PyObject* self_, PyObject* args) {
+    RE_StringInfo str_info;
+    Py_UCS4 (*char_at)(void* text, Py_ssize_t pos);
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo locale_info;
+    Py_ssize_t folded_charsize;
+    void (*set_char_at)(void* text, Py_ssize_t pos, Py_UCS4 ch);
+    Py_ssize_t buf_size;
+    void* folded;
+    Py_ssize_t folded_len;
+    PyObject* result;
+
+    Py_ssize_t flags;
+    PyObject* string;
+    if (!PyArg_ParseTuple(args, "nO:fold_case", &flags, &string))
+        return NULL;
+
+    if (!(flags & RE_FLAG_IGNORECASE)) {
+        Py_INCREF(string);
+        return string;
+    }
+
+    /* Get the string. */
+    if (!get_string(string, &str_info))
+        return NULL;
+
+    /* Get the function for reading from the original string. */
+    switch (str_info.charsize) {
+    case 1:
+        char_at = bytes1_char_at;
+        break;
+    case 2:
+        char_at = bytes2_char_at;
+        break;
+    case 4:
+        char_at = bytes4_char_at;
+        break;
+    default:
+#if PY_VERSION_HEX >= 0x02060000
+        release_buffer(&str_info);
+
+#endif
+        return NULL;
+    }
+
+    /* What's the encoding? */
+    if (flags & RE_FLAG_UNICODE)
+        encoding = &unicode_encoding;
+    else if (flags & RE_FLAG_LOCALE) {
+        encoding = &locale_encoding;
+        scan_locale_chars(&locale_info);
+    } else if (flags & RE_FLAG_ASCII)
+        encoding = &ascii_encoding;
+    else
+        encoding = &unicode_encoding;
+
+    /* The folded string will have the same width as the original string. */
+    folded_charsize = str_info.charsize;
+
+    /* Get the function for writing to the folded string. */
+    switch (folded_charsize) {
+    case 1:
+        set_char_at = bytes1_set_char_at;
+        break;
+    case 2:
+        set_char_at = bytes2_set_char_at;
+        break;
+    case 4:
+        set_char_at = bytes4_set_char_at;
+        break;
+    default:
+#if PY_VERSION_HEX >= 0x02060000
+        release_buffer(&str_info);
+
+#endif
+        return NULL;
+    }
+
+    /* Allocate a buffer for the folded string. */
+    if (flags & RE_FLAG_FULLCASE)
+        /* When using full case-folding with Unicode, some single codepoints
+         * are mapped to multiple codepoints.
+         */
+        buf_size = str_info.length * RE_MAX_FOLDED;
+    else
+        buf_size = str_info.length;
+
+    folded = re_alloc((size_t)(buf_size * folded_charsize));
+    if (!folded) {
+#if PY_VERSION_HEX >= 0x02060000
+        release_buffer(&str_info);
+
+#endif
+        return NULL;
+    }
+
+    /* Fold the case of the string. */
+    folded_len = 0;
+
+    if (flags & RE_FLAG_FULLCASE) {
+        /* Full case-folding. */
+        int (*full_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch, Py_UCS4*
+          folded);
+        Py_ssize_t i;
+        Py_UCS4 codepoints[RE_MAX_FOLDED];
+
+        full_case_fold = encoding->full_case_fold;
+
+        for (i = 0; i < str_info.length; i++) {
+            int count;
+            int j;
+
+            count = full_case_fold(&locale_info, char_at(str_info.characters,
+              i), codepoints);
+            for (j = 0; j < count; j++)
+                set_char_at(folded, folded_len + j, codepoints[j]);
+
+            folded_len += count;
+        }
+    } else {
+        /* Simple case-folding. */
+        Py_UCS4 (*simple_case_fold)(RE_LocaleInfo* locale_info, Py_UCS4 ch);
+        Py_ssize_t i;
+
+        simple_case_fold = encoding->simple_case_fold;
+
+        for (i = 0; i < str_info.length; i++) {
+            Py_UCS4 ch;
+
+            ch = simple_case_fold(&locale_info, char_at(str_info.characters,
+              i));
+            set_char_at(folded, i, ch);
+        }
+
+        folded_len = str_info.length;
+    }
+
+    /* Build the result string. */
+    if (str_info.is_unicode)
+        result = build_unicode_value(folded, folded_len, folded_charsize);
+    else
+        result = build_bytes_value(folded, folded_len, folded_charsize);
+
+    re_dealloc(folded);
+
+#if PY_VERSION_HEX >= 0x02060000
+    /* Release the original string's buffer. */
+    release_buffer(&str_info);
+
+#endif
+    return result;
+}
+
+/* Returns a tuple of the Unicode characters that expand on full case-folding.
+ */
+static PyObject* get_expand_on_folding(PyObject* self, PyObject* unused) {
+    int count;
+    PyObject* result;
+    int i;
+
+    /* How many characters are there? */
+    count = sizeof(re_expand_on_folding) / sizeof(re_expand_on_folding[0]);
+
+    /* Put all the characters in a tuple. */
+    result = PyTuple_New(count);
+    if (!result)
+        return NULL;
+
+    for (i = 0; i < count; i++) {
+        Py_UNICODE codepoint;
+        PyObject* item;
+
+        codepoint = re_expand_on_folding[i];
+
+        item = build_unicode_value(&codepoint, 1, sizeof(codepoint));
+        if (!item)
+            goto error;
+
+        /* PyTuple_SetItem borrows the reference. */
+        PyTuple_SetItem(result, i, item);
+    }
+
+    return result;
+
+error:
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* Returns whether a character has a given value for a Unicode property. */
+static PyObject* has_property_value(PyObject* self_, PyObject* args) {
+    BOOL v;
+
+    Py_ssize_t property_value;
+    Py_ssize_t character;
+    if (!PyArg_ParseTuple(args, "nn:has_property_value", &property_value,
+      &character))
+        return NULL;
+
+    v = unicode_has_property((RE_CODE)property_value, (Py_UCS4)character) ? 1 :
+      0;
+
+    return Py_BuildValue("n", v);
+}
+
+/* Returns a list of all the simple cases of a character.
+ *
+ * If full case-folding is turned on and the character also expands on full
+ * case-folding, a None is appended to the list.
+ */
+static PyObject* get_all_cases(PyObject* self_, PyObject* args) {
+    RE_EncodingTable* encoding;
+    RE_LocaleInfo locale_info;
+    int count;
+    Py_UCS4 cases[RE_MAX_CASES];
+    PyObject* result;
+    int i;
+    Py_UCS4 folded[RE_MAX_FOLDED];
+
+    Py_ssize_t flags;
+    Py_ssize_t character;
+    if (!PyArg_ParseTuple(args, "nn:get_all_cases", &flags, &character))
+        return NULL;
+
+    /* What's the encoding? */
+    if (flags & RE_FLAG_UNICODE)
+        encoding = &unicode_encoding;
+    else if (flags & RE_FLAG_LOCALE) {
+        encoding = &locale_encoding;
+        scan_locale_chars(&locale_info);
+    } else if (flags & RE_FLAG_ASCII)
+        encoding = &ascii_encoding;
+    else
+        encoding = &ascii_encoding;
+
+    /* Get all the simple cases. */
+    count = encoding->all_cases(&locale_info, (Py_UCS4)character, cases);
+
+    result = PyList_New(count);
+    if (!result)
+        return NULL;
+
+    for (i = 0; i < count; i++) {
+        PyObject* item;
+
+        item = Py_BuildValue("n", cases[i]);
+        if (!item)
+            goto error;
+
+        /* PyList_SetItem borrows the reference. */
+        PyList_SetItem(result, i, item);
+    }
+
+    /* If the character also expands on full case-folding, append a None. */
+    if ((flags & RE_FULL_CASE_FOLDING) == RE_FULL_CASE_FOLDING) {
+        count = encoding->full_case_fold(&locale_info, (Py_UCS4)character,
+          folded);
+        if (count > 1)
+            PyList_Append(result, Py_None);
+    }
+
+    return result;
+
+error:
+    Py_DECREF(result);
+    return NULL;
+}
+
+/* The table of the module's functions. */
+static PyMethodDef _functions[] = {
+    {"compile", (PyCFunction)re_compile, METH_VARARGS},
+    {"get_code_size", (PyCFunction)get_code_size, METH_NOARGS},
+    {"get_properties", (PyCFunction)get_properties, METH_VARARGS},
+    {"fold_case", (PyCFunction)fold_case, METH_VARARGS},
+    {"get_expand_on_folding", (PyCFunction)get_expand_on_folding, METH_NOARGS},
+    {"has_property_value", (PyCFunction)has_property_value, METH_VARARGS},
+    {"get_all_cases", (PyCFunction)get_all_cases, METH_VARARGS},
+    {NULL, NULL}
+};
+
+/* Initialises the property dictionary. */
+Py_LOCAL_INLINE(BOOL) init_property_dict(void) {
+    size_t value_set_count;
+    size_t i;
+    PyObject** value_dicts;
+
+    property_dict = NULL;
+
+    /* How many value sets are there? */
+    value_set_count = 0;
+
+    for (i = 0; i < sizeof(re_property_values) / sizeof(re_property_values[0]);
+      i++) {
+        RE_PropertyValue* value;
+
+        value = &re_property_values[i];
+        if (value->value_set >= value_set_count)
+            value_set_count = (size_t)value->value_set + 1;
+    }
+
+    /* Quick references for the value sets. */
+    value_dicts = (PyObject**)re_alloc(value_set_count *
+      sizeof(value_dicts[0]));
+    if (!value_dicts)
+        return FALSE;
+
+    memset(value_dicts, 0, value_set_count * sizeof(value_dicts[0]));
+
+    /* Build the property values dictionaries. */
+    for (i = 0; i < sizeof(re_property_values) / sizeof(re_property_values[0]);
+      i++) {
+        RE_PropertyValue* value;
+        PyObject* v;
+        int status;
+
+        value = &re_property_values[i];
+        if (!value_dicts[value->value_set]) {
+            value_dicts[value->value_set] = PyDict_New();
+            if (!value_dicts[value->value_set])
+                goto error;
+        }
+
+        v = Py_BuildValue("i", value->id);
+        if (!v)
+            goto error;
+
+        status = PyDict_SetItemString(value_dicts[value->value_set],
+          re_strings[value->name], v);
+        Py_DECREF(v);
+        if (status < 0)
+            goto error;
+    }
+
+    /* Build the property dictionary. */
+    property_dict = PyDict_New();
+    if (!property_dict)
+        goto error;
+
+    for (i = 0; i < sizeof(re_properties) / sizeof(re_properties[0]); i++) {
+        RE_Property* property;
+        PyObject* v;
+        int status;
+
+        property = &re_properties[i];
+        v = Py_BuildValue("iO", property->id,
+          value_dicts[property->value_set]);
+        if (!v)
+            goto error;
+
+        status = PyDict_SetItemString(property_dict,
+          re_strings[property->name], v);
+        Py_DECREF(v);
+        if (status < 0)
+            goto error;
+    }
+
+    /* DECREF the value sets. Any unused ones will be deallocated. */
+    for (i = 0; i < value_set_count; i++)
+        Py_XDECREF(value_dicts[i]);
+
+    re_dealloc(value_dicts);
+
+    return TRUE;
+
+error:
+    Py_XDECREF(property_dict);
+
+    /* DECREF the value sets. */
+    for (i = 0; i < value_set_count; i++)
+        Py_XDECREF(value_dicts[i]);
+
+    re_dealloc(value_dicts);
+
+    return FALSE;
+}
+
+/* Initialises the module. */
+PyMODINIT_FUNC init_regex(void) {
+    PyObject* m;
+    PyObject* d;
+    PyObject* x;
+
+#if defined(VERBOSE)
+    /* Unbuffered in case it crashes! */
+    setvbuf(stdout, NULL, _IONBF, 0);
+
+#endif
+    /* Initialise Pattern_Type. */
+    Pattern_Type.tp_dealloc = pattern_dealloc;
+    Pattern_Type.tp_repr = pattern_repr;
+    Pattern_Type.tp_flags = Py_TPFLAGS_HAVE_WEAKREFS;
+    Pattern_Type.tp_doc = pattern_doc;
+    Pattern_Type.tp_weaklistoffset = offsetof(PatternObject, weakreflist);
+    Pattern_Type.tp_methods = pattern_methods;
+    Pattern_Type.tp_members = pattern_members;
+    Pattern_Type.tp_getset = pattern_getset;
+
+    /* Initialise Match_Type. */
+    Match_Type.tp_dealloc = match_dealloc;
+    Match_Type.tp_repr = match_repr;
+    Match_Type.tp_as_mapping = &match_as_mapping;
+    Match_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+    Match_Type.tp_doc = match_doc;
+    Match_Type.tp_methods = match_methods;
+    Match_Type.tp_members = match_members;
+    Match_Type.tp_getset = match_getset;
+
+    /* Initialise Scanner_Type. */
+    Scanner_Type.tp_dealloc = scanner_dealloc;
+    Scanner_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+    Scanner_Type.tp_doc = scanner_doc;
+    Scanner_Type.tp_iter = scanner_iter;
+    Scanner_Type.tp_iternext = scanner_iternext;
+    Scanner_Type.tp_methods = scanner_methods;
+    Scanner_Type.tp_members = scanner_members;
+
+    /* Initialise Splitter_Type. */
+    Splitter_Type.tp_dealloc = splitter_dealloc;
+    Splitter_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+    Splitter_Type.tp_doc = splitter_doc;
+    Splitter_Type.tp_iter = splitter_iter;
+    Splitter_Type.tp_iternext = splitter_iternext;
+    Splitter_Type.tp_methods = splitter_methods;
+    Splitter_Type.tp_members = splitter_members;
+#if PY_VERSION_HEX >= 0x02060000
+
+    /* Initialise Capture_Type. */
+    Capture_Type.tp_dealloc = capture_dealloc;
+    Capture_Type.tp_str = capture_str;
+    Capture_Type.tp_as_mapping = &capture_as_mapping;
+    Capture_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+    Capture_Type.tp_methods = capture_methods;
+#endif
+
+    /* Initialize object types */
+    if (PyType_Ready(&Pattern_Type) < 0)
+        return;
+    if (PyType_Ready(&Match_Type) < 0)
+        return;
+    if (PyType_Ready(&Scanner_Type) < 0)
+        return;
+    if (PyType_Ready(&Splitter_Type) < 0)
+        return;
+#if PY_VERSION_HEX >= 0x02060000
+    if (PyType_Ready(&Capture_Type) < 0)
+        return;
+#endif
+
+    error_exception = NULL;
+
+    m = Py_InitModule("_" RE_MODULE, _functions);
+    if (!m)
+        return;
+
+    d = PyModule_GetDict(m);
+
+    x = PyInt_FromLong(RE_MAGIC);
+    if (x) {
+        PyDict_SetItemString(d, "MAGIC", x);
+        Py_DECREF(x);
+    }
+
+    x = PyInt_FromLong(sizeof(RE_CODE));
+    if (x) {
+        PyDict_SetItemString(d, "CODE_SIZE", x);
+        Py_DECREF(x);
+    }
+
+    x = PyString_FromString(copyright);
+    if (x) {
+        PyDict_SetItemString(d, "copyright", x);
+        Py_DECREF(x);
+    }
+
+    /* Initialise the property dictionary. */
+    if (!init_property_dict())
+        return;
+}
+
+/* vim:ts=4:sw=4:et */
diff --git a/lib/regex/_regex.h b/lib/regex/_regex.h
new file mode 100644
index 000000000..37ab8a9c6
--- /dev/null
+++ b/lib/regex/_regex.h
@@ -0,0 +1,243 @@
+/*
+ * Secret Labs' Regular Expression Engine
+ *
+ * regular expression matching engine
+ *
+ * Copyright (c) 1997-2001 by Secret Labs AB.  All rights reserved.
+ *
+ * NOTE: This file is generated by regex.py.  If you need
+ * to change anything in here, edit regex.py and run it.
+ *
+ * 2010-01-16 mrab Re-written
+ */
+
+/* Supports Unicode version 8.0.0. */
+
+#define RE_MAGIC 20100116
+
+#include "_regex_unicode.h"
+
+/* Operators. */
+#define RE_OP_FAILURE 0
+#define RE_OP_SUCCESS 1
+#define RE_OP_ANY 2
+#define RE_OP_ANY_ALL 3
+#define RE_OP_ANY_ALL_REV 4
+#define RE_OP_ANY_REV 5
+#define RE_OP_ANY_U 6
+#define RE_OP_ANY_U_REV 7
+#define RE_OP_ATOMIC 8
+#define RE_OP_BOUNDARY 9
+#define RE_OP_BRANCH 10
+#define RE_OP_CALL_REF 11
+#define RE_OP_CHARACTER 12
+#define RE_OP_CHARACTER_IGN 13
+#define RE_OP_CHARACTER_IGN_REV 14
+#define RE_OP_CHARACTER_REV 15
+#define RE_OP_CONDITIONAL 16
+#define RE_OP_DEFAULT_BOUNDARY 17
+#define RE_OP_DEFAULT_END_OF_WORD 18
+#define RE_OP_DEFAULT_START_OF_WORD 19
+#define RE_OP_END 20
+#define RE_OP_END_OF_LINE 21
+#define RE_OP_END_OF_LINE_U 22
+#define RE_OP_END_OF_STRING 23
+#define RE_OP_END_OF_STRING_LINE 24
+#define RE_OP_END_OF_STRING_LINE_U 25
+#define RE_OP_END_OF_WORD 26
+#define RE_OP_FUZZY 27
+#define RE_OP_GRAPHEME_BOUNDARY 28
+#define RE_OP_GREEDY_REPEAT 29
+#define RE_OP_GROUP 30
+#define RE_OP_GROUP_CALL 31
+#define RE_OP_GROUP_EXISTS 32
+#define RE_OP_KEEP 33
+#define RE_OP_LAZY_REPEAT 34
+#define RE_OP_LOOKAROUND 35
+#define RE_OP_NEXT 36
+#define RE_OP_PROPERTY 37
+#define RE_OP_PROPERTY_IGN 38
+#define RE_OP_PROPERTY_IGN_REV 39
+#define RE_OP_PROPERTY_REV 40
+#define RE_OP_PRUNE 41
+#define RE_OP_RANGE 42
+#define RE_OP_RANGE_IGN 43
+#define RE_OP_RANGE_IGN_REV 44
+#define RE_OP_RANGE_REV 45
+#define RE_OP_REF_GROUP 46
+#define RE_OP_REF_GROUP_FLD 47
+#define RE_OP_REF_GROUP_FLD_REV 48
+#define RE_OP_REF_GROUP_IGN 49
+#define RE_OP_REF_GROUP_IGN_REV 50
+#define RE_OP_REF_GROUP_REV 51
+#define RE_OP_SEARCH_ANCHOR 52
+#define RE_OP_SET_DIFF 53
+#define RE_OP_SET_DIFF_IGN 54
+#define RE_OP_SET_DIFF_IGN_REV 55
+#define RE_OP_SET_DIFF_REV 56
+#define RE_OP_SET_INTER 57
+#define RE_OP_SET_INTER_IGN 58
+#define RE_OP_SET_INTER_IGN_REV 59
+#define RE_OP_SET_INTER_REV 60
+#define RE_OP_SET_SYM_DIFF 61
+#define RE_OP_SET_SYM_DIFF_IGN 62
+#define RE_OP_SET_SYM_DIFF_IGN_REV 63
+#define RE_OP_SET_SYM_DIFF_REV 64
+#define RE_OP_SET_UNION 65
+#define RE_OP_SET_UNION_IGN 66
+#define RE_OP_SET_UNION_IGN_REV 67
+#define RE_OP_SET_UNION_REV 68
+#define RE_OP_SKIP 69
+#define RE_OP_START_OF_LINE 70
+#define RE_OP_START_OF_LINE_U 71
+#define RE_OP_START_OF_STRING 72
+#define RE_OP_START_OF_WORD 73
+#define RE_OP_STRING 74
+#define RE_OP_STRING_FLD 75
+#define RE_OP_STRING_FLD_REV 76
+#define RE_OP_STRING_IGN 77
+#define RE_OP_STRING_IGN_REV 78
+#define RE_OP_STRING_REV 79
+#define RE_OP_STRING_SET 80
+#define RE_OP_STRING_SET_FLD 81
+#define RE_OP_STRING_SET_FLD_REV 82
+#define RE_OP_STRING_SET_IGN 83
+#define RE_OP_STRING_SET_IGN_REV 84
+#define RE_OP_STRING_SET_REV 85
+#define RE_OP_BODY_END 86
+#define RE_OP_BODY_START 87
+#define RE_OP_END_ATOMIC 88
+#define RE_OP_END_CONDITIONAL 89
+#define RE_OP_END_FUZZY 90
+#define RE_OP_END_GREEDY_REPEAT 91
+#define RE_OP_END_GROUP 92
+#define RE_OP_END_LAZY_REPEAT 93
+#define RE_OP_END_LOOKAROUND 94
+#define RE_OP_GREEDY_REPEAT_ONE 95
+#define RE_OP_GROUP_RETURN 96
+#define RE_OP_LAZY_REPEAT_ONE 97
+#define RE_OP_MATCH_BODY 98
+#define RE_OP_MATCH_TAIL 99
+#define RE_OP_START_GROUP 100
+
+char* re_op_text[] = {
+    "RE_OP_FAILURE",
+    "RE_OP_SUCCESS",
+    "RE_OP_ANY",
+    "RE_OP_ANY_ALL",
+    "RE_OP_ANY_ALL_REV",
+    "RE_OP_ANY_REV",
+    "RE_OP_ANY_U",
+    "RE_OP_ANY_U_REV",
+    "RE_OP_ATOMIC",
+    "RE_OP_BOUNDARY",
+    "RE_OP_BRANCH",
+    "RE_OP_CALL_REF",
+    "RE_OP_CHARACTER",
+    "RE_OP_CHARACTER_IGN",
+    "RE_OP_CHARACTER_IGN_REV",
+    "RE_OP_CHARACTER_REV",
+    "RE_OP_CONDITIONAL",
+    "RE_OP_DEFAULT_BOUNDARY",
+    "RE_OP_DEFAULT_END_OF_WORD",
+    "RE_OP_DEFAULT_START_OF_WORD",
+    "RE_OP_END",
+    "RE_OP_END_OF_LINE",
+    "RE_OP_END_OF_LINE_U",
+    "RE_OP_END_OF_STRING",
+    "RE_OP_END_OF_STRING_LINE",
+    "RE_OP_END_OF_STRING_LINE_U",
+    "RE_OP_END_OF_WORD",
+    "RE_OP_FUZZY",
+    "RE_OP_GRAPHEME_BOUNDARY",
+    "RE_OP_GREEDY_REPEAT",
+    "RE_OP_GROUP",
+    "RE_OP_GROUP_CALL",
+    "RE_OP_GROUP_EXISTS",
+    "RE_OP_KEEP",
+    "RE_OP_LAZY_REPEAT",
+    "RE_OP_LOOKAROUND",
+    "RE_OP_NEXT",
+    "RE_OP_PROPERTY",
+    "RE_OP_PROPERTY_IGN",
+    "RE_OP_PROPERTY_IGN_REV",
+    "RE_OP_PROPERTY_REV",
+    "RE_OP_PRUNE",
+    "RE_OP_RANGE",
+    "RE_OP_RANGE_IGN",
+    "RE_OP_RANGE_IGN_REV",
+    "RE_OP_RANGE_REV",
+    "RE_OP_REF_GROUP",
+    "RE_OP_REF_GROUP_FLD",
+    "RE_OP_REF_GROUP_FLD_REV",
+    "RE_OP_REF_GROUP_IGN",
+    "RE_OP_REF_GROUP_IGN_REV",
+    "RE_OP_REF_GROUP_REV",
+    "RE_OP_SEARCH_ANCHOR",
+    "RE_OP_SET_DIFF",
+    "RE_OP_SET_DIFF_IGN",
+    "RE_OP_SET_DIFF_IGN_REV",
+    "RE_OP_SET_DIFF_REV",
+    "RE_OP_SET_INTER",
+    "RE_OP_SET_INTER_IGN",
+    "RE_OP_SET_INTER_IGN_REV",
+    "RE_OP_SET_INTER_REV",
+    "RE_OP_SET_SYM_DIFF",
+    "RE_OP_SET_SYM_DIFF_IGN",
+    "RE_OP_SET_SYM_DIFF_IGN_REV",
+    "RE_OP_SET_SYM_DIFF_REV",
+    "RE_OP_SET_UNION",
+    "RE_OP_SET_UNION_IGN",
+    "RE_OP_SET_UNION_IGN_REV",
+    "RE_OP_SET_UNION_REV",
+    "RE_OP_SKIP",
+    "RE_OP_START_OF_LINE",
+    "RE_OP_START_OF_LINE_U",
+    "RE_OP_START_OF_STRING",
+    "RE_OP_START_OF_WORD",
+    "RE_OP_STRING",
+    "RE_OP_STRING_FLD",
+    "RE_OP_STRING_FLD_REV",
+    "RE_OP_STRING_IGN",
+    "RE_OP_STRING_IGN_REV",
+    "RE_OP_STRING_REV",
+    "RE_OP_STRING_SET",
+    "RE_OP_STRING_SET_FLD",
+    "RE_OP_STRING_SET_FLD_REV",
+    "RE_OP_STRING_SET_IGN",
+    "RE_OP_STRING_SET_IGN_REV",
+    "RE_OP_STRING_SET_REV",
+    "RE_OP_BODY_END",
+    "RE_OP_BODY_START",
+    "RE_OP_END_ATOMIC",
+    "RE_OP_END_CONDITIONAL",
+    "RE_OP_END_FUZZY",
+    "RE_OP_END_GREEDY_REPEAT",
+    "RE_OP_END_GROUP",
+    "RE_OP_END_LAZY_REPEAT",
+    "RE_OP_END_LOOKAROUND",
+    "RE_OP_GREEDY_REPEAT_ONE",
+    "RE_OP_GROUP_RETURN",
+    "RE_OP_LAZY_REPEAT_ONE",
+    "RE_OP_MATCH_BODY",
+    "RE_OP_MATCH_TAIL",
+    "RE_OP_START_GROUP",
+};
+
+#define RE_FLAG_ASCII 0x80
+#define RE_FLAG_BESTMATCH 0x1000
+#define RE_FLAG_DEBUG 0x200
+#define RE_FLAG_DOTALL 0x10
+#define RE_FLAG_ENHANCEMATCH 0x8000
+#define RE_FLAG_FULLCASE 0x4000
+#define RE_FLAG_IGNORECASE 0x2
+#define RE_FLAG_LOCALE 0x4
+#define RE_FLAG_MULTILINE 0x8
+#define RE_FLAG_POSIX 0x10000
+#define RE_FLAG_REVERSE 0x400
+#define RE_FLAG_TEMPLATE 0x1
+#define RE_FLAG_UNICODE 0x20
+#define RE_FLAG_VERBOSE 0x40
+#define RE_FLAG_VERSION0 0x2000
+#define RE_FLAG_VERSION1 0x100
+#define RE_FLAG_WORD 0x800
diff --git a/lib/regex/_regex.so b/lib/regex/_regex.so
new file mode 100644
index 0000000000000000000000000000000000000000..f0a87043e5c65d0996b2a8dbc501bdeeed7685dc
GIT binary patch
literal 1189938
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
HV{Z%qGi|~Q

literal 0
HcmV?d00001

diff --git a/lib/regex/_regex_core.py b/lib/regex/_regex_core.py
new file mode 100644
index 000000000..25771b6fe
--- /dev/null
+++ b/lib/regex/_regex_core.py
@@ -0,0 +1,4317 @@
+#
+# Secret Labs' Regular Expression Engine core module
+#
+# Copyright (c) 1998-2001 by Secret Labs AB.  All rights reserved.
+#
+# This version of the SRE library can be redistributed under CNRI's
+# Python 1.6 license.  For any other use, please contact Secret Labs
+# AB (info@pythonware.com).
+#
+# Portions of this engine have been developed in cooperation with
+# CNRI.  Hewlett-Packard provided funding for 1.6 integration and
+# other compatibility work.
+#
+# 2010-01-16 mrab Python front-end re-written and extended
+
+import string
+import sys
+import unicodedata
+from collections import defaultdict
+
+import _regex
+
+__all__ = ["A", "ASCII", "B", "BESTMATCH", "D", "DEBUG", "E", "ENHANCEMATCH",
+  "F", "FULLCASE", "I", "IGNORECASE", "L", "LOCALE", "M", "MULTILINE", "P",
+  "POSIX", "R", "REVERSE", "S", "DOTALL", "T", "TEMPLATE", "U", "UNICODE",
+  "V0", "VERSION0", "V1", "VERSION1", "W", "WORD", "X", "VERBOSE", "error",
+  "Scanner"]
+
+# The regex exception.
+class error(Exception):
+    def __init__(self, message, pattern=None, pos=None):
+        newline = u'\n' if isinstance(pattern, unicode) else '\n'
+        self.msg = message
+        self.pattern = pattern
+        self.pos = pos
+        if pattern is not None and pos is not None:
+            self.lineno = pattern.count(newline, 0, pos) + 1
+            self.colno = pos - pattern.rfind(newline, 0, pos)
+
+            message = "%s at position %d" % (message, pos)
+
+            if newline in pattern:
+                message += " (line %d, column %d)" % (self.lineno, self.colno)
+
+        Exception.__init__(self, message)
+
+# The exception for when a positional flag has been turned on in the old
+# behaviour.
+class _UnscopedFlagSet(Exception):
+    pass
+
+# The exception for when parsing fails and we want to try something else.
+class ParseError(Exception):
+    pass
+
+# The exception for when there isn't a valid first set.
+class _FirstSetError(Exception):
+    pass
+
+# Flags.
+A = ASCII = 0x80          # Assume ASCII locale.
+B = BESTMATCH = 0x1000    # Best fuzzy match.
+D = DEBUG = 0x200         # Print parsed pattern.
+E = ENHANCEMATCH = 0x8000 # Attempt to improve the fit after finding the first
+                          # fuzzy match.
+F = FULLCASE = 0x4000     # Unicode full case-folding.
+I = IGNORECASE = 0x2      # Ignore case.
+L = LOCALE = 0x4          # Assume current 8-bit locale.
+M = MULTILINE = 0x8       # Make anchors look for newline.
+P = POSIX = 0x10000       # POSIX-style matching (leftmost longest).
+R = REVERSE = 0x400       # Search backwards.
+S = DOTALL = 0x10         # Make dot match newline.
+U = UNICODE = 0x20        # Assume Unicode locale.
+V0 = VERSION0 = 0x2000    # Old legacy behaviour.
+V1 = VERSION1 = 0x100     # New enhanced behaviour.
+W = WORD = 0x800          # Default Unicode word breaks.
+X = VERBOSE = 0x40        # Ignore whitespace and comments.
+T = TEMPLATE = 0x1        # Template (present because re module has it).
+
+DEFAULT_VERSION = VERSION1
+
+_ALL_VERSIONS = VERSION0 | VERSION1
+_ALL_ENCODINGS = ASCII | LOCALE | UNICODE
+
+# The default flags for the various versions.
+DEFAULT_FLAGS = {VERSION0: 0, VERSION1: FULLCASE}
+
+# The mask for the flags.
+GLOBAL_FLAGS = (_ALL_ENCODINGS | _ALL_VERSIONS | BESTMATCH | DEBUG |
+  ENHANCEMATCH | POSIX | REVERSE)
+SCOPED_FLAGS = FULLCASE | IGNORECASE | MULTILINE | DOTALL | WORD | VERBOSE
+
+ALPHA = frozenset(string.ascii_letters)
+DIGITS = frozenset(string.digits)
+ALNUM = ALPHA | DIGITS
+OCT_DIGITS = frozenset(string.octdigits)
+HEX_DIGITS = frozenset(string.hexdigits)
+SPECIAL_CHARS = frozenset("()|?*+{^$.[\\#") | frozenset([""])
+NAMED_CHAR_PART = ALNUM | frozenset(" -")
+PROPERTY_NAME_PART = ALNUM | frozenset(" &_-.")
+SET_OPS = ("||", "~~", "&&", "--")
+
+# The width of the code words inside the regex engine.
+BYTES_PER_CODE = _regex.get_code_size()
+BITS_PER_CODE = BYTES_PER_CODE * 8
+
+# The repeat count which represents infinity.
+UNLIMITED = (1 << BITS_PER_CODE) - 1
+
+# The regular expression flags.
+REGEX_FLAGS = {"a": ASCII, "b": BESTMATCH, "e": ENHANCEMATCH, "f": FULLCASE,
+  "i": IGNORECASE, "L": LOCALE, "m": MULTILINE, "p": POSIX, "r": REVERSE,
+  "s": DOTALL, "u": UNICODE, "V0": VERSION0, "V1": VERSION1, "w": WORD, "x":
+  VERBOSE}
+
+# The case flags.
+CASE_FLAGS = FULLCASE | IGNORECASE
+NOCASE = 0
+FULLIGNORECASE = FULLCASE | IGNORECASE
+
+FULL_CASE_FOLDING = UNICODE | FULLIGNORECASE
+
+CASE_FLAGS_COMBINATIONS = {0: 0, FULLCASE: 0, IGNORECASE: IGNORECASE,
+  FULLIGNORECASE: FULLIGNORECASE}
+
+# The number of digits in hexadecimal escapes.
+HEX_ESCAPES = {"x": 2, "u": 4, "U": 8}
+
+# A singleton which indicates a comment within a pattern.
+COMMENT = object()
+FLAGS = object()
+
+# The names of the opcodes.
+OPCODES = """
+FAILURE
+SUCCESS
+ANY
+ANY_ALL
+ANY_ALL_REV
+ANY_REV
+ANY_U
+ANY_U_REV
+ATOMIC
+BOUNDARY
+BRANCH
+CALL_REF
+CHARACTER
+CHARACTER_IGN
+CHARACTER_IGN_REV
+CHARACTER_REV
+CONDITIONAL
+DEFAULT_BOUNDARY
+DEFAULT_END_OF_WORD
+DEFAULT_START_OF_WORD
+END
+END_OF_LINE
+END_OF_LINE_U
+END_OF_STRING
+END_OF_STRING_LINE
+END_OF_STRING_LINE_U
+END_OF_WORD
+FUZZY
+GRAPHEME_BOUNDARY
+GREEDY_REPEAT
+GROUP
+GROUP_CALL
+GROUP_EXISTS
+KEEP
+LAZY_REPEAT
+LOOKAROUND
+NEXT
+PROPERTY
+PROPERTY_IGN
+PROPERTY_IGN_REV
+PROPERTY_REV
+PRUNE
+RANGE
+RANGE_IGN
+RANGE_IGN_REV
+RANGE_REV
+REF_GROUP
+REF_GROUP_FLD
+REF_GROUP_FLD_REV
+REF_GROUP_IGN
+REF_GROUP_IGN_REV
+REF_GROUP_REV
+SEARCH_ANCHOR
+SET_DIFF
+SET_DIFF_IGN
+SET_DIFF_IGN_REV
+SET_DIFF_REV
+SET_INTER
+SET_INTER_IGN
+SET_INTER_IGN_REV
+SET_INTER_REV
+SET_SYM_DIFF
+SET_SYM_DIFF_IGN
+SET_SYM_DIFF_IGN_REV
+SET_SYM_DIFF_REV
+SET_UNION
+SET_UNION_IGN
+SET_UNION_IGN_REV
+SET_UNION_REV
+SKIP
+START_OF_LINE
+START_OF_LINE_U
+START_OF_STRING
+START_OF_WORD
+STRING
+STRING_FLD
+STRING_FLD_REV
+STRING_IGN
+STRING_IGN_REV
+STRING_REV
+STRING_SET
+STRING_SET_FLD
+STRING_SET_FLD_REV
+STRING_SET_IGN
+STRING_SET_IGN_REV
+STRING_SET_REV
+"""
+
+# Define the opcodes in a namespace.
+class Namespace(object):
+    pass
+
+OP = Namespace()
+for i, op in enumerate(OPCODES.split()):
+    setattr(OP, op, i)
+
+def _shrink_cache(cache_dict, args_dict, locale_sensitive, max_length, divisor=5):
+    """Make room in the given cache.
+
+    Args:
+        cache_dict: The cache dictionary to modify.
+        args_dict: The dictionary of named list args used by patterns.
+        max_length: Maximum # of entries in cache_dict before it is shrunk.
+        divisor: Cache will shrink to max_length - 1/divisor*max_length items.
+    """
+    # Toss out a fraction of the entries at random to make room for new ones.
+    # A random algorithm was chosen as opposed to simply cache_dict.popitem()
+    # as popitem could penalize the same regular expression repeatedly based
+    # on its internal hash value.  Being random should spread the cache miss
+    # love around.
+    cache_keys = tuple(cache_dict.keys())
+    overage = len(cache_keys) - max_length
+    if overage < 0:
+        # Cache is already within limits.  Normally this should not happen
+        # but it could due to multithreading.
+        return
+
+    number_to_toss = max_length // divisor + overage
+
+    # The import is done here to avoid a circular dependency.
+    import random
+    if not hasattr(random, 'sample'):
+        # Do nothing while resolving the circular dependency:
+        #  re->random->warnings->tokenize->string->re
+        return
+
+    for doomed_key in random.sample(cache_keys, number_to_toss):
+        try:
+            del cache_dict[doomed_key]
+        except KeyError:
+            # Ignore problems if the cache changed from another thread.
+            pass
+
+    # Rebuild the arguments and locale-sensitivity dictionaries.
+    args_dict.clear()
+    sensitivity_dict = {}
+    for pattern, pattern_type, flags, args, default_version, locale in tuple(cache_dict):
+        args_dict[pattern, pattern_type, flags, default_version, locale] = args
+        try:
+            sensitivity_dict[pattern_type, pattern] = locale_sensitive[pattern_type, pattern]
+        except KeyError:
+            pass
+
+    locale_sensitive.clear()
+    locale_sensitive.update(sensitivity_dict)
+
+def _fold_case(info, string):
+    "Folds the case of a string."
+    flags = info.flags
+    if (flags & _ALL_ENCODINGS) == 0:
+        flags |= info.guess_encoding
+
+    return _regex.fold_case(flags, string)
+
+def is_cased(info, char):
+    "Checks whether a character is cased."
+    return len(_regex.get_all_cases(info.flags, char)) > 1
+
+def _compile_firstset(info, fs):
+    "Compiles the firstset for the pattern."
+    if not fs or None in fs:
+        return []
+
+    # If we ignore the case, for simplicity we won't build a firstset.
+    members = set()
+    for i in fs:
+        if isinstance(i, Character) and not i.positive:
+            return []
+
+        if i.case_flags:
+            if isinstance(i, Character):
+                if is_cased(info, i.value):
+                    return []
+            elif isinstance(i, SetBase):
+                return []
+
+        members.add(i.with_flags(case_flags=NOCASE))
+
+    # Build the firstset.
+    fs = SetUnion(info, list(members), zerowidth=True)
+    fs = fs.optimise(info, in_set=True)
+
+    # Compile the firstset.
+    return fs.compile(bool(info.flags & REVERSE))
+
+def _flatten_code(code):
+    "Flattens the code from a list of tuples."
+    flat_code = []
+    for c in code:
+        flat_code.extend(c)
+
+    return flat_code
+
+def make_character(info, value, in_set=False):
+    "Makes a character literal."
+    if in_set:
+        # A character set is built case-sensitively.
+        return Character(value)
+
+    return Character(value, case_flags=info.flags & CASE_FLAGS)
+
+def make_ref_group(info, name, position):
+    "Makes a group reference."
+    return RefGroup(info, name, position, case_flags=info.flags & CASE_FLAGS)
+
+def make_string_set(info, name):
+    "Makes a string set."
+    return StringSet(info, name, case_flags=info.flags & CASE_FLAGS)
+
+def make_property(info, prop, in_set):
+    "Makes a property."
+    if in_set:
+        return prop
+
+    return prop.with_flags(case_flags=info.flags & CASE_FLAGS)
+
+def _parse_pattern(source, info):
+    "Parses a pattern, eg. 'a|b|c'."
+    branches = [parse_sequence(source, info)]
+    while source.match("|"):
+        branches.append(parse_sequence(source, info))
+
+    if len(branches) == 1:
+        return branches[0]
+    return Branch(branches)
+
+def parse_sequence(source, info):
+    "Parses a sequence, eg. 'abc'."
+    sequence = []
+    applied = False
+    while True:
+        # Get literal characters followed by an element.
+        characters, case_flags, element = parse_literal_and_element(source,
+          info)
+        if not element:
+            # No element, just a literal. We've also reached the end of the
+            # sequence.
+            append_literal(characters, case_flags, sequence)
+            break
+
+        if element is COMMENT or element is FLAGS:
+            append_literal(characters, case_flags, sequence)
+        elif type(element) is tuple:
+            # It looks like we've found a quantifier.
+            ch, saved_pos = element
+
+            counts = parse_quantifier(source, info, ch)
+            if counts:
+                # It _is_ a quantifier.
+                apply_quantifier(source, info, counts, characters, case_flags,
+                  ch, saved_pos, applied, sequence)
+                applied = True
+            else:
+                # It's not a quantifier. Maybe it's a fuzzy constraint.
+                constraints = parse_fuzzy(source, ch)
+                if constraints:
+                    # It _is_ a fuzzy constraint.
+                    apply_constraint(source, info, constraints, characters,
+                      case_flags, saved_pos, applied, sequence)
+                    applied = True
+                else:
+                    # The element was just a literal.
+                    characters.append(ord(ch))
+                    append_literal(characters, case_flags, sequence)
+                    applied = False
+        else:
+            # We have a literal followed by something else.
+            append_literal(characters, case_flags, sequence)
+            sequence.append(element)
+            applied = False
+
+    return make_sequence(sequence)
+
+def apply_quantifier(source, info, counts, characters, case_flags, ch,
+  saved_pos, applied, sequence):
+    if characters:
+        # The quantifier applies to the last character.
+        append_literal(characters[ : -1], case_flags, sequence)
+        element = Character(characters[-1], case_flags=case_flags)
+    else:
+        # The quantifier applies to the last item in the sequence.
+        if applied:
+            raise error("multiple repeat", source.string, saved_pos)
+
+        if not sequence:
+            raise error("nothing to repeat", source.string, saved_pos)
+
+        element = sequence.pop()
+
+    min_count, max_count = counts
+    saved_pos = source.pos
+    ch = source.get()
+    if ch == "?":
+        # The "?" suffix that means it's a lazy repeat.
+        repeated = LazyRepeat
+    elif ch == "+":
+        # The "+" suffix that means it's a possessive repeat.
+        repeated = PossessiveRepeat
+    else:
+        # No suffix means that it's a greedy repeat.
+        source.pos = saved_pos
+        repeated = GreedyRepeat
+
+    # Ignore the quantifier if it applies to a zero-width item or the number of
+    # repeats is fixed at 1.
+    if not element.is_empty() and (min_count != 1 or max_count != 1):
+        element = repeated(element, min_count, max_count)
+
+    sequence.append(element)
+
+def apply_constraint(source, info, constraints, characters, case_flags,
+  saved_pos, applied, sequence):
+    if characters:
+        # The constraint applies to the last character.
+        append_literal(characters[ : -1], case_flags, sequence)
+        element = Character(characters[-1], case_flags=case_flags)
+        sequence.append(Fuzzy(element, constraints))
+    else:
+        # The constraint applies to the last item in the sequence.
+        if applied or not sequence:
+            raise error("nothing for fuzzy constraint", source.string,
+              saved_pos)
+
+        element = sequence.pop()
+
+        # If a group is marked as fuzzy then put all of the fuzzy part in the
+        # group.
+        if isinstance(element, Group):
+            element.subpattern = Fuzzy(element.subpattern, constraints)
+            sequence.append(element)
+        else:
+            sequence.append(Fuzzy(element, constraints))
+
+def append_literal(characters, case_flags, sequence):
+    if characters:
+        sequence.append(Literal(characters, case_flags=case_flags))
+
+def PossessiveRepeat(element, min_count, max_count):
+    "Builds a possessive repeat."
+    return Atomic(GreedyRepeat(element, min_count, max_count))
+
+_QUANTIFIERS = {"?": (0, 1), "*": (0, None), "+": (1, None)}
+
+def parse_quantifier(source, info, ch):
+    "Parses a quantifier."
+    q = _QUANTIFIERS.get(ch)
+    if q:
+        # It's a quantifier.
+        return q
+
+    if ch == "{":
+        # Looks like a limited repeated element, eg. 'a{2,3}'.
+        counts = parse_limited_quantifier(source)
+        if counts:
+            return counts
+
+    return None
+
+def is_above_limit(count):
+    "Checks whether a count is above the maximum."
+    return count is not None and count >= UNLIMITED
+
+def parse_limited_quantifier(source):
+    "Parses a limited quantifier."
+    saved_pos = source.pos
+    min_count = parse_count(source)
+    if source.match(","):
+        max_count = parse_count(source)
+
+        # No minimum means 0 and no maximum means unlimited.
+        min_count = int(min_count or 0)
+        max_count = int(max_count) if max_count else None
+
+        if max_count is not None and min_count > max_count:
+            raise error("min repeat greater than max repeat", source.string,
+              saved_pos)
+    else:
+        if not min_count:
+            source.pos = saved_pos
+            return None
+
+        min_count = max_count = int(min_count)
+
+    if is_above_limit(min_count) or is_above_limit(max_count):
+        raise error("repeat count too big", source.string, saved_pos)
+
+    if not source.match ("}"):
+        source.pos = saved_pos
+        return None
+
+    return min_count, max_count
+
+def parse_fuzzy(source, ch):
+    "Parses a fuzzy setting, if present."
+    if ch != "{":
+        return None
+
+    saved_pos = source.pos
+
+    constraints = {}
+    try:
+        parse_fuzzy_item(source, constraints)
+        while source.match(","):
+            parse_fuzzy_item(source, constraints)
+    except ParseError:
+        source.pos = saved_pos
+        return None
+
+    if not source.match("}"):
+        raise error("expected }", source.string, source.pos)
+
+    return constraints
+
+def parse_fuzzy_item(source, constraints):
+    "Parses a fuzzy setting item."
+    saved_pos = source.pos
+    try:
+        parse_cost_constraint(source, constraints)
+    except ParseError:
+        source.pos = saved_pos
+
+        parse_cost_equation(source, constraints)
+
+def parse_cost_constraint(source, constraints):
+    "Parses a cost constraint."
+    saved_pos = source.pos
+    ch = source.get()
+    if ch in ALPHA:
+        # Syntax: constraint [("<=" | "<") cost]
+        constraint = parse_constraint(source, constraints, ch)
+
+        max_inc = parse_fuzzy_compare(source)
+
+        if max_inc is None:
+            # No maximum cost.
+            constraints[constraint] = 0, None
+        else:
+            # There's a maximum cost.
+            cost_pos = source.pos
+            max_cost = int(parse_count(source))
+
+            # Inclusive or exclusive limit?
+            if not max_inc:
+                max_cost -= 1
+
+            if max_cost < 0:
+                raise error("bad fuzzy cost limit", source.string, cost_pos)
+
+            constraints[constraint] = 0, max_cost
+    elif ch in DIGITS:
+        # Syntax: cost ("<=" | "<") constraint ("<=" | "<") cost
+        source.pos = saved_pos
+        try:
+            # Minimum cost.
+            min_cost = int(parse_count(source))
+
+            min_inc = parse_fuzzy_compare(source)
+            if min_inc is None:
+                raise ParseError()
+
+            constraint = parse_constraint(source, constraints, source.get())
+
+            max_inc = parse_fuzzy_compare(source)
+            if max_inc is None:
+                raise ParseError()
+
+            # Maximum cost.
+            cost_pos = source.pos
+            max_cost = int(parse_count(source))
+
+            # Inclusive or exclusive limits?
+            if not min_inc:
+                min_cost += 1
+            if not max_inc:
+                max_cost -= 1
+
+            if not 0 <= min_cost <= max_cost:
+                raise error("bad fuzzy cost limit", source.string, cost_pos)
+
+            constraints[constraint] = min_cost, max_cost
+        except ValueError:
+            raise ParseError()
+    else:
+        raise ParseError()
+
+def parse_constraint(source, constraints, ch):
+    "Parses a constraint."
+    if ch not in "deis":
+        raise error("bad fuzzy constraint", source.string, source.pos)
+
+    if ch in constraints:
+        raise error("repeated fuzzy constraint", source.string, source.pos)
+
+    return ch
+
+def parse_fuzzy_compare(source):
+    "Parses a cost comparator."
+    if source.match("<="):
+        return True
+    elif source.match("<"):
+        return False
+    else:
+        return None
+
+def parse_cost_equation(source, constraints):
+    "Parses a cost equation."
+    if "cost" in constraints:
+        raise error("more than one cost equation", source.string, source.pos)
+
+    cost = {}
+
+    parse_cost_term(source, cost)
+    while source.match("+"):
+        parse_cost_term(source, cost)
+
+    max_inc = parse_fuzzy_compare(source)
+    if max_inc is None:
+        raise error("missing fuzzy cost limit", source.string, source.pos)
+
+    max_cost = int(parse_count(source))
+
+    if not max_inc:
+        max_cost -= 1
+
+    if max_cost < 0:
+        raise error("bad fuzzy cost limit", source.string, source.pos)
+
+    cost["max"] = max_cost
+
+    constraints["cost"] = cost
+
+def parse_cost_term(source, cost):
+    "Parses a cost equation term."
+    coeff = parse_count(source)
+    ch = source.get()
+    if ch not in "dis":
+        raise ParseError()
+
+    if ch in cost:
+        raise error("repeated fuzzy cost", source.string, source.pos)
+
+    cost[ch] = int(coeff or 1)
+
+def parse_count(source):
+    "Parses a quantifier's count, which can be empty."
+    return source.get_while(DIGITS)
+
+def parse_literal_and_element(source, info):
+    """Parses a literal followed by an element. The element is FLAGS if it's an
+    inline flag or None if it has reached the end of a sequence.
+    """
+    characters = []
+    case_flags = info.flags & CASE_FLAGS
+    while True:
+        saved_pos = source.pos
+        ch = source.get()
+        if ch in SPECIAL_CHARS:
+            if ch in ")|":
+                # The end of a sequence. At the end of the pattern ch is "".
+                source.pos = saved_pos
+                return characters, case_flags, None
+            elif ch == "\\":
+                # An escape sequence outside a set.
+                element = parse_escape(source, info, False)
+                return characters, case_flags, element
+            elif ch == "(":
+                # A parenthesised subpattern or a flag.
+                element = parse_paren(source, info)
+                if element and element is not COMMENT:
+                    return characters, case_flags, element
+            elif ch == ".":
+                # Any character.
+                if info.flags & DOTALL:
+                    element = AnyAll()
+                elif info.flags & WORD:
+                    element = AnyU()
+                else:
+                    element = Any()
+
+                return characters, case_flags, element
+            elif ch == "[":
+                # A character set.
+                element = parse_set(source, info)
+                return characters, case_flags, element
+            elif ch == "^":
+                # The start of a line or the string.
+                if info.flags & MULTILINE:
+                    if info.flags & WORD:
+                        element = StartOfLineU()
+                    else:
+                        element = StartOfLine()
+                else:
+                    element = StartOfString()
+
+                return characters, case_flags, element
+            elif ch == "$":
+                # The end of a line or the string.
+                if info.flags & MULTILINE:
+                    if info.flags & WORD:
+                        element = EndOfLineU()
+                    else:
+                        element = EndOfLine()
+                else:
+                    if info.flags & WORD:
+                        element = EndOfStringLineU()
+                    else:
+                        element = EndOfStringLine()
+
+                return characters, case_flags, element
+            elif ch in "?*+{":
+                # Looks like a quantifier.
+                return characters, case_flags, (ch, saved_pos)
+            else:
+                # A literal.
+                characters.append(ord(ch))
+        else:
+            # A literal.
+            characters.append(ord(ch))
+
+def parse_paren(source, info):
+    """Parses a parenthesised subpattern or a flag. Returns FLAGS if it's an
+    inline flag.
+    """
+    saved_pos = source.pos
+    ch = source.get()
+    if ch == "?":
+        # (?...
+        saved_pos_2 = source.pos
+        ch = source.get()
+        if ch == "<":
+            # (?<...
+            saved_pos_3 = source.pos
+            ch = source.get()
+            if ch in ("=", "!"):
+                # (?<=... or (?<!...: lookbehind.
+                return parse_lookaround(source, info, True, ch == "=")
+
+            # (?<...: a named capture group.
+            source.pos = saved_pos_3
+            name = parse_name(source)
+            group = info.open_group(name)
+            source.expect(">")
+            saved_flags = info.flags
+            try:
+                subpattern = _parse_pattern(source, info)
+                source.expect(")")
+            finally:
+                info.flags = saved_flags
+                source.ignore_space = bool(info.flags & VERBOSE)
+
+            info.close_group()
+            return Group(info, group, subpattern)
+        if ch in ("=", "!"):
+            # (?=... or (?!...: lookahead.
+            return parse_lookaround(source, info, False, ch == "=")
+        if ch == "P":
+            # (?P...: a Python extension.
+            return parse_extension(source, info)
+        if ch == "#":
+            # (?#...: a comment.
+            return parse_comment(source)
+        if ch == "(":
+            # (?(...: a conditional subpattern.
+            return parse_conditional(source, info)
+        if ch == ">":
+            # (?>...: an atomic subpattern.
+            return parse_atomic(source, info)
+        if ch == "|":
+            # (?|...: a common/reset groups branch.
+            return parse_common(source, info)
+        if ch == "R" or "0" <= ch <= "9":
+            # (?R...: probably a call to a group.
+            return parse_call_group(source, info, ch, saved_pos_2)
+        if ch == "&":
+            # (?&...: a call to a named group.
+            return parse_call_named_group(source, info, saved_pos_2)
+
+        # (?...: probably a flags subpattern.
+        source.pos = saved_pos_2
+        return parse_flags_subpattern(source, info)
+
+    if ch == "*":
+        # (*...
+        saved_pos_2 = source.pos
+        word = source.get_while(set(")>"), include=False)
+        if word[ : 1].isalpha():
+            verb = VERBS.get(word)
+            if not verb:
+                raise error("unknown verb", source.string, saved_pos_2)
+
+            source.expect(")")
+
+            return verb
+
+    # (...: an unnamed capture group.
+    source.pos = saved_pos
+    group = info.open_group()
+    saved_flags = info.flags
+    try:
+        subpattern = _parse_pattern(source, info)
+        source.expect(")")
+    finally:
+        info.flags = saved_flags
+        source.ignore_space = bool(info.flags & VERBOSE)
+
+    info.close_group()
+
+    return Group(info, group, subpattern)
+
+def parse_extension(source, info):
+    "Parses a Python extension."
+    saved_pos = source.pos
+    ch = source.get()
+    if ch == "<":
+        # (?P<...: a named capture group.
+        name = parse_name(source)
+        group = info.open_group(name)
+        source.expect(">")
+        saved_flags = info.flags
+        try:
+            subpattern = _parse_pattern(source, info)
+            source.expect(")")
+        finally:
+            info.flags = saved_flags
+            source.ignore_space = bool(info.flags & VERBOSE)
+
+        info.close_group()
+
+        return Group(info, group, subpattern)
+    if ch == "=":
+        # (?P=...: a named group reference.
+        name = parse_name(source, allow_numeric=True)
+        source.expect(")")
+        if info.is_open_group(name):
+            raise error("cannot refer to an open group", source.string,
+              saved_pos)
+
+        return make_ref_group(info, name, saved_pos)
+    if ch == ">" or ch == "&":
+        # (?P>...: a call to a group.
+        return parse_call_named_group(source, info, saved_pos)
+
+    source.pos = saved_pos
+    raise error("unknown extension", source.string, saved_pos)
+
+def parse_comment(source):
+    "Parses a comment."
+    source.skip_while(set(")"), include=False)
+    source.expect(")")
+
+    return COMMENT
+
+def parse_lookaround(source, info, behind, positive):
+    "Parses a lookaround."
+    saved_flags = info.flags
+    try:
+        subpattern = _parse_pattern(source, info)
+        source.expect(")")
+    finally:
+        info.flags = saved_flags
+        source.ignore_space = bool(info.flags & VERBOSE)
+
+    return LookAround(behind, positive, subpattern)
+
+def parse_conditional(source, info):
+    "Parses a conditional subpattern."
+    saved_flags = info.flags
+    saved_pos = source.pos
+    ch = source.get()
+    if ch == "?":
+        # (?(?...
+        ch = source.get()
+        if ch in ("=", "!"):
+            # (?(?=... or (?(?!...: lookahead conditional.
+            return parse_lookaround_conditional(source, info, False, ch == "=")
+        if ch == "<":
+            # (?(?<...
+            ch = source.get()
+            if ch in ("=", "!"):
+                # (?(?<=... or (?(?<!...: lookbehind conditional.
+                return parse_lookaround_conditional(source, info, True, ch ==
+                  "=")
+
+        source.pos = saved_pos
+        raise error("expected lookaround conditional", source.string,
+          source.pos)
+
+    source.pos = saved_pos
+    try:
+        group = parse_name(source, True)
+        source.expect(")")
+        yes_branch = parse_sequence(source, info)
+        if source.match("|"):
+            no_branch = parse_sequence(source, info)
+        else:
+            no_branch = Sequence()
+
+        source.expect(")")
+    finally:
+        info.flags = saved_flags
+        source.ignore_space = bool(info.flags & VERBOSE)
+
+    if yes_branch.is_empty() and no_branch.is_empty():
+        return Sequence()
+
+    return Conditional(info, group, yes_branch, no_branch, saved_pos)
+
+def parse_lookaround_conditional(source, info, behind, positive):
+    saved_flags = info.flags
+    try:
+        subpattern = _parse_pattern(source, info)
+        source.expect(")")
+    finally:
+        info.flags = saved_flags
+        source.ignore_space = bool(info.flags & VERBOSE)
+
+    yes_branch = parse_sequence(source, info)
+    if source.match("|"):
+        no_branch = parse_sequence(source, info)
+    else:
+        no_branch = Sequence()
+
+    source.expect(")")
+
+    return LookAroundConditional(behind, positive, subpattern, yes_branch,
+      no_branch)
+
+def parse_atomic(source, info):
+    "Parses an atomic subpattern."
+    saved_flags = info.flags
+    try:
+        subpattern = _parse_pattern(source, info)
+        source.expect(")")
+    finally:
+        info.flags = saved_flags
+        source.ignore_space = bool(info.flags & VERBOSE)
+
+    return Atomic(subpattern)
+
+def parse_common(source, info):
+    "Parses a common groups branch."
+    # Capture group numbers in different branches can reuse the group numbers.
+    initial_group_count = info.group_count
+    branches = [parse_sequence(source, info)]
+    final_group_count = info.group_count
+    while source.match("|"):
+        info.group_count = initial_group_count
+        branches.append(parse_sequence(source, info))
+        final_group_count = max(final_group_count, info.group_count)
+
+    info.group_count = final_group_count
+    source.expect(")")
+
+    if len(branches) == 1:
+        return branches[0]
+    return Branch(branches)
+
+def parse_call_group(source, info, ch, pos):
+    "Parses a call to a group."
+    if ch == "R":
+        group = "0"
+    else:
+        group = ch + source.get_while(DIGITS)
+
+    source.expect(")")
+
+    return CallGroup(info, group, pos)
+
+def parse_call_named_group(source, info, pos):
+    "Parses a call to a named group."
+    group = parse_name(source)
+    source.expect(")")
+
+    return CallGroup(info, group, pos)
+
+def parse_flag_set(source):
+    "Parses a set of inline flags."
+    flags = 0
+
+    try:
+        while True:
+            saved_pos = source.pos
+            ch = source.get()
+            if ch == "V":
+                ch += source.get()
+            flags |= REGEX_FLAGS[ch]
+    except KeyError:
+        source.pos = saved_pos
+
+    return flags
+
+def parse_flags(source, info):
+    "Parses flags being turned on/off."
+    flags_on = parse_flag_set(source)
+    if source.match("-"):
+        flags_off = parse_flag_set(source)
+        if not flags_off:
+            raise error("bad inline flags: no flags after '-'", source.string,
+              source.pos)
+    else:
+        flags_off = 0
+
+    if flags_on & LOCALE:
+        # Remember that this pattern as an inline locale flag.
+        info.inline_locale = True
+
+    return flags_on, flags_off
+
+def parse_subpattern(source, info, flags_on, flags_off):
+    "Parses a subpattern with scoped flags."
+    saved_flags = info.flags
+    info.flags = (info.flags | flags_on) & ~flags_off
+    source.ignore_space = bool(info.flags & VERBOSE)
+    try:
+        subpattern = _parse_pattern(source, info)
+        source.expect(")")
+    finally:
+        info.flags = saved_flags
+        source.ignore_space = bool(info.flags & VERBOSE)
+
+    return subpattern
+
+def parse_flags_subpattern(source, info):
+    """Parses a flags subpattern. It could be inline flags or a subpattern
+    possibly with local flags. If it's a subpattern, then that's returned;
+    if it's a inline flags, then FLAGS is returned.
+    """
+    flags_on, flags_off = parse_flags(source, info)
+
+    if flags_off & GLOBAL_FLAGS:
+        raise error("bad inline flags: cannot turn off global flag",
+          source.string, source.pos)
+
+    if flags_on & flags_off:
+        raise error("bad inline flags: flag turned on and off", source.string,
+          source.pos)
+
+    # Handle flags which are global in all regex behaviours.
+    new_global_flags = (flags_on & ~info.global_flags) & GLOBAL_FLAGS
+    if new_global_flags:
+        info.global_flags |= new_global_flags
+
+        # A global has been turned on, so reparse the pattern.
+        raise _UnscopedFlagSet(info.global_flags)
+
+    # Ensure that from now on we have only scoped flags.
+    flags_on &= ~GLOBAL_FLAGS
+
+    if source.match(":"):
+        return parse_subpattern(source, info, flags_on, flags_off)
+
+    if source.match(")"):
+        parse_positional_flags(source, info, flags_on, flags_off)
+        return FLAGS
+
+    raise error("unknown extension", source.string, source.pos)
+
+def parse_positional_flags(source, info, flags_on, flags_off):
+    "Parses positional flags."
+    version = (info.flags & _ALL_VERSIONS) or DEFAULT_VERSION
+    if version == VERSION0:
+        # Positional flags are global and can only be turned on.
+        if flags_off:
+            raise error("bad inline flags: cannot turn flags off",
+              source.string, source.pos)
+
+        new_global_flags = flags_on & ~info.global_flags
+        if new_global_flags:
+            info.global_flags |= new_global_flags
+
+            # A global has been turned on, so reparse the pattern.
+            raise _UnscopedFlagSet(info.global_flags)
+    else:
+        info.flags = (info.flags | flags_on) & ~flags_off
+
+    source.ignore_space = bool(info.flags & VERBOSE)
+
+def parse_name(source, allow_numeric=False, allow_group_0=False):
+    "Parses a name."
+    name = source.get_while(set(")>"), include=False)
+
+    if not name:
+        raise error("missing group name", source.string, source.pos)
+
+    if name.isdigit():
+        min_group = 0 if allow_group_0 else 1
+        if not allow_numeric or int(name) < min_group:
+            raise error("bad character in group name", source.string,
+              source.pos)
+    else:
+        if not is_identifier(name):
+            raise error("bad character in group name", source.string,
+              source.pos)
+
+    return name
+
+def is_identifier(name):
+    if not name:
+        return False
+
+    if name[0] not in ALPHA and name[0] != "_":
+        return False
+
+    name = name.replace("_", "")
+
+    return not name or all(c in ALNUM for c in name)
+
+def is_octal(string):
+    "Checks whether a string is octal."
+    return all(ch in OCT_DIGITS for ch in string)
+
+def is_decimal(string):
+    "Checks whether a string is decimal."
+    return all(ch in DIGITS for ch in string)
+
+def is_hexadecimal(string):
+    "Checks whether a string is hexadecimal."
+    return all(ch in HEX_DIGITS for ch in string)
+
+def parse_escape(source, info, in_set):
+    "Parses an escape sequence."
+    saved_ignore = source.ignore_space
+    source.ignore_space = False
+    ch = source.get()
+    source.ignore_space = saved_ignore
+    if not ch:
+        # A backslash at the end of the pattern.
+        raise error("bad escape (end of pattern)", source.string, source.pos)
+    if ch in HEX_ESCAPES:
+        # A hexadecimal escape sequence.
+        return parse_hex_escape(source, info, HEX_ESCAPES[ch], in_set, ch)
+    elif ch == "g" and not in_set:
+        # A group reference.
+        saved_pos = source.pos
+        try:
+            return parse_group_ref(source, info)
+        except error:
+            # Invalid as a group reference, so assume it's a literal.
+            source.pos = saved_pos
+
+        return make_character(info, ord(ch), in_set)
+    elif ch == "G" and not in_set:
+        # A search anchor.
+        return SearchAnchor()
+    elif ch == "L" and not in_set:
+        # A string set.
+        return parse_string_set(source, info)
+    elif ch == "N":
+        # A named codepoint.
+        return parse_named_char(source, info, in_set)
+    elif ch in "pP":
+        # A Unicode property, positive or negative.
+        return parse_property(source, info, ch == "p", in_set)
+    elif ch == "X" and not in_set:
+        # A grapheme cluster.
+        return Grapheme()
+    elif ch in ALPHA:
+        # An alphabetic escape sequence.
+        # Positional escapes aren't allowed inside a character set.
+        if not in_set:
+            if info.flags & WORD:
+                value = WORD_POSITION_ESCAPES.get(ch)
+            else:
+                value = POSITION_ESCAPES.get(ch)
+
+            if value:
+                return value
+
+        value = CHARSET_ESCAPES.get(ch)
+        if value:
+            return value
+
+        value = CHARACTER_ESCAPES.get(ch)
+        if value:
+            return Character(ord(value))
+
+        return make_character(info, ord(ch), in_set)
+    elif ch in DIGITS:
+        # A numeric escape sequence.
+        return parse_numeric_escape(source, info, ch, in_set)
+    else:
+        # A literal.
+        return make_character(info, ord(ch), in_set)
+
+def parse_numeric_escape(source, info, ch, in_set):
+    "Parses a numeric escape sequence."
+    if in_set or ch == "0":
+        # Octal escape sequence, max 3 digits.
+        return parse_octal_escape(source, info, [ch], in_set)
+
+    # At least 1 digit, so either octal escape or group.
+    digits = ch
+    saved_pos = source.pos
+    ch = source.get()
+    if ch in DIGITS:
+        # At least 2 digits, so either octal escape or group.
+        digits += ch
+        saved_pos = source.pos
+        ch = source.get()
+        if is_octal(digits) and ch in OCT_DIGITS:
+            # 3 octal digits, so octal escape sequence.
+            encoding = info.flags & _ALL_ENCODINGS
+            if encoding == ASCII or encoding == LOCALE:
+                octal_mask = 0xFF
+            else:
+                octal_mask = 0x1FF
+
+            value = int(digits + ch, 8) & octal_mask
+            return make_character(info, value)
+
+    # Group reference.
+    source.pos = saved_pos
+    if info.is_open_group(digits):
+        raise error("cannot refer to an open group", source.string, source.pos)
+
+    return make_ref_group(info, digits, source.pos)
+
+def parse_octal_escape(source, info, digits, in_set):
+    "Parses an octal escape sequence."
+    saved_pos = source.pos
+    ch = source.get()
+    while len(digits) < 3 and ch in OCT_DIGITS:
+        digits.append(ch)
+        saved_pos = source.pos
+        ch = source.get()
+
+    source.pos = saved_pos
+    try:
+        value = int("".join(digits), 8)
+        return make_character(info, value, in_set)
+    except ValueError:
+        if digits[0] in OCT_DIGITS:
+            raise error("incomplete escape \\%s" % ''.join(digits),
+              source.string, source.pos)
+        else:
+            raise error("bad escape \\%s" % digits[0], source.string,
+              source.pos)
+
+def parse_hex_escape(source, info, expected_len, in_set, type):
+    "Parses a hex escape sequence."
+    digits = []
+    for i in range(expected_len):
+        ch = source.get()
+        if ch not in HEX_DIGITS:
+            raise error("incomplete escape \\%s%s" % (type, ''.join(digits)),
+              source.string, source.pos)
+        digits.append(ch)
+
+    value = int("".join(digits), 16)
+    return make_character(info, value, in_set)
+
+def parse_group_ref(source, info):
+    "Parses a group reference."
+    source.expect("<")
+    saved_pos = source.pos
+    name = parse_name(source, True)
+    source.expect(">")
+    if info.is_open_group(name):
+        raise error("cannot refer to an open group", source.string, source.pos)
+
+    return make_ref_group(info, name, saved_pos)
+
+def parse_string_set(source, info):
+    "Parses a string set reference."
+    source.expect("<")
+    name = parse_name(source, True)
+    source.expect(">")
+    if name is None or name not in info.kwargs:
+        raise error("undefined named list", source.string, source.pos)
+
+    return make_string_set(info, name)
+
+def parse_named_char(source, info, in_set):
+    "Parses a named character."
+    saved_pos = source.pos
+    if source.match("{"):
+        name = source.get_while(NAMED_CHAR_PART)
+        if source.match("}"):
+            try:
+                value = unicodedata.lookup(name)
+                return make_character(info, ord(value), in_set)
+            except KeyError:
+                raise error("undefined character name", source.string,
+                  source.pos)
+
+    source.pos = saved_pos
+    return make_character(info, ord("N"), in_set)
+
+def parse_property(source, info, positive, in_set):
+    "Parses a Unicode property."
+    saved_pos = source.pos
+    ch = source.get()
+    if ch == "{":
+        negate = source.match("^")
+        prop_name, name = parse_property_name(source)
+        if source.match("}"):
+            # It's correctly delimited.
+            prop = lookup_property(prop_name, name, positive != negate, source)
+            return make_property(info, prop, in_set)
+    elif ch and ch in "CLMNPSZ":
+        # An abbreviated property, eg \pL.
+        prop = lookup_property(None, ch, positive, source)
+        return make_property(info, prop, in_set)
+
+    # Not a property, so treat as a literal "p" or "P".
+    source.pos = saved_pos
+    ch = "p" if positive else "P"
+    return make_character(info, ord(ch), in_set)
+
+def parse_property_name(source):
+    "Parses a property name, which may be qualified."
+    name = source.get_while(PROPERTY_NAME_PART)
+    saved_pos = source.pos
+
+    ch = source.get()
+    if ch and ch in ":=":
+        prop_name = name
+        name = source.get_while(ALNUM | set(" &_-./")).strip()
+
+        if name:
+            # Name after the ":" or "=", so it's a qualified name.
+            saved_pos = source.pos
+        else:
+            # No name after the ":" or "=", so assume it's an unqualified name.
+            prop_name, name = None, prop_name
+    else:
+        prop_name = None
+
+    source.pos = saved_pos
+    return prop_name, name
+
+def parse_set(source, info):
+    "Parses a character set."
+    version = (info.flags & _ALL_VERSIONS) or DEFAULT_VERSION
+
+    saved_ignore = source.ignore_space
+    source.ignore_space = False
+    # Negative set?
+    negate = source.match("^")
+    try:
+        if version == VERSION0:
+            item = parse_set_imp_union(source, info)
+        else:
+            item = parse_set_union(source, info)
+
+        if not source.match("]"):
+            raise error("missing ]", source.string, source.pos)
+    finally:
+        source.ignore_space = saved_ignore
+
+    if negate:
+        item = item.with_flags(positive=not item.positive)
+
+    item = item.with_flags(case_flags=info.flags & CASE_FLAGS)
+
+    return item
+
+def parse_set_union(source, info):
+    "Parses a set union ([x||y])."
+    items = [parse_set_symm_diff(source, info)]
+    while source.match("||"):
+        items.append(parse_set_symm_diff(source, info))
+
+    if len(items) == 1:
+        return items[0]
+    return SetUnion(info, items)
+
+def parse_set_symm_diff(source, info):
+    "Parses a set symmetric difference ([x~~y])."
+    items = [parse_set_inter(source, info)]
+    while source.match("~~"):
+        items.append(parse_set_inter(source, info))
+
+    if len(items) == 1:
+        return items[0]
+    return SetSymDiff(info, items)
+
+def parse_set_inter(source, info):
+    "Parses a set intersection ([x&&y])."
+    items = [parse_set_diff(source, info)]
+    while source.match("&&"):
+        items.append(parse_set_diff(source, info))
+
+    if len(items) == 1:
+        return items[0]
+    return SetInter(info, items)
+
+def parse_set_diff(source, info):
+    "Parses a set difference ([x--y])."
+    items = [parse_set_imp_union(source, info)]
+    while source.match("--"):
+        items.append(parse_set_imp_union(source, info))
+
+    if len(items) == 1:
+        return items[0]
+    return SetDiff(info, items)
+
+def parse_set_imp_union(source, info):
+    "Parses a set implicit union ([xy])."
+    version = (info.flags & _ALL_VERSIONS) or DEFAULT_VERSION
+
+    items = [parse_set_member(source, info)]
+    while True:
+        saved_pos = source.pos
+        if source.match("]"):
+            # End of the set.
+            source.pos = saved_pos
+            break
+
+        if version == VERSION1 and any(source.match(op) for op in SET_OPS):
+            # The new behaviour has set operators.
+            source.pos = saved_pos
+            break
+
+        items.append(parse_set_member(source, info))
+
+    if len(items) == 1:
+        return items[0]
+    return SetUnion(info, items)
+
+def parse_set_member(source, info):
+    "Parses a member in a character set."
+    # Parse a set item.
+    start = parse_set_item(source, info)
+    saved_pos1 = source.pos
+    if (not isinstance(start, Character) or not start.positive or not
+      source.match("-")):
+        # It's not the start of a range.
+        return start
+
+    version = (info.flags & _ALL_VERSIONS) or DEFAULT_VERSION
+
+    # It looks like the start of a range of characters.
+    saved_pos2 = source.pos
+    if version == VERSION1 and source.match("-"):
+        # It's actually the set difference operator '--', so return the
+        # character.
+        source.pos = saved_pos1
+        return start
+
+    if source.match("]"):
+        # We've reached the end of the set, so return both the character and
+        # hyphen.
+        source.pos = saved_pos2
+        return SetUnion(info, [start, Character(ord("-"))])
+
+    # Parse a set item.
+    end = parse_set_item(source, info)
+    if not isinstance(end, Character) or not end.positive:
+        # It's not a range, so return the character, hyphen and property.
+        return SetUnion(info, [start, Character(ord("-")), end])
+
+    # It _is_ a range.
+    if start.value > end.value:
+        raise error("bad character range", source.string, source.pos)
+
+    if start.value == end.value:
+        return start
+
+    return Range(start.value, end.value)
+
+def parse_set_item(source, info):
+    "Parses an item in a character set."
+    version = (info.flags & _ALL_VERSIONS) or DEFAULT_VERSION
+
+    if source.match("\\"):
+        # An escape sequence in a set.
+        return parse_escape(source, info, True)
+
+    saved_pos = source.pos
+    if source.match("[:"):
+        # Looks like a POSIX character class.
+        try:
+            return parse_posix_class(source, info)
+        except ParseError:
+            # Not a POSIX character class.
+            source.pos = saved_pos
+
+    if version == VERSION1 and source.match("["):
+        # It's the start of a nested set.
+
+        # Negative set?
+        negate = source.match("^")
+        item = parse_set_union(source, info)
+
+        if not source.match("]"):
+            raise error("missing ]", source.string, source.pos)
+
+        if negate:
+            item = item.with_flags(positive=not item.positive)
+
+        return item
+
+    ch = source.get()
+    if not ch:
+        raise error("unterminated character set", source.string, source.pos)
+
+    return Character(ord(ch))
+
+def parse_posix_class(source, info):
+    "Parses a POSIX character class."
+    negate = source.match("^")
+    prop_name, name = parse_property_name(source)
+    if not source.match(":]"):
+        raise ParseError()
+
+    return lookup_property(prop_name, name, not negate, source, posix=True)
+
+def float_to_rational(flt):
+    "Converts a float to a rational pair."
+    int_part = int(flt)
+    error = flt - int_part
+    if abs(error) < 0.0001:
+        return int_part, 1
+
+    den, num = float_to_rational(1.0 / error)
+
+    return int_part * den + num, den
+
+def numeric_to_rational(numeric):
+    "Converts a numeric string to a rational string, if possible."
+    if numeric[ : 1] == "-":
+        sign, numeric = numeric[0], numeric[1 : ]
+    else:
+        sign = ""
+
+    parts = numeric.split("/")
+    if len(parts) == 2:
+        num, den = float_to_rational(float(parts[0]) / float(parts[1]))
+    elif len(parts) == 1:
+        num, den = float_to_rational(float(parts[0]))
+    else:
+        raise ValueError()
+
+    result = "%s%s/%s" % (sign, num, den)
+    if result.endswith("/1"):
+        return result[ : -2]
+
+    return result
+
+def standardise_name(name):
+    "Standardises a property or value name."
+    try:
+        return numeric_to_rational("".join(name))
+    except (ValueError, ZeroDivisionError):
+        return "".join(ch for ch in name if ch not in "_- ").upper()
+
+_posix_classes = set('ALNUM DIGIT PUNCT XDIGIT'.split())
+
+def lookup_property(property, value, positive, source=None, posix=False):
+    "Looks up a property."
+    # Normalise the names (which may still be lists).
+    property = standardise_name(property) if property else None
+    value = standardise_name(value)
+
+    if (property, value) == ("GENERALCATEGORY", "ASSIGNED"):
+        property, value, positive = "GENERALCATEGORY", "UNASSIGNED", not positive
+
+    if posix and not property and value.upper() in _posix_classes:
+        value = 'POSIX' + value
+
+    if property:
+        # Both the property and the value are provided.
+        prop = PROPERTIES.get(property)
+        if not prop:
+            if not source:
+                raise error("unknown property")
+
+            raise error("unknown property", source.string, source.pos)
+
+        prop_id, value_dict = prop
+        val_id = value_dict.get(value)
+        if val_id is None:
+            if not source:
+                raise error("unknown property value")
+
+            raise error("unknown property value", source.string, source.pos)
+
+        if "YES" in value_dict and val_id == 0:
+            positive, val_id = not positive, 1
+
+        return Property((prop_id << 16) | val_id, positive)
+
+    # Only the value is provided.
+    # It might be the name of a GC, script or block value.
+    for property in ("GC", "SCRIPT", "BLOCK"):
+        prop_id, value_dict = PROPERTIES.get(property)
+        val_id = value_dict.get(value)
+        if val_id is not None:
+            return Property((prop_id << 16) | val_id, positive)
+
+    # It might be the name of a binary property.
+    prop = PROPERTIES.get(value)
+    if prop:
+        prop_id, value_dict = prop
+
+        if "YES" in value_dict:
+            return Property((prop_id << 16) | 1, positive)
+
+    # It might be the name of a binary property starting with a prefix.
+    if value.startswith("IS"):
+        prop = PROPERTIES.get(value[2 : ])
+        if prop:
+            prop_id, value_dict = prop
+            if "YES" in value_dict:
+                return Property((prop_id << 16) | 1, positive)
+
+    # It might be the name of a script or block starting with a prefix.
+    for prefix, property in (("IS", "SCRIPT"), ("IN", "BLOCK")):
+        if value.startswith(prefix):
+            prop_id, value_dict = PROPERTIES.get(property)
+            val_id = value_dict.get(value[2 : ])
+            if val_id is not None:
+                return Property((prop_id << 16) | val_id, positive)
+
+    # Unknown property.
+    if not source:
+        raise error("unknown property")
+
+    raise error("unknown property", source.string, source.pos)
+
+def _compile_replacement(source, pattern, is_unicode):
+    "Compiles a replacement template escape sequence."
+    ch = source.get()
+    if ch in ALPHA:
+        # An alphabetic escape sequence.
+        value = CHARACTER_ESCAPES.get(ch)
+        if value:
+            return False, [ord(value)]
+
+        if ch in HEX_ESCAPES and (ch == "x" or is_unicode):
+            # A hexadecimal escape sequence.
+            return False, [parse_repl_hex_escape(source, HEX_ESCAPES[ch], ch)]
+
+        if ch == "g":
+            # A group preference.
+            return True, [compile_repl_group(source, pattern)]
+
+        if ch == "N" and is_unicode:
+            # A named character.
+            value = parse_repl_named_char(source)
+            if value is not None:
+                return False, [value]
+
+        return False, [ord("\\"), ord(ch)]
+
+    if isinstance(source.sep, str):
+        octal_mask = 0xFF
+    else:
+        octal_mask = 0x1FF
+
+    if ch == "0":
+        # An octal escape sequence.
+        digits = ch
+        while len(digits) < 3:
+            saved_pos = source.pos
+            ch = source.get()
+            if ch not in OCT_DIGITS:
+                source.pos = saved_pos
+                break
+            digits += ch
+
+        return False, [int(digits, 8) & octal_mask]
+
+    if ch in DIGITS:
+        # Either an octal escape sequence (3 digits) or a group reference (max
+        # 2 digits).
+        digits = ch
+        saved_pos = source.pos
+        ch = source.get()
+        if ch in DIGITS:
+            digits += ch
+            saved_pos = source.pos
+            ch = source.get()
+            if ch and is_octal(digits + ch):
+                # An octal escape sequence.
+                return False, [int(digits + ch, 8) & octal_mask]
+
+        # A group reference.
+        source.pos = saved_pos
+        return True, [int(digits)]
+
+    if ch == "\\":
+        # An escaped backslash is a backslash.
+        return False, [ord("\\")]
+
+    if not ch:
+        # A trailing backslash.
+        raise error("bad escape (end of pattern)", source.string, source.pos)
+
+    # An escaped non-backslash is a backslash followed by the literal.
+    return False, [ord("\\"), ord(ch)]
+
+def parse_repl_hex_escape(source, expected_len, type):
+    "Parses a hex escape sequence in a replacement string."
+    digits = []
+    for i in range(expected_len):
+        ch = source.get()
+        if ch not in HEX_DIGITS:
+            raise error("incomplete escape \\%s%s" % (type, ''.join(digits)),
+              source.string, source.pos)
+        digits.append(ch)
+
+    return int("".join(digits), 16)
+
+def parse_repl_named_char(source):
+    "Parses a named character in a replacement string."
+    saved_pos = source.pos
+    if source.match("{"):
+        name = source.get_while(ALPHA | set(" "))
+
+        if source.match("}"):
+            try:
+                value = unicodedata.lookup(name)
+                return ord(value)
+            except KeyError:
+                raise error("undefined character name", source.string,
+                  source.pos)
+
+    source.pos = saved_pos
+    return None
+
+def compile_repl_group(source, pattern):
+    "Compiles a replacement template group reference."
+    source.expect("<")
+    name = parse_name(source, True, True)
+
+    source.expect(">")
+    if name.isdigit():
+        index = int(name)
+        if not 0 <= index <= pattern.groups:
+            raise error("invalid group reference", source.string, source.pos)
+
+        return index
+
+    try:
+        return pattern.groupindex[name]
+    except KeyError:
+        raise IndexError("unknown group")
+
+# The regular expression is parsed into a syntax tree. The different types of
+# node are defined below.
+
+INDENT = "  "
+POSITIVE_OP = 0x1
+ZEROWIDTH_OP = 0x2
+FUZZY_OP = 0x4
+REVERSE_OP = 0x8
+REQUIRED_OP = 0x10
+
+POS_TEXT = {False: "NON-MATCH", True: "MATCH"}
+CASE_TEXT = {NOCASE: "", IGNORECASE: " SIMPLE_IGNORE_CASE", FULLCASE: "",
+  FULLIGNORECASE: " FULL_IGNORE_CASE"}
+
+def make_sequence(items):
+    if len(items) == 1:
+        return items[0]
+    return Sequence(items)
+
+# Common base class for all nodes.
+class RegexBase(object):
+    def __init__(self):
+        self._key = self.__class__
+
+    def with_flags(self, positive=None, case_flags=None, zerowidth=None):
+        if positive is None:
+            positive = self.positive
+        else:
+            positive = bool(positive)
+        if case_flags is None:
+            case_flags = self.case_flags
+        else:
+            case_flags = CASE_FLAGS_COMBINATIONS[case_flags & CASE_FLAGS]
+        if zerowidth is None:
+            zerowidth = self.zerowidth
+        else:
+            zerowidth = bool(zerowidth)
+
+        if (positive == self.positive and case_flags == self.case_flags and
+          zerowidth == self.zerowidth):
+            return self
+
+        return self.rebuild(positive, case_flags, zerowidth)
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        pass
+
+    def optimise(self, info):
+        return self
+
+    def pack_characters(self, info):
+        return self
+
+    def remove_captures(self):
+        return self
+
+    def is_atomic(self):
+        return True
+
+    def can_be_affix(self):
+        return True
+
+    def contains_group(self):
+        return False
+
+    def get_firstset(self, reverse):
+        raise _FirstSetError()
+
+    def has_simple_start(self):
+        return False
+
+    def compile(self, reverse=False, fuzzy=False):
+        return self._compile(reverse, fuzzy)
+
+    def dump(self, indent, reverse):
+        self._dump(indent, reverse)
+
+    def is_empty(self):
+        return False
+
+    def __hash__(self):
+        return hash(self._key)
+
+    def __eq__(self, other):
+        return type(self) is type(other) and self._key == other._key
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def get_required_string(self, reverse):
+        return self.max_width(), None
+
+# Base class for zero-width nodes.
+class ZeroWidthBase(RegexBase):
+    def __init__(self, positive=True):
+        RegexBase.__init__(self)
+        self.positive = bool(positive)
+
+        self._key = self.__class__, self.positive
+
+    def get_firstset(self, reverse):
+        return set([None])
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if self.positive:
+            flags |= POSITIVE_OP
+        if fuzzy:
+            flags |= FUZZY_OP
+        if reverse:
+            flags |= REVERSE_OP
+        return [(self._opcode, flags)]
+
+    def _dump(self, indent, reverse):
+        print "%s%s %s" % (INDENT * indent, self._op_name,
+          POS_TEXT[self.positive])
+
+    def max_width(self):
+        return 0
+
+class Any(RegexBase):
+    _opcode = {False: OP.ANY, True: OP.ANY_REV}
+    _op_name = "ANY"
+
+    def has_simple_start(self):
+        return True
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if fuzzy:
+            flags |= FUZZY_OP
+        return [(self._opcode[reverse], flags)]
+
+    def _dump(self, indent, reverse):
+        print "%s%s" % (INDENT * indent, self._op_name)
+
+    def max_width(self):
+        return 1
+
+class AnyAll(Any):
+    _opcode = {False: OP.ANY_ALL, True: OP.ANY_ALL_REV}
+    _op_name = "ANY_ALL"
+
+class AnyU(Any):
+    _opcode = {False: OP.ANY_U, True: OP.ANY_U_REV}
+    _op_name = "ANY_U"
+
+class Atomic(RegexBase):
+    def __init__(self, subpattern):
+        RegexBase.__init__(self)
+        self.subpattern = subpattern
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        self.subpattern.fix_groups(pattern, reverse, fuzzy)
+
+    def optimise(self, info):
+        self.subpattern = self.subpattern.optimise(info)
+
+        if self.subpattern.is_empty():
+            return self.subpattern
+        return self
+
+    def pack_characters(self, info):
+        self.subpattern = self.subpattern.pack_characters(info)
+        return self
+
+    def remove_captures(self):
+        self.subpattern = self.subpattern.remove_captures()
+        return self
+
+    def can_be_affix(self):
+        return self.subpattern.can_be_affix()
+
+    def contains_group(self):
+        return self.subpattern.contains_group()
+
+    def get_firstset(self, reverse):
+        return self.subpattern.get_firstset(reverse)
+
+    def has_simple_start(self):
+        return self.subpattern.has_simple_start()
+
+    def _compile(self, reverse, fuzzy):
+        return ([(OP.ATOMIC, )] + self.subpattern.compile(reverse, fuzzy) +
+          [(OP.END, )])
+
+    def _dump(self, indent, reverse):
+        print "%sATOMIC" % (INDENT * indent)
+        self.subpattern.dump(indent + 1, reverse)
+
+    def is_empty(self):
+        return self.subpattern.is_empty()
+
+    def __eq__(self, other):
+        return (type(self) is type(other) and self.subpattern ==
+          other.subpattern)
+
+    def max_width(self):
+        return self.subpattern.max_width()
+
+    def get_required_string(self, reverse):
+        return self.subpattern.get_required_string(reverse)
+
+class Boundary(ZeroWidthBase):
+    _opcode = OP.BOUNDARY
+    _op_name = "BOUNDARY"
+
+class Branch(RegexBase):
+    def __init__(self, branches):
+        RegexBase.__init__(self)
+        self.branches = branches
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        for b in self.branches:
+            b.fix_groups(pattern, reverse, fuzzy)
+
+    def optimise(self, info):
+        # Flatten branches within branches.
+        branches = Branch._flatten_branches(info, self.branches)
+
+        # Move any common prefix or suffix out of the branches.
+        prefix, branches = Branch._split_common_prefix(info, branches)
+
+        # Try to reduce adjacent single-character branches to sets.
+        branches = Branch._reduce_to_set(info, branches)
+
+        if len(branches) > 1:
+            sequence = [Branch(branches)]
+        else:
+            sequence = branches
+
+        return make_sequence(prefix + sequence)
+
+    def pack_characters(self, info):
+        self.branches = [b.pack_characters(info) for b in self.branches]
+        return self
+
+    def remove_captures(self):
+        self.branches = [b.remove_captures() for b in self.branches]
+        return self
+
+    def is_atomic(self):
+        return all(b.is_atomic() for b in self.branches)
+
+    def can_be_affix(self):
+        return all(b.can_be_affix() for b in self.branches)
+
+    def contains_group(self):
+        return any(b.contains_group() for b in self.branches)
+
+    def get_firstset(self, reverse):
+        fs = set()
+        for b in self.branches:
+            fs |= b.get_firstset(reverse)
+
+        return fs or set([None])
+
+    def _compile(self, reverse, fuzzy):
+        code = [(OP.BRANCH, )]
+        for b in self.branches:
+            code.extend(b.compile(reverse, fuzzy))
+            code.append((OP.NEXT, ))
+
+        code[-1] = (OP.END, )
+
+        return code
+
+    def _dump(self, indent, reverse):
+        print "%sBRANCH" % (INDENT * indent)
+        self.branches[0].dump(indent + 1, reverse)
+        for b in self.branches[1 : ]:
+            print "%sOR" % (INDENT * indent)
+            b.dump(indent + 1, reverse)
+
+    @staticmethod
+    def _flatten_branches(info, branches):
+        # Flatten the branches so that there aren't branches of branches.
+        new_branches = []
+        for b in branches:
+            b = b.optimise(info)
+            if isinstance(b, Branch):
+                new_branches.extend(b.branches)
+            else:
+                new_branches.append(b)
+
+        return new_branches
+
+    @staticmethod
+    def _split_common_prefix(info, branches):
+        # Common leading items can be moved out of the branches.
+        # Get the items in the branches.
+        alternatives = []
+        for b in branches:
+            if isinstance(b, Sequence):
+                alternatives.append(b.items)
+            else:
+                alternatives.append([b])
+
+        # What is the maximum possible length of the prefix?
+        max_count = min(len(a) for a in alternatives)
+
+        # What is the longest common prefix?
+        prefix = alternatives[0]
+        pos = 0
+        end_pos = max_count
+        while pos < end_pos and prefix[pos].can_be_affix() and all(a[pos] ==
+          prefix[pos] for a in alternatives):
+            pos += 1
+        count = pos
+
+        if info.flags & UNICODE:
+            # We need to check that we're not splitting a sequence of
+            # characters which could form part of full case-folding.
+            count = pos
+            while count > 0 and not all(Branch._can_split(a, count) for a in
+              alternatives):
+                count -= 1
+
+        # No common prefix is possible.
+        if count == 0:
+            return [], branches
+
+        # Rebuild the branches.
+        new_branches = []
+        for a in alternatives:
+            new_branches.append(make_sequence(a[count : ]))
+
+        return prefix[ : count], new_branches
+
+    @staticmethod
+    def _split_common_suffix(info, branches):
+        # Common trailing items can be moved out of the branches.
+        # Get the items in the branches.
+        alternatives = []
+        for b in branches:
+            if isinstance(b, Sequence):
+                alternatives.append(b.items)
+            else:
+                alternatives.append([b])
+
+        # What is the maximum possible length of the suffix?
+        max_count = min(len(a) for a in alternatives)
+
+        # What is the longest common suffix?
+        suffix = alternatives[0]
+        pos = -1
+        end_pos = -1 - max_count
+        while pos > end_pos and suffix[pos].can_be_affix() and all(a[pos] ==
+          suffix[pos] for a in alternatives):
+            pos -= 1
+        count = -1 - pos
+
+        if info.flags & UNICODE:
+            # We need to check that we're not splitting a sequence of
+            # characters which could form part of full case-folding.
+            while count > 0 and not all(Branch._can_split_rev(a, count) for a
+              in alternatives):
+                count -= 1
+
+        # No common suffix is possible.
+        if count == 0:
+            return [], branches
+
+        # Rebuild the branches.
+        new_branches = []
+        for a in alternatives:
+            new_branches.append(make_sequence(a[ : -count]))
+
+        return suffix[-count : ], new_branches
+
+    @staticmethod
+    def _can_split(items, count):
+        # Check the characters either side of the proposed split.
+        if not Branch._is_full_case(items, count - 1):
+            return True
+
+        if not Branch._is_full_case(items, count):
+            return True
+
+        # Check whether a 1-1 split would be OK.
+        if Branch._is_folded(items[count - 1 : count + 1]):
+            return False
+
+        # Check whether a 1-2 split would be OK.
+        if (Branch._is_full_case(items, count + 2) and
+          Branch._is_folded(items[count - 1 : count + 2])):
+            return False
+
+        # Check whether a 2-1 split would be OK.
+        if (Branch._is_full_case(items, count - 2) and
+          Branch._is_folded(items[count - 2 : count + 1])):
+            return False
+
+        return True
+
+    @staticmethod
+    def _can_split_rev(items, count):
+        end = len(items)
+
+        # Check the characters either side of the proposed split.
+        if not Branch._is_full_case(items, end - count):
+            return True
+
+        if not Branch._is_full_case(items, end - count - 1):
+            return True
+
+        # Check whether a 1-1 split would be OK.
+        if Branch._is_folded(items[end - count - 1 : end - count + 1]):
+            return False
+
+        # Check whether a 1-2 split would be OK.
+        if (Branch._is_full_case(items, end - count + 2) and
+          Branch._is_folded(items[end - count - 1 : end - count + 2])):
+            return False
+
+        # Check whether a 2-1 split would be OK.
+        if (Branch._is_full_case(items, end - count - 2) and
+          Branch._is_folded(items[end - count - 2 : end - count + 1])):
+            return False
+
+        return True
+
+    @staticmethod
+    def _merge_common_prefixes(info, branches):
+        # Branches with the same case-sensitive character prefix can be grouped
+        # together if they are separated only by other branches with a
+        # character prefix.
+        prefixed = defaultdict(list)
+        order = {}
+        new_branches = []
+        for b in branches:
+            if Branch._is_simple_character(b):
+                # Branch starts with a simple character.
+                prefixed[b.value].append([b])
+                order.setdefault(b.value, len(order))
+            elif (isinstance(b, Sequence) and b.items and
+              Branch._is_simple_character(b.items[0])):
+                # Branch starts with a simple character.
+                prefixed[b.items[0].value].append(b.items)
+                order.setdefault(b.items[0].value, len(order))
+            else:
+                Branch._flush_char_prefix(info, prefixed, order, new_branches)
+
+                new_branches.append(b)
+
+        Branch._flush_char_prefix(info, prefixed, order, new_branches)
+
+        return new_branches
+
+    @staticmethod
+    def _is_simple_character(c):
+        return isinstance(c, Character) and c.positive and not c.case_flags
+
+    @staticmethod
+    def _reduce_to_set(info, branches):
+        # Can the branches be reduced to a set?
+        new_branches = []
+        items = set()
+        case_flags = NOCASE
+        for b in branches:
+            if isinstance(b, (Character, Property, SetBase)):
+                # Branch starts with a single character.
+                if b.case_flags != case_flags:
+                    # Different case sensitivity, so flush.
+                    Branch._flush_set_members(info, items, case_flags,
+                      new_branches)
+
+                    case_flags = b.case_flags
+
+                items.add(b.with_flags(case_flags=NOCASE))
+            else:
+                Branch._flush_set_members(info, items, case_flags,
+                  new_branches)
+
+                new_branches.append(b)
+
+        Branch._flush_set_members(info, items, case_flags, new_branches)
+
+        return new_branches
+
+    @staticmethod
+    def _flush_char_prefix(info, prefixed, order, new_branches):
+        # Flush the prefixed branches.
+        if not prefixed:
+            return
+
+        for value, branches in sorted(prefixed.items(), key=lambda pair:
+          order[pair[0]]):
+            if len(branches) == 1:
+                new_branches.append(make_sequence(branches[0]))
+            else:
+                subbranches = []
+                optional = False
+                for b in branches:
+                    if len(b) > 1:
+                        subbranches.append(make_sequence(b[1 : ]))
+                    elif not optional:
+                        subbranches.append(Sequence())
+                        optional = True
+
+                sequence = Sequence([Character(value), Branch(subbranches)])
+                new_branches.append(sequence.optimise(info))
+
+        prefixed.clear()
+        order.clear()
+
+    @staticmethod
+    def _flush_set_members(info, items, case_flags, new_branches):
+        # Flush the set members.
+        if not items:
+            return
+
+        if len(items) == 1:
+            item = list(items)[0]
+        else:
+            item = SetUnion(info, list(items)).optimise(info)
+
+        new_branches.append(item.with_flags(case_flags=case_flags))
+
+        items.clear()
+
+    @staticmethod
+    def _is_full_case(items, i):
+        if not 0 <= i < len(items):
+            return False
+
+        item = items[i]
+        return (isinstance(item, Character) and item.positive and
+          (item.case_flags & FULLIGNORECASE) == FULLIGNORECASE)
+
+    @staticmethod
+    def _is_folded(items):
+        if len(items) < 2:
+            return False
+
+        for i in items:
+            if (not isinstance(i, Character) or not i.positive or not
+              i.case_flags):
+                return False
+
+        folded = u"".join(unichr(i.value) for i in items)
+        folded = _regex.fold_case(FULL_CASE_FOLDING, folded)
+
+        # Get the characters which expand to multiple codepoints on folding.
+        expanding_chars = _regex.get_expand_on_folding()
+
+        for c in expanding_chars:
+            if folded == _regex.fold_case(FULL_CASE_FOLDING, c):
+                return True
+
+        return False
+
+    def is_empty(self):
+        return all(b.is_empty() for b in self.branches)
+
+    def __eq__(self, other):
+        return type(self) is type(other) and self.branches == other.branches
+
+    def max_width(self):
+        return max(b.max_width() for b in self.branches)
+
+class CallGroup(RegexBase):
+    def __init__(self, info, group, position):
+        RegexBase.__init__(self)
+        self.info = info
+        self.group = group
+        self.position = position
+
+        self._key = self.__class__, self.group
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        try:
+            self.group = int(self.group)
+        except ValueError:
+            try:
+                self.group = self.info.group_index[self.group]
+            except KeyError:
+                raise error("invalid group reference", pattern, self.position)
+
+        if not 0 <= self.group <= self.info.group_count:
+            raise error("unknown group", pattern, self.position)
+
+        if self.group > 0 and self.info.open_group_count[self.group] > 1:
+            raise error("ambiguous group reference", pattern, self.position)
+
+        self.info.group_calls.append((self, reverse, fuzzy))
+
+        self._key = self.__class__, self.group
+
+    def remove_captures(self):
+        raise error("group reference not allowed", pattern, self.position)
+
+    def _compile(self, reverse, fuzzy):
+        return [(OP.GROUP_CALL, self.call_ref)]
+
+    def _dump(self, indent, reverse):
+        print "%sGROUP_CALL %s" % (INDENT * indent, self.group)
+
+    def __eq__(self, other):
+        return type(self) is type(other) and self.group == other.group
+
+    def max_width(self):
+        return UNLIMITED
+
+class Character(RegexBase):
+    _opcode = {(NOCASE, False): OP.CHARACTER, (IGNORECASE, False):
+      OP.CHARACTER_IGN, (FULLCASE, False): OP.CHARACTER, (FULLIGNORECASE,
+      False): OP.CHARACTER_IGN, (NOCASE, True): OP.CHARACTER_REV, (IGNORECASE,
+      True): OP.CHARACTER_IGN_REV, (FULLCASE, True): OP.CHARACTER_REV,
+      (FULLIGNORECASE, True): OP.CHARACTER_IGN_REV}
+
+    def __init__(self, value, positive=True, case_flags=NOCASE,
+      zerowidth=False):
+        RegexBase.__init__(self)
+        self.value = value
+        self.positive = bool(positive)
+        self.case_flags = CASE_FLAGS_COMBINATIONS[case_flags]
+        self.zerowidth = bool(zerowidth)
+
+        if (self.positive and (self.case_flags & FULLIGNORECASE) ==
+          FULLIGNORECASE):
+            self.folded = _regex.fold_case(FULL_CASE_FOLDING, unichr(self.value))
+        else:
+            self.folded = unichr(self.value)
+
+        self._key = (self.__class__, self.value, self.positive,
+          self.case_flags, self.zerowidth)
+
+    def rebuild(self, positive, case_flags, zerowidth):
+        return Character(self.value, positive, case_flags, zerowidth)
+
+    def optimise(self, info, in_set=False):
+        return self
+
+    def get_firstset(self, reverse):
+        return set([self])
+
+    def has_simple_start(self):
+        return True
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if self.positive:
+            flags |= POSITIVE_OP
+        if self.zerowidth:
+            flags |= ZEROWIDTH_OP
+        if fuzzy:
+            flags |= FUZZY_OP
+
+        code = PrecompiledCode([self._opcode[self.case_flags, reverse], flags,
+          self.value])
+
+        if len(self.folded) > 1:
+            # The character expands on full case-folding.
+            code = Branch([code, String([ord(c) for c in self.folded],
+              case_flags=self.case_flags)])
+
+        return code.compile(reverse, fuzzy)
+
+    def _dump(self, indent, reverse):
+        display = repr(unichr(self.value)).lstrip("bu")
+        print "%sCHARACTER %s %s%s" % (INDENT * indent,
+          POS_TEXT[self.positive], display, CASE_TEXT[self.case_flags])
+
+    def matches(self, ch):
+        return (ch == self.value) == self.positive
+
+    def max_width(self):
+        return len(self.folded)
+
+    def get_required_string(self, reverse):
+        if not self.positive:
+            return 1, None
+
+        self.folded_characters = tuple(ord(c) for c in self.folded)
+
+        return 0, self
+
+class Conditional(RegexBase):
+    def __init__(self, info, group, yes_item, no_item, position):
+        RegexBase.__init__(self)
+        self.info = info
+        self.group = group
+        self.yes_item = yes_item
+        self.no_item = no_item
+        self.position = position
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        try:
+            self.group = int(self.group)
+        except ValueError:
+            try:
+                self.group = self.info.group_index[self.group]
+            except KeyError:
+                if self.group == 'DEFINE':
+                    # 'DEFINE' is a special name unless there's a group with
+                    # that name.
+                    self.group = 0
+                else:
+                    raise error("unknown group", pattern, self.position)
+
+        if not 0 <= self.group <= self.info.group_count:
+            raise error("invalid group reference", pattern, self.position)
+
+        self.yes_item.fix_groups(pattern, reverse, fuzzy)
+        self.no_item.fix_groups(pattern, reverse, fuzzy)
+
+    def optimise(self, info):
+        yes_item = self.yes_item.optimise(info)
+        no_item = self.no_item.optimise(info)
+
+        return Conditional(info, self.group, yes_item, no_item, self.position)
+
+    def pack_characters(self, info):
+        self.yes_item = self.yes_item.pack_characters(info)
+        self.no_item = self.no_item.pack_characters(info)
+        return self
+
+    def remove_captures(self):
+        self.yes_item = self.yes_item.remove_captures()
+        self.no_item = self.no_item.remove_captures()
+
+    def is_atomic(self):
+        return self.yes_item.is_atomic() and self.no_item.is_atomic()
+
+    def can_be_affix(self):
+        return self.yes_item.can_be_affix() and self.no_item.can_be_affix()
+
+    def contains_group(self):
+        return self.yes_item.contains_group() or self.no_item.contains_group()
+
+    def get_firstset(self, reverse):
+        return (self.yes_item.get_firstset(reverse) |
+          self.no_item.get_firstset(reverse))
+
+    def _compile(self, reverse, fuzzy):
+        code = [(OP.GROUP_EXISTS, self.group)]
+        code.extend(self.yes_item.compile(reverse, fuzzy))
+        add_code = self.no_item.compile(reverse, fuzzy)
+        if add_code:
+            code.append((OP.NEXT, ))
+            code.extend(add_code)
+
+        code.append((OP.END, ))
+
+        return code
+
+    def _dump(self, indent, reverse):
+        print "%sGROUP_EXISTS %s" % (INDENT * indent, self.group)
+        self.yes_item.dump(indent + 1, reverse)
+        if not self.no_item.is_empty():
+            print "%sOR" % (INDENT * indent)
+            self.no_item.dump(indent + 1, reverse)
+
+    def is_empty(self):
+        return self.yes_item.is_empty() and self.no_item.is_empty()
+
+    def __eq__(self, other):
+        return type(self) is type(other) and (self.group, self.yes_item,
+          self.no_item) == (other.group, other.yes_item, other.no_item)
+
+    def max_width(self):
+        return max(self.yes_item.max_width(), self.no_item.max_width())
+
+class DefaultBoundary(ZeroWidthBase):
+    _opcode = OP.DEFAULT_BOUNDARY
+    _op_name = "DEFAULT_BOUNDARY"
+
+class DefaultEndOfWord(ZeroWidthBase):
+    _opcode = OP.DEFAULT_END_OF_WORD
+    _op_name = "DEFAULT_END_OF_WORD"
+
+class DefaultStartOfWord(ZeroWidthBase):
+    _opcode = OP.DEFAULT_START_OF_WORD
+    _op_name = "DEFAULT_START_OF_WORD"
+
+class EndOfLine(ZeroWidthBase):
+    _opcode = OP.END_OF_LINE
+    _op_name = "END_OF_LINE"
+
+class EndOfLineU(EndOfLine):
+    _opcode = OP.END_OF_LINE_U
+    _op_name = "END_OF_LINE_U"
+
+class EndOfString(ZeroWidthBase):
+    _opcode = OP.END_OF_STRING
+    _op_name = "END_OF_STRING"
+
+class EndOfStringLine(ZeroWidthBase):
+    _opcode = OP.END_OF_STRING_LINE
+    _op_name = "END_OF_STRING_LINE"
+
+class EndOfStringLineU(EndOfStringLine):
+    _opcode = OP.END_OF_STRING_LINE_U
+    _op_name = "END_OF_STRING_LINE_U"
+
+class EndOfWord(ZeroWidthBase):
+    _opcode = OP.END_OF_WORD
+    _op_name = "END_OF_WORD"
+
+class Failure(ZeroWidthBase):
+    _op_name = "FAILURE"
+
+    def _compile(self, reverse, fuzzy):
+        return [(OP.FAILURE, )]
+
+class Fuzzy(RegexBase):
+    def __init__(self, subpattern, constraints=None):
+        RegexBase.__init__(self)
+        if constraints is None:
+            constraints = {}
+        self.subpattern = subpattern
+        self.constraints = constraints
+
+        # If an error type is mentioned in the cost equation, then its maximum
+        # defaults to unlimited.
+        if "cost" in constraints:
+            for e in "dis":
+                if e in constraints["cost"]:
+                    constraints.setdefault(e, (0, None))
+
+        # If any error type is mentioned, then all the error maxima default to
+        # 0, otherwise they default to unlimited.
+        if set(constraints) & set("dis"):
+            for e in "dis":
+                constraints.setdefault(e, (0, 0))
+        else:
+            for e in "dis":
+                constraints.setdefault(e, (0, None))
+
+        # The maximum of the generic error type defaults to unlimited.
+        constraints.setdefault("e", (0, None))
+
+        # The cost equation defaults to equal costs. Also, the cost of any
+        # error type not mentioned in the cost equation defaults to 0.
+        if "cost" in constraints:
+            for e in "dis":
+                constraints["cost"].setdefault(e, 0)
+        else:
+            constraints["cost"] = {"d": 1, "i": 1, "s": 1, "max":
+              constraints["e"][1]}
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        self.subpattern.fix_groups(pattern, reverse, True)
+
+    def pack_characters(self, info):
+        self.subpattern = self.subpattern.pack_characters(info)
+        return self
+
+    def remove_captures(self):
+        self.subpattern = self.subpattern.remove_captures()
+        return self
+
+    def is_atomic(self):
+        return self.subpattern.is_atomic()
+
+    def contains_group(self):
+        return self.subpattern.contains_group()
+
+    def _compile(self, reverse, fuzzy):
+        # The individual limits.
+        arguments = []
+        for e in "dise":
+            v = self.constraints[e]
+            arguments.append(v[0])
+            arguments.append(UNLIMITED if v[1] is None else v[1])
+
+        # The coeffs of the cost equation.
+        for e in "dis":
+            arguments.append(self.constraints["cost"][e])
+
+        # The maximum of the cost equation.
+        v = self.constraints["cost"]["max"]
+        arguments.append(UNLIMITED if v is None else v)
+
+        flags = 0
+        if reverse:
+            flags |= REVERSE_OP
+
+        return ([(OP.FUZZY, flags) + tuple(arguments)] +
+          self.subpattern.compile(reverse, True) + [(OP.END,)])
+
+    def _dump(self, indent, reverse):
+        constraints = self._constraints_to_string()
+        if constraints:
+            constraints = " " + constraints
+        print "%sFUZZY%s" % (INDENT * indent, constraints)
+        self.subpattern.dump(indent + 1, reverse)
+
+    def is_empty(self):
+        return self.subpattern.is_empty()
+
+    def __eq__(self, other):
+        return (type(self) is type(other) and self.subpattern ==
+          other.subpattern)
+
+    def max_width(self):
+        return UNLIMITED
+
+    def _constraints_to_string(self):
+        constraints = []
+
+        for name in "ids":
+            min, max = self.constraints[name]
+            if max == 0:
+                continue
+
+            con = ""
+
+            if min > 0:
+                con = "%s<=" % min
+
+            con += name
+
+            if max is not None:
+                con += "<=%s" % max
+
+            constraints.append(con)
+
+        cost = []
+        for name in "ids":
+            coeff = self.constraints["cost"][name]
+            if coeff > 0:
+                cost.append("%s%s" % (coeff, name))
+
+        limit = self.constraints["cost"]["max"]
+        if limit is not None and limit > 0:
+            cost = "%s<=%s" % ("+".join(cost), limit)
+            constraints.append(cost)
+
+        return ",".join(constraints)
+
+class Grapheme(RegexBase):
+    def _compile(self, reverse, fuzzy):
+        # Match at least 1 character until a grapheme boundary is reached. Note
+        # that this is the same whether matching forwards or backwards.
+        grapheme_matcher = Atomic(Sequence([LazyRepeat(AnyAll(), 1, None),
+          GraphemeBoundary()]))
+
+        return grapheme_matcher.compile(reverse, fuzzy)
+
+    def _dump(self, indent, reverse):
+        print "%sGRAPHEME" % (INDENT * indent)
+
+    def max_width(self):
+        return UNLIMITED
+
+class GraphemeBoundary:
+    def compile(self, reverse, fuzzy):
+        return [(OP.GRAPHEME_BOUNDARY, 1)]
+
+class GreedyRepeat(RegexBase):
+    _opcode = OP.GREEDY_REPEAT
+    _op_name = "GREEDY_REPEAT"
+
+    def __init__(self, subpattern, min_count, max_count):
+        RegexBase.__init__(self)
+        self.subpattern = subpattern
+        self.min_count = min_count
+        self.max_count = max_count
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        self.subpattern.fix_groups(pattern, reverse, fuzzy)
+
+    def optimise(self, info):
+        subpattern = self.subpattern.optimise(info)
+
+        return type(self)(subpattern, self.min_count, self.max_count)
+
+    def pack_characters(self, info):
+        self.subpattern = self.subpattern.pack_characters(info)
+        return self
+
+    def remove_captures(self):
+        self.subpattern = self.subpattern.remove_captures()
+        return self
+
+    def is_atomic(self):
+        return self.min_count == self.max_count and self.subpattern.is_atomic()
+
+    def contains_group(self):
+        return self.subpattern.contains_group()
+
+    def get_firstset(self, reverse):
+        fs = self.subpattern.get_firstset(reverse)
+        if self.min_count == 0:
+            fs.add(None)
+
+        return fs
+
+    def _compile(self, reverse, fuzzy):
+        repeat = [self._opcode, self.min_count]
+        if self.max_count is None:
+            repeat.append(UNLIMITED)
+        else:
+            repeat.append(self.max_count)
+
+        subpattern = self.subpattern.compile(reverse, fuzzy)
+        if not subpattern:
+            return []
+
+        return ([tuple(repeat)] + subpattern + [(OP.END, )])
+
+    def _dump(self, indent, reverse):
+        if self.max_count is None:
+            limit = "INF"
+        else:
+            limit = self.max_count
+        print "%s%s %s %s" % (INDENT * indent, self._op_name, self.min_count,
+          limit)
+
+        self.subpattern.dump(indent + 1, reverse)
+
+    def is_empty(self):
+        return self.subpattern.is_empty()
+
+    def __eq__(self, other):
+        return type(self) is type(other) and (self.subpattern, self.min_count,
+          self.max_count) == (other.subpattern, other.min_count,
+          other.max_count)
+
+    def max_width(self):
+        if self.max_count is None:
+            return UNLIMITED
+
+        return self.subpattern.max_width() * self.max_count
+
+    def get_required_string(self, reverse):
+        max_count = UNLIMITED if self.max_count is None else self.max_count
+        if self.min_count == 0:
+            w = self.subpattern.max_width() * max_count
+            return min(w, UNLIMITED), None
+
+        ofs, req = self.subpattern.get_required_string(reverse)
+        if req:
+            return ofs, req
+
+        w = self.subpattern.max_width() * max_count
+        return min(w, UNLIMITED), None
+
+class Group(RegexBase):
+    def __init__(self, info, group, subpattern):
+        RegexBase.__init__(self)
+        self.info = info
+        self.group = group
+        self.subpattern = subpattern
+
+        self.call_ref = None
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        self.info.defined_groups[self.group] = (self, reverse, fuzzy)
+        self.subpattern.fix_groups(pattern, reverse, fuzzy)
+
+    def optimise(self, info):
+        subpattern = self.subpattern.optimise(info)
+
+        return Group(self.info, self.group, subpattern)
+
+    def pack_characters(self, info):
+        self.subpattern = self.subpattern.pack_characters(info)
+        return self
+
+    def remove_captures(self):
+        return self.subpattern.remove_captures()
+
+    def is_atomic(self):
+        return self.subpattern.is_atomic()
+
+    def can_be_affix(self):
+        return False
+
+    def contains_group(self):
+        return True
+
+    def get_firstset(self, reverse):
+        return self.subpattern.get_firstset(reverse)
+
+    def has_simple_start(self):
+        return self.subpattern.has_simple_start()
+
+    def _compile(self, reverse, fuzzy):
+        code = []
+
+        key = self.group, reverse, fuzzy
+        ref = self.info.call_refs.get(key)
+        if ref is not None:
+            code += [(OP.CALL_REF, ref)]
+
+        public_group = private_group = self.group
+        if private_group < 0:
+            public_group = self.info.private_groups[private_group]
+            private_group = self.info.group_count - private_group
+
+        code += ([(OP.GROUP, private_group, public_group)] +
+          self.subpattern.compile(reverse, fuzzy) + [(OP.END, )])
+
+        if ref is not None:
+            code += [(OP.END, )]
+
+        return code
+
+    def _dump(self, indent, reverse):
+        group = self.group
+        if group < 0:
+            group = private_groups[group]
+        print "%sGROUP %s" % (INDENT * indent, group)
+        self.subpattern.dump(indent + 1, reverse)
+
+    def __eq__(self, other):
+        return (type(self) is type(other) and (self.group, self.subpattern) ==
+          (other.group, other.subpattern))
+
+    def max_width(self):
+        return self.subpattern.max_width()
+
+    def get_required_string(self, reverse):
+        return self.subpattern.get_required_string(reverse)
+
+class Keep(ZeroWidthBase):
+    _opcode = OP.KEEP
+    _op_name = "KEEP"
+
+class LazyRepeat(GreedyRepeat):
+    _opcode = OP.LAZY_REPEAT
+    _op_name = "LAZY_REPEAT"
+
+class LookAround(RegexBase):
+    _dir_text = {False: "AHEAD", True: "BEHIND"}
+
+    def __init__(self, behind, positive, subpattern):
+        RegexBase.__init__(self)
+        self.behind = bool(behind)
+        self.positive = bool(positive)
+        self.subpattern = subpattern
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        self.subpattern.fix_groups(pattern, self.behind, fuzzy)
+
+    def optimise(self, info):
+        subpattern = self.subpattern.optimise(info)
+        if self.positive and subpattern.is_empty():
+            return subpattern
+
+        return LookAround(self.behind, self.positive, subpattern)
+
+    def pack_characters(self, info):
+        self.subpattern = self.subpattern.pack_characters(info)
+        return self
+
+    def remove_captures(self):
+        return self.subpattern.remove_captures()
+
+    def is_atomic(self):
+        return self.subpattern.is_atomic()
+
+    def can_be_affix(self):
+        return self.subpattern.can_be_affix()
+
+    def contains_group(self):
+        return self.subpattern.contains_group()
+
+    def _compile(self, reverse, fuzzy):
+        return ([(OP.LOOKAROUND, int(self.positive), int(not self.behind))] +
+          self.subpattern.compile(self.behind) + [(OP.END, )])
+
+    def _dump(self, indent, reverse):
+        print "%sLOOK%s %s" % (INDENT * indent, self._dir_text[self.behind],
+          POS_TEXT[self.positive])
+        self.subpattern.dump(indent + 1, self.behind)
+
+    def is_empty(self):
+        return self.positive and self.subpattern.is_empty()
+
+    def __eq__(self, other):
+        return type(self) is type(other) and (self.behind, self.positive,
+          self.subpattern) == (other.behind, other.positive, other.subpattern)
+
+    def max_width(self):
+        return 0
+
+class LookAroundConditional(RegexBase):
+    _dir_text = {False: "AHEAD", True: "BEHIND"}
+
+    def __init__(self, behind, positive, subpattern, yes_item, no_item):
+        RegexBase.__init__(self)
+        self.behind = bool(behind)
+        self.positive = bool(positive)
+        self.subpattern = subpattern
+        self.yes_item = yes_item
+        self.no_item = no_item
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        self.subpattern.fix_groups(pattern, reverse, fuzzy)
+        self.yes_item.fix_groups(pattern, reverse, fuzzy)
+        self.no_item.fix_groups(pattern, reverse, fuzzy)
+
+    def optimise(self, info):
+        subpattern = self.subpattern.optimise(info)
+        yes_item = self.yes_item.optimise(info)
+        no_item = self.no_item.optimise(info)
+
+        return LookAroundConditional(self.behind, self.positive, subpattern,
+          yes_item, no_item)
+
+    def pack_characters(self, info):
+        self.subpattern = self.subpattern.pack_characters(info)
+        self.yes_item = self.yes_item.pack_characters(info)
+        self.no_item = self.no_item.pack_characters(info)
+        return self
+
+    def remove_captures(self):
+        self.subpattern = self.subpattern.remove_captures()
+        self.yes_item = self.yes_item.remove_captures()
+        self.no_item = self.no_item.remove_captures()
+
+    def is_atomic(self):
+        return (self.subpattern.is_atomic() and self.yes_item.is_atomic() and
+          self.no_item.is_atomic())
+
+    def can_be_affix(self):
+        return (self.subpattern.can_be_affix() and self.yes_item.can_be_affix()
+          and self.no_item.can_be_affix())
+
+    def contains_group(self):
+        return (self.subpattern.contains_group() or
+          self.yes_item.contains_group() or self.no_item.contains_group())
+
+    def get_firstset(self, reverse):
+        return (self.subpattern.get_firstset(reverse) |
+          self.no_item.get_firstset(reverse))
+
+    def _compile(self, reverse, fuzzy):
+        code = [(OP.CONDITIONAL, int(self.positive), int(not self.behind))]
+        code.extend(self.subpattern.compile(self.behind, fuzzy))
+        code.append((OP.NEXT, ))
+        code.extend(self.yes_item.compile(reverse, fuzzy))
+        add_code = self.no_item.compile(reverse, fuzzy)
+        if add_code:
+            code.append((OP.NEXT, ))
+            code.extend(add_code)
+
+        code.append((OP.END, ))
+
+        return code
+
+    def _dump(self, indent, reverse):
+        print("%sCONDITIONAL %s %s" % (INDENT * indent,
+          self._dir_text[self.behind], POS_TEXT[self.positive]))
+        self.subpattern.dump(indent + 1, self.behind)
+        print("%sEITHER" % (INDENT * indent))
+        self.yes_item.dump(indent + 1, reverse)
+        if not self.no_item.is_empty():
+            print("%sOR".format(INDENT * indent))
+            self.no_item.dump(indent + 1, reverse)
+
+    def is_empty(self):
+        return (self.subpattern.is_empty() and self.yes_item.is_empty() or
+          self.no_item.is_empty())
+
+    def __eq__(self, other):
+        return type(self) is type(other) and (self.subpattern, self.yes_item,
+          self.no_item) == (other.subpattern, other.yes_item, other.no_item)
+
+    def max_width(self):
+        return max(self.yes_item.max_width(), self.no_item.max_width())
+
+    def get_required_string(self, reverse):
+        return self.max_width(), None
+
+class PrecompiledCode(RegexBase):
+    def __init__(self, code):
+        self.code = code
+
+    def _compile(self, reverse, fuzzy):
+        return [tuple(self.code)]
+
+class Property(RegexBase):
+    _opcode = {(NOCASE, False): OP.PROPERTY, (IGNORECASE, False):
+      OP.PROPERTY_IGN, (FULLCASE, False): OP.PROPERTY, (FULLIGNORECASE, False):
+      OP.PROPERTY_IGN, (NOCASE, True): OP.PROPERTY_REV, (IGNORECASE, True):
+      OP.PROPERTY_IGN_REV, (FULLCASE, True): OP.PROPERTY_REV, (FULLIGNORECASE,
+      True): OP.PROPERTY_IGN_REV}
+
+    def __init__(self, value, positive=True, case_flags=NOCASE,
+      zerowidth=False):
+        RegexBase.__init__(self)
+        self.value = value
+        self.positive = bool(positive)
+        self.case_flags = CASE_FLAGS_COMBINATIONS[case_flags]
+        self.zerowidth = bool(zerowidth)
+
+        self._key = (self.__class__, self.value, self.positive,
+          self.case_flags, self.zerowidth)
+
+    def rebuild(self, positive, case_flags, zerowidth):
+        return Property(self.value, positive, case_flags, zerowidth)
+
+    def optimise(self, info, in_set=False):
+        return self
+
+    def get_firstset(self, reverse):
+        return set([self])
+
+    def has_simple_start(self):
+        return True
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if self.positive:
+            flags |= POSITIVE_OP
+        if self.zerowidth:
+            flags |= ZEROWIDTH_OP
+        if fuzzy:
+            flags |= FUZZY_OP
+        return [(self._opcode[self.case_flags, reverse], flags, self.value)]
+
+    def _dump(self, indent, reverse):
+        prop = PROPERTY_NAMES[self.value >> 16]
+        name, value = prop[0], prop[1][self.value & 0xFFFF]
+        print "%sPROPERTY %s %s:%s%s" % (INDENT * indent,
+          POS_TEXT[self.positive], name, value, CASE_TEXT[self.case_flags])
+
+    def matches(self, ch):
+        return _regex.has_property_value(self.value, ch) == self.positive
+
+    def max_width(self):
+        return 1
+
+class Prune(ZeroWidthBase):
+    _op_name = "PRUNE"
+
+    def _compile(self, reverse, fuzzy):
+        return [(OP.PRUNE, )]
+
+class Range(RegexBase):
+    _opcode = {(NOCASE, False): OP.RANGE, (IGNORECASE, False): OP.RANGE_IGN,
+      (FULLCASE, False): OP.RANGE, (FULLIGNORECASE, False): OP.RANGE_IGN,
+      (NOCASE, True): OP.RANGE_REV, (IGNORECASE, True): OP.RANGE_IGN_REV,
+      (FULLCASE, True): OP.RANGE_REV, (FULLIGNORECASE, True): OP.RANGE_IGN_REV}
+    _op_name = "RANGE"
+
+    def __init__(self, lower, upper, positive=True, case_flags=NOCASE,
+      zerowidth=False):
+        RegexBase.__init__(self)
+        self.lower = lower
+        self.upper = upper
+        self.positive = bool(positive)
+        self.case_flags = CASE_FLAGS_COMBINATIONS[case_flags]
+        self.zerowidth = bool(zerowidth)
+
+        self._key = (self.__class__, self.lower, self.upper, self.positive,
+          self.case_flags, self.zerowidth)
+
+    def rebuild(self, positive, case_flags, zerowidth):
+        return Range(self.lower, self.upper, positive, case_flags, zerowidth)
+
+    def optimise(self, info, in_set=False):
+        # Is the range case-sensitive?
+        if not self.positive or not (self.case_flags & IGNORECASE) or in_set:
+            return self
+
+        # Is full case-folding possible?
+        if (not (info.flags & UNICODE) or (self.case_flags & FULLIGNORECASE) !=
+          FULLIGNORECASE):
+            return self
+
+        # Get the characters which expand to multiple codepoints on folding.
+        expanding_chars = _regex.get_expand_on_folding()
+
+        # Get the folded characters in the range.
+        items = []
+        for ch in expanding_chars:
+            if self.lower <= ord(ch) <= self.upper:
+                folded = _regex.fold_case(FULL_CASE_FOLDING, ch)
+                items.append(String([ord(c) for c in folded],
+                  case_flags=self.case_flags))
+
+        if not items:
+            # We can fall back to simple case-folding.
+            return self
+
+        if len(items) < self.upper - self.lower + 1:
+            # Not all the characters are covered by the full case-folding.
+            items.insert(0, self)
+
+        return Branch(items)
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if self.positive:
+            flags |= POSITIVE_OP
+        if self.zerowidth:
+            flags |= ZEROWIDTH_OP
+        if fuzzy:
+            flags |= FUZZY_OP
+        return [(self._opcode[self.case_flags, reverse], flags, self.lower,
+          self.upper)]
+
+    def _dump(self, indent, reverse):
+        display_lower = repr(unichr(self.lower)).lstrip("bu")
+        display_upper = repr(unichr(self.upper)).lstrip("bu")
+        print "%sRANGE %s %s %s%s" % (INDENT * indent, POS_TEXT[self.positive],
+          display_lower, display_upper, CASE_TEXT[self.case_flags])
+
+    def matches(self, ch):
+        return (self.lower <= ch <= self.upper) == self.positive
+
+    def max_width(self):
+        return 1
+
+class RefGroup(RegexBase):
+    _opcode = {(NOCASE, False): OP.REF_GROUP, (IGNORECASE, False):
+      OP.REF_GROUP_IGN, (FULLCASE, False): OP.REF_GROUP, (FULLIGNORECASE,
+      False): OP.REF_GROUP_FLD, (NOCASE, True): OP.REF_GROUP_REV, (IGNORECASE,
+      True): OP.REF_GROUP_IGN_REV, (FULLCASE, True): OP.REF_GROUP_REV,
+      (FULLIGNORECASE, True): OP.REF_GROUP_FLD_REV}
+
+    def __init__(self, info, group, position, case_flags=NOCASE):
+        RegexBase.__init__(self)
+        self.info = info
+        self.group = group
+        self.position = position
+        self.case_flags = CASE_FLAGS_COMBINATIONS[case_flags]
+
+        self._key = self.__class__, self.group, self.case_flags
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        try:
+            self.group = int(self.group)
+        except ValueError:
+            try:
+                self.group = self.info.group_index[self.group]
+            except KeyError:
+                raise error("unknown group", pattern, self.position)
+
+        if not 1 <= self.group <= self.info.group_count:
+            raise error("invalid group reference", pattern, self.position)
+
+        self._key = self.__class__, self.group, self.case_flags
+
+    def remove_captures(self):
+        raise error("group reference not allowed", pattern, self.position)
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if fuzzy:
+            flags |= FUZZY_OP
+        return [(self._opcode[self.case_flags, reverse], flags, self.group)]
+
+    def _dump(self, indent, reverse):
+        print "%sREF_GROUP %s%s" % (INDENT * indent, self.group,
+          CASE_TEXT[self.case_flags])
+
+    def max_width(self):
+        return UNLIMITED
+
+class SearchAnchor(ZeroWidthBase):
+    _opcode = OP.SEARCH_ANCHOR
+    _op_name = "SEARCH_ANCHOR"
+
+class Sequence(RegexBase):
+    def __init__(self, items=None):
+        RegexBase.__init__(self)
+        if items is None:
+            items = []
+
+        self.items = items
+
+    def fix_groups(self, pattern, reverse, fuzzy):
+        for s in self.items:
+            s.fix_groups(pattern, reverse, fuzzy)
+
+    def optimise(self, info):
+        # Flatten the sequences.
+        items = []
+        for s in self.items:
+            s = s.optimise(info)
+            if isinstance(s, Sequence):
+                items.extend(s.items)
+            else:
+                items.append(s)
+
+        return make_sequence(items)
+
+    def pack_characters(self, info):
+        "Packs sequences of characters into strings."
+        items = []
+        characters = []
+        case_flags = NOCASE
+        for s in self.items:
+            if type(s) is Character and s.positive:
+                if s.case_flags != case_flags:
+                    # Different case sensitivity, so flush, unless neither the
+                    # previous nor the new character are cased.
+                    if s.case_flags or is_cased(info, s.value):
+                        Sequence._flush_characters(info, characters,
+                          case_flags, items)
+
+                        case_flags = s.case_flags
+
+                characters.append(s.value)
+            elif type(s) is String or type(s) is Literal:
+                if s.case_flags != case_flags:
+                    # Different case sensitivity, so flush, unless the neither
+                    # the previous nor the new string are cased.
+                    if s.case_flags or any(is_cased(info, c) for c in
+                      characters):
+                        Sequence._flush_characters(info, characters,
+                          case_flags, items)
+
+                        case_flags = s.case_flags
+
+                characters.extend(s.characters)
+            else:
+                Sequence._flush_characters(info, characters, case_flags, items)
+
+                items.append(s.pack_characters(info))
+
+        Sequence._flush_characters(info, characters, case_flags, items)
+
+        return make_sequence(items)
+
+    def remove_captures(self):
+        self.items = [s.remove_captures() for s in self.items]
+        return self
+
+    def is_atomic(self):
+        return all(s.is_atomic() for s in self.items)
+
+    def can_be_affix(self):
+        return False
+
+    def contains_group(self):
+        return any(s.contains_group() for s in self.items)
+
+    def get_firstset(self, reverse):
+        fs = set()
+        items = self.items
+        if reverse:
+            items.reverse()
+        for s in items:
+            fs |= s.get_firstset(reverse)
+            if None not in fs:
+                return fs
+            fs.discard(None)
+
+        return fs | set([None])
+
+    def has_simple_start(self):
+        return bool(self.items) and self.items[0].has_simple_start()
+
+    def _compile(self, reverse, fuzzy):
+        seq = self.items
+        if reverse:
+            seq = seq[::-1]
+
+        code = []
+        for s in seq:
+            code.extend(s.compile(reverse, fuzzy))
+
+        return code
+
+    def _dump(self, indent, reverse):
+        for s in self.items:
+            s.dump(indent, reverse)
+
+    @staticmethod
+    def _flush_characters(info, characters, case_flags, items):
+        if not characters:
+            return
+
+        # Disregard case_flags if all of the characters are case-less.
+        if case_flags & IGNORECASE:
+            if not any(is_cased(info, c) for c in characters):
+                case_flags = NOCASE
+
+        if len(characters) == 1:
+            items.append(Character(characters[0], case_flags=case_flags))
+        else:
+            items.append(String(characters, case_flags=case_flags))
+
+        characters[:] = []
+
+    def is_empty(self):
+        return all(i.is_empty() for i in self.items)
+
+    def __eq__(self, other):
+        return type(self) is type(other) and self.items == other.items
+
+    def max_width(self):
+        return sum(s.max_width() for s in self.items)
+
+    def get_required_string(self, reverse):
+        seq = self.items
+        if reverse:
+            seq = seq[::-1]
+
+        offset = 0
+
+        for s in seq:
+            ofs, req = s.get_required_string(reverse)
+            offset += ofs
+            if req:
+                return offset, req
+
+        return offset, None
+
+class SetBase(RegexBase):
+    def __init__(self, info, items, positive=True, case_flags=NOCASE,
+      zerowidth=False):
+        RegexBase.__init__(self)
+        self.info = info
+        self.items = tuple(items)
+        self.positive = bool(positive)
+        self.case_flags = CASE_FLAGS_COMBINATIONS[case_flags]
+        self.zerowidth = bool(zerowidth)
+
+        self.char_width = 1
+
+        self._key = (self.__class__, self.items, self.positive,
+          self.case_flags, self.zerowidth)
+
+    def rebuild(self, positive, case_flags, zerowidth):
+        return type(self)(self.info, self.items, positive, case_flags,
+          zerowidth).optimise(self.info)
+
+    def get_firstset(self, reverse):
+        return set([self])
+
+    def has_simple_start(self):
+        return True
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if self.positive:
+            flags |= POSITIVE_OP
+        if self.zerowidth:
+            flags |= ZEROWIDTH_OP
+        if fuzzy:
+            flags |= FUZZY_OP
+        code = [(self._opcode[self.case_flags, reverse], flags)]
+        for m in self.items:
+            code.extend(m.compile())
+
+        code.append((OP.END, ))
+
+        return code
+
+    def _dump(self, indent, reverse):
+        print "%s%s %s%s" % (INDENT * indent, self._op_name,
+          POS_TEXT[self.positive], CASE_TEXT[self.case_flags])
+        for i in self.items:
+            i.dump(indent + 1, reverse)
+
+    def _handle_case_folding(self, info, in_set):
+        # Is the set case-sensitive?
+        if not self.positive or not (self.case_flags & IGNORECASE) or in_set:
+            return self
+
+        # Is full case-folding possible?
+        if (not (self.info.flags & UNICODE) or (self.case_flags &
+          FULLIGNORECASE) != FULLIGNORECASE):
+            return self
+
+        # Get the characters which expand to multiple codepoints on folding.
+        expanding_chars = _regex.get_expand_on_folding()
+
+        # Get the folded characters in the set.
+        items = []
+        seen = set()
+        for ch in expanding_chars:
+            if self.matches(ord(ch)):
+                folded = _regex.fold_case(FULL_CASE_FOLDING, ch)
+                if folded not in seen:
+                    items.append(String([ord(c) for c in folded],
+                      case_flags=self.case_flags))
+                    seen.add(folded)
+
+        if not items:
+            # We can fall back to simple case-folding.
+            return self
+
+        return Branch([self] + items)
+
+    def max_width(self):
+        # Is the set case-sensitive?
+        if not self.positive or not (self.case_flags & IGNORECASE):
+            return 1
+
+        # Is full case-folding possible?
+        if (not (self.info.flags & UNICODE) or (self.case_flags &
+          FULLIGNORECASE) != FULLIGNORECASE):
+            return 1
+
+        # Get the characters which expand to multiple codepoints on folding.
+        expanding_chars = _regex.get_expand_on_folding()
+
+        # Get the folded characters in the set.
+        seen = set()
+        for ch in expanding_chars:
+            if self.matches(ord(ch)):
+                folded = _regex.fold_case(FULL_CASE_FOLDING, ch)
+                seen.add(folded)
+
+        if not seen:
+            return 1
+
+        return max(len(folded) for folded in seen)
+
+class SetDiff(SetBase):
+    _opcode = {(NOCASE, False): OP.SET_DIFF, (IGNORECASE, False):
+      OP.SET_DIFF_IGN, (FULLCASE, False): OP.SET_DIFF, (FULLIGNORECASE, False):
+      OP.SET_DIFF_IGN, (NOCASE, True): OP.SET_DIFF_REV, (IGNORECASE, True):
+      OP.SET_DIFF_IGN_REV, (FULLCASE, True): OP.SET_DIFF_REV, (FULLIGNORECASE,
+      True): OP.SET_DIFF_IGN_REV}
+    _op_name = "SET_DIFF"
+
+    def optimise(self, info, in_set=False):
+        items = self.items
+        if len(items) > 2:
+            items = [items[0], SetUnion(info, items[1 : ])]
+
+        if len(items) == 1:
+            return items[0].with_flags(case_flags=self.case_flags,
+              zerowidth=self.zerowidth).optimise(info, in_set)
+
+        self.items = tuple(m.optimise(info, in_set=True) for m in items)
+
+        return self._handle_case_folding(info, in_set)
+
+    def matches(self, ch):
+        m = self.items[0].matches(ch) and not self.items[1].matches(ch)
+        return m == self.positive
+
+class SetInter(SetBase):
+    _opcode = {(NOCASE, False): OP.SET_INTER, (IGNORECASE, False):
+      OP.SET_INTER_IGN, (FULLCASE, False): OP.SET_INTER, (FULLIGNORECASE,
+      False): OP.SET_INTER_IGN, (NOCASE, True): OP.SET_INTER_REV, (IGNORECASE,
+      True): OP.SET_INTER_IGN_REV, (FULLCASE, True): OP.SET_INTER_REV,
+      (FULLIGNORECASE, True): OP.SET_INTER_IGN_REV}
+    _op_name = "SET_INTER"
+
+    def optimise(self, info, in_set=False):
+        items = []
+        for m in self.items:
+            m = m.optimise(info, in_set=True)
+            if isinstance(m, SetInter) and m.positive:
+                # Intersection in intersection.
+                items.extend(m.items)
+            else:
+                items.append(m)
+
+        if len(items) == 1:
+            return items[0].with_flags(case_flags=self.case_flags,
+              zerowidth=self.zerowidth).optimise(info, in_set)
+
+        self.items = tuple(items)
+
+        return self._handle_case_folding(info, in_set)
+
+    def matches(self, ch):
+        m = all(i.matches(ch) for i in self.items)
+        return m == self.positive
+
+class SetSymDiff(SetBase):
+    _opcode = {(NOCASE, False): OP.SET_SYM_DIFF, (IGNORECASE, False):
+      OP.SET_SYM_DIFF_IGN, (FULLCASE, False): OP.SET_SYM_DIFF, (FULLIGNORECASE,
+      False): OP.SET_SYM_DIFF_IGN, (NOCASE, True): OP.SET_SYM_DIFF_REV,
+      (IGNORECASE, True): OP.SET_SYM_DIFF_IGN_REV, (FULLCASE, True):
+      OP.SET_SYM_DIFF_REV, (FULLIGNORECASE, True): OP.SET_SYM_DIFF_IGN_REV}
+    _op_name = "SET_SYM_DIFF"
+
+    def optimise(self, info, in_set=False):
+        items = []
+        for m in self.items:
+            m = m.optimise(info, in_set=True)
+            if isinstance(m, SetSymDiff) and m.positive:
+                # Symmetric difference in symmetric difference.
+                items.extend(m.items)
+            else:
+                items.append(m)
+
+        if len(items) == 1:
+            return items[0].with_flags(case_flags=self.case_flags,
+              zerowidth=self.zerowidth).optimise(info, in_set)
+
+        self.items = tuple(items)
+
+        return self._handle_case_folding(info, in_set)
+
+    def matches(self, ch):
+        m = False
+        for i in self.items:
+            m = m != i.matches(ch)
+
+        return m == self.positive
+
+class SetUnion(SetBase):
+    _opcode = {(NOCASE, False): OP.SET_UNION, (IGNORECASE, False):
+      OP.SET_UNION_IGN, (FULLCASE, False): OP.SET_UNION, (FULLIGNORECASE,
+      False): OP.SET_UNION_IGN, (NOCASE, True): OP.SET_UNION_REV, (IGNORECASE,
+      True): OP.SET_UNION_IGN_REV, (FULLCASE, True): OP.SET_UNION_REV,
+      (FULLIGNORECASE, True): OP.SET_UNION_IGN_REV}
+    _op_name = "SET_UNION"
+
+    def optimise(self, info, in_set=False):
+        items = []
+        for m in self.items:
+            m = m.optimise(info, in_set=True)
+            if isinstance(m, SetUnion) and m.positive:
+                # Union in union.
+                items.extend(m.items)
+            else:
+                items.append(m)
+
+        if len(items) == 1:
+            i = items[0]
+            return i.with_flags(positive=i.positive == self.positive,
+              case_flags=self.case_flags,
+              zerowidth=self.zerowidth).optimise(info, in_set)
+
+        self.items = tuple(items)
+
+        return self._handle_case_folding(info, in_set)
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if self.positive:
+            flags |= POSITIVE_OP
+        if self.zerowidth:
+            flags |= ZEROWIDTH_OP
+        if fuzzy:
+            flags |= FUZZY_OP
+
+        characters, others = defaultdict(list), []
+        for m in self.items:
+            if isinstance(m, Character):
+                characters[m.positive].append(m.value)
+            else:
+                others.append(m)
+
+        code = [(self._opcode[self.case_flags, reverse], flags)]
+
+        for positive, values in characters.items():
+            flags = 0
+            if positive:
+                flags |= POSITIVE_OP
+            if len(values) == 1:
+                code.append((OP.CHARACTER, flags, values[0]))
+            else:
+                code.append((OP.STRING, flags, len(values)) + tuple(values))
+
+        for m in others:
+            code.extend(m.compile())
+
+        code.append((OP.END, ))
+
+        return code
+
+    def matches(self, ch):
+        m = any(i.matches(ch) for i in self.items)
+        return m == self.positive
+
+class Skip(ZeroWidthBase):
+    _op_name = "SKIP"
+    _opcode = OP.SKIP
+
+class StartOfLine(ZeroWidthBase):
+    _opcode = OP.START_OF_LINE
+    _op_name = "START_OF_LINE"
+
+class StartOfLineU(StartOfLine):
+    _opcode = OP.START_OF_LINE_U
+    _op_name = "START_OF_LINE_U"
+
+class StartOfString(ZeroWidthBase):
+    _opcode = OP.START_OF_STRING
+    _op_name = "START_OF_STRING"
+
+class StartOfWord(ZeroWidthBase):
+    _opcode = OP.START_OF_WORD
+    _op_name = "START_OF_WORD"
+
+class String(RegexBase):
+    _opcode = {(NOCASE, False): OP.STRING, (IGNORECASE, False): OP.STRING_IGN,
+      (FULLCASE, False): OP.STRING, (FULLIGNORECASE, False): OP.STRING_FLD,
+      (NOCASE, True): OP.STRING_REV, (IGNORECASE, True): OP.STRING_IGN_REV,
+      (FULLCASE, True): OP.STRING_REV, (FULLIGNORECASE, True):
+      OP.STRING_FLD_REV}
+
+    def __init__(self, characters, case_flags=NOCASE):
+        self.characters = tuple(characters)
+        self.case_flags = CASE_FLAGS_COMBINATIONS[case_flags]
+
+        if (self.case_flags & FULLIGNORECASE) == FULLIGNORECASE:
+            folded_characters = []
+            for char in self.characters:
+                folded = _regex.fold_case(FULL_CASE_FOLDING, unichr(char))
+                folded_characters.extend(ord(c) for c in folded)
+        else:
+            folded_characters = self.characters
+
+        self.folded_characters = tuple(folded_characters)
+        self.required = False
+
+        self._key = self.__class__, self.characters, self.case_flags
+
+    def get_firstset(self, reverse):
+        if reverse:
+            pos = -1
+        else:
+            pos = 0
+        return set([Character(self.characters[pos],
+          case_flags=self.case_flags)])
+
+    def has_simple_start(self):
+        return True
+
+    def _compile(self, reverse, fuzzy):
+        flags = 0
+        if fuzzy:
+            flags |= FUZZY_OP
+        if self.required:
+            flags |= REQUIRED_OP
+        return [(self._opcode[self.case_flags, reverse], flags,
+          len(self.folded_characters)) + self.folded_characters]
+
+    def _dump(self, indent, reverse):
+        display = repr("".join(unichr(c) for c in self.characters)).lstrip("bu")
+        print "%sSTRING %s%s" % (INDENT * indent, display,
+          CASE_TEXT[self.case_flags])
+
+    def max_width(self):
+        return len(self.folded_characters)
+
+    def get_required_string(self, reverse):
+        return 0, self
+
+class Literal(String):
+    def _dump(self, indent, reverse):
+        for c in self.characters:
+            display = repr(unichr(c)).lstrip("bu")
+            print "%sCHARACTER MATCH %s%s" % (INDENT * indent, display,
+              CASE_TEXT[self.case_flags])
+
+class StringSet(RegexBase):
+    _opcode = {(NOCASE, False): OP.STRING_SET, (IGNORECASE, False):
+      OP.STRING_SET_IGN, (FULLCASE, False): OP.STRING_SET, (FULLIGNORECASE,
+      False): OP.STRING_SET_FLD, (NOCASE, True): OP.STRING_SET_REV,
+      (IGNORECASE, True): OP.STRING_SET_IGN_REV, (FULLCASE, True):
+      OP.STRING_SET_REV, (FULLIGNORECASE, True): OP.STRING_SET_FLD_REV}
+
+    def __init__(self, info, name, case_flags=NOCASE):
+        self.info = info
+        self.name = name
+        self.case_flags = CASE_FLAGS_COMBINATIONS[case_flags]
+
+        self._key = self.__class__, self.name, self.case_flags
+
+        self.set_key = (name, self.case_flags)
+        if self.set_key not in info.named_lists_used:
+            info.named_lists_used[self.set_key] = len(info.named_lists_used)
+
+    def _compile(self, reverse, fuzzy):
+        index = self.info.named_lists_used[self.set_key]
+        items = self.info.kwargs[self.name]
+
+        case_flags = self.case_flags
+
+        if not items:
+            return []
+
+        encoding = self.info.flags & _ALL_ENCODINGS
+        fold_flags = encoding | case_flags
+
+        if fuzzy:
+            choices = [self._folded(fold_flags, i) for i in items]
+
+            # Sort from longest to shortest.
+            choices.sort(key=lambda s: (-len(s), s))
+
+            branches = []
+            for string in choices:
+                branches.append(Sequence([Character(c, case_flags=case_flags)
+                  for c in string]))
+
+            if len(branches) > 1:
+                branch = Branch(branches)
+            else:
+                branch = branches[0]
+            branch = branch.optimise(self.info).pack_characters(self.info)
+
+            return branch.compile(reverse, fuzzy)
+        else:
+            min_len = min(len(i) for i in items)
+            max_len = max(len(self._folded(fold_flags, i)) for i in items)
+            return [(self._opcode[case_flags, reverse], index, min_len,
+              max_len)]
+
+    def _dump(self, indent, reverse):
+        print "%sSTRING_SET %s%s" % (INDENT * indent, self.name,
+          CASE_TEXT[self.case_flags])
+
+    def _folded(self, fold_flags, item):
+        if isinstance(item, unicode):
+            return [ord(c) for c in _regex.fold_case(fold_flags, item)]
+        else:
+            return [ord(c) for c in item]
+
+    def _flatten(self, s):
+        # Flattens the branches.
+        if isinstance(s, Branch):
+            for b in s.branches:
+                self._flatten(b)
+        elif isinstance(s, Sequence) and s.items:
+            seq = s.items
+
+            while isinstance(seq[-1], Sequence):
+                seq[-1 : ] = seq[-1].items
+
+            n = 0
+            while n < len(seq) and isinstance(seq[n], Character):
+                n += 1
+
+            if n > 1:
+                seq[ : n] = [String([c.value for c in seq[ : n]],
+                  case_flags=self.case_flags)]
+
+            self._flatten(seq[-1])
+
+    def max_width(self):
+        if not self.info.kwargs[self.name]:
+            return 0
+
+        if self.case_flags & IGNORECASE:
+            fold_flags = (self.info.flags & _ALL_ENCODINGS) | self.case_flags
+            return max(len(_regex.fold_case(fold_flags, i)) for i in
+              self.info.kwargs[self.name])
+        else:
+            return max(len(i) for i in self.info.kwargs[self.name])
+
+class Source(object):
+    "Scanner for the regular expression source string."
+    def __init__(self, string):
+        if isinstance(string, unicode):
+            self.string = string
+            self.char_type = unichr
+        else:
+            self.string = string
+            self.char_type = chr
+
+        self.pos = 0
+        self.ignore_space = False
+        self.sep = string[ : 0]
+
+    def get(self):
+        string = self.string
+        pos = self.pos
+
+        try:
+            if self.ignore_space:
+                while True:
+                    if string[pos].isspace():
+                        # Skip over the whitespace.
+                        pos += 1
+                    elif string[pos] == "#":
+                        # Skip over the comment to the end of the line.
+                        pos = string.index("\n", pos)
+                    else:
+                        break
+
+            ch = string[pos]
+            self.pos = pos + 1
+            return ch
+        except IndexError:
+            # We've reached the end of the string.
+            self.pos = pos
+            return string[ : 0]
+        except ValueError:
+            # The comment extended to the end of the string.
+            self.pos = len(string)
+            return string[ : 0]
+
+    def get_many(self, count=1):
+        string = self.string
+        pos = self.pos
+
+        try:
+            if self.ignore_space:
+                substring = []
+
+                while len(substring) < count:
+                    while True:
+                        if string[pos].isspace():
+                            # Skip over the whitespace.
+                            pos += 1
+                        elif string[pos] == "#":
+                            # Skip over the comment to the end of the line.
+                            pos = string.index("\n", pos)
+                        else:
+                            break
+
+                    substring.append(string[pos])
+                    pos += 1
+
+                substring = "".join(substring)
+            else:
+                substring = string[pos : pos + count]
+                pos += len(substring)
+
+            self.pos = pos
+            return substring
+        except IndexError:
+            # We've reached the end of the string.
+            self.pos = len(string)
+            return "".join(substring)
+        except ValueError:
+            # The comment extended to the end of the string.
+            self.pos = len(string)
+            return "".join(substring)
+
+    def get_while(self, test_set, include=True):
+        string = self.string
+        pos = self.pos
+
+        if self.ignore_space:
+            try:
+                substring = []
+
+                while True:
+                    if string[pos].isspace():
+                        # Skip over the whitespace.
+                        pos += 1
+                    elif string[pos] == "#":
+                        # Skip over the comment to the end of the line.
+                        pos = string.index("\n", pos)
+                    elif (string[pos] in test_set) == include:
+                        substring.append(string[pos])
+                        pos += 1
+                    else:
+                        break
+
+                self.pos = pos
+            except IndexError:
+                # We've reached the end of the string.
+                self.pos = len(string)
+            except ValueError:
+                # The comment extended to the end of the string.
+                self.pos = len(string)
+
+            return "".join(substring)
+        else:
+            try:
+                while (string[pos] in test_set) == include:
+                    pos += 1
+
+                substring = string[self.pos : pos]
+
+                self.pos = pos
+
+                return substring
+            except IndexError:
+                # We've reached the end of the string.
+                substring = string[self.pos : pos]
+
+                self.pos = pos
+
+                return substring
+
+    def skip_while(self, test_set, include=True):
+        string = self.string
+        pos = self.pos
+
+        try:
+            if self.ignore_space:
+                while True:
+                    if string[pos].isspace():
+                        # Skip over the whitespace.
+                        pos += 1
+                    elif string[pos] == "#":
+                        # Skip over the comment to the end of the line.
+                        pos = string.index("\n", pos)
+                    elif (string[pos] in test_set) == include:
+                        pos += 1
+                    else:
+                        break
+            else:
+                while (string[pos] in test_set) == include:
+                    pos += 1
+
+            self.pos = pos
+        except IndexError:
+            # We've reached the end of the string.
+            self.pos = len(string)
+        except ValueError:
+            # The comment extended to the end of the string.
+            self.pos = len(string)
+
+    def match(self, substring):
+        string = self.string
+        pos = self.pos
+
+        if self.ignore_space:
+            try:
+                for c in substring:
+                    while True:
+                        if string[pos].isspace():
+                            # Skip over the whitespace.
+                            pos += 1
+                        elif string[pos] == "#":
+                            # Skip over the comment to the end of the line.
+                            pos = string.index("\n", pos)
+                        else:
+                            break
+
+                    if string[pos] != c:
+                        return False
+
+                    pos += 1
+
+                self.pos = pos
+
+                return True
+            except IndexError:
+                # We've reached the end of the string.
+                return False
+            except ValueError:
+                # The comment extended to the end of the string.
+                return False
+        else:
+            if not string.startswith(substring, pos):
+                return False
+
+            self.pos = pos + len(substring)
+
+            return True
+
+    def expect(self, substring):
+        if not self.match(substring):
+            raise error("missing %s" % substring, self.string, self.pos)
+
+    def at_end(self):
+        string = self.string
+        pos = self.pos
+
+        try:
+            if self.ignore_space:
+                while True:
+                    if string[pos].isspace():
+                        pos += 1
+                    elif string[pos] == "#":
+                        pos = string.index("\n", pos)
+                    else:
+                        break
+
+            return pos >= len(string)
+        except IndexError:
+            # We've reached the end of the string.
+            return True
+        except ValueError:
+            # The comment extended to the end of the string.
+            return True
+
+class Info(object):
+    "Info about the regular expression."
+
+    def __init__(self, flags=0, char_type=None, kwargs={}):
+        flags |= DEFAULT_FLAGS[(flags & _ALL_VERSIONS) or DEFAULT_VERSION]
+        self.flags = flags
+        self.global_flags = flags
+        self.inline_locale = False
+
+        self.kwargs = kwargs
+
+        self.group_count = 0
+        self.group_index = {}
+        self.group_name = {}
+        self.char_type = char_type
+        self.named_lists_used = {}
+        self.open_groups = []
+        self.open_group_count = {}
+        self.defined_groups = {}
+        self.group_calls = []
+        self.private_groups = {}
+
+    def open_group(self, name=None):
+        group = self.group_index.get(name)
+        if group is None:
+            while True:
+                self.group_count += 1
+                if name is None or self.group_count not in self.group_name:
+                    break
+
+            group = self.group_count
+            if name:
+                self.group_index[name] = group
+                self.group_name[group] = name
+
+        if group in self.open_groups:
+            # We have a nested named group. We'll assign it a private group
+            # number, initially negative until we can assign a proper
+            # (positive) number.
+            group_alias = -(len(self.private_groups) + 1)
+            self.private_groups[group_alias] = group
+            group = group_alias
+
+        self.open_groups.append(group)
+        self.open_group_count[group] = self.open_group_count.get(group, 0) + 1
+
+        return group
+
+    def close_group(self):
+        self.open_groups.pop()
+
+    def is_open_group(self, name):
+        # In version 1, a group reference can refer to an open group. We'll
+        # just pretend the group isn't open.
+        version = (self.flags & _ALL_VERSIONS) or DEFAULT_VERSION
+        if version == VERSION1:
+            return False
+
+        if name.isdigit():
+            group = int(name)
+        else:
+            group = self.group_index.get(name)
+
+        return group in self.open_groups
+
+def _check_group_features(info, parsed):
+    """Checks whether the reverse and fuzzy features of the group calls match
+    the groups which they call.
+    """
+    call_refs = {}
+    additional_groups = []
+    for call, reverse, fuzzy in info.group_calls:
+        # Look up the reference of this group call.
+        key = (call.group, reverse, fuzzy)
+        ref = call_refs.get(key)
+        if ref is None:
+            # This group doesn't have a reference yet, so look up its features.
+            if call.group == 0:
+                # Calling the pattern as a whole.
+                rev = bool(info.flags & REVERSE)
+                fuz = isinstance(parsed, Fuzzy)
+                if (rev, fuz) != (reverse, fuzzy):
+                    # The pattern as a whole doesn't have the features we want,
+                    # so we'll need to make a copy of it with the desired
+                    # features.
+                    additional_groups.append((parsed, reverse, fuzzy))
+            else:
+                # Calling a capture group.
+                def_info = info.defined_groups[call.group]
+                group = def_info[0]
+                if def_info[1 : ] != (reverse, fuzzy):
+                    # The group doesn't have the features we want, so we'll
+                    # need to make a copy of it with the desired features.
+                    additional_groups.append((group, reverse, fuzzy))
+
+            ref = len(call_refs)
+            call_refs[key] = ref
+
+        call.call_ref = ref
+
+    info.call_refs = call_refs
+    info.additional_groups = additional_groups
+
+def _get_required_string(parsed, flags):
+    "Gets the required string and related info of a parsed pattern."
+
+    req_offset, required = parsed.get_required_string(bool(flags & REVERSE))
+    if required:
+        required.required = True
+        if req_offset >= UNLIMITED:
+            req_offset = -1
+
+        req_flags = required.case_flags
+        if not (flags & UNICODE):
+            req_flags &= ~UNICODE
+
+        req_chars = required.folded_characters
+    else:
+        req_offset = 0
+        req_chars = ()
+        req_flags = 0
+
+    return req_offset, req_chars, req_flags
+
+class Scanner:
+    def __init__(self, lexicon, flags=0):
+        self.lexicon = lexicon
+
+        # Combine phrases into a compound pattern.
+        patterns = []
+        for phrase, action in lexicon:
+            # Parse the regular expression.
+            source = Source(phrase)
+            info = Info(flags, source.char_type)
+            source.ignore_space = bool(info.flags & VERBOSE)
+            parsed = _parse_pattern(source, info)
+            if not source.at_end():
+                raise error("unbalanced parenthesis", source.string, source.pos)
+
+            # We want to forbid capture groups within each phrase.
+            patterns.append(parsed.remove_captures())
+
+        # Combine all the subpatterns into one pattern.
+        info = Info(flags)
+        patterns = [Group(info, g + 1, p) for g, p in enumerate(patterns)]
+        parsed = Branch(patterns)
+
+        # Optimise the compound pattern.
+        parsed = parsed.optimise(info)
+        parsed = parsed.pack_characters(info)
+
+        # Get the required string.
+        req_offset, req_chars, req_flags = _get_required_string(parsed,
+          info.flags)
+
+        # Check the features of the groups.
+        _check_group_features(info, parsed)
+
+        # Complain if there are any group calls. They are not supported by the
+        # Scanner class.
+        if info.call_refs:
+            raise error("recursive regex not supported by Scanner",
+              source.string, source.pos)
+
+        reverse = bool(info.flags & REVERSE)
+
+        # Compile the compound pattern. The result is a list of tuples.
+        code = parsed.compile(reverse) + [(OP.SUCCESS, )]
+
+        # Flatten the code into a list of ints.
+        code = _flatten_code(code)
+
+        if not parsed.has_simple_start():
+            # Get the first set, if possible.
+            try:
+                fs_code = _compile_firstset(info, parsed.get_firstset(reverse))
+                fs_code = _flatten_code(fs_code)
+                code = fs_code + code
+            except _FirstSetError:
+                pass
+
+        # Check the global flags for conflicts.
+        version = (info.flags & _ALL_VERSIONS) or DEFAULT_VERSION
+        if version not in (0, VERSION0, VERSION1):
+            raise ValueError("VERSION0 and VERSION1 flags are mutually incompatible")
+
+        # Create the PatternObject.
+        #
+        # Local flags like IGNORECASE affect the code generation, but aren't
+        # needed by the PatternObject itself. Conversely, global flags like
+        # LOCALE _don't_ affect the code generation but _are_ needed by the
+        # PatternObject.
+        self.scanner = _regex.compile(None, (flags & GLOBAL_FLAGS) | version,
+          code, {}, {}, {}, [], req_offset, req_chars, req_flags,
+          len(patterns))
+
+    def scan(self, string):
+        result = []
+        append = result.append
+        match = self.scanner.scanner(string).match
+        i = 0
+        while True:
+            m = match()
+            if not m:
+                break
+            j = m.end()
+            if i == j:
+                break
+            action = self.lexicon[m.lastindex - 1][1]
+            if hasattr(action, '__call__'):
+                self.match = m
+                action = action(self, m.group())
+            if action is not None:
+                append(action)
+            i = j
+
+        return result, string[i : ]
+
+# Get the known properties dict.
+PROPERTIES = _regex.get_properties()
+
+# Build the inverse of the properties dict.
+PROPERTY_NAMES = {}
+for prop_name, (prop_id, values) in PROPERTIES.items():
+    name, prop_values = PROPERTY_NAMES.get(prop_id, ("", {}))
+    name = max(name, prop_name, key=len)
+    PROPERTY_NAMES[prop_id] = name, prop_values
+
+    for val_name, val_id in values.items():
+        prop_values[val_id] = max(prop_values.get(val_id, ""), val_name,
+      key=len)
+
+# Character escape sequences.
+CHARACTER_ESCAPES = {
+    "a": "\a",
+    "b": "\b",
+    "f": "\f",
+    "n": "\n",
+    "r": "\r",
+    "t": "\t",
+    "v": "\v",
+}
+
+# Predefined character set escape sequences.
+CHARSET_ESCAPES = {
+    "d": lookup_property(None, "Digit", True),
+    "D": lookup_property(None, "Digit", False),
+    "s": lookup_property(None, "Space", True),
+    "S": lookup_property(None, "Space", False),
+    "w": lookup_property(None, "Word", True),
+    "W": lookup_property(None, "Word", False),
+}
+
+# Positional escape sequences.
+POSITION_ESCAPES = {
+    "A": StartOfString(),
+    "b": Boundary(),
+    "B": Boundary(False),
+    "K": Keep(),
+    "m": StartOfWord(),
+    "M": EndOfWord(),
+    "Z": EndOfString(),
+}
+
+# Positional escape sequences when WORD flag set.
+WORD_POSITION_ESCAPES = dict(POSITION_ESCAPES)
+WORD_POSITION_ESCAPES.update({
+    "b": DefaultBoundary(),
+    "B": DefaultBoundary(False),
+    "m": DefaultStartOfWord(),
+    "M": DefaultEndOfWord(),
+})
+
+# Regex control verbs.
+VERBS = {
+    "FAIL": Failure(),
+    "F": Failure(),
+    "PRUNE": Prune(),
+    "SKIP": Skip(),
+}
diff --git a/lib/regex/_regex_unicode.c b/lib/regex/_regex_unicode.c
new file mode 100644
index 000000000..47c896e68
--- /dev/null
+++ b/lib/regex/_regex_unicode.c
@@ -0,0 +1,14258 @@
+/* For Unicode version 8.0.0 */
+
+#include "_regex_unicode.h"
+
+#define RE_BLANK_MASK ((1 << RE_PROP_ZL) | (1 << RE_PROP_ZP))
+#define RE_GRAPH_MASK ((1 << RE_PROP_CC) | (1 << RE_PROP_CS) | (1 << RE_PROP_CN))
+#define RE_WORD_MASK (RE_PROP_M_MASK | (1 << RE_PROP_ND) | (1 << RE_PROP_PC))
+
+typedef struct RE_AllCases {
+    RE_INT32 diffs[RE_MAX_CASES - 1];
+} RE_AllCases;
+
+typedef struct RE_FullCaseFolding {
+    RE_INT32 diff;
+    RE_UINT16 codepoints[RE_MAX_FOLDED - 1];
+} RE_FullCaseFolding;
+
+/* strings. */
+
+char* re_strings[] = {
+    "-1/2",
+    "0",
+    "1",
+    "1/10",
+    "1/12",
+    "1/16",
+    "1/2",
+    "1/3",
+    "1/4",
+    "1/5",
+    "1/6",
+    "1/7",
+    "1/8",
+    "1/9",
+    "10",
+    "100",
+    "1000",
+    "10000",
+    "100000",
+    "1000000",
+    "100000000",
+    "10000000000",
+    "1000000000000",
+    "103",
+    "107",
+    "11",
+    "11/12",
+    "11/2",
+    "118",
+    "12",
+    "122",
+    "129",
+    "13",
+    "13/2",
+    "130",
+    "132",
+    "133",
+    "14",
+    "15",
+    "15/2",
+    "16",
+    "17",
+    "17/2",
+    "18",
+    "19",
+    "2",
+    "2/3",
+    "2/5",
+    "20",
+    "200",
+    "2000",
+    "20000",
+    "200000",
+    "202",
+    "21",
+    "214",
+    "216",
+    "216000",
+    "218",
+    "22",
+    "220",
+    "222",
+    "224",
+    "226",
+    "228",
+    "23",
+    "230",
+    "232",
+    "233",
+    "234",
+    "24",
+    "240",
+    "25",
+    "26",
+    "27",
+    "28",
+    "29",
+    "3",
+    "3/16",
+    "3/2",
+    "3/4",
+    "3/5",
+    "3/8",
+    "30",
+    "300",
+    "3000",
+    "30000",
+    "300000",
+    "31",
+    "32",
+    "33",
+    "34",
+    "35",
+    "36",
+    "37",
+    "38",
+    "39",
+    "4",
+    "4/5",
+    "40",
+    "400",
+    "4000",
+    "40000",
+    "400000",
+    "41",
+    "42",
+    "43",
+    "432000",
+    "44",
+    "45",
+    "46",
+    "47",
+    "48",
+    "49",
+    "5",
+    "5/12",
+    "5/2",
+    "5/6",
+    "5/8",
+    "50",
+    "500",
+    "5000",
+    "50000",
+    "500000",
+    "6",
+    "60",
+    "600",
+    "6000",
+    "60000",
+    "600000",
+    "7",
+    "7/12",
+    "7/2",
+    "7/8",
+    "70",
+    "700",
+    "7000",
+    "70000",
+    "700000",
+    "8",
+    "80",
+    "800",
+    "8000",
+    "80000",
+    "800000",
+    "84",
+    "9",
+    "9/2",
+    "90",
+    "900",
+    "9000",
+    "90000",
+    "900000",
+    "91",
+    "A",
+    "ABOVE",
+    "ABOVELEFT",
+    "ABOVERIGHT",
+    "AEGEANNUMBERS",
+    "AGHB",
+    "AHEX",
+    "AHOM",
+    "AI",
+    "AIN",
+    "AL",
+    "ALAPH",
+    "ALCHEMICAL",
+    "ALCHEMICALSYMBOLS",
+    "ALEF",
+    "ALETTER",
+    "ALNUM",
+    "ALPHA",
+    "ALPHABETIC",
+    "ALPHABETICPF",
+    "ALPHABETICPRESENTATIONFORMS",
+    "ALPHANUMERIC",
+    "AMBIGUOUS",
+    "AN",
+    "ANATOLIANHIEROGLYPHS",
+    "ANCIENTGREEKMUSIC",
+    "ANCIENTGREEKMUSICALNOTATION",
+    "ANCIENTGREEKNUMBERS",
+    "ANCIENTSYMBOLS",
+    "ANY",
+    "AR",
+    "ARAB",
+    "ARABIC",
+    "ARABICEXTA",
+    "ARABICEXTENDEDA",
+    "ARABICLETTER",
+    "ARABICMATH",
+    "ARABICMATHEMATICALALPHABETICSYMBOLS",
+    "ARABICNUMBER",
+    "ARABICPFA",
+    "ARABICPFB",
+    "ARABICPRESENTATIONFORMSA",
+    "ARABICPRESENTATIONFORMSB",
+    "ARABICSUP",
+    "ARABICSUPPLEMENT",
+    "ARMENIAN",
+    "ARMI",
+    "ARMN",
+    "ARROWS",
+    "ASCII",
+    "ASCIIHEXDIGIT",
+    "ASSIGNED",
+    "AT",
+    "ATA",
+    "ATAR",
+    "ATB",
+    "ATBL",
+    "ATERM",
+    "ATTACHEDABOVE",
+    "ATTACHEDABOVERIGHT",
+    "ATTACHEDBELOW",
+    "ATTACHEDBELOWLEFT",
+    "AVAGRAHA",
+    "AVESTAN",
+    "AVST",
+    "B",
+    "B2",
+    "BA",
+    "BALI",
+    "BALINESE",
+    "BAMU",
+    "BAMUM",
+    "BAMUMSUP",
+    "BAMUMSUPPLEMENT",
+    "BASICLATIN",
+    "BASS",
+    "BASSAVAH",
+    "BATAK",
+    "BATK",
+    "BB",
+    "BC",
+    "BEH",
+    "BELOW",
+    "BELOWLEFT",
+    "BELOWRIGHT",
+    "BENG",
+    "BENGALI",
+    "BETH",
+    "BIDIC",
+    "BIDICLASS",
+    "BIDICONTROL",
+    "BIDIM",
+    "BIDIMIRRORED",
+    "BINDU",
+    "BK",
+    "BL",
+    "BLANK",
+    "BLK",
+    "BLOCK",
+    "BLOCKELEMENTS",
+    "BN",
+    "BOPO",
+    "BOPOMOFO",
+    "BOPOMOFOEXT",
+    "BOPOMOFOEXTENDED",
+    "BOTTOM",
+    "BOTTOMANDRIGHT",
+    "BOUNDARYNEUTRAL",
+    "BOXDRAWING",
+    "BR",
+    "BRAH",
+    "BRAHMI",
+    "BRAHMIJOININGNUMBER",
+    "BRAI",
+    "BRAILLE",
+    "BRAILLEPATTERNS",
+    "BREAKAFTER",
+    "BREAKBEFORE",
+    "BREAKBOTH",
+    "BREAKSYMBOLS",
+    "BUGI",
+    "BUGINESE",
+    "BUHD",
+    "BUHID",
+    "BURUSHASKIYEHBARREE",
+    "BYZANTINEMUSIC",
+    "BYZANTINEMUSICALSYMBOLS",
+    "C",
+    "C&",
+    "CAKM",
+    "CAN",
+    "CANADIANABORIGINAL",
+    "CANADIANSYLLABICS",
+    "CANONICAL",
+    "CANONICALCOMBININGCLASS",
+    "CANS",
+    "CANTILLATIONMARK",
+    "CARI",
+    "CARIAN",
+    "CARRIAGERETURN",
+    "CASED",
+    "CASEDLETTER",
+    "CASEIGNORABLE",
+    "CAUCASIANALBANIAN",
+    "CB",
+    "CC",
+    "CCC",
+    "CCC10",
+    "CCC103",
+    "CCC107",
+    "CCC11",
+    "CCC118",
+    "CCC12",
+    "CCC122",
+    "CCC129",
+    "CCC13",
+    "CCC130",
+    "CCC132",
+    "CCC133",
+    "CCC14",
+    "CCC15",
+    "CCC16",
+    "CCC17",
+    "CCC18",
+    "CCC19",
+    "CCC20",
+    "CCC21",
+    "CCC22",
+    "CCC23",
+    "CCC24",
+    "CCC25",
+    "CCC26",
+    "CCC27",
+    "CCC28",
+    "CCC29",
+    "CCC30",
+    "CCC31",
+    "CCC32",
+    "CCC33",
+    "CCC34",
+    "CCC35",
+    "CCC36",
+    "CCC84",
+    "CCC91",
+    "CF",
+    "CHAKMA",
+    "CHAM",
+    "CHANGESWHENCASEFOLDED",
+    "CHANGESWHENCASEMAPPED",
+    "CHANGESWHENLOWERCASED",
+    "CHANGESWHENTITLECASED",
+    "CHANGESWHENUPPERCASED",
+    "CHER",
+    "CHEROKEE",
+    "CHEROKEESUP",
+    "CHEROKEESUPPLEMENT",
+    "CI",
+    "CIRCLE",
+    "CJ",
+    "CJK",
+    "CJKCOMPAT",
+    "CJKCOMPATFORMS",
+    "CJKCOMPATIBILITY",
+    "CJKCOMPATIBILITYFORMS",
+    "CJKCOMPATIBILITYIDEOGRAPHS",
+    "CJKCOMPATIBILITYIDEOGRAPHSSUPPLEMENT",
+    "CJKCOMPATIDEOGRAPHS",
+    "CJKCOMPATIDEOGRAPHSSUP",
+    "CJKEXTA",
+    "CJKEXTB",
+    "CJKEXTC",
+    "CJKEXTD",
+    "CJKEXTE",
+    "CJKRADICALSSUP",
+    "CJKRADICALSSUPPLEMENT",
+    "CJKSTROKES",
+    "CJKSYMBOLS",
+    "CJKSYMBOLSANDPUNCTUATION",
+    "CJKUNIFIEDIDEOGRAPHS",
+    "CJKUNIFIEDIDEOGRAPHSEXTENSIONA",
+    "CJKUNIFIEDIDEOGRAPHSEXTENSIONB",
+    "CJKUNIFIEDIDEOGRAPHSEXTENSIONC",
+    "CJKUNIFIEDIDEOGRAPHSEXTENSIOND",
+    "CJKUNIFIEDIDEOGRAPHSEXTENSIONE",
+    "CL",
+    "CLOSE",
+    "CLOSEPARENTHESIS",
+    "CLOSEPUNCTUATION",
+    "CM",
+    "CN",
+    "CNTRL",
+    "CO",
+    "COM",
+    "COMBININGDIACRITICALMARKS",
+    "COMBININGDIACRITICALMARKSEXTENDED",
+    "COMBININGDIACRITICALMARKSFORSYMBOLS",
+    "COMBININGDIACRITICALMARKSSUPPLEMENT",
+    "COMBININGHALFMARKS",
+    "COMBININGMARK",
+    "COMBININGMARKSFORSYMBOLS",
+    "COMMON",
+    "COMMONINDICNUMBERFORMS",
+    "COMMONSEPARATOR",
+    "COMPAT",
+    "COMPATJAMO",
+    "COMPLEXCONTEXT",
+    "CONDITIONALJAPANESESTARTER",
+    "CONNECTORPUNCTUATION",
+    "CONSONANT",
+    "CONSONANTDEAD",
+    "CONSONANTFINAL",
+    "CONSONANTHEADLETTER",
+    "CONSONANTKILLER",
+    "CONSONANTMEDIAL",
+    "CONSONANTPLACEHOLDER",
+    "CONSONANTPRECEDINGREPHA",
+    "CONSONANTPREFIXED",
+    "CONSONANTSUBJOINED",
+    "CONSONANTSUCCEEDINGREPHA",
+    "CONSONANTWITHSTACKER",
+    "CONTINGENTBREAK",
+    "CONTROL",
+    "CONTROLPICTURES",
+    "COPT",
+    "COPTIC",
+    "COPTICEPACTNUMBERS",
+    "COUNTINGROD",
+    "COUNTINGRODNUMERALS",
+    "CP",
+    "CPRT",
+    "CR",
+    "CS",
+    "CUNEIFORM",
+    "CUNEIFORMNUMBERS",
+    "CUNEIFORMNUMBERSANDPUNCTUATION",
+    "CURRENCYSYMBOL",
+    "CURRENCYSYMBOLS",
+    "CWCF",
+    "CWCM",
+    "CWL",
+    "CWT",
+    "CWU",
+    "CYPRIOT",
+    "CYPRIOTSYLLABARY",
+    "CYRILLIC",
+    "CYRILLICEXTA",
+    "CYRILLICEXTB",
+    "CYRILLICEXTENDEDA",
+    "CYRILLICEXTENDEDB",
+    "CYRILLICSUP",
+    "CYRILLICSUPPLEMENT",
+    "CYRILLICSUPPLEMENTARY",
+    "CYRL",
+    "D",
+    "DA",
+    "DAL",
+    "DALATHRISH",
+    "DASH",
+    "DASHPUNCTUATION",
+    "DB",
+    "DE",
+    "DECIMAL",
+    "DECIMALNUMBER",
+    "DECOMPOSITIONTYPE",
+    "DEFAULTIGNORABLECODEPOINT",
+    "DEP",
+    "DEPRECATED",
+    "DESERET",
+    "DEVA",
+    "DEVANAGARI",
+    "DEVANAGARIEXT",
+    "DEVANAGARIEXTENDED",
+    "DI",
+    "DIA",
+    "DIACRITIC",
+    "DIACRITICALS",
+    "DIACRITICALSEXT",
+    "DIACRITICALSFORSYMBOLS",
+    "DIACRITICALSSUP",
+    "DIGIT",
+    "DINGBATS",
+    "DOMINO",
+    "DOMINOTILES",
+    "DOUBLEABOVE",
+    "DOUBLEBELOW",
+    "DOUBLEQUOTE",
+    "DQ",
+    "DSRT",
+    "DT",
+    "DUALJOINING",
+    "DUPL",
+    "DUPLOYAN",
+    "E",
+    "EA",
+    "EARLYDYNASTICCUNEIFORM",
+    "EASTASIANWIDTH",
+    "EGYP",
+    "EGYPTIANHIEROGLYPHS",
+    "ELBA",
+    "ELBASAN",
+    "EMOTICONS",
+    "EN",
+    "ENC",
+    "ENCLOSEDALPHANUM",
+    "ENCLOSEDALPHANUMERICS",
+    "ENCLOSEDALPHANUMERICSUPPLEMENT",
+    "ENCLOSEDALPHANUMSUP",
+    "ENCLOSEDCJK",
+    "ENCLOSEDCJKLETTERSANDMONTHS",
+    "ENCLOSEDIDEOGRAPHICSUP",
+    "ENCLOSEDIDEOGRAPHICSUPPLEMENT",
+    "ENCLOSINGMARK",
+    "ES",
+    "ET",
+    "ETHI",
+    "ETHIOPIC",
+    "ETHIOPICEXT",
+    "ETHIOPICEXTA",
+    "ETHIOPICEXTENDED",
+    "ETHIOPICEXTENDEDA",
+    "ETHIOPICSUP",
+    "ETHIOPICSUPPLEMENT",
+    "EUROPEANNUMBER",
+    "EUROPEANSEPARATOR",
+    "EUROPEANTERMINATOR",
+    "EX",
+    "EXCLAMATION",
+    "EXT",
+    "EXTEND",
+    "EXTENDER",
+    "EXTENDNUMLET",
+    "F",
+    "FALSE",
+    "FARSIYEH",
+    "FE",
+    "FEH",
+    "FIN",
+    "FINAL",
+    "FINALPUNCTUATION",
+    "FINALSEMKATH",
+    "FIRSTSTRONGISOLATE",
+    "FO",
+    "FONT",
+    "FORMAT",
+    "FRA",
+    "FRACTION",
+    "FSI",
+    "FULLWIDTH",
+    "GAF",
+    "GAMAL",
+    "GC",
+    "GCB",
+    "GEMINATIONMARK",
+    "GENERALCATEGORY",
+    "GENERALPUNCTUATION",
+    "GEOMETRICSHAPES",
+    "GEOMETRICSHAPESEXT",
+    "GEOMETRICSHAPESEXTENDED",
+    "GEOR",
+    "GEORGIAN",
+    "GEORGIANSUP",
+    "GEORGIANSUPPLEMENT",
+    "GL",
+    "GLAG",
+    "GLAGOLITIC",
+    "GLUE",
+    "GOTH",
+    "GOTHIC",
+    "GRAN",
+    "GRANTHA",
+    "GRAPH",
+    "GRAPHEMEBASE",
+    "GRAPHEMECLUSTERBREAK",
+    "GRAPHEMEEXTEND",
+    "GRAPHEMELINK",
+    "GRBASE",
+    "GREEK",
+    "GREEKANDCOPTIC",
+    "GREEKEXT",
+    "GREEKEXTENDED",
+    "GREK",
+    "GREXT",
+    "GRLINK",
+    "GUJARATI",
+    "GUJR",
+    "GURMUKHI",
+    "GURU",
+    "H",
+    "H2",
+    "H3",
+    "HAH",
+    "HALFANDFULLFORMS",
+    "HALFMARKS",
+    "HALFWIDTH",
+    "HALFWIDTHANDFULLWIDTHFORMS",
+    "HAMZAONHEHGOAL",
+    "HAN",
+    "HANG",
+    "HANGUL",
+    "HANGULCOMPATIBILITYJAMO",
+    "HANGULJAMO",
+    "HANGULJAMOEXTENDEDA",
+    "HANGULJAMOEXTENDEDB",
+    "HANGULSYLLABLES",
+    "HANGULSYLLABLETYPE",
+    "HANI",
+    "HANO",
+    "HANUNOO",
+    "HATR",
+    "HATRAN",
+    "HE",
+    "HEBR",
+    "HEBREW",
+    "HEBREWLETTER",
+    "HEH",
+    "HEHGOAL",
+    "HETH",
+    "HEX",
+    "HEXDIGIT",
+    "HIGHPRIVATEUSESURROGATES",
+    "HIGHPUSURROGATES",
+    "HIGHSURROGATES",
+    "HIRA",
+    "HIRAGANA",
+    "HL",
+    "HLUW",
+    "HMNG",
+    "HRKT",
+    "HST",
+    "HUNG",
+    "HY",
+    "HYPHEN",
+    "ID",
+    "IDC",
+    "IDCONTINUE",
+    "IDEO",
+    "IDEOGRAPHIC",
+    "IDEOGRAPHICDESCRIPTIONCHARACTERS",
+    "IDS",
+    "IDSB",
+    "IDSBINARYOPERATOR",
+    "IDST",
+    "IDSTART",
+    "IDSTRINARYOPERATOR",
+    "IMPERIALARAMAIC",
+    "IN",
+    "INDICNUMBERFORMS",
+    "INDICPOSITIONALCATEGORY",
+    "INDICSYLLABICCATEGORY",
+    "INFIXNUMERIC",
+    "INHERITED",
+    "INIT",
+    "INITIAL",
+    "INITIALPUNCTUATION",
+    "INPC",
+    "INSC",
+    "INSCRIPTIONALPAHLAVI",
+    "INSCRIPTIONALPARTHIAN",
+    "INSEPARABLE",
+    "INSEPERABLE",
+    "INVISIBLESTACKER",
+    "IOTASUBSCRIPT",
+    "IPAEXT",
+    "IPAEXTENSIONS",
+    "IS",
+    "ISO",
+    "ISOLATED",
+    "ITAL",
+    "JAMO",
+    "JAMOEXTA",
+    "JAMOEXTB",
+    "JAVA",
+    "JAVANESE",
+    "JG",
+    "JL",
+    "JOINC",
+    "JOINCAUSING",
+    "JOINCONTROL",
+    "JOINER",
+    "JOININGGROUP",
+    "JOININGTYPE",
+    "JT",
+    "JV",
+    "KA",
+    "KAF",
+    "KAITHI",
+    "KALI",
+    "KANA",
+    "KANASUP",
+    "KANASUPPLEMENT",
+    "KANAVOICING",
+    "KANBUN",
+    "KANGXI",
+    "KANGXIRADICALS",
+    "KANNADA",
+    "KAPH",
+    "KATAKANA",
+    "KATAKANAEXT",
+    "KATAKANAORHIRAGANA",
+    "KATAKANAPHONETICEXTENSIONS",
+    "KAYAHLI",
+    "KHAPH",
+    "KHAR",
+    "KHAROSHTHI",
+    "KHMER",
+    "KHMERSYMBOLS",
+    "KHMR",
+    "KHOJ",
+    "KHOJKI",
+    "KHUDAWADI",
+    "KNDA",
+    "KNOTTEDHEH",
+    "KTHI",
+    "KV",
+    "L",
+    "L&",
+    "LAM",
+    "LAMADH",
+    "LANA",
+    "LAO",
+    "LAOO",
+    "LATIN",
+    "LATIN1",
+    "LATIN1SUP",
+    "LATIN1SUPPLEMENT",
+    "LATINEXTA",
+    "LATINEXTADDITIONAL",
+    "LATINEXTB",
+    "LATINEXTC",
+    "LATINEXTD",
+    "LATINEXTE",
+    "LATINEXTENDEDA",
+    "LATINEXTENDEDADDITIONAL",
+    "LATINEXTENDEDB",
+    "LATINEXTENDEDC",
+    "LATINEXTENDEDD",
+    "LATINEXTENDEDE",
+    "LATN",
+    "LB",
+    "LC",
+    "LE",
+    "LEADINGJAMO",
+    "LEFT",
+    "LEFTANDRIGHT",
+    "LEFTJOINING",
+    "LEFTTORIGHT",
+    "LEFTTORIGHTEMBEDDING",
+    "LEFTTORIGHTISOLATE",
+    "LEFTTORIGHTOVERRIDE",
+    "LEPC",
+    "LEPCHA",
+    "LETTER",
+    "LETTERLIKESYMBOLS",
+    "LETTERNUMBER",
+    "LF",
+    "LIMB",
+    "LIMBU",
+    "LINA",
+    "LINB",
+    "LINEARA",
+    "LINEARB",
+    "LINEARBIDEOGRAMS",
+    "LINEARBSYLLABARY",
+    "LINEBREAK",
+    "LINEFEED",
+    "LINESEPARATOR",
+    "LISU",
+    "LL",
+    "LM",
+    "LO",
+    "LOE",
+    "LOGICALORDEREXCEPTION",
+    "LOWER",
+    "LOWERCASE",
+    "LOWERCASELETTER",
+    "LOWSURROGATES",
+    "LRE",
+    "LRI",
+    "LRO",
+    "LT",
+    "LU",
+    "LV",
+    "LVSYLLABLE",
+    "LVT",
+    "LVTSYLLABLE",
+    "LYCI",
+    "LYCIAN",
+    "LYDI",
+    "LYDIAN",
+    "M",
+    "M&",
+    "MAHAJANI",
+    "MAHJ",
+    "MAHJONG",
+    "MAHJONGTILES",
+    "MALAYALAM",
+    "MAND",
+    "MANDAIC",
+    "MANDATORYBREAK",
+    "MANI",
+    "MANICHAEAN",
+    "MANICHAEANALEPH",
+    "MANICHAEANAYIN",
+    "MANICHAEANBETH",
+    "MANICHAEANDALETH",
+    "MANICHAEANDHAMEDH",
+    "MANICHAEANFIVE",
+    "MANICHAEANGIMEL",
+    "MANICHAEANHETH",
+    "MANICHAEANHUNDRED",
+    "MANICHAEANKAPH",
+    "MANICHAEANLAMEDH",
+    "MANICHAEANMEM",
+    "MANICHAEANNUN",
+    "MANICHAEANONE",
+    "MANICHAEANPE",
+    "MANICHAEANQOPH",
+    "MANICHAEANRESH",
+    "MANICHAEANSADHE",
+    "MANICHAEANSAMEKH",
+    "MANICHAEANTAW",
+    "MANICHAEANTEN",
+    "MANICHAEANTETH",
+    "MANICHAEANTHAMEDH",
+    "MANICHAEANTWENTY",
+    "MANICHAEANWAW",
+    "MANICHAEANYODH",
+    "MANICHAEANZAYIN",
+    "MARK",
+    "MATH",
+    "MATHALPHANUM",
+    "MATHEMATICALALPHANUMERICSYMBOLS",
+    "MATHEMATICALOPERATORS",
+    "MATHOPERATORS",
+    "MATHSYMBOL",
+    "MB",
+    "MC",
+    "ME",
+    "MED",
+    "MEDIAL",
+    "MEEM",
+    "MEETEIMAYEK",
+    "MEETEIMAYEKEXT",
+    "MEETEIMAYEKEXTENSIONS",
+    "MEND",
+    "MENDEKIKAKUI",
+    "MERC",
+    "MERO",
+    "MEROITICCURSIVE",
+    "MEROITICHIEROGLYPHS",
+    "MIAO",
+    "MIDLETTER",
+    "MIDNUM",
+    "MIDNUMLET",
+    "MIM",
+    "MISCARROWS",
+    "MISCELLANEOUSMATHEMATICALSYMBOLSA",
+    "MISCELLANEOUSMATHEMATICALSYMBOLSB",
+    "MISCELLANEOUSSYMBOLS",
+    "MISCELLANEOUSSYMBOLSANDARROWS",
+    "MISCELLANEOUSSYMBOLSANDPICTOGRAPHS",
+    "MISCELLANEOUSTECHNICAL",
+    "MISCMATHSYMBOLSA",
+    "MISCMATHSYMBOLSB",
+    "MISCPICTOGRAPHS",
+    "MISCSYMBOLS",
+    "MISCTECHNICAL",
+    "ML",
+    "MLYM",
+    "MN",
+    "MODI",
+    "MODIFIERLETTER",
+    "MODIFIERLETTERS",
+    "MODIFIERSYMBOL",
+    "MODIFIERTONELETTERS",
+    "MODIFYINGLETTER",
+    "MONG",
+    "MONGOLIAN",
+    "MRO",
+    "MROO",
+    "MTEI",
+    "MULT",
+    "MULTANI",
+    "MUSIC",
+    "MUSICALSYMBOLS",
+    "MYANMAR",
+    "MYANMAREXTA",
+    "MYANMAREXTB",
+    "MYANMAREXTENDEDA",
+    "MYANMAREXTENDEDB",
+    "MYMR",
+    "N",
+    "N&",
+    "NA",
+    "NABATAEAN",
+    "NAN",
+    "NAR",
+    "NARB",
+    "NARROW",
+    "NB",
+    "NBAT",
+    "NCHAR",
+    "ND",
+    "NEUTRAL",
+    "NEWLINE",
+    "NEWTAILUE",
+    "NEXTLINE",
+    "NK",
+    "NKO",
+    "NKOO",
+    "NL",
+    "NO",
+    "NOBLOCK",
+    "NOBREAK",
+    "NOJOININGGROUP",
+    "NONCHARACTERCODEPOINT",
+    "NONE",
+    "NONJOINER",
+    "NONJOINING",
+    "NONSPACINGMARK",
+    "NONSTARTER",
+    "NOON",
+    "NOTAPPLICABLE",
+    "NOTREORDERED",
+    "NR",
+    "NS",
+    "NSM",
+    "NT",
+    "NU",
+    "NUKTA",
+    "NUMBER",
+    "NUMBERFORMS",
+    "NUMBERJOINER",
+    "NUMERIC",
+    "NUMERICTYPE",
+    "NUMERICVALUE",
+    "NUN",
+    "NV",
+    "NYA",
+    "OALPHA",
+    "OCR",
+    "ODI",
+    "OGAM",
+    "OGHAM",
+    "OGREXT",
+    "OIDC",
+    "OIDS",
+    "OLCHIKI",
+    "OLCK",
+    "OLDHUNGARIAN",
+    "OLDITALIC",
+    "OLDNORTHARABIAN",
+    "OLDPERMIC",
+    "OLDPERSIAN",
+    "OLDSOUTHARABIAN",
+    "OLDTURKIC",
+    "OLETTER",
+    "OLOWER",
+    "OMATH",
+    "ON",
+    "OP",
+    "OPENPUNCTUATION",
+    "OPTICALCHARACTERRECOGNITION",
+    "ORIYA",
+    "ORKH",
+    "ORNAMENTALDINGBATS",
+    "ORYA",
+    "OSMA",
+    "OSMANYA",
+    "OTHER",
+    "OTHERALPHABETIC",
+    "OTHERDEFAULTIGNORABLECODEPOINT",
+    "OTHERGRAPHEMEEXTEND",
+    "OTHERIDCONTINUE",
+    "OTHERIDSTART",
+    "OTHERLETTER",
+    "OTHERLOWERCASE",
+    "OTHERMATH",
+    "OTHERNEUTRAL",
+    "OTHERNUMBER",
+    "OTHERPUNCTUATION",
+    "OTHERSYMBOL",
+    "OTHERUPPERCASE",
+    "OUPPER",
+    "OV",
+    "OVERLAY",
+    "OVERSTRUCK",
+    "P",
+    "P&",
+    "PAHAWHHMONG",
+    "PALM",
+    "PALMYRENE",
+    "PARAGRAPHSEPARATOR",
+    "PATSYN",
+    "PATTERNSYNTAX",
+    "PATTERNWHITESPACE",
+    "PATWS",
+    "PAUC",
+    "PAUCINHAU",
+    "PC",
+    "PD",
+    "PDF",
+    "PDI",
+    "PE",
+    "PERM",
+    "PF",
+    "PHAG",
+    "PHAGSPA",
+    "PHAISTOS",
+    "PHAISTOSDISC",
+    "PHLI",
+    "PHLP",
+    "PHNX",
+    "PHOENICIAN",
+    "PHONETICEXT",
+    "PHONETICEXTENSIONS",
+    "PHONETICEXTENSIONSSUPPLEMENT",
+    "PHONETICEXTSUP",
+    "PI",
+    "PLAYINGCARDS",
+    "PLRD",
+    "PO",
+    "POPDIRECTIONALFORMAT",
+    "POPDIRECTIONALISOLATE",
+    "POSIXALNUM",
+    "POSIXDIGIT",
+    "POSIXPUNCT",
+    "POSIXXDIGIT",
+    "POSTFIXNUMERIC",
+    "PP",
+    "PR",
+    "PREFIXNUMERIC",
+    "PREPEND",
+    "PRINT",
+    "PRIVATEUSE",
+    "PRIVATEUSEAREA",
+    "PRTI",
+    "PS",
+    "PSALTERPAHLAVI",
+    "PUA",
+    "PUNCT",
+    "PUNCTUATION",
+    "PUREKILLER",
+    "QAAC",
+    "QAAI",
+    "QAF",
+    "QAPH",
+    "QMARK",
+    "QU",
+    "QUOTATION",
+    "QUOTATIONMARK",
+    "R",
+    "RADICAL",
+    "REGIONALINDICATOR",
+    "REGISTERSHIFTER",
+    "REH",
+    "REJANG",
+    "REVERSEDPE",
+    "RI",
+    "RIGHT",
+    "RIGHTJOINING",
+    "RIGHTTOLEFT",
+    "RIGHTTOLEFTEMBEDDING",
+    "RIGHTTOLEFTISOLATE",
+    "RIGHTTOLEFTOVERRIDE",
+    "RJNG",
+    "RLE",
+    "RLI",
+    "RLO",
+    "ROHINGYAYEH",
+    "RUMI",
+    "RUMINUMERALSYMBOLS",
+    "RUNIC",
+    "RUNR",
+    "S",
+    "S&",
+    "SA",
+    "SAD",
+    "SADHE",
+    "SAMARITAN",
+    "SAMR",
+    "SARB",
+    "SAUR",
+    "SAURASHTRA",
+    "SB",
+    "SC",
+    "SCONTINUE",
+    "SCRIPT",
+    "SD",
+    "SE",
+    "SEEN",
+    "SEGMENTSEPARATOR",
+    "SEMKATH",
+    "SENTENCEBREAK",
+    "SEP",
+    "SEPARATOR",
+    "SG",
+    "SGNW",
+    "SHARADA",
+    "SHAVIAN",
+    "SHAW",
+    "SHIN",
+    "SHORTHANDFORMATCONTROLS",
+    "SHRD",
+    "SIDD",
+    "SIDDHAM",
+    "SIGNWRITING",
+    "SIND",
+    "SINGLEQUOTE",
+    "SINH",
+    "SINHALA",
+    "SINHALAARCHAICNUMBERS",
+    "SK",
+    "SM",
+    "SMALL",
+    "SMALLFORMS",
+    "SMALLFORMVARIANTS",
+    "SML",
+    "SO",
+    "SOFTDOTTED",
+    "SORA",
+    "SORASOMPENG",
+    "SP",
+    "SPACE",
+    "SPACESEPARATOR",
+    "SPACINGMARK",
+    "SPACINGMODIFIERLETTERS",
+    "SPECIALS",
+    "SQ",
+    "SQR",
+    "SQUARE",
+    "ST",
+    "STERM",
+    "STRAIGHTWAW",
+    "SUB",
+    "SUND",
+    "SUNDANESE",
+    "SUNDANESESUP",
+    "SUNDANESESUPPLEMENT",
+    "SUP",
+    "SUPARROWSA",
+    "SUPARROWSB",
+    "SUPARROWSC",
+    "SUPER",
+    "SUPERANDSUB",
+    "SUPERSCRIPTSANDSUBSCRIPTS",
+    "SUPMATHOPERATORS",
+    "SUPPLEMENTALARROWSA",
+    "SUPPLEMENTALARROWSB",
+    "SUPPLEMENTALARROWSC",
+    "SUPPLEMENTALMATHEMATICALOPERATORS",
+    "SUPPLEMENTALPUNCTUATION",
+    "SUPPLEMENTALSYMBOLSANDPICTOGRAPHS",
+    "SUPPLEMENTARYPRIVATEUSEAREAA",
+    "SUPPLEMENTARYPRIVATEUSEAREAB",
+    "SUPPUAA",
+    "SUPPUAB",
+    "SUPPUNCTUATION",
+    "SUPSYMBOLSANDPICTOGRAPHS",
+    "SURROGATE",
+    "SUTTONSIGNWRITING",
+    "SWASHKAF",
+    "SY",
+    "SYLLABLEMODIFIER",
+    "SYLO",
+    "SYLOTINAGRI",
+    "SYMBOL",
+    "SYRC",
+    "SYRIAC",
+    "SYRIACWAW",
+    "T",
+    "TAGALOG",
+    "TAGB",
+    "TAGBANWA",
+    "TAGS",
+    "TAH",
+    "TAILE",
+    "TAITHAM",
+    "TAIVIET",
+    "TAIXUANJING",
+    "TAIXUANJINGSYMBOLS",
+    "TAKR",
+    "TAKRI",
+    "TALE",
+    "TALU",
+    "TAMIL",
+    "TAML",
+    "TAVT",
+    "TAW",
+    "TEHMARBUTA",
+    "TEHMARBUTAGOAL",
+    "TELU",
+    "TELUGU",
+    "TERM",
+    "TERMINALPUNCTUATION",
+    "TETH",
+    "TFNG",
+    "TGLG",
+    "THAA",
+    "THAANA",
+    "THAI",
+    "TIBETAN",
+    "TIBT",
+    "TIFINAGH",
+    "TIRH",
+    "TIRHUTA",
+    "TITLECASELETTER",
+    "TONELETTER",
+    "TONEMARK",
+    "TOP",
+    "TOPANDBOTTOM",
+    "TOPANDBOTTOMANDRIGHT",
+    "TOPANDLEFT",
+    "TOPANDLEFTANDRIGHT",
+    "TOPANDRIGHT",
+    "TRAILINGJAMO",
+    "TRANSPARENT",
+    "TRANSPORTANDMAP",
+    "TRANSPORTANDMAPSYMBOLS",
+    "TRUE",
+    "U",
+    "UCAS",
+    "UCASEXT",
+    "UGAR",
+    "UGARITIC",
+    "UIDEO",
+    "UNASSIGNED",
+    "UNIFIEDCANADIANABORIGINALSYLLABICS",
+    "UNIFIEDCANADIANABORIGINALSYLLABICSEXTENDED",
+    "UNIFIEDIDEOGRAPH",
+    "UNKNOWN",
+    "UP",
+    "UPPER",
+    "UPPERCASE",
+    "UPPERCASELETTER",
+    "V",
+    "VAI",
+    "VAII",
+    "VARIATIONSELECTOR",
+    "VARIATIONSELECTORS",
+    "VARIATIONSELECTORSSUPPLEMENT",
+    "VEDICEXT",
+    "VEDICEXTENSIONS",
+    "VERT",
+    "VERTICAL",
+    "VERTICALFORMS",
+    "VIRAMA",
+    "VISARGA",
+    "VISUALORDERLEFT",
+    "VOWEL",
+    "VOWELDEPENDENT",
+    "VOWELINDEPENDENT",
+    "VOWELJAMO",
+    "VR",
+    "VS",
+    "VSSUP",
+    "W",
+    "WARA",
+    "WARANGCITI",
+    "WAW",
+    "WB",
+    "WHITESPACE",
+    "WIDE",
+    "WJ",
+    "WORD",
+    "WORDBREAK",
+    "WORDJOINER",
+    "WS",
+    "WSPACE",
+    "XDIGIT",
+    "XIDC",
+    "XIDCONTINUE",
+    "XIDS",
+    "XIDSTART",
+    "XPEO",
+    "XSUX",
+    "XX",
+    "Y",
+    "YEH",
+    "YEHBARREE",
+    "YEHWITHTAIL",
+    "YES",
+    "YI",
+    "YIII",
+    "YIJING",
+    "YIJINGHEXAGRAMSYMBOLS",
+    "YIRADICALS",
+    "YISYLLABLES",
+    "YUDH",
+    "YUDHHE",
+    "Z",
+    "Z&",
+    "ZAIN",
+    "ZHAIN",
+    "ZINH",
+    "ZL",
+    "ZP",
+    "ZS",
+    "ZW",
+    "ZWSPACE",
+    "ZYYY",
+    "ZZZZ",
+};
+
+/* strings: 12240 bytes. */
+
+/* properties. */
+
+RE_Property re_properties[] = {
+    { 547,  0,  0},
+    { 544,  0,  0},
+    { 252,  1,  1},
+    { 251,  1,  1},
+    {1081,  2,  2},
+    {1079,  2,  2},
+    {1259,  3,  3},
+    {1254,  3,  3},
+    { 566,  4,  4},
+    { 545,  4,  4},
+    {1087,  5,  5},
+    {1078,  5,  5},
+    { 823,  6,  6},
+    { 172,  7,  6},
+    { 171,  7,  6},
+    { 767,  8,  6},
+    { 766,  8,  6},
+    {1227,  9,  6},
+    {1226,  9,  6},
+    { 294, 10,  6},
+    { 296, 11,  6},
+    { 350, 11,  6},
+    { 343, 12,  6},
+    { 433, 12,  6},
+    { 345, 13,  6},
+    { 435, 13,  6},
+    { 344, 14,  6},
+    { 434, 14,  6},
+    { 341, 15,  6},
+    { 431, 15,  6},
+    { 342, 16,  6},
+    { 432, 16,  6},
+    { 636, 17,  6},
+    { 632, 17,  6},
+    { 628, 18,  6},
+    { 627, 18,  6},
+    {1267, 19,  6},
+    {1266, 19,  6},
+    {1265, 20,  6},
+    {1264, 20,  6},
+    { 458, 21,  6},
+    { 466, 21,  6},
+    { 567, 22,  6},
+    { 575, 22,  6},
+    { 565, 23,  6},
+    { 569, 23,  6},
+    { 568, 24,  6},
+    { 576, 24,  6},
+    {1255, 25,  6},
+    {1262, 25,  6},
+    {1117, 25,  6},
+    { 244, 26,  6},
+    { 242, 26,  6},
+    { 671, 27,  6},
+    { 669, 27,  6},
+    { 451, 28,  6},
+    { 625, 29,  6},
+    {1044, 30,  6},
+    {1041, 30,  6},
+    {1188, 31,  6},
+    {1187, 31,  6},
+    { 971, 32,  6},
+    { 952, 32,  6},
+    { 612, 33,  6},
+    { 611, 33,  6},
+    { 204, 34,  6},
+    { 160, 34,  6},
+    { 964, 35,  6},
+    { 933, 35,  6},
+    { 630, 36,  6},
+    { 629, 36,  6},
+    { 468, 37,  6},
+    { 467, 37,  6},
+    { 523, 38,  6},
+    { 521, 38,  6},
+    { 970, 39,  6},
+    { 951, 39,  6},
+    { 976, 40,  6},
+    { 977, 40,  6},
+    { 909, 41,  6},
+    { 895, 41,  6},
+    { 966, 42,  6},
+    { 938, 42,  6},
+    { 634, 43,  6},
+    { 633, 43,  6},
+    { 637, 44,  6},
+    { 635, 44,  6},
+    {1046, 45,  6},
+    {1223, 46,  6},
+    {1219, 46,  6},
+    { 965, 47,  6},
+    { 935, 47,  6},
+    { 460, 48,  6},
+    { 459, 48,  6},
+    {1113, 49,  6},
+    {1082, 49,  6},
+    { 765, 50,  6},
+    { 764, 50,  6},
+    { 968, 51,  6},
+    { 940, 51,  6},
+    { 967, 52,  6},
+    { 939, 52,  6},
+    {1126, 53,  6},
+    {1232, 54,  6},
+    {1248, 54,  6},
+    { 989, 55,  6},
+    { 990, 55,  6},
+    { 988, 56,  6},
+    { 987, 56,  6},
+    { 598, 57,  7},
+    { 622, 57,  7},
+    { 243, 58,  8},
+    { 234, 58,  8},
+    { 288, 59,  9},
+    { 300, 59,  9},
+    { 457, 60, 10},
+    { 482, 60, 10},
+    { 489, 61, 11},
+    { 487, 61, 11},
+    { 673, 62, 12},
+    { 667, 62, 12},
+    { 674, 63, 13},
+    { 675, 63, 13},
+    { 757, 64, 14},
+    { 732, 64, 14},
+    { 928, 65, 15},
+    { 921, 65, 15},
+    { 929, 66, 16},
+    { 931, 66, 16},
+    { 246, 67,  6},
+    { 245, 67,  6},
+    { 641, 68, 17},
+    { 648, 68, 17},
+    { 642, 69, 18},
+    { 649, 69, 18},
+    { 175, 70,  6},
+    { 170, 70,  6},
+    { 183, 71,  6},
+    { 250, 72,  6},
+    { 564, 73,  6},
+    {1027, 74,  6},
+    {1258, 75,  6},
+    {1263, 76,  6},
+    {1019, 77,  6},
+    {1018, 78,  6},
+    {1020, 79,  6},
+    {1021, 80,  6},
+};
+
+/* properties: 588 bytes. */
+
+/* property values. */
+
+RE_PropertyValue re_property_values[] = {
+    {1220,  0,   0},
+    { 383,  0,   0},
+    {1228,  0,   1},
+    { 774,  0,   1},
+    { 768,  0,   2},
+    { 761,  0,   2},
+    {1200,  0,   3},
+    { 773,  0,   3},
+    { 865,  0,   4},
+    { 762,  0,   4},
+    { 969,  0,   5},
+    { 763,  0,   5},
+    { 913,  0,   6},
+    { 863,  0,   6},
+    { 505,  0,   7},
+    { 831,  0,   7},
+    {1119,  0,   8},
+    { 830,  0,   8},
+    { 456,  0,   9},
+    { 896,  0,   9},
+    { 473,  0,   9},
+    { 747,  0,  10},
+    { 904,  0,  10},
+    { 973,  0,  11},
+    { 905,  0,  11},
+    {1118,  0,  12},
+    {1291,  0,  12},
+    { 759,  0,  13},
+    {1289,  0,  13},
+    { 986,  0,  14},
+    {1290,  0,  14},
+    { 415,  0,  15},
+    { 299,  0,  15},
+    { 384,  0,  15},
+    { 537,  0,  16},
+    { 338,  0,  16},
+    {1028,  0,  17},
+    { 385,  0,  17},
+    {1153,  0,  18},
+    { 425,  0,  18},
+    { 452,  0,  19},
+    { 994,  0,  19},
+    { 955,  0,  20},
+    {1031,  0,  20},
+    { 381,  0,  21},
+    { 997,  0,  21},
+    { 401,  0,  22},
+    { 993,  0,  22},
+    { 974,  0,  23},
+    {1015,  0,  23},
+    { 828,  0,  24},
+    {1107,  0,  24},
+    { 429,  0,  25},
+    {1079,  0,  25},
+    { 867,  0,  26},
+    {1106,  0,  26},
+    { 975,  0,  27},
+    {1112,  0,  27},
+    { 647,  0,  28},
+    {1012,  0,  28},
+    { 532,  0,  29},
+    { 999,  0,  29},
+    { 963,  0,  30},
+    { 281,  0,  30},
+    { 282,  0,  30},
+    { 745,  0,  31},
+    { 708,  0,  31},
+    { 709,  0,  31},
+    { 822,  0,  32},
+    { 783,  0,  32},
+    { 392,  0,  32},
+    { 784,  0,  32},
+    { 924,  0,  33},
+    { 885,  0,  33},
+    { 886,  0,  33},
+    {1035,  0,  34},
+    { 981,  0,  34},
+    {1034,  0,  34},
+    { 982,  0,  34},
+    {1160,  0,  35},
+    {1068,  0,  35},
+    {1069,  0,  35},
+    {1089,  0,  36},
+    {1284,  0,  36},
+    {1285,  0,  36},
+    { 295,  0,  37},
+    { 733,  0,  37},
+    { 205,  0,  38},
+    { 906,  1,   0},
+    { 893,  1,   0},
+    { 228,  1,   1},
+    { 203,  1,   1},
+    { 718,  1,   2},
+    { 717,  1,   2},
+    { 716,  1,   2},
+    { 725,  1,   3},
+    { 719,  1,   3},
+    { 727,  1,   4},
+    { 721,  1,   4},
+    { 657,  1,   5},
+    { 656,  1,   5},
+    {1120,  1,   6},
+    { 866,  1,   6},
+    { 387,  1,   7},
+    { 469,  1,   7},
+    { 571,  1,   8},
+    { 570,  1,   8},
+    { 438,  1,   9},
+    { 444,  1,  10},
+    { 443,  1,  10},
+    { 445,  1,  10},
+    { 199,  1,  11},
+    { 606,  1,  12},
+    { 186,  1,  13},
+    {1162,  1,  14},
+    { 198,  1,  15},
+    { 197,  1,  15},
+    {1193,  1,  16},
+    { 902,  1,  17},
+    {1073,  1,  18},
+    { 791,  1,  19},
+    { 188,  1,  20},
+    { 187,  1,  20},
+    { 463,  1,  21},
+    { 240,  1,  22},
+    { 579,  1,  23},
+    { 577,  1,  24},
+    { 957,  1,  25},
+    {1179,  1,  26},
+    {1186,  1,  27},
+    { 688,  1,  28},
+    { 789,  1,  29},
+    {1104,  1,  30},
+    {1194,  1,  31},
+    { 713,  1,  32},
+    {1195,  1,  33},
+    { 879,  1,  34},
+    { 553,  1,  35},
+    { 594,  1,  36},
+    { 662,  1,  36},
+    { 509,  1,  37},
+    { 515,  1,  38},
+    { 514,  1,  38},
+    { 347,  1,  39},
+    {1221,  1,  40},
+    {1215,  1,  40},
+    { 286,  1,  40},
+    { 937,  1,  41},
+    {1066,  1,  42},
+    {1165,  1,  43},
+    { 601,  1,  44},
+    { 277,  1,  45},
+    {1167,  1,  46},
+    { 698,  1,  47},
+    { 871,  1,  48},
+    {1222,  1,  49},
+    {1216,  1,  49},
+    { 750,  1,  50},
+    {1170,  1,  51},
+    { 899,  1,  52},
+    { 699,  1,  53},
+    { 275,  1,  54},
+    {1171,  1,  55},
+    { 388,  1,  56},
+    { 470,  1,  56},
+    { 223,  1,  57},
+    {1130,  1,  58},
+    { 231,  1,  59},
+    { 744,  1,  60},
+    { 941,  1,  61},
+    {1132,  1,  62},
+    {1131,  1,  62},
+    {1236,  1,  63},
+    {1235,  1,  63},
+    {1009,  1,  64},
+    {1008,  1,  64},
+    {1010,  1,  65},
+    {1011,  1,  65},
+    { 390,  1,  66},
+    { 472,  1,  66},
+    { 726,  1,  67},
+    { 720,  1,  67},
+    { 573,  1,  68},
+    { 572,  1,  68},
+    { 548,  1,  69},
+    {1035,  1,  69},
+    {1139,  1,  70},
+    {1138,  1,  70},
+    { 430,  1,  71},
+    { 389,  1,  72},
+    { 471,  1,  72},
+    { 393,  1,  72},
+    { 746,  1,  73},
+    { 925,  1,  74},
+    { 202,  1,  75},
+    { 826,  1,  76},
+    { 827,  1,  76},
+    { 855,  1,  77},
+    { 860,  1,  77},
+    { 416,  1,  78},
+    { 956,  1,  79},
+    { 934,  1,  79},
+    { 498,  1,  80},
+    { 497,  1,  80},
+    { 262,  1,  81},
+    { 253,  1,  82},
+    { 549,  1,  83},
+    { 852,  1,  84},
+    { 859,  1,  84},
+    { 474,  1,  85},
+    { 850,  1,  86},
+    { 856,  1,  86},
+    {1141,  1,  87},
+    {1134,  1,  87},
+    { 269,  1,  88},
+    { 268,  1,  88},
+    {1142,  1,  89},
+    {1135,  1,  89},
+    { 851,  1,  90},
+    { 857,  1,  90},
+    {1144,  1,  91},
+    {1140,  1,  91},
+    { 853,  1,  92},
+    { 849,  1,  92},
+    { 558,  1,  93},
+    { 728,  1,  94},
+    { 722,  1,  94},
+    { 418,  1,  95},
+    { 555,  1,  96},
+    { 554,  1,  96},
+    {1197,  1,  97},
+    { 512,  1,  98},
+    { 510,  1,  98},
+    { 441,  1,  99},
+    { 439,  1,  99},
+    {1145,  1, 100},
+    {1151,  1, 100},
+    { 368,  1, 101},
+    { 367,  1, 101},
+    { 687,  1, 102},
+    { 686,  1, 102},
+    { 631,  1, 103},
+    { 627,  1, 103},
+    { 371,  1, 104},
+    { 370,  1, 104},
+    { 617,  1, 105},
+    { 690,  1, 106},
+    { 256,  1, 107},
+    { 593,  1, 108},
+    { 398,  1, 108},
+    { 685,  1, 109},
+    { 258,  1, 110},
+    { 257,  1, 110},
+    { 369,  1, 111},
+    { 693,  1, 112},
+    { 691,  1, 112},
+    { 502,  1, 113},
+    { 501,  1, 113},
+    { 356,  1, 114},
+    { 354,  1, 114},
+    { 373,  1, 115},
+    { 362,  1, 115},
+    {1279,  1, 116},
+    {1278,  1, 116},
+    { 372,  1, 117},
+    { 353,  1, 117},
+    {1281,  1, 118},
+    {1280,  1, 119},
+    { 760,  1, 120},
+    {1230,  1, 121},
+    { 442,  1, 122},
+    { 440,  1, 122},
+    { 225,  1, 123},
+    { 868,  1, 124},
+    { 729,  1, 125},
+    { 723,  1, 125},
+    {1159,  1, 126},
+    { 395,  1, 127},
+    { 640,  1, 127},
+    {1001,  1, 128},
+    {1077,  1, 129},
+    { 465,  1, 130},
+    { 464,  1, 130},
+    { 694,  1, 131},
+    {1050,  1, 132},
+    { 595,  1, 133},
+    { 663,  1, 133},
+    { 666,  1, 134},
+    { 883,  1, 135},
+    { 881,  1, 135},
+    { 340,  1, 136},
+    { 882,  1, 137},
+    { 880,  1, 137},
+    {1172,  1, 138},
+    { 837,  1, 139},
+    { 836,  1, 139},
+    { 513,  1, 140},
+    { 511,  1, 140},
+    { 730,  1, 141},
+    { 724,  1, 141},
+    { 349,  1, 142},
+    { 348,  1, 142},
+    { 835,  1, 143},
+    { 597,  1, 144},
+    { 592,  1, 144},
+    { 596,  1, 145},
+    { 664,  1, 145},
+    { 615,  1, 146},
+    { 613,  1, 147},
+    { 614,  1, 147},
+    { 769,  1, 148},
+    {1029,  1, 149},
+    {1033,  1, 149},
+    {1028,  1, 149},
+    { 358,  1, 150},
+    { 360,  1, 150},
+    { 174,  1, 151},
+    { 173,  1, 151},
+    { 195,  1, 152},
+    { 193,  1, 152},
+    {1233,  1, 153},
+    {1248,  1, 153},
+    {1239,  1, 154},
+    { 391,  1, 155},
+    { 586,  1, 155},
+    { 357,  1, 156},
+    { 355,  1, 156},
+    {1110,  1, 157},
+    {1109,  1, 157},
+    { 196,  1, 158},
+    { 194,  1, 158},
+    { 588,  1, 159},
+    { 585,  1, 159},
+    {1121,  1, 160},
+    { 756,  1, 161},
+    { 755,  1, 162},
+    { 158,  1, 163},
+    { 181,  1, 164},
+    { 182,  1, 165},
+    {1003,  1, 166},
+    {1002,  1, 166},
+    { 780,  1, 167},
+    { 292,  1, 168},
+    { 419,  1, 169},
+    { 944,  1, 170},
+    { 561,  1, 171},
+    { 946,  1, 172},
+    {1218,  1, 173},
+    { 947,  1, 174},
+    { 461,  1, 175},
+    {1093,  1, 176},
+    { 962,  1, 177},
+    { 493,  1, 178},
+    { 297,  1, 179},
+    { 753,  1, 180},
+    { 437,  1, 181},
+    { 638,  1, 182},
+    { 985,  1, 183},
+    { 888,  1, 184},
+    { 603,  1, 185},
+    {1007,  1, 186},
+    { 782,  1, 187},
+    { 843,  1, 188},
+    { 842,  1, 189},
+    { 697,  1, 190},
+    { 948,  1, 191},
+    { 945,  1, 192},
+    { 794,  1, 193},
+    { 217,  1, 194},
+    { 651,  1, 195},
+    { 650,  1, 196},
+    {1032,  1, 197},
+    { 949,  1, 198},
+    { 943,  1, 199},
+    {1065,  1, 200},
+    {1064,  1, 200},
+    { 265,  1, 201},
+    { 679,  1, 202},
+    {1115,  1, 203},
+    { 339,  1, 204},
+    { 785,  1, 205},
+    {1092,  1, 206},
+    {1105,  1, 207},
+    { 702,  1, 208},
+    { 876,  1, 209},
+    { 703,  1, 210},
+    { 563,  1, 211},
+    {1199,  1, 212},
+    {1099,  1, 213},
+    { 864,  1, 214},
+    {1176,  1, 215},
+    { 161,  1, 216},
+    {1252,  1, 217},
+    { 992,  1, 218},
+    { 426,  1, 219},
+    { 428,  1, 220},
+    { 427,  1, 220},
+    { 488,  1, 221},
+    { 491,  1, 222},
+    { 178,  1, 223},
+    { 227,  1, 224},
+    { 226,  1, 224},
+    { 872,  1, 225},
+    { 230,  1, 226},
+    { 983,  1, 227},
+    { 844,  1, 228},
+    { 683,  1, 229},
+    { 682,  1, 229},
+    { 485,  1, 230},
+    {1096,  1, 231},
+    { 280,  1, 232},
+    { 279,  1, 232},
+    { 878,  1, 233},
+    { 877,  1, 233},
+    { 180,  1, 234},
+    { 179,  1, 234},
+    {1174,  1, 235},
+    {1173,  1, 235},
+    { 421,  1, 236},
+    { 420,  1, 236},
+    { 825,  1, 237},
+    { 824,  1, 237},
+    {1154,  1, 238},
+    { 839,  1, 239},
+    { 191,  1, 240},
+    { 190,  1, 240},
+    { 788,  1, 241},
+    { 787,  1, 241},
+    { 476,  1, 242},
+    { 475,  1, 242},
+    {1013,  1, 243},
+    { 499,  1, 244},
+    { 500,  1, 244},
+    { 504,  1, 245},
+    { 503,  1, 245},
+    { 854,  1, 246},
+    { 858,  1, 246},
+    { 494,  1, 247},
+    { 959,  1, 248},
+    {1212,  1, 249},
+    {1211,  1, 249},
+    { 167,  1, 250},
+    { 166,  1, 250},
+    { 551,  1, 251},
+    { 550,  1, 251},
+    {1143,  1, 252},
+    {1136,  1, 252},
+    {1146,  1, 253},
+    {1152,  1, 253},
+    { 374,  1, 254},
+    { 363,  1, 254},
+    { 375,  1, 255},
+    { 364,  1, 255},
+    { 376,  1, 256},
+    { 365,  1, 256},
+    { 377,  1, 257},
+    { 366,  1, 257},
+    { 359,  1, 258},
+    { 361,  1, 258},
+    {1168,  1, 259},
+    {1234,  1, 260},
+    {1249,  1, 260},
+    {1147,  1, 261},
+    {1149,  1, 261},
+    {1148,  1, 262},
+    {1150,  1, 262},
+    {1224,  2,   0},
+    {1295,  2,   0},
+    { 394,  2,   1},
+    {1294,  2,   1},
+    { 715,  2,   2},
+    { 731,  2,   2},
+    { 570,  2,   3},
+    { 574,  2,   3},
+    { 438,  2,   4},
+    { 446,  2,   4},
+    { 199,  2,   5},
+    { 201,  2,   5},
+    { 606,  2,   6},
+    { 605,  2,   6},
+    { 186,  2,   7},
+    { 185,  2,   7},
+    {1162,  2,   8},
+    {1161,  2,   8},
+    {1193,  2,   9},
+    {1192,  2,   9},
+    { 463,  2,  10},
+    { 462,  2,  10},
+    { 240,  2,  11},
+    { 239,  2,  11},
+    { 579,  2,  12},
+    { 580,  2,  12},
+    { 577,  2,  13},
+    { 578,  2,  13},
+    { 957,  2,  14},
+    { 960,  2,  14},
+    {1179,  2,  15},
+    {1180,  2,  15},
+    {1186,  2,  16},
+    {1185,  2,  16},
+    { 688,  2,  17},
+    { 704,  2,  17},
+    { 789,  2,  18},
+    { 862,  2,  18},
+    {1104,  2,  19},
+    {1103,  2,  19},
+    {1194,  2,  20},
+    { 713,  2,  21},
+    { 714,  2,  21},
+    {1195,  2,  22},
+    {1196,  2,  22},
+    { 879,  2,  23},
+    { 884,  2,  23},
+    { 553,  2,  24},
+    { 552,  2,  24},
+    { 592,  2,  25},
+    { 591,  2,  25},
+    { 509,  2,  26},
+    { 508,  2,  26},
+    { 347,  2,  27},
+    { 346,  2,  27},
+    { 285,  2,  28},
+    { 289,  2,  28},
+    { 937,  2,  29},
+    { 936,  2,  29},
+    {1066,  2,  30},
+    {1067,  2,  30},
+    { 698,  2,  31},
+    { 700,  2,  31},
+    { 871,  2,  32},
+    { 870,  2,  32},
+    { 617,  2,  33},
+    { 616,  2,  33},
+    { 690,  2,  34},
+    { 681,  2,  34},
+    { 256,  2,  35},
+    { 255,  2,  35},
+    { 590,  2,  36},
+    { 599,  2,  36},
+    {1276,  2,  37},
+    {1277,  2,  37},
+    { 944,  2,  38},
+    { 661,  2,  38},
+    { 561,  2,  39},
+    { 560,  2,  39},
+    { 461,  2,  40},
+    { 481,  2,  40},
+    { 644,  2,  41},
+    {1288,  2,  41},
+    {1038,  2,  41},
+    {1165,  2,  42},
+    {1191,  2,  42},
+    { 601,  2,  43},
+    { 600,  2,  43},
+    { 277,  2,  44},
+    { 276,  2,  44},
+    {1167,  2,  45},
+    {1166,  2,  45},
+    { 750,  2,  46},
+    { 749,  2,  46},
+    {1170,  2,  47},
+    {1177,  2,  47},
+    { 754,  2,  48},
+    { 752,  2,  48},
+    {1218,  2,  49},
+    {1217,  2,  49},
+    {1093,  2,  50},
+    {1094,  2,  50},
+    { 962,  2,  51},
+    { 961,  2,  51},
+    { 436,  2,  52},
+    { 423,  2,  52},
+    { 268,  2,  53},
+    { 267,  2,  53},
+    { 275,  2,  54},
+    { 274,  2,  54},
+    { 418,  2,  55},
+    { 417,  2,  55},
+    {1037,  2,  55},
+    { 899,  2,  56},
+    {1178,  2,  56},
+    { 558,  2,  57},
+    { 557,  2,  57},
+    {1197,  2,  58},
+    {1190,  2,  58},
+    {1159,  2,  59},
+    {1158,  2,  59},
+    { 947,  2,  60},
+    {1268,  2,  60},
+    { 697,  2,  61},
+    { 696,  2,  61},
+    { 223,  2,  62},
+    { 222,  2,  62},
+    { 426,  2,  63},
+    {1269,  2,  63},
+    {1007,  2,  64},
+    {1006,  2,  64},
+    {1001,  2,  65},
+    {1000,  2,  65},
+    { 902,  2,  66},
+    { 903,  2,  66},
+    {1130,  2,  67},
+    {1129,  2,  67},
+    { 744,  2,  68},
+    { 743,  2,  68},
+    { 941,  2,  69},
+    { 942,  2,  69},
+    {1230,  2,  70},
+    {1231,  2,  70},
+    {1077,  2,  71},
+    {1076,  2,  71},
+    { 694,  2,  72},
+    { 680,  2,  72},
+    {1050,  2,  73},
+    {1059,  2,  73},
+    { 780,  2,  74},
+    { 779,  2,  74},
+    { 292,  2,  75},
+    { 291,  2,  75},
+    { 782,  2,  76},
+    { 781,  2,  76},
+    { 340,  2,  77},
+    {1171,  2,  78},
+    { 712,  2,  78},
+    {1172,  2,  79},
+    {1181,  2,  79},
+    { 217,  2,  80},
+    { 218,  2,  80},
+    { 491,  2,  81},
+    { 490,  2,  81},
+    {1073,  2,  82},
+    {1074,  2,  82},
+    { 760,  2,  83},
+    { 225,  2,  84},
+    { 224,  2,  84},
+    { 666,  2,  85},
+    { 665,  2,  85},
+    { 835,  2,  86},
+    { 874,  2,  86},
+    { 638,  2,  87},
+    { 200,  2,  87},
+    { 948,  2,  88},
+    {1075,  2,  88},
+    { 651,  2,  89},
+    {1030,  2,  89},
+    { 650,  2,  90},
+    {1004,  2,  90},
+    { 949,  2,  91},
+    { 958,  2,  91},
+    { 679,  2,  92},
+    { 706,  2,  92},
+    { 231,  2,  93},
+    { 232,  2,  93},
+    { 265,  2,  94},
+    { 264,  2,  94},
+    { 791,  2,  95},
+    { 790,  2,  95},
+    { 339,  2,  96},
+    { 283,  2,  96},
+    { 842,  2,  97},
+    { 840,  2,  97},
+    { 843,  2,  98},
+    { 841,  2,  98},
+    { 844,  2,  99},
+    {1014,  2,  99},
+    {1092,  2, 100},
+    {1097,  2, 100},
+    {1115,  2, 101},
+    {1114,  2, 101},
+    {1176,  2, 102},
+    {1175,  2, 102},
+    { 297,  2, 103},
+    { 159,  2, 103},
+    { 230,  2, 104},
+    { 229,  2, 104},
+    { 485,  2, 105},
+    { 484,  2, 105},
+    { 493,  2, 106},
+    { 492,  2, 106},
+    { 563,  2, 107},
+    { 562,  2, 107},
+    { 983,  2, 108},
+    { 620,  2, 108},
+    { 702,  2, 109},
+    { 701,  2, 109},
+    { 753,  2, 110},
+    { 751,  2, 110},
+    { 785,  2, 111},
+    { 786,  2, 111},
+    { 794,  2, 112},
+    { 793,  2, 112},
+    { 839,  2, 113},
+    { 838,  2, 113},
+    { 864,  2, 114},
+    { 872,  2, 115},
+    { 873,  2, 115},
+    { 945,  2, 116},
+    { 891,  2, 116},
+    { 888,  2, 117},
+    { 894,  2, 117},
+    { 985,  2, 118},
+    { 984,  2, 118},
+    { 992,  2, 119},
+    { 991,  2, 119},
+    { 946,  2, 120},
+    { 998,  2, 120},
+    {1032,  2, 121},
+    {1005,  2, 121},
+    {1099,  2, 122},
+    {1098,  2, 122},
+    { 703,  2, 123},
+    {1101,  2, 123},
+    {1199,  2, 124},
+    {1198,  2, 124},
+    {1252,  2, 125},
+    {1251,  2, 125},
+    { 161,  2, 126},
+    { 178,  2, 127},
+    { 619,  2, 127},
+    { 603,  2, 128},
+    { 602,  2, 128},
+    { 876,  2, 129},
+    { 875,  2, 129},
+    { 943,  2, 130},
+    { 623,  2, 130},
+    {1100,  2, 131},
+    {1091,  2, 131},
+    { 692,  2, 132},
+    { 621,  2, 132},
+    { 963,  3,   0},
+    {1270,  3,   0},
+    { 479,  3,   1},
+    { 480,  3,   1},
+    {1102,  3,   2},
+    {1122,  3,   2},
+    { 607,  3,   3},
+    { 618,  3,   3},
+    { 424,  3,   4},
+    { 748,  3,   5},
+    { 898,  3,   6},
+    { 904,  3,   6},
+    { 522,  3,   7},
+    {1047,  3,   8},
+    {1052,  3,   8},
+    { 537,  3,   9},
+    { 535,  3,   9},
+    { 690,  3,  10},
+    { 677,  3,  10},
+    { 169,  3,  11},
+    { 734,  3,  11},
+    { 845,  3,  12},
+    { 861,  3,  12},
+    { 846,  3,  13},
+    { 863,  3,  13},
+    { 847,  3,  14},
+    { 829,  3,  14},
+    { 927,  3,  15},
+    { 922,  3,  15},
+    { 524,  3,  16},
+    { 519,  3,  16},
+    { 963,  4,   0},
+    {1270,  4,   0},
+    { 424,  4,   1},
+    { 748,  4,   2},
+    { 415,  4,   3},
+    { 383,  4,   3},
+    { 522,  4,   4},
+    { 519,  4,   4},
+    {1047,  4,   5},
+    {1052,  4,   5},
+    {1119,  4,   6},
+    {1107,  4,   6},
+    { 708,  4,   7},
+    {1229,  4,   8},
+    {1164,  4,   9},
+    { 775,  4,  10},
+    { 777,  4,  11},
+    {1026,  4,  12},
+    {1023,  4,  12},
+    { 963,  5,   0},
+    {1270,  5,   0},
+    { 424,  5,   1},
+    { 748,  5,   2},
+    { 522,  5,   3},
+    { 519,  5,   3},
+    {1088,  5,   4},
+    {1083,  5,   4},
+    { 537,  5,   5},
+    { 535,  5,   5},
+    {1116,  5,   6},
+    { 766,  5,   7},
+    { 763,  5,   7},
+    {1226,  5,   8},
+    {1225,  5,   8},
+    { 950,  5,   9},
+    { 734,  5,   9},
+    { 927,  5,  10},
+    { 922,  5,  10},
+    { 211,  5,  11},
+    { 206,  5,  11},
+    {1126,  5,  12},
+    {1125,  5,  12},
+    { 379,  5,  13},
+    { 378,  5,  13},
+    {1080,  5,  14},
+    {1079,  5,  14},
+    { 905,  6,   0},
+    { 885,  6,   0},
+    { 525,  6,   0},
+    { 526,  6,   0},
+    {1275,  6,   1},
+    {1271,  6,   1},
+    {1164,  6,   1},
+    {1213,  6,   1},
+    { 916,  7,   0},
+    { 887,  7,   0},
+    { 735,  7,   1},
+    { 708,  7,   1},
+    {1246,  7,   2},
+    {1229,  7,   2},
+    {1209,  7,   3},
+    {1164,  7,   3},
+    { 776,  7,   4},
+    { 775,  7,   4},
+    { 778,  7,   5},
+    { 777,  7,   5},
+    { 739,  8,   0},
+    { 708,  8,   0},
+    {1055,  8,   1},
+    {1045,  8,   1},
+    { 516,  8,   2},
+    { 495,  8,   2},
+    { 517,  8,   3},
+    { 506,  8,   3},
+    { 518,  8,   4},
+    { 507,  8,   4},
+    { 192,  8,   5},
+    { 177,  8,   5},
+    { 396,  8,   6},
+    { 425,  8,   6},
+    { 986,  8,   7},
+    { 219,  8,   7},
+    {1085,  8,   8},
+    {1068,  8,   8},
+    {1255,  8,   9},
+    {1261,  8,   9},
+    { 972,  8,  10},
+    { 953,  8,  10},
+    { 261,  8,  11},
+    { 254,  8,  11},
+    { 913,  8,  12},
+    { 920,  8,  12},
+    { 189,  8,  13},
+    { 164,  8,  13},
+    { 742,  8,  14},
+    { 772,  8,  14},
+    {1058,  8,  15},
+    {1062,  8,  15},
+    { 740,  8,  16},
+    { 770,  8,  16},
+    {1056,  8,  17},
+    {1060,  8,  17},
+    {1016,  8,  18},
+    { 995,  8,  18},
+    { 741,  8,  19},
+    { 771,  8,  19},
+    {1057,  8,  20},
+    {1061,  8,  20},
+    { 534,  8,  21},
+    { 540,  8,  21},
+    {1017,  8,  22},
+    { 996,  8,  22},
+    { 917,  9,   0},
+    {   1,  9,   0},
+    { 918,  9,   0},
+    { 979,  9,   1},
+    {   2,  9,   1},
+    { 978,  9,   1},
+    { 923,  9,   2},
+    { 130,  9,   2},
+    { 901,  9,   2},
+    { 684,  9,   3},
+    { 139,  9,   3},
+    { 707,  9,   3},
+    {1240,  9,   4},
+    { 146,  9,   4},
+    {1247,  9,   4},
+    { 301,  9,   5},
+    {  14,  9,   5},
+    { 304,  9,   6},
+    {  25,  9,   6},
+    { 306,  9,   7},
+    {  29,  9,   7},
+    { 309,  9,   8},
+    {  32,  9,   8},
+    { 313,  9,   9},
+    {  37,  9,   9},
+    { 314,  9,  10},
+    {  38,  9,  10},
+    { 315,  9,  11},
+    {  40,  9,  11},
+    { 316,  9,  12},
+    {  41,  9,  12},
+    { 317,  9,  13},
+    {  43,  9,  13},
+    { 318,  9,  14},
+    {  44,  9,  14},
+    { 319,  9,  15},
+    {  48,  9,  15},
+    { 320,  9,  16},
+    {  54,  9,  16},
+    { 321,  9,  17},
+    {  59,  9,  17},
+    { 322,  9,  18},
+    {  65,  9,  18},
+    { 323,  9,  19},
+    {  70,  9,  19},
+    { 324,  9,  20},
+    {  72,  9,  20},
+    { 325,  9,  21},
+    {  73,  9,  21},
+    { 326,  9,  22},
+    {  74,  9,  22},
+    { 327,  9,  23},
+    {  75,  9,  23},
+    { 328,  9,  24},
+    {  76,  9,  24},
+    { 329,  9,  25},
+    {  83,  9,  25},
+    { 330,  9,  26},
+    {  88,  9,  26},
+    { 331,  9,  27},
+    {  89,  9,  27},
+    { 332,  9,  28},
+    {  90,  9,  28},
+    { 333,  9,  29},
+    {  91,  9,  29},
+    { 334,  9,  30},
+    {  92,  9,  30},
+    { 335,  9,  31},
+    {  93,  9,  31},
+    { 336,  9,  32},
+    { 145,  9,  32},
+    { 337,  9,  33},
+    { 153,  9,  33},
+    { 302,  9,  34},
+    {  23,  9,  34},
+    { 303,  9,  35},
+    {  24,  9,  35},
+    { 305,  9,  36},
+    {  28,  9,  36},
+    { 307,  9,  37},
+    {  30,  9,  37},
+    { 308,  9,  38},
+    {  31,  9,  38},
+    { 310,  9,  39},
+    {  34,  9,  39},
+    { 311,  9,  40},
+    {  35,  9,  40},
+    { 214,  9,  41},
+    {  53,  9,  41},
+    { 209,  9,  41},
+    { 212,  9,  42},
+    {  55,  9,  42},
+    { 207,  9,  42},
+    { 213,  9,  43},
+    {  56,  9,  43},
+    { 208,  9,  43},
+    { 237,  9,  44},
+    {  58,  9,  44},
+    { 249,  9,  44},
+    { 236,  9,  45},
+    {  60,  9,  45},
+    { 219,  9,  45},
+    { 238,  9,  46},
+    {  61,  9,  46},
+    { 263,  9,  46},
+    { 736,  9,  47},
+    {  62,  9,  47},
+    { 708,  9,  47},
+    {1053,  9,  48},
+    {  63,  9,  48},
+    {1045,  9,  48},
+    { 156,  9,  49},
+    {  64,  9,  49},
+    { 164,  9,  49},
+    { 155,  9,  50},
+    {  66,  9,  50},
+    { 154,  9,  50},
+    { 157,  9,  51},
+    {  67,  9,  51},
+    { 184,  9,  51},
+    { 478,  9,  52},
+    {  68,  9,  52},
+    { 453,  9,  52},
+    { 477,  9,  53},
+    {  69,  9,  53},
+    { 448,  9,  53},
+    { 655,  9,  54},
+    {  71,  9,  54},
+    { 658,  9,  54},
+    { 312,  9,  55},
+    {  36,  9,  55},
+    { 215,  9,  56},
+    {  49,  9,  56},
+    { 210,  9,  56},
+    { 910, 10,   0},
+    { 287, 10,   1},
+    { 284, 10,   1},
+    { 397, 10,   2},
+    { 386, 10,   2},
+    { 536, 10,   3},
+    { 907, 10,   4},
+    { 893, 10,   4},
+    { 646, 10,   5},
+    { 645, 10,   5},
+    { 833, 10,   6},
+    { 832, 10,   6},
+    { 531, 10,   7},
+    { 530, 10,   7},
+    { 660, 10,   8},
+    { 659, 10,   8},
+    { 351, 10,   9},
+    { 496, 10,   9},
+    {1137, 10,  10},
+    {1133, 10,  10},
+    {1128, 10,  11},
+    {1238, 10,  12},
+    {1237, 10,  12},
+    {1256, 10,  13},
+    { 892, 10,  14},
+    { 890, 10,  14},
+    {1108, 10,  15},
+    {1111, 10,  15},
+    {1124, 10,  16},
+    {1123, 10,  16},
+    { 539, 10,  17},
+    { 538, 10,  17},
+    { 897, 11,   0},
+    { 885, 11,   0},
+    { 176, 11,   1},
+    { 154, 11,   1},
+    { 587, 11,   2},
+    { 581, 11,   2},
+    {1256, 11,   3},
+    {1250, 11,   3},
+    { 541, 11,   4},
+    { 525, 11,   4},
+    { 892, 11,   5},
+    { 887, 11,   5},
+    { 908, 12,   0},
+    { 163, 12,   1},
+    { 165, 12,   2},
+    { 168, 12,   3},
+    { 235, 12,   4},
+    { 241, 12,   5},
+    { 449, 12,   6},
+    { 450, 12,   7},
+    { 486, 12,   8},
+    { 529, 12,   9},
+    { 533, 12,  10},
+    { 542, 12,  11},
+    { 543, 12,  12},
+    { 584, 12,  13},
+    { 589, 12,  14},
+    {1184, 12,  14},
+    { 604, 12,  15},
+    { 608, 12,  16},
+    { 609, 12,  17},
+    { 610, 12,  18},
+    { 678, 12,  19},
+    { 689, 12,  20},
+    { 705, 12,  21},
+    { 710, 12,  22},
+    { 711, 12,  23},
+    { 834, 12,  24},
+    { 848, 12,  25},
+    { 915, 12,  26},
+    { 930, 12,  27},
+    { 997, 12,  28},
+    {1039, 12,  29},
+    {1040, 12,  30},
+    {1049, 12,  31},
+    {1051, 12,  32},
+    {1071, 12,  33},
+    {1072, 12,  34},
+    {1084, 12,  35},
+    {1086, 12,  36},
+    {1095, 12,  37},
+    {1155, 12,  38},
+    {1169, 12,  39},
+    {1182, 12,  40},
+    {1183, 12,  41},
+    {1189, 12,  42},
+    {1253, 12,  43},
+    {1163, 12,  44},
+    {1272, 12,  45},
+    {1273, 12,  46},
+    {1274, 12,  47},
+    {1282, 12,  48},
+    {1283, 12,  49},
+    {1286, 12,  50},
+    {1287, 12,  51},
+    { 695, 12,  52},
+    { 528, 12,  53},
+    { 278, 12,  54},
+    { 527, 12,  55},
+    { 932, 12,  56},
+    {1063, 12,  57},
+    {1127, 12,  58},
+    { 795, 12,  59},
+    { 796, 12,  60},
+    { 797, 12,  61},
+    { 798, 12,  62},
+    { 799, 12,  63},
+    { 800, 12,  64},
+    { 801, 12,  65},
+    { 802, 12,  66},
+    { 803, 12,  67},
+    { 804, 12,  68},
+    { 805, 12,  69},
+    { 806, 12,  70},
+    { 807, 12,  71},
+    { 808, 12,  72},
+    { 809, 12,  73},
+    { 810, 12,  74},
+    { 811, 12,  75},
+    { 812, 12,  76},
+    { 813, 12,  77},
+    { 814, 12,  78},
+    { 815, 12,  79},
+    { 816, 12,  80},
+    { 817, 12,  81},
+    { 818, 12,  82},
+    { 819, 12,  83},
+    { 820, 12,  84},
+    { 821, 12,  85},
+    { 912, 13,   0},
+    {1214, 13,   0},
+    { 670, 13,   1},
+    { 281, 13,   1},
+    { 483, 13,   2},
+    { 447, 13,   2},
+    {1054, 13,   3},
+    {1045, 13,   3},
+    { 738, 13,   4},
+    { 708, 13,   4},
+    {1210, 13,   5},
+    {1164, 13,   5},
+    {1224, 14,   0},
+    {1270, 14,   0},
+    { 955, 14,   1},
+    { 954, 14,   1},
+    { 381, 14,   2},
+    { 378, 14,   2},
+    {1043, 14,   3},
+    {1042, 14,   3},
+    { 559, 14,   4},
+    { 556, 14,   4},
+    { 914, 14,   5},
+    { 919, 14,   5},
+    { 520, 14,   6},
+    { 519, 14,   6},
+    { 273, 14,   7},
+    {1156, 14,   7},
+    { 643, 14,   8},
+    { 658, 14,   8},
+    {1025, 14,   9},
+    {1024, 14,   9},
+    {1022, 14,  10},
+    {1015, 14,  10},
+    { 927, 14,  11},
+    { 922, 14,  11},
+    { 172, 14,  12},
+    { 164, 14,  12},
+    { 630, 14,  13},
+    { 626, 14,  13},
+    { 652, 14,  14},
+    { 639, 14,  14},
+    { 653, 14,  14},
+    { 625, 14,  15},
+    { 624, 14,  15},
+    { 392, 14,  16},
+    { 382, 14,  16},
+    { 271, 14,  17},
+    { 233, 14,  17},
+    { 270, 14,  18},
+    { 221, 14,  18},
+    {1117, 14,  19},
+    {1116, 14,  19},
+    { 792, 14,  20},
+    { 248, 14,  20},
+    { 293, 14,  21},
+    { 424, 14,  21},
+    { 758, 14,  22},
+    { 748, 14,  22},
+    { 414, 14,  23},
+    { 298, 14,  23},
+    { 399, 14,  24},
+    {1070, 14,  24},
+    { 176, 14,  25},
+    { 162, 14,  25},
+    { 272, 14,  26},
+    { 220, 14,  26},
+    {1153, 14,  27},
+    {1090, 14,  27},
+    {1293, 14,  28},
+    {1292, 14,  28},
+    { 900, 14,  29},
+    { 904, 14,  29},
+    {1260, 14,  30},
+    {1257, 14,  30},
+    { 668, 14,  31},
+    { 676, 14,  32},
+    { 675, 14,  33},
+    { 582, 14,  34},
+    { 583, 14,  35},
+    { 380, 14,  36},
+    { 422, 14,  36},
+    { 607, 14,  37},
+    { 618, 14,  37},
+    { 400, 14,  38},
+    { 352, 14,  38},
+    {1047, 14,  39},
+    {1052, 14,  39},
+    { 910, 15,   0},
+    { 927, 15,   1},
+    { 922, 15,   1},
+    { 473, 15,   2},
+    { 466, 15,   2},
+    { 455, 15,   3},
+    { 454, 15,   3},
+    { 889, 16,   0},
+    {   0, 16,   1},
+    {   1, 16,   2},
+    {   5, 16,   3},
+    {   4, 16,   4},
+    {   3, 16,   5},
+    {  13, 16,   6},
+    {  12, 16,   7},
+    {  11, 16,   8},
+    {  10, 16,   9},
+    {  78, 16,  10},
+    {   9, 16,  11},
+    {   8, 16,  12},
+    {   7, 16,  13},
+    {  82, 16,  14},
+    {  47, 16,  15},
+    { 115, 16,  16},
+    {   6, 16,  17},
+    { 131, 16,  18},
+    {  81, 16,  19},
+    { 118, 16,  20},
+    {  46, 16,  21},
+    {  80, 16,  22},
+    {  98, 16,  23},
+    { 117, 16,  24},
+    { 133, 16,  25},
+    {  26, 16,  26},
+    {   2, 16,  27},
+    {  79, 16,  28},
+    {  45, 16,  29},
+    { 116, 16,  30},
+    {  77, 16,  31},
+    { 132, 16,  32},
+    {  97, 16,  33},
+    { 147, 16,  34},
+    { 114, 16,  35},
+    {  27, 16,  36},
+    { 124, 16,  37},
+    {  33, 16,  38},
+    { 130, 16,  39},
+    {  39, 16,  40},
+    { 139, 16,  41},
+    {  42, 16,  42},
+    { 146, 16,  43},
+    {  14, 16,  44},
+    {  25, 16,  45},
+    {  29, 16,  46},
+    {  32, 16,  47},
+    {  37, 16,  48},
+    {  38, 16,  49},
+    {  40, 16,  50},
+    {  41, 16,  51},
+    {  43, 16,  52},
+    {  44, 16,  53},
+    {  48, 16,  54},
+    {  54, 16,  55},
+    {  59, 16,  56},
+    {  65, 16,  57},
+    {  70, 16,  58},
+    {  72, 16,  59},
+    {  73, 16,  60},
+    {  74, 16,  61},
+    {  75, 16,  62},
+    {  76, 16,  63},
+    {  83, 16,  64},
+    {  88, 16,  65},
+    {  89, 16,  66},
+    {  90, 16,  67},
+    {  91, 16,  68},
+    {  92, 16,  69},
+    {  93, 16,  70},
+    {  94, 16,  71},
+    {  95, 16,  72},
+    {  96, 16,  73},
+    {  99, 16,  74},
+    { 104, 16,  75},
+    { 105, 16,  76},
+    { 106, 16,  77},
+    { 108, 16,  78},
+    { 109, 16,  79},
+    { 110, 16,  80},
+    { 111, 16,  81},
+    { 112, 16,  82},
+    { 113, 16,  83},
+    { 119, 16,  84},
+    { 125, 16,  85},
+    { 134, 16,  86},
+    { 140, 16,  87},
+    { 148, 16,  88},
+    {  15, 16,  89},
+    {  49, 16,  90},
+    {  84, 16,  91},
+    { 100, 16,  92},
+    { 120, 16,  93},
+    { 126, 16,  94},
+    { 135, 16,  95},
+    { 141, 16,  96},
+    { 149, 16,  97},
+    {  16, 16,  98},
+    {  50, 16,  99},
+    {  85, 16, 100},
+    { 101, 16, 101},
+    { 121, 16, 102},
+    { 127, 16, 103},
+    { 136, 16, 104},
+    { 142, 16, 105},
+    { 150, 16, 106},
+    {  17, 16, 107},
+    {  51, 16, 108},
+    {  86, 16, 109},
+    { 102, 16, 110},
+    { 122, 16, 111},
+    { 128, 16, 112},
+    { 137, 16, 113},
+    { 143, 16, 114},
+    { 151, 16, 115},
+    {  18, 16, 116},
+    {  52, 16, 117},
+    {  57, 16, 118},
+    {  87, 16, 119},
+    { 103, 16, 120},
+    { 107, 16, 121},
+    { 123, 16, 122},
+    { 129, 16, 123},
+    { 138, 16, 124},
+    { 144, 16, 125},
+    { 152, 16, 126},
+    {  19, 16, 127},
+    {  20, 16, 128},
+    {  21, 16, 129},
+    {  22, 16, 130},
+    { 887, 17,   0},
+    {1053, 17,   1},
+    { 736, 17,   2},
+    {1242, 17,   3},
+    { 737, 17,   4},
+    {1203, 17,   5},
+    { 259, 17,   6},
+    {1204, 17,   7},
+    {1208, 17,   8},
+    {1206, 17,   9},
+    {1207, 17,  10},
+    { 260, 17,  11},
+    {1205, 17,  12},
+    { 980, 17,  13},
+    { 963, 18,   0},
+    { 247, 18,   1},
+    {1241, 18,   2},
+    { 216, 18,   3},
+    { 923, 18,   4},
+    {1240, 18,   5},
+    {1036, 18,   6},
+    { 654, 18,   7},
+    {1245, 18,   8},
+    {1244, 18,   9},
+    {1243, 18,  10},
+    { 408, 18,  11},
+    { 402, 18,  12},
+    { 403, 18,  13},
+    { 413, 18,  14},
+    { 410, 18,  15},
+    { 409, 18,  16},
+    { 412, 18,  17},
+    { 411, 18,  18},
+    { 407, 18,  19},
+    { 404, 18,  20},
+    { 405, 18,  21},
+    { 869, 18,  22},
+    {1201, 18,  23},
+    {1202, 18,  24},
+    { 546, 18,  25},
+    { 290, 18,  26},
+    {1048, 18,  27},
+    {1157, 18,  28},
+    { 406, 18,  29},
+    { 911, 18,  30},
+    { 672, 18,  31},
+    { 926, 18,  32},
+    { 924, 18,  33},
+    { 266, 18,  34},
+};
+
+/* property values: 5648 bytes. */
+
+/* Codepoints which expand on full case-folding. */
+
+RE_UINT16 re_expand_on_folding[] = {
+      223,   304,   329,   496,   912,   944,  1415,  7830,
+     7831,  7832,  7833,  7834,  7838,  8016,  8018,  8020,
+     8022,  8064,  8065,  8066,  8067,  8068,  8069,  8070,
+     8071,  8072,  8073,  8074,  8075,  8076,  8077,  8078,
+     8079,  8080,  8081,  8082,  8083,  8084,  8085,  8086,
+     8087,  8088,  8089,  8090,  8091,  8092,  8093,  8094,
+     8095,  8096,  8097,  8098,  8099,  8100,  8101,  8102,
+     8103,  8104,  8105,  8106,  8107,  8108,  8109,  8110,
+     8111,  8114,  8115,  8116,  8118,  8119,  8124,  8130,
+     8131,  8132,  8134,  8135,  8140,  8146,  8147,  8150,
+     8151,  8162,  8163,  8164,  8166,  8167,  8178,  8179,
+     8180,  8182,  8183,  8188, 64256, 64257, 64258, 64259,
+    64260, 64261, 64262, 64275, 64276, 64277, 64278, 64279,
+};
+
+/* expand_on_folding: 208 bytes. */
+
+/* General_Category. */
+
+static RE_UINT8 re_general_category_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 14, 14, 14, 15,
+    16, 17, 18, 19, 20, 21, 22, 21, 23, 21, 21, 21, 21, 24, 21, 21,
+    21, 21, 21, 21, 21, 21, 25, 26, 21, 21, 27, 28, 21, 29, 30, 31,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 32,  7, 33, 34,  7, 35, 21, 21, 21, 21, 21, 36,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 38,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 38,
+};
+
+static RE_UINT8 re_general_category_stage_2[] = {
+      0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
+     16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
+     32,  33,  34,  34,  35,  36,  37,  38,  39,  34,  34,  34,  40,  41,  42,  43,
+     44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
+     60,  61,  62,  63,  64,  64,  65,  66,  67,  68,  69,  70,  71,  69,  72,  73,
+     69,  69,  64,  74,  64,  64,  75,  76,  77,  78,  79,  80,  81,  82,  69,  83,
+     84,  85,  86,  87,  88,  89,  69,  69,  34,  34,  34,  34,  34,  34,  34,  34,
+     34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,
+     34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  90,  34,  34,  34,  34,
+     34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  91,
+     92,  34,  34,  34,  34,  34,  34,  34,  34,  93,  34,  34,  94,  95,  96,  97,
+     98,  99, 100, 101, 102, 103, 104, 105,  34,  34,  34,  34,  34,  34,  34,  34,
+     34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34, 106,
+    107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+    108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+    108, 108,  34,  34, 109, 110, 111, 112,  34,  34, 113, 114, 115, 116, 117, 118,
+    119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 123,  34,  34, 130, 123,
+    131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 123, 123, 141, 123, 123, 123,
+    142, 143, 144, 145, 146, 147, 148, 123, 123, 149, 123, 150, 151, 152, 153, 123,
+    123, 154, 123, 123, 123, 155, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+     34,  34,  34,  34,  34,  34,  34, 156, 157,  34, 158, 123, 123, 123, 123, 123,
+    123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+     34,  34,  34,  34,  34,  34,  34,  34, 159, 123, 123, 123, 123, 123, 123, 123,
+    123, 123, 123, 123, 123, 123, 123, 123,  34,  34,  34,  34, 160, 123, 123, 123,
+     34,  34,  34,  34, 161, 162, 163, 164, 123, 123, 123, 123, 123, 123, 165, 166,
+    167, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+    123, 123, 123, 123, 123, 123, 123, 123, 168, 169, 123, 123, 123, 123, 123, 123,
+     69, 170, 171, 172, 173, 123, 174, 123, 175, 176, 177, 178, 179, 180, 181, 182,
+     69,  69,  69,  69, 183, 184, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+     34, 185, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 186, 187, 123, 123,
+    188, 189, 190, 191, 192, 123,  69, 193,  69,  69, 194, 195,  69, 196, 197, 198,
+    199, 200, 201, 202, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+     34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34, 203,  34,  34,
+     34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34, 204,  34,
+    205,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,
+     34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34, 206, 123, 123,
+     34,  34,  34,  34, 207, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+    208, 123, 209, 210, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+    108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 211,
+};
+
+static RE_UINT16 re_general_category_stage_3[] = {
+      0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
+     13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
+     13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
+     32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
+      9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
+     13,  13,  13,  42,   9,  43,  44,  11,  45,  46,  32,  47,  48,  49,  50,  51,
+     52,  53,  49,  49,  54,  32,  55,  56,  49,  49,  49,  49,  49,  57,  58,  59,
+     60,  61,  49,  32,  62,  49,  49,  49,  49,  49,  63,  64,  65,  49,  66,  67,
+     49,  68,  69,  70,  49,  71,  72,  72,  72,  72,  49,  73,  72,  72,  74,  32,
+     75,  49,  49,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,
+     89,  82,  83,  90,  91,  92,  93,  94,  95,  96,  83,  97,  98,  99,  87, 100,
+    101,  82,  83, 102, 103, 104,  87, 105, 106, 107, 108, 109, 110, 111,  93, 112,
+    113, 114,  83, 115, 116, 117,  87, 118, 119, 114,  83, 120, 121, 122,  87, 123,
+    119, 114,  49, 124, 125, 126,  87, 127, 128, 129,  49, 130, 131, 132,  93, 133,
+    134,  49,  49, 135, 136, 137,  72,  72, 138, 139, 140, 141, 142, 143,  72,  72,
+    144, 145, 146, 147, 148,  49, 149, 150, 151, 152,  32, 153, 154, 155,  72,  72,
+     49,  49, 156, 157, 158, 159, 160, 161, 162, 163,   9,   9, 164,  49,  49, 165,
+     49,  49,  49,  49,  49,  49,  49,  49,  49,  49,  49,  49, 166, 167,  49,  49,
+    166,  49,  49, 168, 169, 170,  49,  49,  49, 169,  49,  49,  49, 171, 172, 173,
+     49, 174,   9,   9,   9,   9,   9, 175, 176,  49,  49,  49,  49,  49,  49,  49,
+     49,  49,  49,  49,  49,  49, 177,  49, 178, 179,  49,  49,  49,  49, 180, 181,
+    182, 183,  49, 184,  49, 185, 182, 186,  49,  49,  49, 187, 188, 189, 190, 191,
+    192, 190,  49,  49, 193,  49,  49, 194,  49,  49, 195,  49,  49,  49,  49, 196,
+     49, 197, 198, 199, 200,  49, 201,  73,  49,  49, 202,  49, 203, 204, 205, 205,
+     49, 206,  49,  49,  49, 207, 208, 209, 190, 190, 210, 211,  72,  72,  72,  72,
+    212,  49,  49, 213, 214, 158, 215, 216, 217,  49, 218,  65,  49,  49, 219, 220,
+     49,  49, 221, 222, 223,  65,  49, 224,  72,  72,  72,  72, 225, 226, 227, 228,
+     11,  11, 229,  27,  27,  27, 230, 231,  11, 232,  27,  27,  32,  32,  32, 233,
+     13,  13,  13,  13,  13,  13,  13,  13,  13, 234,  13,  13,  13,  13,  13,  13,
+    235, 236, 235, 235, 236, 237, 235, 238, 239, 239, 239, 240, 241, 242, 243, 244,
+    245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256,  72, 257, 258, 259,
+    260, 261, 262, 263, 264, 265, 266, 266, 267, 268, 269, 205, 270, 271, 205, 272,
+    273, 273, 273, 273, 273, 273, 273, 273, 274, 205, 275, 205, 205, 205, 205, 276,
+    205, 277, 273, 278, 205, 279, 280, 281, 205, 205, 282,  72, 281,  72, 265, 265,
+    265, 283, 205, 205, 205, 205, 284, 265, 205, 205, 205, 205, 205, 205, 205, 205,
+    205, 205, 205, 285, 286, 205, 205, 287, 205, 205, 205, 205, 205, 205, 288, 205,
+    205, 205, 205, 205, 205, 205, 289, 290, 265, 291, 205, 205, 292, 273, 293, 273,
+    294, 295, 273, 273, 273, 296, 273, 297, 205, 205, 205, 273, 298, 205, 205, 299,
+    205, 300, 205, 301, 302, 303, 304,  72,   9,   9, 305,  11,  11, 306, 307, 308,
+     13,  13,  13,  13,  13,  13, 309, 310,  11,  11, 311,  49,  49,  49, 312, 313,
+     49, 314, 315, 315, 315, 315,  32,  32, 316, 317, 318, 319, 320,  72,  72,  72,
+    205, 321, 205, 205, 205, 205, 205, 322, 205, 205, 205, 205, 205, 323,  72, 324,
+    325, 326, 327, 328, 134,  49,  49,  49,  49, 329, 176,  49,  49,  49,  49, 330,
+    331,  49, 201, 134,  49,  49,  49,  49, 197, 332,  49,  50, 205, 205, 322,  49,
+    205, 333, 334, 205, 335, 336, 205, 205, 334, 205, 205, 336, 205, 205, 205, 333,
+     49,  49,  49, 196, 205, 205, 205, 205,  49,  49,  49,  49,  49, 196,  72,  72,
+     49, 337,  49,  49,  49,  49,  49,  49, 149, 205, 205, 205, 282,  49,  49, 224,
+    338,  49, 339,  72,  13,  13, 340, 341,  13, 342,  49,  49,  49,  49, 343, 344,
+     31, 345, 346, 347,  13,  13,  13, 348, 349, 350, 351, 352,  72,  72,  72, 353,
+    354,  49, 355, 356,  49,  49,  49, 357, 358,  49,  49, 359, 360, 190,  32, 361,
+     65,  49, 362,  49, 363, 364,  49, 149,  75,  49,  49, 365, 366, 367, 368, 369,
+     49,  49, 370, 371, 372, 373,  49, 374,  49,  49,  49, 375, 376, 377, 378, 379,
+    380, 381, 315,  11,  11, 382, 383,  11,  11,  11,  11,  11,  49,  49, 384, 190,
+     49,  49, 385,  49, 386,  49,  49, 202, 387, 387, 387, 387, 387, 387, 387, 387,
+    388, 388, 388, 388, 388, 388, 388, 388,  49,  49,  49,  49,  49,  49, 201,  49,
+     49,  49,  49,  49,  49, 203,  72,  72, 389, 390, 391, 392, 393,  49,  49,  49,
+     49,  49,  49, 394, 395, 396,  49,  49,  49,  49,  49, 397,  72,  49,  49,  49,
+     49, 398,  49,  49, 194,  72,  72, 399,  32, 400,  32, 401, 402, 403, 404, 405,
+     49,  49,  49,  49,  49,  49,  49, 406, 407,   2,   3,   4,   5, 408, 409, 410,
+     49, 411,  49, 197, 412, 413, 414, 415, 416,  49, 170, 417, 201, 201,  72,  72,
+     49,  49,  49,  49,  49,  49,  49,  50, 418, 265, 265, 419, 266, 266, 266, 420,
+    421, 324, 422,  72,  72, 205, 205, 423,  72,  72,  72,  72,  72,  72,  72,  72,
+     49, 149,  49,  49,  49,  99, 424, 425,  49,  49, 426,  49, 427,  49,  49, 428,
+     49, 429,  49,  49, 430, 431,  72,  72,   9,   9, 432,  11,  11,  49,  49,  49,
+     49, 201, 190,  72,  72,  72,  72,  72,  49,  49, 194,  49,  49,  49, 433,  72,
+     49,  49,  49, 314,  49, 196, 194,  72, 434,  49,  49, 435,  49, 436,  49, 437,
+     49, 197, 438,  72,  72,  72,  49, 439,  49, 440,  49, 441,  72,  72,  72,  72,
+     49,  49,  49, 442, 265, 443, 265, 265, 444, 445,  49, 446, 447, 448,  49, 449,
+     49, 450,  72,  72, 451,  49, 452, 453,  49,  49,  49, 454,  49, 455,  49, 456,
+     49, 457, 458,  72,  72,  72,  72,  72,  49,  49,  49,  49, 459,  72,  72,  72,
+      9,   9,   9, 460,  11,  11,  11, 461,  72,  72,  72,  72,  72,  72, 265, 462,
+    463,  49,  49, 464, 465, 443, 466, 467, 217,  49,  49, 468, 469,  49, 459, 190,
+    470,  49, 471, 472, 473,  49,  49, 474, 217,  49,  49, 475, 476, 477, 478, 479,
+     49,  96, 480, 481,  72,  72,  72,  72, 482, 483, 484,  49,  49, 485, 486, 190,
+    487,  82,  83,  97, 488, 489, 490, 491,  49,  49,  49, 492, 493, 190,  72,  72,
+     49,  49, 494, 495, 496, 497,  72,  72,  49,  49,  49, 498, 499, 190,  72,  72,
+     49,  49, 500, 501, 190,  72,  72,  72,  49, 502, 503, 504,  72,  72,  72,  72,
+     72,  72,   9,   9,  11,  11, 146, 505,  72,  72,  72,  72,  49,  49,  49, 459,
+     49, 203,  72,  72,  72,  72,  72,  72, 266, 266, 266, 266, 266, 266, 506, 507,
+     49,  49,  49,  49, 385,  72,  72,  72,  49,  49, 197,  72,  72,  72,  72,  72,
+     49,  49,  49,  49, 314,  72,  72,  72,  49,  49,  49, 459,  49, 197, 367,  72,
+     72,  72,  72,  72,  72,  49, 201, 508,  49,  49,  49, 509, 510, 511, 512, 513,
+     49,  72,  72,  72,  72,  72,  72,  72,  49,  49,  49,  49,  73, 514, 515, 516,
+    467, 517,  72,  72,  72,  72,  72,  72, 518,  72,  72,  72,  72,  72,  72,  72,
+     49,  49,  49,  49,  49,  49,  50, 149, 459, 519, 520,  72,  72,  72,  72,  72,
+    205, 205, 205, 205, 205, 205, 205, 323, 205, 205, 521, 205, 205, 205, 522, 523,
+    524, 205, 525, 205, 205, 205, 526,  72, 205, 205, 205, 205, 527,  72,  72,  72,
+    205, 205, 205, 205, 205, 282, 265, 528,   9, 529,  11, 530, 531, 532, 235,   9,
+    533, 534, 535, 536, 537,   9, 529,  11, 538, 539,  11, 540, 541, 542, 543,   9,
+    544,  11,   9, 529,  11, 530, 531,  11, 235,   9, 533, 543,   9, 544,  11,   9,
+    529,  11, 545,   9, 546, 547, 548, 549,  11, 550,   9, 551, 552, 553, 554,  11,
+    555,   9, 556,  11, 557, 558, 558, 558,  32,  32,  32, 559,  32,  32, 560, 561,
+    562, 563,  46,  72,  72,  72,  72,  72,  49,  49,  49,  49, 564, 565,  72,  72,
+    566,  49, 567, 568, 569, 570, 571, 572, 573, 202, 574, 202,  72,  72,  72, 575,
+    205, 205, 324, 205, 205, 205, 205, 205, 205, 322, 333, 576, 576, 576, 205, 323,
+    173, 205, 333, 205, 205, 205, 324, 205, 205, 281,  72,  72,  72,  72, 577, 205,
+    578, 205, 205, 281, 526, 303,  72,  72, 205, 205, 205, 205, 205, 205, 205, 579,
+    205, 205, 205, 205, 205, 205, 205, 321, 205, 205, 580, 205, 205, 205, 205, 205,
+    205, 205, 205, 205, 205, 422, 581, 322, 205, 205, 205, 205, 205, 205, 205, 322,
+    205, 205, 205, 205, 205, 582,  72,  72, 324, 205, 205, 205, 583, 174, 205, 205,
+    583, 205, 584,  72,  72,  72,  72,  72,  72, 526,  72,  72,  72,  72,  72,  72,
+    582,  72,  72,  72, 422,  72,  72,  72,  49,  49,  49,  49,  49, 314,  72,  72,
+     49,  49,  49,  73,  49,  49,  49,  49,  49, 201,  49,  49,  49,  49,  49,  49,
+     49,  49, 518,  72,  72,  72,  72,  72,  49, 201,  72,  72,  72,  72,  72,  72,
+    585,  72, 586, 586, 586, 586, 586, 586,  32,  32,  32,  32,  32,  32,  32,  32,
+     32,  32,  32,  32,  32,  32,  32,  72, 388, 388, 388, 388, 388, 388, 388, 587,
+};
+
+static RE_UINT8 re_general_category_stage_4[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   3,   2,   4,   5,   6,   2,
+      7,   7,   7,   7,   7,   2,   8,   9,  10,  11,  11,  11,  11,  11,  11,  11,
+     11,  11,  11,  11,  11,  12,  13,  14,  15,  16,  16,  16,  16,  16,  16,  16,
+     16,  16,  16,  16,  16,  17,  18,  19,   1,  20,  20,  21,  22,  23,  24,  25,
+     26,  27,  15,   2,  28,  29,  27,  30,  11,  11,  11,  11,  11,  11,  11,  11,
+     11,  11,  11,  31,  11,  11,  11,  32,  16,  16,  16,  16,  16,  16,  16,  16,
+     16,  16,  16,  33,  16,  16,  16,  16,  32,  32,  32,  32,  32,  32,  32,  32,
+     32,  32,  32,  32,  34,  34,  34,  34,  34,  34,  34,  34,  16,  32,  32,  32,
+     32,  32,  32,  32,  11,  34,  34,  16,  34,  32,  32,  11,  34,  11,  16,  11,
+     11,  34,  32,  11,  32,  16,  11,  34,  32,  32,  32,  11,  34,  16,  32,  11,
+     34,  11,  34,  34,  32,  35,  32,  16,  36,  36,  37,  34,  38,  37,  34,  34,
+     34,  34,  34,  34,  34,  34,  16,  32,  34,  38,  32,  11,  32,  32,  32,  32,
+     32,  32,  16,  16,  16,  11,  34,  32,  34,  34,  11,  32,  32,  32,  32,  32,
+     16,  16,  39,  16,  16,  16,  16,  16,  40,  40,  40,  40,  40,  40,  40,  40,
+     40,  41,  41,  40,  40,  40,  40,  40,  40,  41,  41,  41,  41,  41,  41,  41,
+     40,  40,  42,  41,  41,  41,  42,  42,  41,  41,  41,  41,  41,  41,  41,  41,
+     43,  43,  43,  43,  43,  43,  43,  43,  32,  32,  42,  32,  44,  45,  16,  10,
+     44,  44,  41,  46,  11,  47,  47,  11,  34,  11,  11,  11,  11,  11,  11,  11,
+     11,  48,  11,  11,  11,  11,  16,  16,  16,  16,  16,  16,  16,  16,  16,  34,
+     16,  11,  32,  16,  32,  32,  32,  32,  16,  16,  32,  49,  34,  32,  34,  11,
+     32,  50,  43,  43,  51,  32,  32,  32,  11,  34,  34,  34,  34,  34,  34,  16,
+     48,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  47,  52,   2,   2,   2,
+     53,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  54,  55,  56,  57,
+     58,  43,  43,  43,  43,  43,  43,  43,  43,  43,  43,  43,  43,  43,  43,  59,
+     60,  61,  43,  60,  44,  44,  44,  44,  36,  36,  36,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  62,  44,  44,  36,  63,  64,  44,  44,  44,  44,  44,
+     65,  65,  65,   8,   9,  66,   2,  67,  43,  43,  43,  43,  43,  61,  68,   2,
+     69,  36,  36,  36,  36,  70,  43,  43,   7,   7,   7,   7,   7,   2,   2,  36,
+     71,  36,  36,  36,  36,  36,  36,  36,  36,  36,  72,  43,  43,  43,  73,  50,
+     43,  43,  74,  75,  76,  43,  43,  36,   7,   7,   7,   7,   7,  36,  77,  78,
+      2,   2,   2,   2,   2,   2,   2,  79,  70,  36,  36,  36,  36,  36,  36,  36,
+     43,  43,  43,  43,  43,  80,  81,  36,  36,  36,  36,  43,  43,  43,  43,  43,
+     71,  44,  44,  44,  44,  44,  44,  44,   7,   7,   7,   7,   7,  36,  36,  36,
+     36,  36,  36,  36,  36,  70,  43,  43,  43,  43,  40,  21,   2,  82,  44,  44,
+     36,  36,  36,  43,  43,  75,  43,  43,  43,  43,  75,  43,  75,  43,  43,  44,
+      2,   2,   2,   2,   2,   2,   2,  64,  36,  36,  36,  36,  70,  43,  44,  64,
+     44,  44,  44,  44,  44,  44,  44,  44,  36,  36,  62,  44,  44,  44,  44,  44,
+     44,  58,  43,  43,  43,  43,  43,  43,  43,  83,  36,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  83,  71,  84,  85,  43,  43,  43,  83,  84,  85,  84,
+     70,  43,  43,  43,  36,  36,  36,  36,  36,  43,   2,   7,   7,   7,   7,   7,
+     86,  36,  36,  36,  36,  36,  36,  36,  70,  84,  81,  36,  36,  36,  62,  81,
+     62,  81,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  62,  36,  36,  36,
+     62,  62,  44,  36,  36,  44,  71,  84,  85,  43,  80,  87,  88,  87,  85,  62,
+     44,  44,  44,  87,  44,  44,  36,  81,  36,  43,  44,   7,   7,   7,   7,   7,
+     36,  20,  27,  27,  27,  57,  44,  44,  58,  83,  81,  36,  36,  62,  44,  81,
+     62,  36,  81,  62,  36,  44,  80,  84,  85,  80,  44,  58,  80,  58,  43,  44,
+     58,  44,  44,  44,  81,  36,  62,  62,  44,  44,  44,   7,   7,   7,   7,   7,
+     43,  36,  70,  44,  44,  44,  44,  44,  58,  83,  81,  36,  36,  36,  36,  81,
+     36,  81,  36,  36,  36,  36,  36,  36,  62,  36,  81,  36,  36,  44,  71,  84,
+     85,  43,  43,  58,  83,  87,  85,  44,  62,  44,  44,  44,  44,  44,  44,  44,
+     66,  44,  44,  44,  81,  44,  44,  44,  58,  84,  81,  36,  36,  36,  62,  81,
+     62,  36,  81,  36,  36,  44,  71,  85,  85,  43,  80,  87,  88,  87,  85,  44,
+     44,  44,  44,  83,  44,  44,  36,  81,  78,  27,  27,  27,  44,  44,  44,  44,
+     44,  71,  81,  36,  36,  62,  44,  36,  62,  36,  36,  44,  81,  62,  62,  36,
+     44,  81,  62,  44,  36,  62,  44,  36,  36,  36,  36,  36,  36,  44,  44,  84,
+     83,  88,  44,  84,  88,  84,  85,  44,  62,  44,  44,  87,  44,  44,  44,  44,
+     27,  89,  67,  67,  57,  90,  44,  44,  83,  84,  81,  36,  36,  36,  62,  36,
+     62,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  44,  81,  43,
+     83,  84,  88,  43,  80,  43,  43,  44,  44,  44,  58,  80,  36,  62,  44,  44,
+     44,  44,  44,  44,  27,  27,  27,  89,  58,  84,  81,  36,  36,  36,  62,  36,
+     36,  36,  81,  36,  36,  44,  71,  85,  84,  84,  88,  83,  88,  84,  43,  44,
+     44,  44,  87,  88,  44,  44,  44,  62,  81,  62,  44,  44,  44,  44,  44,  44,
+     36,  36,  36,  36,  36,  62,  81,  84,  85,  43,  80,  84,  88,  84,  85,  62,
+     44,  44,  44,  87,  44,  44,  44,  81,  27,  27,  27,  44,  56,  36,  36,  36,
+     44,  84,  81,  36,  36,  36,  36,  36,  36,  36,  36,  62,  44,  36,  36,  36,
+     36,  81,  36,  36,  36,  36,  81,  44,  36,  36,  36,  62,  44,  80,  44,  87,
+     84,  43,  80,  80,  84,  84,  84,  84,  44,  84,  64,  44,  44,  44,  44,  44,
+     81,  36,  36,  36,  36,  36,  36,  36,  70,  36,  43,  43,  43,  80,  44,  91,
+     36,  36,  36,  75,  43,  43,  43,  61,   7,   7,   7,   7,   7,   2,  44,  44,
+     81,  62,  62,  81,  62,  62,  81,  44,  44,  44,  36,  36,  81,  36,  36,  36,
+     81,  36,  81,  81,  44,  36,  81,  36,  70,  36,  43,  43,  43,  58,  71,  44,
+     36,  36,  62,  82,  43,  43,  43,  44,   7,   7,   7,   7,   7,  44,  36,  36,
+     77,  67,   2,   2,   2,   2,   2,   2,   2,  92,  92,  67,  43,  67,  67,  67,
+      7,   7,   7,   7,   7,  27,  27,  27,  27,  27,  50,  50,  50,   4,   4,  84,
+     36,  36,  36,  36,  81,  36,  36,  36,  36,  36,  36,  36,  36,  36,  62,  44,
+     58,  43,  43,  43,  43,  43,  43,  83,  43,  43,  61,  43,  36,  36,  70,  43,
+     43,  43,  43,  43,  58,  43,  43,  43,  43,  43,  43,  43,  43,  43,  80,  67,
+     67,  67,  67,  76,  67,  67,  90,  67,   2,   2,  92,  67,  21,  64,  44,  44,
+     36,  36,  36,  36,  36,  93,  85,  43,  83,  43,  43,  43,  85,  83,  85,  71,
+      7,   7,   7,   7,   7,   2,   2,   2,  36,  36,  36,  84,  43,  36,  36,  43,
+     71,  84,  94,  93,  84,  84,  84,  36,  70,  43,  71,  36,  36,  36,  36,  36,
+     36,  83,  85,  83,  84,  84,  85,  93,   7,   7,   7,   7,   7,  84,  85,  67,
+     11,  11,  11,  48,  44,  44,  48,  44,  36,  36,  36,  36,  36,  63,  69,  36,
+     36,  36,  36,  36,  62,  36,  36,  44,  36,  36,  36,  62,  62,  36,  36,  44,
+     62,  36,  36,  44,  36,  36,  36,  62,  62,  36,  36,  44,  36,  36,  36,  36,
+     36,  36,  36,  62,  36,  36,  36,  36,  36,  36,  36,  36,  36,  62,  58,  43,
+      2,   2,   2,   2,  95,  27,  27,  27,  27,  27,  27,  27,  27,  27,  96,  44,
+     67,  67,  67,  67,  67,  44,  44,  44,  11,  11,  11,  44,  16,  16,  16,  44,
+     97,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  63,  72,
+     98,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  99, 100,  44,
+     36,  36,  36,  36,  36,  63,   2, 101, 102,  36,  36,  36,  62,  44,  44,  44,
+     36,  36,  36,  36,  36,  36,  62,  36,  36,  43,  80,  44,  44,  44,  44,  44,
+     36,  43,  61,  64,  44,  44,  44,  44,  36,  43,  44,  44,  44,  44,  44,  44,
+     62,  43,  44,  44,  44,  44,  44,  44,  36,  36,  43,  85,  43,  43,  43,  84,
+     84,  84,  84,  83,  85,  43,  43,  43,  43,  43,   2,  86,   2,  66,  70,  44,
+      7,   7,   7,   7,   7,  44,  44,  44,  27,  27,  27,  27,  27,  44,  44,  44,
+      2,   2,   2, 103,   2,  60,  43,  68,  36, 104,  36,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  44,  44,  44,  44,  36,  36,  36,  36,  70,  62,  44,  44,
+     36,  36,  36,  44,  44,  44,  44,  44,  36,  36,  36,  36,  36,  36,  36,  62,
+     43,  83,  84,  85,  83,  84,  44,  44,  84,  83,  84,  84,  85,  43,  44,  44,
+     90,  44,   2,   7,   7,   7,   7,   7,  36,  36,  36,  36,  36,  36,  36,  44,
+     36,  36,  36,  36,  36,  36,  44,  44,  36,  36,  36,  36,  36,  44,  44,  44,
+      7,   7,   7,   7,   7,  96,  44,  67,  67,  67,  67,  67,  67,  67,  67,  67,
+     36,  36,  36,  70,  83,  85,  44,   2,  36,  36,  93,  83,  43,  43,  43,  80,
+     83,  83,  85,  43,  43,  43,  83,  84,  84,  85,  43,  43,  43,  43,  80,  58,
+      2,   2,   2,  86,   2,   2,   2,  44,  43,  43,  43,  43,  43,  43,  43, 105,
+     43,  43,  94,  36,  36,  36,  36,  36,  36,  36,  83,  43,  43,  83,  83,  84,
+     84,  83,  94,  36,  36,  36,  44,  44,  92,  67,  67,  67,  67,  50,  43,  43,
+     43,  43,  67,  67,  67,  67,  90,  44,  43,  94,  36,  36,  36,  36,  36,  36,
+     93,  43,  43,  84,  43,  85,  43,  36,  36,  36,  36,  83,  43,  84,  85,  85,
+     43,  84,  44,  44,  44,  44,   2,   2,  36,  36,  84,  84,  84,  84,  43,  43,
+     43,  43,  84,  43,  44,  54,   2,   2,   7,   7,   7,   7,   7,  44,  81,  36,
+     36,  36,  36,  36,  40,  40,  40,   2,   2,   2,   2,   2,  44,  44,  44,  44,
+     43,  61,  43,  43,  43,  43,  43,  43,  83,  43,  43,  43,  71,  36,  70,  36,
+     36,  84,  71,  62,  43,  44,  44,  44,  16,  16,  16,  16,  16,  16,  40,  40,
+     40,  40,  40,  40,  40,  45,  16,  16,  16,  16,  16,  16,  45,  16,  16,  16,
+     16,  16,  16,  16,  16, 106,  40,  40,  43,  43,  43,  44,  44,  44,  43,  43,
+     32,  32,  32,  16,  16,  16,  16,  32,  16,  16,  16,  16,  11,  11,  11,  11,
+     16,  16,  16,  44,  11,  11,  11,  44,  16,  16,  16,  16,  48,  48,  48,  48,
+     16,  16,  16,  16,  16,  16,  16,  44,  16,  16,  16,  16, 107, 107, 107, 107,
+     16,  16, 108,  16,  11,  11, 109, 110,  41,  16, 108,  16,  11,  11, 109,  41,
+     16,  16,  44,  16,  11,  11, 111,  41,  16,  16,  16,  16,  11,  11, 112,  41,
+     44,  16, 108,  16,  11,  11, 109, 113, 114, 114, 114, 114, 114, 115,  65,  65,
+    116, 116, 116,   2, 117, 118, 117, 118,   2,   2,   2,   2, 119,  65,  65, 120,
+      2,   2,   2,   2, 121, 122,   2, 123, 124,   2, 125, 126,   2,   2,   2,   2,
+      2,   9, 124,   2,   2,   2,   2, 127,  65,  65,  68,  65,  65,  65,  65,  65,
+    128,  44,  27,  27,  27,   8, 125, 129,  27,  27,  27,  27,  27,   8, 125, 100,
+     40,  40,  40,  40,  40,  40,  82,  44,  20,  20,  20,  20,  20,  20,  20,  20,
+     20,  20,  20,  20,  20,  20,  20, 130,  43,  43,  43,  43,  43,  43, 131,  51,
+    132,  51, 132,  43,  43,  43,  43,  43,  80,  44,  44,  44,  44,  44,  44,  44,
+     67, 133,  67, 134,  67,  34,  11,  16,  11,  32, 134,  67,  49,  11,  11,  67,
+     67,  67, 133, 133, 133,  11,  11, 135,  11,  11,  35,  36,  39,  67,  16,  11,
+      8,   8,  49,  16,  16,  26,  67, 136,  27,  27,  27,  27,  27,  27,  27,  27,
+    101, 101, 101, 101, 101, 101, 101, 101, 101, 137, 138, 101, 139,  67,  44,  44,
+      8,   8, 140,  67,  67,   8,  67,  67, 140,  26,  67, 140,  67,  67,  67, 140,
+     67,  67,  67,  67,  67,  67,  67,   8,  67, 140, 140,  67,  67,  67,  67,  67,
+     67,  67,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,
+     67,  67,  67,  67,   4,   4,  67,  67,   8,  67,  67,  67, 141, 142,  67,  67,
+     67,  67,  67,  67,  67,  67, 140,  67,  67,  67,  67,  67,  67,  26,   8,   8,
+      8,   8,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,   8,   8,
+      8,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  90,  44,  44,
+     67,  67,  67,  90,  44,  44,  44,  44,  27,  27,  27,  27,  27,  27,  67,  67,
+     67,  67,  67,  67,  67,  27,  27,  27,  67,  67,  67,  26,  67,  67,  67,  67,
+     26,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,   8,   8,   8,   8,
+     67,  67,  67,  67,  67,  67,  67,  26,  67,  67,  67,  67,   4,   4,   4,   4,
+      4,   4,   4,  27,  27,  27,  27,  27,  27,  27,  67,  67,  67,  67,  67,  67,
+      8,   8, 125, 143,   8,   8,   8,   8,   8,   8,   8,   4,   4,   4,   4,   4,
+      8, 125, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 143,   8,   8,   8,
+      8,   8,   8,   8,   4,   4,   8,   8,   8,   8,   8,   8,   8,   8,   4,   8,
+      8,   8, 140,  26,   8,   8, 140,  67,  67,  67,  44,  67,  67,  67,  67,  67,
+     67,  67,  67,  44,  67,  67,  67,  67,  67,  67,  67,  67,  67,  44,  56,  67,
+     67,  67,  67,  67,  90,  67,  67,  67,  67,  44,  44,  44,  44,  44,  44,  44,
+     44,  44,  44,  44,  44,  44,  67,  67,  11,  11,  11,  11,  11,  11,  11,  47,
+     16,  16,  16,  16,  16,  16,  16, 108,  32,  11,  32,  34,  34,  34,  34,  11,
+     32,  32,  34,  16,  16,  16,  40,  11,  32,  32, 136,  67,  67, 134,  34, 145,
+     43,  32,  44,  44,  54,   2,  95,   2,  16,  16,  16,  53,  44,  44,  53,  44,
+     36,  36,  36,  36,  44,  44,  44,  52,  64,  44,  44,  44,  44,  44,  44,  58,
+     36,  36,  36,  62,  44,  44,  44,  44,  36,  36,  36,  62,  36,  36,  36,  62,
+      2, 117, 117,   2, 121, 122, 117,   2,   2,   2,   2,   6,   2, 103, 117,   2,
+    117,   4,   4,   4,   4,   2,   2,  86,   2,   2,   2,   2,   2, 116,   2,   2,
+    103, 146,  44,  44,  44,  44,  44,  44,  67,  67,  67,  67,  67,  56,  67,  67,
+     67,  67,  44,  44,  44,  44,  44,  44,  67,  67,  67,  44,  44,  44,  44,  44,
+     67,  67,  67,  67,  67,  67,  44,  44,   1,   2, 147, 148,   4,   4,   4,   4,
+      4,  67,   4,   4,   4,   4, 149, 150, 151, 101, 101, 101, 101,  43,  43,  84,
+    152,  40,  40,  67, 101, 153,  63,  67,  36,  36,  36,  62,  58, 154, 155,  69,
+     36,  36,  36,  36,  36,  63,  40,  69,  44,  44,  81,  36,  36,  36,  36,  36,
+     67,  27,  27,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  90,
+     27,  27,  27,  27,  27,  67,  67,  67,  67,  67,  67,  67,  27,  27,  27,  27,
+    156,  27,  27,  27,  27,  27,  27,  27,  36,  36, 104,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  36, 157,   2,   7,   7,   7,   7,   7,  36,  44,  44,
+     32,  32,  32,  32,  32,  32,  32,  70,  51, 158,  43,  43,  43,  43,  43,  86,
+     32,  32,  32,  32,  32,  32,  40,  43,  36,  36,  36, 101, 101, 101, 101, 101,
+     43,   2,   2,   2,  44,  44,  44,  44,  41,  41,  41, 155,  40,  40,  40,  40,
+     41,  32,  32,  32,  32,  32,  32,  32,  16,  32,  32,  32,  32,  32,  32,  32,
+     45,  16,  16,  16,  34,  34,  34,  32,  32,  32,  32,  32,  42, 159,  34,  35,
+     32,  32,  16,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  11,  11,  44,
+     11,  11,  32,  32,  44,  44,  44,  44,  44,  44,  44,  81,  40,  35,  36,  36,
+     36,  71,  36,  71,  36,  70,  36,  36,  36,  93,  85,  83,  67,  67,  44,  44,
+     27,  27,  27,  67, 160,  44,  44,  44,  36,  36,   2,   2,  44,  44,  44,  44,
+     84,  36,  36,  36,  36,  36,  36,  36,  36,  36,  84,  84,  84,  84,  84,  84,
+     84,  84,  80,  44,  44,  44,  44,   2,  43,  36,  36,  36,   2,  72,  72,  44,
+     36,  36,  36,  43,  43,  43,  43,   2,  36,  36,  36,  70,  43,  43,  43,  43,
+     43,  84,  44,  44,  44,  44,  44,  54,  36,  70,  84,  43,  43,  84,  83,  84,
+    161,   2,   2,   2,   2,   2,   2,  52,   7,   7,   7,   7,   7,  44,  44,   2,
+     36,  36,  70,  69,  36,  36,  36,  36,   7,   7,   7,   7,   7,  36,  36,  62,
+     36,  36,  36,  36,  70,  43,  43,  83,  85,  83,  85,  80,  44,  44,  44,  44,
+     36,  70,  36,  36,  36,  36,  83,  44,   7,   7,   7,   7,   7,  44,   2,   2,
+     69,  36,  36,  77,  67,  93,  83,  36,  71,  43,  71,  70,  71,  36,  36,  43,
+     70,  62,  44,  44,  44,  44,  44,  44,  44,  44,  44,  44,  44,  81, 104,   2,
+     36,  36,  36,  36,  36,  93,  43,  84,   2, 104, 162,  80,  44,  44,  44,  44,
+     81,  36,  36,  62,  81,  36,  36,  62,  81,  36,  36,  62,  44,  44,  44,  44,
+     16,  16,  16,  16,  16, 110,  40,  40,  16,  16,  16,  44,  44,  44,  44,  44,
+     36,  93,  85,  84,  83, 161,  85,  44,  36,  36,  44,  44,  44,  44,  44,  44,
+     36,  36,  36,  62,  44,  81,  36,  36, 163, 163, 163, 163, 163, 163, 163, 163,
+    164, 164, 164, 164, 164, 164, 164, 164,  16,  16,  16, 108,  44,  44,  44,  44,
+     44,  53,  16,  16,  44,  44,  81,  71,  36,  36,  36,  36, 165,  36,  36,  36,
+     36,  36,  36,  62,  36,  36,  62,  62,  36,  81,  62,  36,  36,  36,  36,  36,
+     36,  41,  41,  41,  41,  41,  41,  41,  41,  44,  44,  44,  44,  44,  44,  44,
+     44,  81,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36, 144,
+     44,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36, 160,  44,
+      2,   2,   2, 166, 126,  44,  44,  44,   6, 167, 168, 144, 144, 144, 144, 144,
+    144, 144, 126, 166, 126,   2, 123, 169,   2,  64,   2,   2, 149, 144, 144, 126,
+      2, 170,   8, 171,  66,   2,  44,  44,  36,  36,  62,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  36,  62,  79,  54,   2,   3,   2,   4,   5,   6,   2,
+     16,  16,  16,  16,  16,  17,  18, 125, 126,   4,   2,  36,  36,  36,  36,  36,
+     69,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  40,
+     44,  36,  36,  36,  44,  36,  36,  36,  44,  36,  36,  36,  44,  36,  62,  44,
+     20, 172,  57, 130,  26,   8, 140,  90,  44,  44,  44,  44,  79,  65,  67,  44,
+     36,  36,  36,  36,  36,  36,  81,  36,  36,  36,  36,  36,  36,  62,  36,  81,
+      2,  64,  44, 173,  27,  27,  27,  27,  27,  27,  44,  56,  67,  67,  67,  67,
+    101, 101, 139,  27,  89,  67,  67,  67,  67,  67,  67,  67,  67,  27,  90,  44,
+     90,  44,  44,  44,  44,  44,  44,  44,  67,  67,  67,  67,  67,  67,  50,  44,
+    174,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  44,  44,
+     27,  27,  44,  44,  44,  44,  44,  44, 148,  36,  36,  36,  36, 175,  44,  44,
+     36,  36,  36,  43,  43,  80,  44,  44,  36,  36,  36,  36,  36,  36,  36,  54,
+     36,  36,  44,  44,  36,  36,  36,  36, 176, 101, 101,  44,  44,  44,  44,  44,
+     11,  11,  11,  11,  16,  16,  16,  16,  36,  36,  44,  44,  44,  44,  44,  54,
+     36,  36,  36,  44,  62,  36,  36,  36,  36,  36,  36,  81,  62,  44,  62,  81,
+     36,  36,  36,  54,  27,  27,  27,  27,  36,  36,  36,  77, 156,  27,  27,  27,
+     44,  44,  44, 173,  27,  27,  27,  27,  36,  62,  36,  44,  44, 173,  27,  27,
+     36,  36,  36,  27,  27,  27,  44,  54,  36,  36,  36,  36,  36,  44,  44,  54,
+     36,  36,  36,  36,  44,  44,  27,  36,  44,  27,  27,  27,  27,  27,  27,  27,
+     70,  43,  58,  80,  44,  44,  43,  43,  36,  36,  81,  36,  81,  36,  36,  36,
+     36,  36,  44,  44,  43,  80,  44,  58,  27,  27,  27,  27,  44,  44,  44,  44,
+      2,   2,   2,   2,  64,  44,  44,  44,  36,  36,  36,  36,  36,  36, 177,  30,
+     36,  36,  36,  36,  36,  36, 177,  27,  36,  36,  36,  36,  78,  36,  36,  36,
+     36,  36,  70,  80,  44, 173,  27,  27,   2,   2,   2,  64,  44,  44,  44,  44,
+     36,  36,  36,  44,  54,   2,   2,   2,  36,  36,  36,  44,  27,  27,  27,  27,
+     36,  62,  44,  44,  27,  27,  27,  27,  36,  44,  44,  44,  54,   2,  64,  44,
+     44,  44,  44,  44, 173,  27,  27,  27,  36,  36,  36,  36,  62,  44,  44,  44,
+     11,  47,  44,  44,  44,  44,  44,  44,  16, 108,  44,  44,  44,  27,  27,  27,
+     27,  27,  27,  27,  27,  27,  27,  96,  85,  94,  36,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  43,  43,  43,  43,  43,  43,  43,  61,   2,   2,   2,  44,
+     27,  27,  27,   7,   7,   7,   7,   7,  44,  44,  44,  44,  44,  44,  44,  58,
+     84,  85,  43,  83,  85,  61, 178,   2,   2,  44,  44,  44,  44,  44,  44,  44,
+     43,  71,  36,  36,  36,  36,  36,  36,  36,  36,  36,  70,  43,  43,  85,  43,
+     43,  43,  80,   7,   7,   7,   7,   7,   2,   2,  44,  44,  44,  44,  44,  44,
+     36,  70,   2,  62,  44,  44,  44,  44,  36,  93,  84,  43,  43,  43,  43,  83,
+     94,  36,  63,   2,   2,  43,  61,  44,   7,   7,   7,   7,   7,  63,  63,   2,
+    173,  27,  27,  27,  27,  27,  27,  27,  27,  27,  96,  44,  44,  44,  44,  44,
+     36,  36,  36,  36,  36,  36,  84,  85,  43,  84,  83,  43,   2,   2,   2,  44,
+     36,  36,  36,  62,  62,  36,  36,  81,  36,  36,  36,  36,  36,  36,  36,  81,
+     36,  36,  36,  36,  63,  44,  44,  44,  36,  36,  36,  36,  36,  36,  36,  70,
+     84,  85,  43,  43,  43,  80,  44,  44,  43,  84,  81,  36,  36,  36,  62,  81,
+     83,  84,  88,  87,  88,  87,  84,  44,  62,  44,  44,  87,  44,  44,  81,  36,
+     36,  84,  44,  43,  43,  43,  80,  44,  43,  43,  80,  44,  44,  44,  44,  44,
+     84,  85,  43,  43,  83,  83,  84,  85,  83,  43,  36,  72,  44,  44,  44,  44,
+     36,  36,  36,  36,  36,  36,  36,  93,  84,  43,  43,  44,  84,  84,  43,  85,
+     61,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,  36,  36,  43,  44,
+     84,  85,  43,  43,  43,  83,  85,  85,  61,   2,  62,  44,  44,  44,  44,  44,
+     36,  36,  36,  36,  36,  70,  85,  84,  43,  43,  43,  85,  44,  44,  44,  44,
+     36,  36,  36,  36,  36,  44,  58,  43,  84,  43,  43,  85,  43,  43,  44,  44,
+      7,   7,   7,   7,   7,  27,   2,  92,  27,  96,  44,  44,  44,  44,  44,  81,
+    101, 101, 101, 101, 101, 101, 101, 175,   2,   2,  64,  44,  44,  44,  44,  44,
+     43,  43,  61,  44,  44,  44,  44,  44,  43,  43,  43,  61,   2,   2,  67,  67,
+     40,  40,  92,  44,  44,  44,  44,  44,   7,   7,   7,   7,   7, 173,  27,  27,
+     27,  81,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  44,  44,  81,  36,
+     93,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,
+     84,  84,  84,  84,  84,  84,  84,  88,  43,  74,  40,  40,  40,  40,  40,  40,
+     36,  44,  44,  44,  44,  44,  44,  44,  36,  36,  36,  36,  36,  44,  50,  61,
+     65,  65,  44,  44,  44,  44,  44,  44,  67,  67,  67,  90,  56,  67,  67,  67,
+     67,  67, 179,  85,  43,  67, 179,  84,  84, 180,  65,  65,  65, 181,  43,  43,
+     43,  76,  50,  43,  43,  43,  67,  67,  67,  67,  67,  67,  67,  43,  43,  67,
+     67,  67,  67,  67,  90,  44,  44,  44,  67,  43,  76,  44,  44,  44,  44,  44,
+     27,  44,  44,  44,  44,  44,  44,  44,  11,  11,  11,  11,  11,  16,  16,  16,
+     16,  16,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  16,
+     16,  16, 108,  16,  16,  16,  16,  16,  11,  16,  16,  16,  16,  16,  16,  16,
+     16,  16,  16,  16,  16,  16,  47,  11,  44,  47,  48,  47,  48,  11,  47,  11,
+     11,  11,  11,  16,  16,  53,  53,  16,  16,  16,  53,  16,  16,  16,  16,  16,
+     16,  16,  11,  48,  11,  47,  48,  11,  11,  11,  47,  11,  11,  11,  47,  16,
+     16,  16,  16,  16,  11,  48,  11,  47,  11,  11,  47,  47,  44,  11,  11,  11,
+     47,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  11,  11,
+     11,  11,  11,  16,  16,  16,  16,  16,  16,  16,  16,  44,  11,  11,  11,  11,
+     31,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  33,  16,  16,
+     16,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  31,  16,  16,
+     16,  16,  33,  16,  16,  16,  11,  11,  11,  11,  31,  16,  16,  16,  16,  16,
+     16,  16,  16,  16,  16,  16,  16,  33,  16,  16,  16,  11,  11,  11,  11,  11,
+     11,  11,  11,  11,  11,  11,  11,  31,  16,  16,  16,  16,  33,  16,  16,  16,
+     11,  11,  11,  11,  31,  16,  16,  16,  16,  33,  16,  16,  16,  32,  44,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,  43,  43,  43,  76,  67,  50,  43,  43,
+     43,  43,  43,  43,  43,  43,  76,  67,  67,  67,  50,  67,  67,  67,  67,  67,
+     67,  67,  76,  21,   2,   2,  44,  44,  44,  44,  44,  44,  44,  58,  43,  43,
+     36,  36,  62, 173,  27,  27,  27,  27,  43,  43,  43,  80,  44,  44,  44,  44,
+     36,  36,  81,  36,  36,  36,  36,  36,  81,  62,  62,  81,  81,  36,  36,  36,
+     36,  62,  36,  36,  81,  81,  44,  44,  44,  62,  44,  81,  81,  81,  81,  36,
+     81,  62,  62,  81,  81,  81,  81,  81,  81,  62,  62,  81,  36,  62,  36,  36,
+     36,  62,  36,  36,  81,  36,  62,  62,  36,  36,  36,  36,  36,  81,  36,  36,
+     81,  36,  81,  36,  36,  81,  36,  36,   8,  44,  44,  44,  44,  44,  44,  44,
+     56,  67,  67,  67,  67,  67,  67,  67,  44,  44,  44,  67,  67,  67,  67,  67,
+     67,  90,  44,  44,  44,  44,  44,  44,  67,  67,  67,  67,  67,  25,  41,  41,
+     67,  67,  56,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  67,  90,  44,
+     67,  67,  90,  44,  44,  44,  44,  44,  67,  67,  67,  67,  44,  44,  44,  44,
+     67,  67,  67,  67,  67,  67,  67,  44,  79,  44,  44,  44,  44,  44,  44,  44,
+     65,  65,  65,  65,  65,  65,  65,  65, 164, 164, 164, 164, 164, 164, 164,  44,
+};
+
+static RE_UINT8 re_general_category_stage_5[] = {
+    15, 15, 12, 23, 23, 23, 25, 23, 20, 21, 23, 24, 23, 19,  9,  9,
+    24, 24, 24, 23, 23,  1,  1,  1,  1, 20, 23, 21, 26, 22, 26,  2,
+     2,  2,  2, 20, 24, 21, 24, 15, 25, 25, 27, 23, 26, 27,  5, 28,
+    24, 16, 27, 26, 27, 24, 11, 11, 26, 11,  5, 29, 11, 23,  1, 24,
+     1,  2,  2, 24,  2,  1,  2,  5,  5,  5,  1,  3,  3,  2,  5,  2,
+     4,  4, 26, 26,  4, 26,  6,  6,  0,  0,  4,  2,  1, 23,  1,  0,
+     0,  1, 24,  1, 27,  6,  7,  7,  0,  4,  0,  2,  0, 23, 19,  0,
+     0, 27, 27, 25,  0,  6, 19,  6, 23,  6,  6, 23,  5,  0,  5, 23,
+    23,  0, 16, 16, 23, 25, 27, 27, 16,  0,  4,  5,  5,  6,  6,  5,
+    23,  5,  6, 16,  6,  4,  4,  6,  6, 27,  5, 27, 27,  5,  0, 16,
+     6,  0,  0,  5,  4,  0,  6,  8,  8,  8,  8,  6, 23,  4,  0,  8,
+     8,  0, 11, 27, 27,  0,  0, 25, 23, 27,  5,  8,  8,  5, 23, 11,
+    11,  0, 19,  5, 12,  5,  5, 20, 21,  0, 10, 10, 10,  5, 19, 23,
+     5,  4,  7,  0,  2,  4,  3,  3,  2,  0,  3, 26,  2, 26,  0, 26,
+     1, 26, 26,  0, 12, 12, 12, 16, 19, 19, 28, 29, 20, 28, 13, 14,
+    16, 12, 23, 28, 29, 23, 23, 22, 22, 23, 24, 20, 21, 23, 23, 12,
+    11,  4, 21,  4, 25,  0,  6,  7,  7,  6,  1, 27, 27,  1, 27,  2,
+     2, 27, 10,  1,  2, 10, 10, 11, 24, 27, 27, 20, 21, 27, 21, 24,
+    21, 20,  2,  6, 20,  0, 27,  4,  5, 10, 19, 20, 21, 21, 27, 10,
+    19,  4, 10,  4,  6, 26, 26,  4, 27, 11,  4, 23,  7, 23, 26,  1,
+    25, 27,  8, 23,  4,  8, 18, 18, 17, 17,  5, 24, 23, 20, 19, 22,
+    22, 20, 22, 22, 24, 19, 24,  0, 24, 26,  0, 11,  6, 11, 10,  0,
+    23, 10,  5, 11, 23, 16, 27,  8,  8, 16, 16,  6,
+};
+
+/* General_Category: 9628 bytes. */
+
+RE_UINT32 re_get_general_category(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 11;
+    code = ch ^ (f << 11);
+    pos = (RE_UINT32)re_general_category_stage_1[f] << 4;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_general_category_stage_2[pos + f] << 3;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_general_category_stage_3[pos + f] << 3;
+    f = code >> 1;
+    code ^= f << 1;
+    pos = (RE_UINT32)re_general_category_stage_4[pos + f] << 1;
+    value = re_general_category_stage_5[pos + code];
+
+    return value;
+}
+
+/* Block. */
+
+static RE_UINT8 re_block_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  6,  7,  7,  8,  9, 10,
+    11, 12, 13, 14, 15, 16, 17, 16, 16, 16, 16, 18, 16, 19, 20, 21,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 24, 25, 16, 16, 26,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    27, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+};
+
+static RE_UINT8 re_block_stage_2[] = {
+      0,   1,   2,   3,   4,   5,   6,   7,   8,   8,   9,  10,  11,  11,  12,  13,
+     14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  28,
+     29,  30,  31,  31,  32,  32,  32,  33,  34,  34,  34,  34,  34,  35,  36,  37,
+     38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  50,  51,  51,
+     52,  53,  54,  55,  56,  56,  57,  57,  58,  59,  60,  61,  62,  62,  63,  64,
+     65,  65,  66,  67,  68,  68,  69,  69,  70,  71,  72,  73,  74,  75,  76,  77,
+     78,  79,  80,  81,  82,  82,  83,  83,  84,  84,  84,  84,  84,  84,  84,  84,
+     84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,
+     84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,
+     84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  84,  85,  86,  86,  86,  86,
+     86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,
+     86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,
+     87,  87,  87,  87,  87,  87,  87,  87,  87,  88,  89,  89,  90,  91,  92,  93,
+     94,  95,  96,  97,  98,  99, 100, 101, 102, 102, 102, 102, 102, 102, 102, 102,
+    102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+    102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+    102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 103,
+    104, 104, 104, 104, 104, 104, 104, 105, 106, 106, 106, 106, 106, 106, 106, 106,
+    107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+    107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+    107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+    107, 107, 108, 108, 108, 108, 109, 110, 110, 110, 110, 110, 111, 112, 113, 114,
+    115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 119, 126, 126, 126, 119,
+    127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 119, 119, 137, 119, 119, 119,
+    138, 139, 140, 141, 142, 143, 144, 119, 119, 145, 119, 146, 147, 148, 149, 119,
+    119, 150, 119, 119, 119, 151, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    152, 152, 152, 152, 152, 152, 152, 152, 153, 154, 155, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    156, 156, 156, 156, 156, 156, 156, 156, 157, 119, 119, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 158, 158, 158, 158, 158, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    159, 159, 159, 159, 160, 161, 162, 163, 119, 119, 119, 119, 119, 119, 164, 165,
+    166, 166, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 167, 168, 119, 119, 119, 119, 119, 119,
+    169, 169, 170, 170, 171, 119, 172, 119, 173, 173, 173, 173, 173, 173, 173, 173,
+    174, 174, 174, 174, 174, 175, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    176, 177, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 178, 178, 119, 119,
+    179, 180, 181, 181, 182, 182, 183, 183, 183, 183, 183, 183, 184, 185, 186, 187,
+    188, 188, 189, 189, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+    190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+    190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 191, 192, 192,
+    192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+    192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 193, 194,
+    195, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196,
+    196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196,
+    196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 197, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    198, 198, 198, 198, 199, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    200, 119, 201, 202, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+    203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
+    203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
+    204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
+    204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
+};
+
+static RE_UINT16 re_block_stage_3[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,
+      2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   4,   5,   5,   5,   5,   5,
+      6,   6,   6,   6,   6,   6,   6,   7,   7,   7,   7,   7,   7,   7,   7,   7,
+      8,   8,   8,   8,   8,   8,   8,   8,   9,   9,   9,  10,  10,  10,  10,  10,
+     10,  11,  11,  11,  11,  11,  11,  11,  12,  12,  12,  12,  12,  12,  12,  12,
+     13,  13,  13,  13,  13,  14,  14,  14,  15,  15,  15,  15,  16,  16,  16,  16,
+     17,  17,  17,  17,  18,  18,  19,  19,  19,  19,  20,  20,  20,  20,  20,  20,
+     21,  21,  21,  21,  21,  21,  21,  21,  22,  22,  22,  22,  22,  22,  22,  22,
+     23,  23,  23,  23,  23,  23,  23,  23,  24,  24,  24,  24,  24,  24,  24,  24,
+     25,  25,  25,  25,  25,  25,  25,  25,  26,  26,  26,  26,  26,  26,  26,  26,
+     27,  27,  27,  27,  27,  27,  27,  27,  28,  28,  28,  28,  28,  28,  28,  28,
+     29,  29,  29,  29,  29,  29,  29,  29,  30,  30,  30,  30,  30,  30,  30,  30,
+     31,  31,  31,  31,  31,  31,  31,  31,  32,  32,  32,  32,  32,  32,  32,  32,
+     33,  33,  33,  33,  33,  33,  33,  33,  34,  34,  34,  34,  34,  34,  34,  34,
+     34,  34,  35,  35,  35,  35,  35,  35,  36,  36,  36,  36,  36,  36,  36,  36,
+     37,  37,  37,  37,  37,  37,  37,  37,  38,  38,  39,  39,  39,  39,  39,  39,
+     40,  40,  40,  40,  40,  40,  40,  40,  41,  41,  42,  42,  42,  42,  42,  42,
+     43,  43,  44,  44,  45,  45,  46,  46,  47,  47,  47,  47,  47,  47,  47,  47,
+     48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  49,  49,  49,  49,  49,
+     50,  50,  50,  50,  50,  51,  51,  51,  52,  52,  52,  52,  52,  52,  53,  53,
+     54,  54,  55,  55,  55,  55,  55,  55,  55,  55,  55,  56,  56,  56,  56,  56,
+     57,  57,  57,  57,  57,  57,  57,  57,  58,  58,  58,  58,  59,  59,  59,  59,
+     60,  60,  60,  60,  60,  61,  61,  61,  19,  19,  19,  19,  62,  63,  63,  63,
+     64,  64,  64,  64,  64,  64,  64,  64,  65,  65,  65,  65,  66,  66,  66,  66,
+     67,  67,  67,  67,  67,  67,  67,  67,  68,  68,  68,  68,  68,  68,  68,  68,
+     69,  69,  69,  69,  69,  69,  69,  70,  70,  70,  71,  71,  71,  72,  72,  72,
+     73,  73,  73,  73,  73,  74,  74,  74,  74,  75,  75,  75,  75,  75,  75,  75,
+     76,  76,  76,  76,  76,  76,  76,  76,  77,  77,  77,  77,  77,  77,  77,  77,
+     78,  78,  78,  78,  79,  79,  80,  80,  80,  80,  80,  80,  80,  80,  80,  80,
+     81,  81,  81,  81,  81,  81,  81,  81,  82,  82,  83,  83,  83,  83,  83,  83,
+     84,  84,  84,  84,  84,  84,  84,  84,  85,  85,  85,  85,  85,  85,  85,  85,
+     85,  85,  85,  85,  86,  86,  86,  87,  88,  88,  88,  88,  88,  88,  88,  88,
+     89,  89,  89,  89,  89,  89,  89,  89,  90,  90,  90,  90,  90,  90,  90,  90,
+     91,  91,  91,  91,  91,  91,  91,  91,  92,  92,  92,  92,  92,  92,  92,  92,
+     93,  93,  93,  93,  93,  93,  94,  94,  95,  95,  95,  95,  95,  95,  95,  95,
+     96,  96,  96,  97,  97,  97,  97,  97,  98,  98,  98,  98,  98,  98,  99,  99,
+    100, 100, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 101,
+    102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,  19, 103,
+    104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 106, 106, 106, 106, 106, 106,
+    107, 107, 107, 108, 108, 108, 108, 108, 108, 109, 110, 110, 111, 111, 111, 112,
+    113, 113, 113, 113, 113, 113, 113, 113, 114, 114, 114, 114, 114, 114, 114, 114,
+    115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, 116, 116,
+    117, 117, 117, 117, 117, 117, 117, 117, 118, 118, 118, 118, 118, 118, 118, 118,
+    118, 119, 119, 119, 119, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121,
+    121, 121, 121, 121, 122, 122, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123,
+    124, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
+    126, 126, 126, 127, 128, 128, 128, 128, 129, 129, 129, 129, 129, 129, 130, 130,
+    131, 131, 131, 132, 132, 132, 133, 133, 134, 134, 134, 134, 134, 134, 135, 135,
+    136, 136, 136, 136, 136, 136, 137, 137, 138, 138, 138, 138, 138, 138, 139, 139,
+    140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 142, 143, 143, 143, 143,
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145,
+    146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 147, 147, 147, 147, 147, 147,
+    148, 148, 148, 148, 148, 148, 148, 148, 149, 149, 149, 149, 149, 149, 149, 149,
+    150, 150, 150, 150, 150, 150, 150, 150, 151, 151, 151, 151, 151, 152, 152, 152,
+    152, 152, 152, 152, 152, 152, 152, 152, 153, 154, 155, 156, 156, 157, 157, 158,
+    158, 158, 158, 158, 158, 158, 158, 158, 159, 159, 159, 159, 159, 159, 159, 159,
+    159, 159, 159, 159, 159, 159, 159, 160, 161, 161, 161, 161, 161, 161, 161, 161,
+    162, 162, 162, 162, 162, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 164,
+    164, 165, 165, 165, 165, 166, 166, 166,  19,  19,  19,  19,  19,  19,  19,  19,
+    167, 167, 168, 168, 168, 168, 169, 169, 170, 170, 170, 171, 171, 172, 172, 172,
+    173, 173, 174, 174, 174, 174,  19,  19, 175, 175, 175, 175, 175, 176, 176, 176,
+    177, 177, 177,  19,  19,  19,  19,  19, 178, 178, 178, 179, 179, 179, 179,  19,
+    180, 180, 180, 180, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 183, 183,
+    184, 184, 184,  19,  19,  19, 185, 185, 186, 186, 187, 187,  19,  19,  19,  19,
+    188, 188, 189, 189, 189, 189, 189, 189, 190, 190, 190, 190, 190, 190, 191, 191,
+    192, 192,  19,  19, 193, 193, 193, 193, 194, 194, 194, 194, 195, 195, 196, 196,
+    197, 197, 197,  19,  19,  19,  19,  19, 198, 198, 198, 198, 198,  19,  19,  19,
+    199, 199, 199, 199, 199, 199, 199, 199,  19,  19,  19,  19,  19,  19, 200, 200,
+    201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 202, 202, 202, 203, 203, 203,
+    204, 204, 204, 204, 204, 205, 205, 205, 206, 206, 206, 206, 206, 206, 207, 207,
+    208, 208, 208, 208, 208,  19,  19,  19, 209, 209, 209, 210, 210, 210, 210, 210,
+    211, 211, 211, 211, 211, 211, 211, 211, 212, 212, 212, 212, 212, 212,  19,  19,
+    213, 213, 213, 213, 213, 213, 213, 213, 214, 214, 214, 214, 214, 214,  19,  19,
+    215, 215, 215, 215, 215,  19,  19,  19, 216, 216, 216, 216,  19,  19,  19,  19,
+     19,  19, 217, 217, 217, 217, 217, 217,  19,  19,  19,  19, 218, 218, 218, 218,
+    219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 220,
+    221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221,  19,  19,  19,
+    222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222,  19,  19,  19,  19,  19,
+    223, 223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 224, 224, 224, 224,
+    224, 224, 224, 224, 225, 225, 225,  19,  19,  19,  19,  19,  19, 226, 226, 226,
+    227, 227, 227, 227, 227, 227, 227, 227, 227,  19,  19,  19,  19,  19,  19,  19,
+    228, 228, 228, 228, 228, 228, 228, 228, 228, 228,  19,  19,  19,  19,  19,  19,
+    229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, 230, 230, 230, 230, 230,
+    230, 230, 231,  19,  19,  19,  19,  19, 232, 232, 232, 232, 232, 232, 232, 232,
+    233, 233, 233, 233, 233, 233, 233, 233, 234, 234, 234, 234, 234,  19,  19,  19,
+    235, 235, 235, 235, 235, 235, 236, 236, 237, 237, 237, 237, 237, 237, 237, 237,
+    238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238,  19,  19,  19,  19,  19,
+    239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239,  19,  19,
+    240, 240, 240, 240, 240, 240, 240, 240, 241, 241, 241, 242, 242, 242, 242, 242,
+    242, 242, 243, 243, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244,
+    245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246,
+    247, 247, 247, 247, 247, 248, 248, 248, 249, 249, 249, 249, 249, 249, 249, 249,
+    250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251, 251,
+    252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253,
+    254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,  19,  19,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 256, 256, 256, 256,
+    256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 257, 257, 257, 257, 257, 257,
+    257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,  19,  19,  19,  19,  19,
+    258, 258, 258, 258, 258, 258, 258, 258, 258, 258,  19,  19,  19,  19,  19,  19,
+    259, 259, 259, 259, 259, 259, 259, 259, 260, 260, 260, 260, 260, 260, 260, 260,
+    260, 260, 260, 260, 260, 260, 260,  19, 261, 261, 261, 261, 261, 261, 261, 261,
+    262, 262, 262, 262, 262, 262, 262, 262,
+};
+
+static RE_UINT16 re_block_stage_4[] = {
+      0,   0,   0,   0,   1,   1,   1,   1,   2,   2,   2,   2,   3,   3,   3,   3,
+      4,   4,   4,   4,   5,   5,   5,   5,   6,   6,   6,   6,   7,   7,   7,   7,
+      8,   8,   8,   8,   9,   9,   9,   9,  10,  10,  10,  10,  11,  11,  11,  11,
+     12,  12,  12,  12,  13,  13,  13,  13,  14,  14,  14,  14,  15,  15,  15,  15,
+     16,  16,  16,  16,  17,  17,  17,  17,  18,  18,  18,  18,  19,  19,  19,  19,
+     20,  20,  20,  20,  21,  21,  21,  21,  22,  22,  22,  22,  23,  23,  23,  23,
+     24,  24,  24,  24,  25,  25,  25,  25,  26,  26,  26,  26,  27,  27,  27,  27,
+     28,  28,  28,  28,  29,  29,  29,  29,  30,  30,  30,  30,  31,  31,  31,  31,
+     32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  35,  35,  35,  35,
+     36,  36,  36,  36,  37,  37,  37,  37,  38,  38,  38,  38,  39,  39,  39,  39,
+     40,  40,  40,  40,  41,  41,  41,  41,  42,  42,  42,  42,  43,  43,  43,  43,
+     44,  44,  44,  44,  45,  45,  45,  45,  46,  46,  46,  46,  47,  47,  47,  47,
+     48,  48,  48,  48,  49,  49,  49,  49,  50,  50,  50,  50,  51,  51,  51,  51,
+     52,  52,  52,  52,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,  55,  55,
+     56,  56,  56,  56,  57,  57,  57,  57,  58,  58,  58,  58,  59,  59,  59,  59,
+     60,  60,  60,  60,  61,  61,  61,  61,  62,  62,  62,  62,  63,  63,  63,  63,
+     64,  64,  64,  64,  65,  65,  65,  65,  66,  66,  66,  66,  67,  67,  67,  67,
+     68,  68,  68,  68,  69,  69,  69,  69,  70,  70,  70,  70,  71,  71,  71,  71,
+     72,  72,  72,  72,  73,  73,  73,  73,  74,  74,  74,  74,  75,  75,  75,  75,
+     76,  76,  76,  76,  77,  77,  77,  77,  78,  78,  78,  78,  79,  79,  79,  79,
+     80,  80,  80,  80,  81,  81,  81,  81,  82,  82,  82,  82,  83,  83,  83,  83,
+     84,  84,  84,  84,  85,  85,  85,  85,  86,  86,  86,  86,  87,  87,  87,  87,
+     88,  88,  88,  88,  89,  89,  89,  89,  90,  90,  90,  90,  91,  91,  91,  91,
+     92,  92,  92,  92,  93,  93,  93,  93,  94,  94,  94,  94,  95,  95,  95,  95,
+     96,  96,  96,  96,  97,  97,  97,  97,  98,  98,  98,  98,  99,  99,  99,  99,
+    100, 100, 100, 100, 101, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 103,
+    104, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, 107, 107,
+    108, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111, 111,
+    112, 112, 112, 112, 113, 113, 113, 113, 114, 114, 114, 114, 115, 115, 115, 115,
+    116, 116, 116, 116, 117, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 119,
+    120, 120, 120, 120, 121, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123,
+    124, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 126, 127, 127, 127, 127,
+    128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131,
+    132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135,
+    136, 136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 139, 139, 139, 139,
+    140, 140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143,
+    144, 144, 144, 144, 145, 145, 145, 145, 146, 146, 146, 146, 147, 147, 147, 147,
+    148, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151,
+    152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 155, 155,
+    156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 158, 158, 159, 159, 159, 159,
+    160, 160, 160, 160, 161, 161, 161, 161, 162, 162, 162, 162, 163, 163, 163, 163,
+    164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 166, 166, 167, 167, 167, 167,
+    168, 168, 168, 168, 169, 169, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171,
+    172, 172, 172, 172, 173, 173, 173, 173, 174, 174, 174, 174, 175, 175, 175, 175,
+    176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, 179, 179, 179,
+    180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, 183, 183, 183,
+    184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, 187, 187, 187,
+    188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 191,
+    192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, 195, 195, 195,
+    196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, 199, 199, 199,
+    200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, 203, 203, 203, 203,
+    204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, 207, 207,
+    208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 211, 211, 211, 211,
+    212, 212, 212, 212, 213, 213, 213, 213, 214, 214, 214, 214, 215, 215, 215, 215,
+    216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219,
+    220, 220, 220, 220, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223,
+    224, 224, 224, 224, 225, 225, 225, 225, 226, 226, 226, 226, 227, 227, 227, 227,
+    228, 228, 228, 228, 229, 229, 229, 229, 230, 230, 230, 230, 231, 231, 231, 231,
+    232, 232, 232, 232, 233, 233, 233, 233, 234, 234, 234, 234, 235, 235, 235, 235,
+    236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 239, 239, 239, 239,
+    240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 243, 243, 243, 243,
+    244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, 247, 247,
+    248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251,
+    252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 255, 255, 255, 255,
+    256, 256, 256, 256, 257, 257, 257, 257, 258, 258, 258, 258, 259, 259, 259, 259,
+    260, 260, 260, 260, 261, 261, 261, 261, 262, 262, 262, 262,
+};
+
+static RE_UINT16 re_block_stage_5[] = {
+      1,   1,   1,   1,   2,   2,   2,   2,   3,   3,   3,   3,   4,   4,   4,   4,
+      5,   5,   5,   5,   6,   6,   6,   6,   7,   7,   7,   7,   8,   8,   8,   8,
+      9,   9,   9,   9,  10,  10,  10,  10,  11,  11,  11,  11,  12,  12,  12,  12,
+     13,  13,  13,  13,  14,  14,  14,  14,  15,  15,  15,  15,  16,  16,  16,  16,
+     17,  17,  17,  17,  18,  18,  18,  18,  19,  19,  19,  19,   0,   0,   0,   0,
+     20,  20,  20,  20,  21,  21,  21,  21,  22,  22,  22,  22,  23,  23,  23,  23,
+     24,  24,  24,  24,  25,  25,  25,  25,  26,  26,  26,  26,  27,  27,  27,  27,
+     28,  28,  28,  28,  29,  29,  29,  29,  30,  30,  30,  30,  31,  31,  31,  31,
+     32,  32,  32,  32,  33,  33,  33,  33,  34,  34,  34,  34,  35,  35,  35,  35,
+     36,  36,  36,  36,  37,  37,  37,  37,  38,  38,  38,  38,  39,  39,  39,  39,
+     40,  40,  40,  40,  41,  41,  41,  41,  42,  42,  42,  42,  43,  43,  43,  43,
+     44,  44,  44,  44,  45,  45,  45,  45,  46,  46,  46,  46,  47,  47,  47,  47,
+     48,  48,  48,  48,  49,  49,  49,  49,  50,  50,  50,  50,  51,  51,  51,  51,
+     52,  52,  52,  52,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,  55,  55,
+     56,  56,  56,  56,  57,  57,  57,  57,  58,  58,  58,  58,  59,  59,  59,  59,
+     60,  60,  60,  60,  61,  61,  61,  61,  62,  62,  62,  62,  63,  63,  63,  63,
+     64,  64,  64,  64,  65,  65,  65,  65,  66,  66,  66,  66,  67,  67,  67,  67,
+     68,  68,  68,  68,  69,  69,  69,  69,  70,  70,  70,  70,  71,  71,  71,  71,
+     72,  72,  72,  72,  73,  73,  73,  73,  74,  74,  74,  74,  75,  75,  75,  75,
+     76,  76,  76,  76,  77,  77,  77,  77,  78,  78,  78,  78,  79,  79,  79,  79,
+     80,  80,  80,  80,  81,  81,  81,  81,  82,  82,  82,  82,  83,  83,  83,  83,
+     84,  84,  84,  84,  85,  85,  85,  85,  86,  86,  86,  86,  87,  87,  87,  87,
+     88,  88,  88,  88,  89,  89,  89,  89,  90,  90,  90,  90,  91,  91,  91,  91,
+     92,  92,  92,  92,  93,  93,  93,  93,  94,  94,  94,  94,  95,  95,  95,  95,
+     96,  96,  96,  96,  97,  97,  97,  97,  98,  98,  98,  98,  99,  99,  99,  99,
+    100, 100, 100, 100, 101, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 103,
+    104, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, 107, 107,
+    108, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111, 111,
+    112, 112, 112, 112, 113, 113, 113, 113, 114, 114, 114, 114, 115, 115, 115, 115,
+    116, 116, 116, 116, 117, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 119,
+    120, 120, 120, 120, 121, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123,
+    124, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 126, 127, 127, 127, 127,
+    128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131,
+    132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135,
+    136, 136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 139, 139, 139, 139,
+    140, 140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143,
+    144, 144, 144, 144, 145, 145, 145, 145, 146, 146, 146, 146, 147, 147, 147, 147,
+    148, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 151,
+    152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 155, 155,
+    156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 158, 158, 159, 159, 159, 159,
+    160, 160, 160, 160, 161, 161, 161, 161, 162, 162, 162, 162, 163, 163, 163, 163,
+    164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 166, 166, 167, 167, 167, 167,
+    168, 168, 168, 168, 169, 169, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171,
+    172, 172, 172, 172, 173, 173, 173, 173, 174, 174, 174, 174, 175, 175, 175, 175,
+    176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, 179, 179, 179,
+    180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, 183, 183, 183,
+    184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, 187, 187, 187,
+    188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 191,
+    192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, 195, 195, 195,
+    196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, 199, 199, 199,
+    200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, 203, 203, 203, 203,
+    204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, 207, 207,
+    208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 211, 211, 211, 211,
+    212, 212, 212, 212, 213, 213, 213, 213, 214, 214, 214, 214, 215, 215, 215, 215,
+    216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219,
+    220, 220, 220, 220, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223,
+    224, 224, 224, 224, 225, 225, 225, 225, 226, 226, 226, 226, 227, 227, 227, 227,
+    228, 228, 228, 228, 229, 229, 229, 229, 230, 230, 230, 230, 231, 231, 231, 231,
+    232, 232, 232, 232, 233, 233, 233, 233, 234, 234, 234, 234, 235, 235, 235, 235,
+    236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 239, 239, 239, 239,
+    240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 243, 243, 243, 243,
+    244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, 247, 247,
+    248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251,
+    252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 255, 255, 255, 255,
+    256, 256, 256, 256, 257, 257, 257, 257, 258, 258, 258, 258, 259, 259, 259, 259,
+    260, 260, 260, 260, 261, 261, 261, 261, 262, 262, 262, 262,
+};
+
+/* Block: 8720 bytes. */
+
+RE_UINT32 re_get_block(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_block_stage_1[f] << 5;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_block_stage_2[pos + f] << 3;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_block_stage_3[pos + f] << 2;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_block_stage_4[pos + f] << 2;
+    value = re_block_stage_5[pos + code];
+
+    return value;
+}
+
+/* Script. */
+
+static RE_UINT8 re_script_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11, 12, 12, 12, 12, 13, 14, 14, 14, 14, 15,
+    16, 17, 18, 19, 20, 14, 21, 14, 22, 14, 14, 14, 14, 23, 14, 14,
+    14, 14, 14, 14, 14, 14, 24, 25, 14, 14, 26, 27, 14, 28, 29, 30,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 31,  7, 32, 33,  7, 34, 14, 14, 14, 14, 14, 35,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    36, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+};
+
+static RE_UINT8 re_script_stage_2[] = {
+      0,   1,   2,   2,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
+     14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
+     30,  31,  32,  32,  33,  34,  35,  36,  37,  37,  37,  37,  37,  38,  39,  40,
+     41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,   2,   2,  53,  54,
+     55,  56,  57,  58,  59,  59,  59,  60,  61,  59,  59,  59,  59,  59,  59,  59,
+     62,  62,  59,  59,  59,  59,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,
+     73,  74,  75,  76,  77,  78,  79,  59,  71,  71,  71,  71,  71,  71,  71,  71,
+     71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,
+     71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  80,  71,  71,  71,  71,
+     71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  81,
+     82,  82,  82,  82,  82,  82,  82,  82,  82,  83,  84,  84,  85,  86,  87,  88,
+     89,  90,  91,  92,  93,  94,  95,  96,  32,  32,  32,  32,  32,  32,  32,  32,
+     32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+     32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  97,
+     98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+     98,  98,  71,  71,  99, 100, 101, 102, 103, 103, 104, 105, 106, 107, 108, 109,
+    110, 111, 112, 113,  98, 114, 115, 116, 117, 118, 119,  98, 120, 120, 121,  98,
+    122, 123, 124, 125, 126, 127, 128, 129, 130, 131,  98,  98, 132,  98,  98,  98,
+    133, 134, 135, 136, 137, 138, 139,  98,  98, 140,  98, 141, 142, 143, 144,  98,
+     98, 145,  98,  98,  98, 146,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+    147, 147, 147, 147, 147, 147, 147, 148, 149, 147, 150,  98,  98,  98,  98,  98,
+    151, 151, 151, 151, 151, 151, 151, 151, 152,  98,  98,  98,  98,  98,  98,  98,
+     98,  98,  98,  98,  98,  98,  98,  98, 153, 153, 153, 153, 154,  98,  98,  98,
+    155, 155, 155, 155, 156, 157, 158, 159,  98,  98,  98,  98,  98,  98, 160, 161,
+    162,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+     98,  98,  98,  98,  98,  98,  98,  98, 163, 164,  98,  98,  98,  98,  98,  98,
+     59, 165, 166, 167, 168,  98, 169,  98, 170, 171, 172,  59,  59, 173,  59, 174,
+    175, 175, 175, 175, 175, 176,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+    177, 178,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98, 179, 180,  98,  98,
+    181, 182, 183, 184, 185,  98,  59,  59,  59,  59, 186, 187,  59, 188, 189, 190,
+    191, 192, 193, 194,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+     71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71, 195,  71,  71,
+     71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71, 196,  71,
+    197,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,
+     71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71,  71, 198,  98,  98,
+     71,  71,  71,  71, 199,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+    200,  98, 201, 202,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+};
+
+static RE_UINT16 re_script_stage_3[] = {
+      0,   0,   0,   0,   1,   2,   1,   2,   0,   0,   3,   3,   4,   5,   4,   5,
+      4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   6,   0,   0,   7,   0,
+      8,   8,   8,   8,   8,   8,   8,   9,  10,  11,  12,  11,  11,  11,  13,  11,
+     14,  14,  14,  14,  14,  14,  14,  14,  15,  14,  14,  14,  14,  14,  14,  14,
+     14,  14,  14,  16,  17,  18,  16,  17,  19,  20,  21,  21,  22,  21,  23,  24,
+     25,  26,  27,  27,  28,  29,  27,  30,  27,  27,  27,  27,  27,  31,  27,  27,
+     32,  33,  33,  33,  34,  27,  27,  27,  35,  35,  35,  36,  37,  37,  37,  38,
+     39,  39,  40,  41,  42,  43,  44,  44,  44,  44,  27,  45,  44,  44,  46,  27,
+     47,  47,  47,  47,  47,  48,  49,  47,  50,  51,  52,  53,  54,  55,  56,  57,
+     58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,
+     74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
+     90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105,
+    106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+    122, 123, 123, 124, 123, 125,  44,  44, 126, 127, 128, 129, 130, 131,  44,  44,
+    132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137,  44,  44,
+    138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 140, 139, 139, 141,
+    142, 142, 142, 142, 142, 142, 142, 142, 143, 143, 143, 143, 144, 145, 143, 143,
+    144, 143, 143, 146, 147, 148, 143, 143, 143, 147, 143, 143, 143, 149, 143, 150,
+    143, 151, 152, 152, 152, 152, 152, 153, 154, 154, 154, 154, 154, 154, 154, 154,
+    155, 156, 157, 157, 157, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+    168, 168, 168, 168, 168, 169, 170, 170, 171, 172, 173, 173, 173, 173, 173, 174,
+    173, 173, 175, 154, 154, 154, 154, 176, 177, 178, 179, 179, 180, 181, 182, 183,
+    184, 184, 185, 184, 186, 187, 168, 168, 188, 189, 190, 190, 190, 191, 190, 192,
+    193, 193, 194, 195,  44,  44,  44,  44, 196, 196, 196, 196, 197, 196, 196, 198,
+    199, 199, 199, 199, 200, 200, 200, 201, 202, 202, 202, 203, 204, 205, 205, 205,
+     44,  44,  44,  44, 206, 207, 208, 209,   4,   4, 210,   4,   4, 211, 212, 213,
+      4,   4,   4, 214,   8,   8,   8, 215,  11, 216,  11,  11, 216, 217,  11, 218,
+     11,  11,  11, 219, 219, 220,  11, 221, 222,   0,   0,   0,   0,   0, 223, 224,
+    225, 226,   0, 225,  44,   8,   8, 227,   0,   0, 228, 229, 230,   0,   4,   4,
+    231,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 232,   0,   0, 233,  44, 232,  44,   0,   0,
+    234, 234, 234, 234, 234, 234, 234, 234,   0,   0,   0,   0,   0,   0,   0, 235,
+      0, 236,   0, 237, 238, 239, 240,  44, 241, 241, 242, 241, 241, 242,   4,   4,
+    243, 243, 243, 243, 243, 243, 243, 244, 139, 139, 140, 245, 245, 245, 246, 247,
+    143, 248, 249, 249, 249, 249,  14,  14,   0,   0,   0,   0, 250,  44,  44,  44,
+    251, 252, 251, 251, 251, 251, 251, 253, 251, 251, 251, 251, 251, 251, 251, 251,
+    251, 251, 251, 251, 251, 254,  44, 255, 256,   0, 257, 258, 259, 260, 260, 260,
+    260, 261, 262, 263, 263, 263, 263, 264, 265, 266, 267, 268, 142, 142, 142, 142,
+    269,   0, 266, 270,   0,   0, 271, 263, 142, 269,   0,   0,   0,   0, 142, 272,
+      0,   0,   0,   0,   0, 263, 263, 273, 263, 263, 263, 263, 263, 274,   0,   0,
+    251, 251, 251, 254,   0,   0,   0,   0, 251, 251, 251, 251, 251, 254,  44,  44,
+    275, 275, 275, 275, 275, 275, 275, 275, 276, 275, 275, 275, 277, 278, 278, 278,
+    279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280,  44,  14,  14,  14,  14,
+     14,  14, 281, 281, 281, 281, 281, 282,   0,   0, 283,   4,   4,   4,   4,   4,
+    284,   4, 285, 286,  44,  44,  44, 287, 288, 288, 289, 290, 291, 291, 291, 292,
+    293, 293, 293, 293, 294, 295,  47, 296, 297, 297, 298, 299, 299, 300, 142, 301,
+    302, 302, 302, 302, 303, 304, 138, 305, 306, 306, 306, 307, 308, 309, 138, 138,
+    310, 310, 310, 310, 311, 312, 313, 314, 315, 316, 249,   4,   4, 317, 318, 152,
+    152, 152, 152, 152, 313, 313, 319, 320, 142, 142, 321, 142, 322, 142, 142, 323,
+     44,  44,  44,  44,  44,  44,  44,  44, 251, 251, 251, 251, 251, 251, 324, 251,
+    251, 251, 251, 251, 251, 325,  44,  44, 326, 327,  21, 328, 329,  27,  27,  27,
+     27,  27,  27,  27, 330,  46,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,
+     27,  27,  27, 331,  44,  27,  27,  27,  27, 332,  27,  27, 333,  44,  44, 334,
+      8, 290, 335,   0,   0, 336, 337, 338,  27,  27,  27,  27,  27,  27,  27, 339,
+    340,   0,   1,   2,   1,   2, 341, 262, 263, 342, 142, 269, 343, 344, 345, 346,
+    347, 348, 349, 350, 351, 351,  44,  44, 348, 348, 348, 348, 348, 348, 348, 352,
+    353,   0,   0, 354,  11,  11,  11,  11, 355, 255, 356,  44,  44,   0,   0, 357,
+    358, 359, 360, 360, 360, 361, 362, 255, 363, 363, 364, 365, 366, 367, 367, 368,
+    369, 370, 371, 371, 372, 373,  44,  44, 374, 374, 374, 374, 374, 375, 375, 375,
+    376, 377, 378,  44,  44,  44,  44,  44, 379, 379, 380, 381, 381, 381, 382,  44,
+    383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 383, 385, 386,  44,
+    387, 388, 388, 389, 390, 391, 392, 392, 393, 394, 395,  44,  44,  44, 396, 397,
+    398, 399, 400, 401,  44,  44,  44,  44, 402, 402, 403, 404, 403, 405, 403, 403,
+    406, 407, 408, 409, 410, 411, 412, 412, 413, 413,  44,  44, 414, 414, 415, 416,
+    417, 417, 417, 418, 419, 420, 421, 422, 423, 424, 425,  44,  44,  44,  44,  44,
+    426, 426, 426, 426, 427,  44,  44,  44, 428, 428, 428, 429, 428, 428, 428, 430,
+     44,  44,  44,  44,  44,  44,  27, 431, 432, 432, 432, 432, 433, 434, 432, 435,
+    436, 436, 436, 436, 437, 438, 439, 440, 441, 441, 441, 442, 443, 444, 444, 445,
+    446, 446, 446, 446, 447, 446, 448, 449, 450, 451, 450, 452,  44,  44,  44,  44,
+    453, 454, 455, 456, 456, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466,
+    467, 467, 467, 467, 468, 469,  44,  44, 470, 470, 470, 471, 470, 472,  44,  44,
+    473, 473, 473, 473, 474, 475,  44,  44, 476, 476, 476, 477, 478,  44,  44,  44,
+    479, 480, 481, 479,  44,  44,  44,  44,  44,  44, 482, 482, 482, 482, 482, 483,
+     44,  44,  44,  44, 484, 484, 484, 485, 486, 486, 486, 486, 486, 486, 486, 486,
+    486, 487,  44,  44,  44,  44,  44,  44, 486, 486, 486, 486, 486, 486, 488, 489,
+    486, 486, 486, 486, 490,  44,  44,  44, 491, 491, 491, 491, 491, 491, 491, 491,
+    491, 491, 492,  44,  44,  44,  44,  44, 493, 493, 493, 493, 493, 493, 493, 493,
+    493, 493, 493, 493, 494,  44,  44,  44, 281, 281, 281, 281, 281, 281, 281, 281,
+    281, 281, 281, 495, 496, 497, 498,  44,  44,  44,  44,  44,  44, 499, 500, 501,
+    502, 502, 502, 502, 503, 504, 505, 506, 502,  44,  44,  44,  44,  44,  44,  44,
+    507, 507, 507, 507, 508, 507, 507, 509, 510, 507,  44,  44,  44,  44,  44,  44,
+    511,  44,  44,  44,  44,  44,  44,  44, 512, 512, 512, 512, 512, 512, 513, 514,
+    515, 516, 271,  44,  44,  44,  44,  44,   0,   0,   0,   0,   0,   0,   0, 517,
+      0,   0, 518,   0,   0,   0, 519, 520, 521,   0, 522,   0,   0,   0, 523,  44,
+     11,  11,  11,  11, 524,  44,  44,  44,   0,   0,   0,   0,   0, 233,   0, 239,
+      0,   0,   0,   0,   0, 223,   0,   0,   0, 525, 526, 527, 528,   0,   0,   0,
+    529, 530,   0, 531, 532, 533,   0,   0,   0,   0, 236,   0,   0,   0,   0,   0,
+      0,   0,   0,   0, 534,   0,   0,   0, 535, 535, 535, 535, 535, 535, 535, 535,
+    536, 537, 538,  44,  44,  44,  44,  44, 539, 539, 539, 539, 539, 539, 539, 539,
+    539, 539, 539, 539, 540, 541,  44,  44, 542,  27, 543, 544, 545, 546, 547, 548,
+    549, 550, 551, 550,  44,  44,  44, 330,   0,   0, 255,   0,   0,   0,   0,   0,
+      0, 271, 225, 340, 340, 340,   0, 517, 552,   0, 225,   0,   0,   0, 255,   0,
+      0, 232,  44,  44,  44,  44, 553,   0, 554,   0,   0, 232, 523, 239,  44,  44,
+      0,   0,   0,   0,   0,   0,   0, 555,   0,   0, 528,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 556, 552, 271,   0,   0,   0,   0,   0,   0,   0, 271,
+      0,   0,   0,   0,   0, 557,  44,  44, 255,   0,   0,   0, 558, 290,   0,   0,
+    558,   0, 559,  44,  44,  44,  44,  44,  44, 523,  44,  44,  44,  44,  44,  44,
+    557,  44,  44,  44, 556,  44,  44,  44, 251, 251, 251, 251, 251, 560,  44,  44,
+    251, 251, 251, 561, 251, 251, 251, 251, 251, 324, 251, 251, 251, 251, 251, 251,
+    251, 251, 562,  44,  44,  44,  44,  44, 251, 324,  44,  44,  44,  44,  44,  44,
+    563,  44,   0,   0,   0,   0,   0,   0,   8,   8,   8,   8,   8,   8,   8,   8,
+      8,   8,   8,   8,   8,   8,   8,  44,
+};
+
+static RE_UINT16 re_script_stage_4[] = {
+      0,   0,   0,   0,   1,   2,   2,   2,   2,   2,   3,   0,   0,   0,   4,   0,
+      2,   2,   2,   2,   2,   3,   2,   2,   2,   2,   5,   0,   2,   5,   6,   0,
+      7,   7,   7,   7,   8,   9,  10,  11,  12,  13,  14,  15,   8,   8,   8,   8,
+     16,   8,   8,   8,  17,  18,  18,  18,  19,  19,  19,  19,  19,  20,  19,  19,
+     21,  22,  22,  22,  22,  22,  22,  22,  22,  23,  21,  22,  22,  22,  24,  21,
+     25,  26,  26,  26,  26,  26,  26,  26,  26,  26,  12,  12,  26,  26,  27,  12,
+     26,  28,  12,  12,  29,  30,  29,  31,  29,  29,  32,  33,  29,  29,  29,  29,
+     31,  29,  34,   7,   7,  35,  29,  29,  36,  29,  29,  29,  29,  29,  29,  30,
+     37,  37,  37,  38,  37,  37,  37,  37,  37,  37,  39,  40,  41,  41,  41,  41,
+     42,  12,  12,  12,  43,  43,  43,  43,  43,  43,  44,  12,  45,  45,  45,  45,
+     45,  45,  45,  46,  45,  45,  45,  47,  48,  48,  48,  48,  48,  48,  48,  49,
+     12,  12,  12,  12,  29,  50,  12,  12,  51,  29,  29,  29,  52,  52,  52,  52,
+     53,  52,  52,  52,  52,  54,  52,  52,  55,  56,  55,  57,  57,  55,  55,  55,
+     55,  55,  58,  55,  59,  60,  61,  55,  55,  57,  57,  62,  12,  63,  12,  64,
+     55,  60,  55,  55,  55,  55,  55,  12,  65,  65,  66,  67,  68,  69,  69,  69,
+     69,  69,  70,  69,  70,  71,  72,  70,  66,  67,  68,  72,  73,  12,  65,  74,
+     12,  75,  69,  69,  69,  72,  12,  12,  76,  76,  77,  78,  78,  77,  77,  77,
+     77,  77,  79,  77,  79,  76,  80,  77,  77,  78,  78,  80,  81,  12,  12,  12,
+     77,  82,  77,  77,  80,  12,  83,  12,  84,  84,  85,  86,  86,  85,  85,  85,
+     85,  85,  87,  85,  87,  84,  88,  85,  85,  86,  86,  88,  12,  89,  12,  90,
+     85,  89,  85,  85,  85,  85,  12,  12,  91,  92,  93,  91,  94,  95,  96,  94,
+     97,  98,  93,  91,  99,  99,  95,  91,  93,  91,  94,  95,  98,  97,  12,  12,
+     12,  91,  99,  99,  99,  99,  93,  12, 100, 101, 100, 102, 102, 100, 100, 100,
+    100, 100, 102, 100, 100, 100, 103, 101, 100, 102, 102, 103,  12, 104, 105,  12,
+    100, 106, 100, 100,  12,  12, 100, 100, 107, 107, 108, 109, 109, 108, 108, 108,
+    108, 108, 109, 108, 108, 107, 110, 108, 108, 109, 109, 110,  12, 111,  12, 112,
+    108, 113, 108, 108, 111,  12,  12,  12, 114, 114, 115, 116, 116, 115, 115, 115,
+    115, 115, 115, 115, 115, 115, 117, 114, 115, 116, 116, 117,  12, 118,  12, 118,
+    115, 119, 115, 115, 115, 120, 114, 115, 121, 122, 123, 123, 123, 124, 121, 123,
+    123, 123, 123, 123, 125, 123, 123, 126, 123, 124, 127, 128, 123, 129, 123, 123,
+     12, 121, 123, 123, 121, 130,  12,  12, 131, 132, 132, 132, 132, 132, 132, 132,
+    132, 132, 133, 134, 132, 132, 132,  12, 135, 136, 137, 138,  12, 139, 140, 139,
+    140, 141, 142, 140, 139, 139, 143, 144, 139, 137, 139, 144, 139, 139, 144, 139,
+    145, 145, 145, 145, 145, 145, 146, 145, 145, 145, 145, 147, 146, 145, 145, 145,
+    145, 145, 145, 148, 145, 149, 150,  12, 151, 151, 151, 151, 152, 152, 152, 152,
+    152, 153,  12, 154, 152, 152, 155, 152, 156, 156, 156, 156, 157, 157, 157, 157,
+    157, 157, 158, 159, 157, 160, 158, 159, 158, 159, 157, 160, 158, 159, 157, 157,
+    157, 160, 157, 157, 157, 157, 160, 161, 157, 157, 157, 162, 157, 157, 159,  12,
+    163, 163, 163, 163, 163, 164, 163, 164, 165, 165, 165, 165, 166, 166, 166, 166,
+    166, 166, 166, 167, 168, 168, 168, 168, 168, 168, 169, 170, 168, 168, 171,  12,
+    172, 172, 172, 173, 172, 174,  12,  12, 175, 175, 175, 175, 175, 176,  12,  12,
+    177, 177, 177, 177, 177,  12,  12,  12, 178, 178, 178, 179, 179,  12,  12,  12,
+    180, 180, 180, 180, 180, 180, 180, 181, 180, 180, 181,  12, 182, 183, 184, 185,
+    184, 184, 186,  12, 184, 184, 184, 184, 184, 184,  12,  12, 184, 184, 185,  12,
+    165, 187,  12,  12, 188, 188, 188, 188, 188, 188, 188, 189, 188, 188, 188,  12,
+    190, 188, 188, 188, 191, 191, 191, 191, 191, 191, 191, 192, 191, 193,  12,  12,
+    194, 194, 194, 194, 194, 194, 194,  12, 194, 194, 195,  12, 194, 194, 196, 197,
+    198, 198, 198, 198, 198, 198, 198, 199, 200, 200, 200, 200, 200, 200, 200, 201,
+    200, 200, 200, 202, 200, 200, 203,  12, 200, 200, 200, 203,   7,   7,   7, 204,
+    205, 205, 205, 205, 205, 205, 205,  12, 205, 205, 205, 206, 207, 207, 207, 207,
+    208, 208, 208, 208, 208,  12,  12, 208, 209, 209, 209, 209, 209, 209, 210, 209,
+    209, 209, 211, 212, 213, 213, 213, 213, 207, 207,  12,  12, 214,   7,   7,   7,
+    215,   7, 216, 217,   0, 218, 219,  12,   2, 220, 221,   2,   2,   2,   2, 222,
+    223, 220, 224,   2,   2,   2, 225,   2,   2,   2,   2, 226,   7, 219,  12,   7,
+      8, 227,   8, 227,   8,   8, 228, 228,   8,   8,   8, 227,   8,  15,   8,   8,
+      8,  10,   8, 229,  10,  15,   8,  14,   0,   0,   0, 230,   0, 231,   0,   0,
+    232,   0,   0, 233,   0,   0,   0, 234,   2,   2,   2, 235, 236,  12,  12,  12,
+      0, 237, 238,   0,   4,   0,   0,   0,   0,   0,   0,   4,   2,   2,   5,  12,
+      0,   0, 234,  12,   0, 234,  12,  12, 239, 239, 239, 239,   0, 240,   0,   0,
+      0, 241,   0,   0,   0,   0, 241, 242,   0,   0, 231,   0, 241,  12,  12,  12,
+     12,  12,  12,   0, 243, 243, 243, 243, 243, 243, 243, 244,  18,  18,  18,  18,
+     18,  12, 245,  18, 246, 246, 246, 246, 246, 246,  12, 247, 248,  12,  12, 247,
+    157, 160,  12,  12, 157, 160, 157, 160, 234,  12,  12,  12, 249, 249, 249, 249,
+    249, 249, 250, 249, 249,  12,  12,  12, 249, 251,  12,  12,   0,   0,   0,  12,
+      0, 252,   0,   0, 253, 249, 254, 255,   0,   0, 249,   0, 256, 257, 257, 257,
+    257, 257, 257, 257, 257, 258, 259, 260, 261, 262, 262, 262, 262, 262, 262, 262,
+    262, 262, 263, 261,  12, 264, 265, 265, 265, 265, 265, 265, 265, 265, 265, 266,
+    267, 156, 156, 156, 156, 156, 156, 268, 265, 265, 269,  12,   0,  12,  12,  12,
+    156, 156, 156, 270, 262, 262, 262, 271, 262, 262,   0,   0, 272, 272, 272, 272,
+    272, 272, 272, 273, 272, 274,  12,  12, 275, 275, 275, 275, 276, 276, 276, 276,
+    276, 276, 276,  12, 277, 277, 277, 277, 277, 277,  12,  12, 238,   2,   2,   2,
+      2,   2, 233,   2,   2,   2,   2, 278,   2,   2,  12,  12,  12, 279,   2,   2,
+    280, 280, 280, 280, 280, 280, 280,  12,   0,   0, 241,  12, 281, 281, 281, 281,
+    281, 281,  12,  12, 282, 282, 282, 282, 282, 283,  12, 284, 282, 282, 285,  12,
+     52,  52,  52, 286, 287, 287, 287, 287, 287, 287, 287, 288, 289, 289, 289, 289,
+    289,  12,  12, 290, 156, 156, 156, 291, 292, 292, 292, 292, 292, 292, 292, 293,
+    292, 292, 294, 295, 151, 151, 151, 296, 297, 297, 297, 297, 297, 298,  12,  12,
+    297, 297, 297, 299, 297, 297, 299, 297, 300, 300, 300, 300, 301,  12,  12,  12,
+     12,  12, 302, 300, 303, 303, 303, 303, 303, 304,  12,  12, 161, 160, 161, 160,
+    161, 160,  12,  12,   2,   2,   3,   2,   2, 305,  12,  12, 303, 303, 303, 306,
+    303, 303, 306,  12, 156,  12,  12,  12, 156, 268, 307, 156, 156, 156, 156,  12,
+    249, 249, 249, 251, 249, 249, 251,  12,   2, 308,  12,  12, 309,  22,  12,  25,
+     26,  27,  26, 310, 311, 312,  26,  26, 313,  12,  12,  12,  29,  29,  29, 314,
+    315,  29,  29,  29,  29,  29,  12,  12,  29,  29,  29, 313,   7,   7,   7, 316,
+    234,   0,   0,   0,   0, 234,   0,  12,  29, 317,  29,  29,  29,  29,  29, 318,
+    242,   0,   0,   0,   0, 319, 262, 262, 262, 262, 262, 320, 321, 156, 321, 156,
+    321, 156, 321, 291,   0, 234,   0, 234,  12,  12, 242, 241, 322, 322, 322, 323,
+    322, 322, 322, 322, 322, 324, 322, 322, 322, 322, 324, 325, 322, 322, 322, 326,
+    322, 322, 324,  12, 234, 134,   0,   0,   0, 134,   0,   0,   8,   8,   8, 327,
+    327,  12,  12,  12,   0,   0,   0, 328, 329, 329, 329, 329, 329, 329, 329, 330,
+    331, 331, 331, 331, 332,  12,  12,  12, 216,   0,   0,   0, 333, 333, 333, 333,
+    333,  12,  12,  12, 334, 334, 334, 334, 334, 334, 335,  12, 336, 336, 336, 336,
+    336, 336, 337,  12, 338, 338, 338, 338, 338, 338, 338, 339, 340, 340, 340, 340,
+    340,  12, 340, 340, 340, 341,  12,  12, 342, 342, 342, 342, 343, 343, 343, 343,
+    344, 344, 344, 344, 344, 344, 344, 345, 344, 344, 345,  12, 346, 346, 346, 346,
+    346, 346,  12,  12, 347, 347, 347, 347, 347,  12,  12, 348, 349, 349, 349, 349,
+    349, 350,  12,  12, 349, 351,  12,  12, 349, 349,  12,  12, 352, 353, 354, 352,
+    352, 352, 352, 352, 352, 355, 356, 357, 358, 358, 358, 358, 358, 359, 358, 358,
+    360, 360, 360, 360, 361, 361, 361, 361, 361, 361, 361, 362,  12, 363, 361, 361,
+    364, 364, 364, 364, 365, 366, 367, 364, 368, 368, 368, 368, 368, 368, 368, 369,
+    370, 370, 370, 370, 370, 370, 371, 372, 373, 373, 373, 373, 374, 374, 374, 374,
+    374, 374,  12, 374, 375, 374, 374, 374, 376, 377,  12, 376, 376, 378, 378, 376,
+    376, 376, 376, 376, 376,  12, 379, 380, 376, 376,  12,  12, 376, 376, 381,  12,
+    382, 382, 382, 382, 383, 383, 383, 383, 384, 384, 384, 384, 384, 385, 386, 384,
+    384, 385,  12,  12, 387, 387, 387, 387, 387, 388, 389, 387, 390, 390, 390, 390,
+    390, 391, 390, 390, 392, 392, 392, 392, 393,  12, 392, 392, 394, 394, 394, 394,
+    395,  12, 396, 397,  12,  12, 396, 394, 398, 398, 398, 398, 398, 398, 399,  12,
+    400, 400, 400, 400, 401,  12,  12,  12, 401,  12, 402, 400,  29,  29,  29, 403,
+    404, 404, 404, 404, 404, 404, 404, 405, 406, 404, 404, 404,  12,  12,  12, 407,
+    408, 408, 408, 408, 409,  12,  12,  12, 410, 410, 410, 410, 410, 410, 411,  12,
+    410, 410, 412,  12, 413, 413, 413, 413, 413, 414, 413, 413, 413,  12,  12,  12,
+    415, 415, 415, 415, 415, 416,  12,  12, 417, 417, 417, 417, 417, 417, 417, 418,
+    122, 123, 123, 123, 123, 130,  12,  12, 419, 419, 419, 419, 420, 419, 419, 419,
+    419, 419, 419, 421, 422, 423, 424, 425, 422, 422, 422, 425, 422, 422, 426,  12,
+    427, 427, 427, 427, 427, 427, 428,  12, 427, 427, 429,  12, 430, 431, 430, 432,
+    432, 430, 430, 430, 430, 430, 433, 430, 433, 431, 434, 430, 430, 432, 432, 434,
+    435, 436,  12, 431, 430, 437, 430, 435, 430, 435,  12,  12, 438, 438, 438, 438,
+    438, 438,  12,  12, 438, 438, 439,  12, 440, 440, 440, 440, 440, 441, 440, 440,
+    440, 440, 440, 441, 442, 442, 442, 442, 442, 443,  12,  12, 442, 442, 444,  12,
+    445, 445, 445, 445, 445, 445,  12,  12, 445, 445, 446,  12, 447, 447, 447, 447,
+    447, 447, 448, 449, 447, 447, 447,  12, 450, 450, 450, 450, 451,  12,  12, 452,
+    453, 453, 453, 453, 453, 453, 454,  12, 455, 455, 455, 455, 455, 455, 456,  12,
+    455, 455, 455, 457, 455, 458,  12,  12, 455,  12,  12,  12, 459, 459, 459, 459,
+    459, 459, 459, 460, 461, 461, 461, 461, 461, 462,  12,  12, 277, 277, 463,  12,
+    464, 464, 464, 464, 464, 464, 464, 465, 464, 464, 466, 467, 468, 468, 468, 468,
+    468, 468, 468, 469, 468, 469,  12,  12, 470, 470, 470, 470, 470, 471,  12,  12,
+    470, 470, 472, 470, 472, 470, 470, 470, 470, 470,  12, 473, 474, 474, 474, 474,
+    474, 475,  12,  12, 474, 474, 474, 476,  12,  12,  12, 477, 478,  12,  12,  12,
+    479, 479, 479, 479, 479, 479, 480,  12, 479, 479, 479, 481, 479, 479, 481,  12,
+    479, 479, 482, 479,   0, 241,  12,  12,   0, 234, 242,   0,   0, 483, 230,   0,
+      0,   0, 483,   7, 214, 484,   7,   0,   0,   0, 485, 230,   0,   0, 486,  12,
+      8, 227,  12,  12,   0,   0,   0, 231, 487, 488, 242, 231,   0,   0, 489, 242,
+      0, 242,   0,   0,   0, 489, 234, 242,   0, 231,   0, 231,   0,   0, 489, 234,
+      0, 490, 240,   0, 231,   0,   0,   0,   0,   0,   0, 240, 491, 491, 491, 491,
+    491, 491, 491,  12,  12,  12, 492, 491, 493, 491, 491, 491, 494, 494, 494, 494,
+    494, 495, 494, 494, 494, 496,  12,  12,  29, 497,  29,  29, 498, 499, 497,  29,
+    403,  29, 500,  12, 501,  51, 500, 497, 498, 499, 500, 500, 498, 499, 403,  29,
+    403,  29, 497, 502,  29,  29, 503,  29,  29,  29,  29,  12, 497, 497, 503,  29,
+      0,   0,   0, 486,  12, 240,   0,   0, 504,  12,  12,  12,   0,   0, 489,   0,
+    486,  12,  12,  12,   0, 486,  12,  12,   0,   0,  12,  12,   0,   0,   0, 241,
+    249, 505,  12,  12, 249, 506,  12,  12, 251,  12,  12,  12, 507,  12,  12,  12,
+};
+
+static RE_UINT8 re_script_stage_5[] = {
+      1,   1,   1,   1,   1,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   1,
+      1,   1,   2,   1,   2,   1,   1,   1,   1,   1,  35,  35,  41,  41,  41,  41,
+      3,   3,   3,   3,   1,   3,   3,   3,   0,   0,   3,   3,   3,   3,   1,   3,
+      0,   0,   0,   0,   3,   1,   3,   1,   3,   3,   3,   0,   3,   0,   3,   3,
+      3,   3,   0,   3,   3,   3,  55,  55,  55,  55,  55,  55,   4,   4,   4,   4,
+      4,  41,  41,   4,   0,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   0,
+      0,   1,   5,   0,   0,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   0,
+      6,   0,   0,   0,   7,   7,   7,   7,   7,   1,   7,   7,   1,   7,   7,   7,
+      7,   7,   7,   1,   1,   0,   7,   1,   7,   7,   7,  41,  41,  41,   7,   7,
+     41,   7,   7,   7,   8,   8,   8,   8,   8,   8,   0,   8,   8,   8,   8,   0,
+      0,   8,   8,   8,   9,   9,   9,   9,   9,   9,   0,   0,  66,  66,  66,  66,
+     66,  66,  66,   0,  82,  82,  82,  82,  82,  82,   0,   0,  82,  82,  82,   0,
+     95,  95,  95,  95,   0,   0,  95,   0,   7,   0,   0,   0,   0,   0,   0,   7,
+     10,  10,  10,  10,  10,  41,  41,  10,   1,   1,  10,  10,  11,  11,  11,  11,
+      0,  11,  11,  11,  11,   0,   0,  11,  11,   0,  11,  11,  11,   0,  11,   0,
+      0,   0,  11,  11,  11,  11,   0,   0,  11,  11,  11,   0,   0,   0,   0,  11,
+     11,  11,   0,  11,   0,  12,  12,  12,  12,  12,  12,   0,   0,   0,   0,  12,
+     12,   0,   0,  12,  12,  12,  12,  12,  12,   0,  12,  12,   0,  12,  12,   0,
+     12,  12,   0,   0,   0,  12,   0,   0,  12,   0,  12,   0,   0,   0,  12,  12,
+      0,  13,  13,  13,  13,  13,  13,  13,  13,  13,   0,  13,  13,   0,  13,  13,
+     13,  13,   0,   0,  13,   0,   0,   0,   0,   0,  13,  13,   0,  13,   0,   0,
+      0,  14,  14,  14,  14,  14,  14,  14,  14,   0,   0,  14,  14,   0,  14,  14,
+     14,  14,   0,   0,   0,   0,  14,  14,  14,  14,   0,  14,   0,   0,  15,  15,
+      0,  15,  15,  15,  15,  15,  15,   0,  15,   0,  15,  15,  15,  15,   0,   0,
+      0,  15,  15,   0,   0,   0,   0,  15,  15,   0,   0,   0,  15,  15,  15,  15,
+     16,  16,  16,  16,   0,  16,  16,  16,  16,   0,  16,  16,  16,  16,   0,   0,
+      0,  16,  16,   0,  16,  16,  16,   0,   0,   0,  16,  16,   0,  17,  17,  17,
+     17,  17,  17,  17,  17,   0,  17,  17,  17,  17,   0,   0,   0,  17,  17,   0,
+      0,   0,  17,   0,   0,   0,  17,  17,   0,  18,  18,  18,  18,  18,  18,  18,
+     18,   0,  18,  18,  18,  18,  18,   0,   0,   0,   0,  18,   0,   0,  18,  18,
+     18,  18,   0,   0,   0,   0,  19,  19,   0,  19,  19,  19,  19,  19,  19,  19,
+     19,  19,  19,   0,  19,  19,   0,  19,   0,  19,   0,   0,   0,   0,  19,   0,
+      0,   0,   0,  19,  19,   0,  19,   0,  19,   0,   0,   0,   0,  20,  20,  20,
+     20,  20,  20,  20,  20,  20,  20,   0,   0,   0,   0,   1,   0,  21,  21,   0,
+     21,   0,   0,  21,  21,   0,  21,   0,   0,  21,   0,   0,  21,  21,  21,  21,
+      0,  21,  21,  21,   0,  21,   0,  21,   0,   0,  21,  21,  21,  21,   0,  21,
+     21,  21,   0,   0,  22,  22,  22,  22,   0,  22,  22,  22,  22,   0,   0,   0,
+     22,   0,  22,  22,  22,   1,   1,   1,   1,  22,  22,   0,  23,  23,  23,  23,
+     24,  24,  24,  24,  24,  24,   0,  24,   0,  24,   0,   0,  24,  24,  24,   1,
+     25,  25,  25,  25,  26,  26,  26,  26,  26,   0,  26,  26,  26,  26,   0,   0,
+     26,  26,  26,   0,   0,  26,  26,  26,  26,   0,   0,   0,  27,  27,  27,  27,
+     27,  27,   0,   0,  28,  28,  28,  28,  29,  29,  29,  29,  29,   0,   0,   0,
+     30,  30,  30,  30,  30,  30,  30,   1,   1,   1,  30,  30,  30,   0,   0,   0,
+     42,  42,  42,  42,  42,   0,  42,  42,  42,   0,   0,   0,  43,  43,  43,  43,
+     43,   1,   1,   0,  44,  44,  44,  44,  45,  45,  45,  45,  45,   0,  45,  45,
+     31,  31,  31,  31,  31,  31,   0,   0,  32,  32,   1,   1,  32,   1,  32,  32,
+     32,  32,  32,  32,  32,  32,  32,   0,  32,  32,   0,   0,  28,  28,   0,   0,
+     46,  46,  46,  46,  46,  46,  46,   0,  46,   0,   0,   0,  47,  47,  47,  47,
+     47,  47,   0,   0,  47,   0,   0,   0,  56,  56,  56,  56,  56,  56,   0,   0,
+     56,  56,  56,   0,   0,   0,  56,  56,  54,  54,  54,  54,   0,   0,  54,  54,
+     78,  78,  78,  78,  78,  78,  78,   0,  78,   0,   0,  78,  78,  78,   0,   0,
+     41,  41,  41,   0,  62,  62,  62,  62,  62,   0,   0,   0,  67,  67,  67,  67,
+     93,  93,  93,  93,  68,  68,  68,  68,   0,   0,   0,  68,  68,  68,   0,   0,
+      0,  68,  68,  68,  69,  69,  69,  69,  41,  41,  41,   1,  41,   1,  41,  41,
+     41,   1,   1,   1,   1,  41,   1,   1,  41,   1,   1,   0,  41,  41,   0,   0,
+      2,   2,   3,   3,   3,   3,   3,   4,   2,   3,   3,   3,   3,   3,   2,   2,
+      3,   3,   3,   2,   4,   2,   2,   2,   2,   2,   2,   3,   3,   3,   0,   0,
+      0,   3,   0,   3,   0,   3,   3,   3,  41,  41,   1,   1,   1,   0,   1,   1,
+      1,   2,   0,   0,   1,   1,   1,   2,   1,   1,   1,   0,   2,   0,   0,   0,
+     41,   0,   0,   0,   1,   1,   3,   1,   1,   1,   2,   2,  53,  53,  53,  53,
+      0,   0,   1,   1,   1,   1,   0,   0,   0,   1,   1,   1,  57,  57,  57,  57,
+     57,  57,  57,   0,   0,  55,  55,  55,  58,  58,  58,  58,   0,   0,   0,  58,
+     58,   0,   0,   0,  36,  36,  36,  36,  36,  36,   0,  36,  36,  36,   0,   0,
+      1,  36,   1,  36,   1,  36,  36,  36,  36,  36,  41,  41,  41,  41,  25,  25,
+      0,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,   0,   0,  41,  41,   1,
+      1,  33,  33,  33,   1,  34,  34,  34,  34,  34,  34,  34,  34,  34,  34,   1,
+      0,  35,  35,  35,  35,  35,  35,  35,  35,  35,   0,   0,   0,  25,  25,  25,
+     25,  25,  25,   0,  35,  35,  35,   0,  25,  25,  25,   1,  34,  34,  34,   0,
+     37,  37,  37,  37,  37,   0,   0,   0,  37,  37,  37,   0,  83,  83,  83,  83,
+     70,  70,  70,  70,  84,  84,  84,  84,   2,   2,   0,   0,   0,   0,   0,   2,
+     59,  59,  59,  59,  65,  65,  65,  65,  71,  71,  71,  71,  71,   0,   0,   0,
+      0,   0,  71,  71,  71,  71,   0,   0,  10,  10,   0,   0,  72,  72,  72,  72,
+     72,  72,   1,  72,  73,  73,  73,  73,   0,   0,   0,  73,  25,   0,   0,   0,
+     85,  85,  85,  85,  85,  85,   0,   1,  85,  85,   0,   0,   0,   0,  85,  85,
+     23,  23,  23,   0,  77,  77,  77,  77,  77,  77,  77,   0,  77,  77,   0,   0,
+     79,  79,  79,  79,  79,  79,  79,   0,   0,   0,   0,  79,  86,  86,  86,  86,
+     86,  86,  86,   0,   2,   3,   0,   0,  86,  86,   0,   0,   0,   0,   0,  25,
+      2,   2,   2,   0,   0,   0,   0,   5,   6,   0,   6,   0,   6,   6,   0,   6,
+      6,   0,   6,   6,   7,   7,   0,   0,   7,   7,   1,   1,   0,   0,   7,   7,
+     41,  41,   4,   4,   7,   0,   7,   7,   7,   0,   0,   1,   1,   1,  34,  34,
+     34,  34,   1,   1,   0,   0,  25,  25,  48,  48,  48,  48,   0,  48,  48,  48,
+     48,  48,  48,   0,  48,  48,   0,  48,  48,  48,   0,   0,   3,   0,   0,   0,
+      1,  41,   0,   0,  74,  74,  74,  74,  74,   0,   0,   0,  75,  75,  75,  75,
+     75,   0,   0,   0,  38,  38,  38,  38,  39,  39,  39,  39,  39,  39,  39,   0,
+    120, 120, 120, 120, 120, 120, 120,   0,  49,  49,  49,  49,  49,  49,   0,  49,
+     60,  60,  60,  60,  60,  60,   0,   0,  40,  40,  40,  40,  50,  50,  50,  50,
+     51,  51,  51,  51,  51,  51,   0,   0, 106, 106, 106, 106, 103, 103, 103, 103,
+      0,   0,   0, 103, 110, 110, 110, 110, 110, 110, 110,   0, 110, 110,   0,   0,
+     52,  52,  52,  52,  52,  52,   0,   0,  52,   0,  52,  52,  52,  52,   0,  52,
+     52,   0,   0,   0,  52,   0,   0,  52,  87,  87,  87,  87,  87,  87,   0,  87,
+    118, 118, 118, 118, 117, 117, 117, 117, 117, 117, 117,   0,   0,   0,   0, 117,
+    128, 128, 128, 128, 128, 128, 128,   0, 128, 128,   0,   0,   0,   0,   0, 128,
+     64,  64,  64,  64,   0,   0,   0,  64,  76,  76,  76,  76,  76,  76,   0,   0,
+      0,   0,   0,  76,  98,  98,  98,  98,  97,  97,  97,  97,   0,   0,  97,  97,
+     61,  61,  61,  61,   0,  61,  61,   0,   0,  61,  61,  61,  61,  61,  61,   0,
+      0,   0,   0,  61,  61,   0,   0,   0,  88,  88,  88,  88, 116, 116, 116, 116,
+    112, 112, 112, 112, 112, 112, 112,   0,   0,   0,   0, 112,  80,  80,  80,  80,
+     80,  80,   0,   0,   0,  80,  80,  80,  89,  89,  89,  89,  89,  89,   0,   0,
+     90,  90,  90,  90,  90,  90,  90,   0, 121, 121, 121, 121, 121, 121,   0,   0,
+      0, 121, 121, 121, 121,   0,   0,   0,  91,  91,  91,  91,  91,   0,   0,   0,
+    130, 130, 130, 130, 130, 130, 130,   0,   0,   0, 130, 130,   7,   7,   7,   0,
+     94,  94,  94,  94,  94,  94,   0,   0,   0,   0,  94,  94,   0,   0,   0,  94,
+     92,  92,  92,  92,  92,  92,   0,   0, 101, 101, 101, 101, 101,   0,   0,   0,
+    101, 101,   0,   0,  96,  96,  96,  96,  96,   0,  96,  96, 111, 111, 111, 111,
+    111, 111, 111,   0, 100, 100, 100, 100, 100, 100,   0,   0, 109, 109, 109, 109,
+    109, 109,   0, 109, 109, 109,   0,   0, 129, 129, 129, 129, 129, 129, 129,   0,
+    129,   0, 129, 129, 129, 129,   0, 129, 129, 129,   0,   0, 123, 123, 123, 123,
+    123, 123, 123,   0, 123, 123,   0,   0, 107, 107, 107, 107,   0, 107, 107, 107,
+    107,   0,   0, 107, 107,   0, 107, 107, 107, 107,   0,   0, 107,   0,   0,   0,
+      0,   0,   0, 107,   0,   0, 107, 107, 124, 124, 124, 124, 124, 124,   0,   0,
+    122, 122, 122, 122, 122, 122,   0,   0, 114, 114, 114, 114, 114,   0,   0,   0,
+    114, 114,   0,   0, 102, 102, 102, 102, 102, 102,   0,   0, 126, 126, 126, 126,
+    126, 126,   0,   0,   0, 126, 126, 126, 125, 125, 125, 125, 125, 125, 125,   0,
+      0,   0,   0, 125, 119, 119, 119, 119, 119,   0,   0,   0,  63,  63,  63,  63,
+     63,  63,   0,   0,  63,  63,  63,   0,  63,   0,   0,   0,  81,  81,  81,  81,
+     81,  81,  81,   0, 127, 127, 127, 127, 127, 127, 127,   0,  84,   0,   0,   0,
+    115, 115, 115, 115, 115, 115, 115,   0, 115, 115,   0,   0,   0,   0, 115, 115,
+    104, 104, 104, 104, 104, 104,   0,   0, 108, 108, 108, 108, 108, 108,   0,   0,
+    108, 108,   0, 108,   0, 108, 108, 108,  99,  99,  99,  99,  99,   0,   0,   0,
+     99,  99,  99,   0,   0,   0,   0,  99,  34,  33,   0,   0, 105, 105, 105, 105,
+    105, 105, 105,   0, 105,   0,   0,   0, 105, 105,   0,   0,   1,   1,   1,  41,
+      1,  41,  41,  41,   1,   1,  41,  41,   1,   0,   0,   0,   0,   0,   1,   0,
+      0,   1,   1,   0,   1,   1,   0,   1,   1,   0,   1,   0, 131, 131, 131, 131,
+      0,   0,   0, 131,   0, 131, 131, 131, 113, 113, 113, 113, 113,   0,   0, 113,
+    113, 113, 113,   0,   0,   7,   7,   7,   0,   7,   7,   0,   7,   0,   0,   7,
+      0,   7,   0,   7,   0,   0,   7,   0,   7,   0,   7,   0,   7,   7,   0,   7,
+     33,   1,   1,   0,  36,  36,  36,   0,  36,   0,   0,   0,   0,   1,   0,   0,
+};
+
+/* Script: 10928 bytes. */
+
+RE_UINT32 re_get_script(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 11;
+    code = ch ^ (f << 11);
+    pos = (RE_UINT32)re_script_stage_1[f] << 4;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_script_stage_2[pos + f] << 3;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_script_stage_3[pos + f] << 2;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_script_stage_4[pos + f] << 2;
+    value = re_script_stage_5[pos + code];
+
+    return value;
+}
+
+/* Word_Break. */
+
+static RE_UINT8 re_word_break_stage_1[] = {
+     0,  1,  2,  3,  4,  4,  4,  4,  4,  4,  5,  6,  6,  7,  4,  8,
+     9, 10, 11, 12, 13,  4, 14,  4,  4,  4,  4, 15,  4, 16, 17, 18,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    19,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+};
+
+static RE_UINT8 re_word_break_stage_2[] = {
+      0,   1,   2,   2,   2,   3,   4,   5,   2,   6,   7,   8,   9,  10,  11,  12,
+     13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,
+     29,  30,   2,   2,  31,  32,  33,  34,  35,   2,   2,   2,  36,  37,  38,  39,
+     40,  41,  42,  43,  44,  45,  46,  47,  48,  49,   2,  50,   2,   2,  51,  52,
+     53,  54,  55,  56,  57,  57,  57,  57,  57,  58,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  59,  60,  61,  62,  63,  57,  57,  57,
+     64,  65,  66,  67,  57,  68,  69,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,  70,   2,   2,  71,  72,  73,  74,
+     75,  76,  77,  78,  79,  80,  81,  82,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,  83,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  84,  85,   2,   2,  86,  87,  88,  89,  90,  91,
+     92,  93,  94,  95,  57,  96,  97,  98,   2,  99, 100,  57,   2,   2, 101,  57,
+    102, 103, 104, 105, 106, 107, 108, 109, 110, 111,  57,  57,  57,  57,  57,  57,
+    112, 113, 114, 115, 116, 117, 118,  57,  57, 119,  57, 120, 121, 122, 123,  57,
+     57, 124,  57,  57,  57, 125,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+      2,   2,   2,   2,   2,   2,   2, 126, 127,   2, 128,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+      2,   2,   2,   2,   2,   2,   2,   2, 129,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,   2,   2,   2,   2, 130,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+      2,   2,   2,   2, 131, 132, 133, 134,  57,  57,  57,  57,  57,  57, 135, 136,
+    137,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57, 138, 139,  57,  57,  57,  57,  57,  57,
+     57,  57, 140, 141, 142,  57,  57,  57, 143, 144, 145,   2,   2, 146, 147, 148,
+     57,  57,  57,  57, 149, 150,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+      2, 151,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57, 152, 153,  57,  57,
+     57,  57, 154, 155,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+    156,  57, 157, 158,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+     57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,  57,
+};
+
+static RE_UINT8 re_word_break_stage_3[] = {
+      0,   1,   0,   0,   2,   3,   4,   5,   6,   7,   7,   8,   6,   7,   7,   9,
+     10,   0,   0,   0,   0,  11,  12,  13,   7,   7,  14,   7,   7,   7,  14,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,  15,   7,  16,   0,  17,  18,   0,   0,
+     19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  20,  21,
+     22,  23,   7,   7,  24,   7,   7,   7,   7,   7,   7,   7,   7,   7,  25,   7,
+     26,  27,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,   6,   7,   7,   7,  14,  28,   6,   7,   7,   7,
+      7,  29,  30,  19,  19,  19,  19,  31,  32,   0,  33,  33,  33,  34,  35,   0,
+     36,  37,  19,  38,   7,   7,   7,   7,   7,  39,  19,  19,   4,  40,  41,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,  42,  43,  44,  45,   4,  46,
+      0,  47,  48,   7,   7,   7,  19,  19,  19,  49,   7,   7,   7,   7,   7,   7,
+      7,   7,   7,   7,  50,  19,  51,   0,   4,  52,   7,   7,   7,  39,  53,  54,
+      7,   7,  50,  55,  56,  57,   0,   0,   7,   7,   7,  58,   0,   0,   0,   0,
+      0,   0,   0,   0,   7,   7,  17,   0,   0,   0,   0,   0,  59,  19,  19,  19,
+     60,   7,   7,   7,   7,   7,   7,  61,  19,  19,  62,   7,  63,   4,   6,   7,
+     64,  65,  66,   7,   7,  67,  68,  69,  70,  71,  72,  73,  63,   4,  74,   0,
+     75,  76,  66,   7,   7,  67,  77,  78,  79,  80,  81,  82,  83,   4,  84,   0,
+     75,  25,  24,   7,   7,  67,  85,  69,  31,  86,  87,   0,  63,   4,   0,  28,
+     75,  65,  66,   7,   7,  67,  85,  69,  70,  80,  88,  73,  63,   4,  28,   0,
+     89,  90,  91,  92,  93,  90,   7,  94,  95,  96,  97,   0,  83,   4,   0,   0,
+     98,  20,  67,   7,   7,  67,   7,  99, 100,  96, 101,   9,  63,   4,   0,   0,
+     75,  20,  67,   7,   7,  67, 102,  69, 100,  96, 101, 103,  63,   4, 104,   0,
+     75,  20,  67,   7,   7,   7,   7, 105, 100, 106,  72, 107,  63,   4,   0, 108,
+    109,   7,  14, 108,   7,   7,  24, 110,  14, 111, 112,  19,  83,   4, 113,   0,
+      0,   0,   0,   0,   0,   0, 114, 115,  72, 116,   4, 117,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 114, 118,   0, 119,   4, 117,   0,   0,   0,   0,
+     87,   0,   0, 120,   4, 117, 121, 122,   7,   6,   7,   7,   7,  17,  30,  19,
+    100, 123,  19,  30,  19,  19,  19, 124, 125,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,  59,  19, 116,   4, 117,  88, 126, 127, 119, 128,   0,
+    129,  31,   4, 130,   7,   7,   7,   7,  25, 131,   7,   7,   7,   7,   7, 132,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,  91,  14,  91,   7,   7,   7,   7,
+      7,  91,   7,   7,   7,   7,  91,  14,  91,   7,  14,   7,   7,   7,   7,   7,
+      7,   7,  91,   7,   7,   7,   7,   7,   7,   7,   7, 133,   0,   0,   0,   0,
+      7,   7,   0,   0,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7, 134, 134,
+      6,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,  65,   7,   7,
+      6,   7,   7,   9,   7,   7,   7,   7,   7,   7,   7,   7,   7,  90,   7,  87,
+      7,  20, 135,   0,   7,   7, 135,   0,   7,   7, 136,   0,   7,  20, 137,   0,
+      0,   0,   0,   0,   0,   0, 138,  19,  19,  19, 139, 140,   4, 117,   0,   0,
+      0, 141,   4, 117,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   0,
+      7,   7,   7,   7,   7, 142,   7,   7,   7,   7,   7,   7,   7,   7, 134,   0,
+      7,   7,   7,  14,  19, 139,  19, 139,  83,   4,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   4, 117,   0,   0,   0,   0,
+      7,   7, 143, 139,   0,   0,   0,   0,   0,   0, 144, 116,  19,  19,  19,  70,
+      4, 117,   4, 117,   0,   0,  19, 116,   0,   0,   0,   0,   0,   0,   0,   0,
+    145,   7,   7,   7,   7,   7, 146,  19, 145, 147,   4, 117,   0,  59, 139,   0,
+    148,   7,   7,   7,  62, 149,   4,  52,   7,   7,   7,   7,  50,  19, 139,   0,
+      7,   7,   7,   7, 146,  19,  19,   0,   4, 150,   4,  52,   7,   7,   7, 134,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 151,  19,  19, 152, 153, 120,
+      7,   7,   7,   7,   7,   7,   7,   7,  19,  19,  19,  19,  19,  19, 119, 138,
+      7,   7, 134, 134,   7,   7,   7,   7, 134, 134,   7, 154,   7,   7,   7, 134,
+      7,   7,   7,   7,   7,   7,  20, 155, 156,  17, 157, 147,   7,  17, 156,  17,
+      0, 158,   0, 159, 160, 161,   0, 162, 163,   0, 164,   0, 165, 166,  28, 107,
+      0,   0,   7,  17,   0,   0,   0,   0,   0,   0,  19,  19,  19,  19, 167,   0,
+    168, 108, 110, 169,  18, 170,   7, 171, 172, 173,   0,   0,   7,   7,   7,   7,
+      7,  87,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 174,   7,   7,   7,   7,   7,   7,  74,   0,   0,
+      7,   7,   7,   7,   7,  14,   7,   7,   7,   7,   7,  14,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,  17, 175, 176,   0,
+      7,   7,   7,   7,  25, 131,   7,   7,   7,   7,   7,   7,   7, 107,   0,  72,
+      7,   7,  14,   0,  14,  14,  14,  14,  14,  14,  14,  14,  19,  19,  19,  19,
+      0,   0,   0,   0,   0, 107,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    131,   0,   0,   0,   0, 129, 177,  93,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0, 178, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 180,
+    172,   7,   7,   7,   7, 134,   6,   7,   7,   7,   7,   7,   7,   7,   7,   7,
+      7,  14,   0,   0,   7,   7,   7,   9,   0,   0,   0,   0,   0,   0, 179, 179,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 179, 179, 179, 179, 179, 181,
+    179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179,   0,   0,   0,   0,   0,
+      7,  17,   0,   0,   0,   0,   0,   0,   0,   0,   7,   7,   7,   7,   7, 134,
+      7,  17,   7,   7,   4, 182,   0,   0,   7,   7,   7,   7,   7, 143, 151, 183,
+      7,   7,   7,  50,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7, 120,   0,
+      0,   0, 107,   7, 108,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,
+      7,  66,   7,   7,   7, 134,   7,   0,   0,   0,   0,   0,   0,   0, 107,   7,
+    184, 185,   7,   7,  39,   0,   0,   0,   7,   7,   7,   7,   7,   7, 147,   0,
+     27,   7,   7,   7,   7,   7, 146,  19, 124,   0,   4, 117,  19,  19,  27, 186,
+      4,  52,   7,   7,  50, 119,   7,   7, 143,  19, 139,   0,   7,   7,   7,  17,
+     60,   7,   7,   7,   7,   7,  39,  19, 167, 107,   4, 117, 140,   0,   4, 117,
+      7,   7,   7,   7,   7,  62, 116,   0, 185, 187,   4, 117,   0,   0,   0, 188,
+      0,   0,   0,   0,   0,   0, 127, 189,  81,   0,   0,   0,   7,  39, 190,   0,
+    191, 191, 191,   0,  14,  14,   7,   7,   7,   7,   7, 132, 134,   0,   7,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,  39, 192,   4, 117,
+      7,   7,   7,   7, 147,   0,   7,   7,  14, 193,   7,   7,   7,   7,   7, 147,
+     14,   0, 193, 194,  33, 195, 196, 197, 198,  33,   7,   7,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,  74,   0,   0,   0, 193,   7,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,   7, 134,   0,   0,   7,   7,   7,   7,   7,   7,
+      7,   7, 108,   7,   7,   7,   7,   7,   7,   0,   0,   0,   0,   0,   7, 147,
+     19,  19, 199,   0,  19,  19, 200,   0,   0, 201, 202,   0,   0,   0,  20,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7, 203,
+    204,   3,   0, 205,   6,   7,   7,   8,   6,   7,   7,   9, 206, 179, 179, 179,
+    179, 179, 179, 207,   7,   7,   7,  14, 108, 108, 108, 208,   0,   0,   0, 209,
+      7, 102,   7,   7,  14,   7,   7, 210,   7, 134,   7, 134,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   9,
+      0,   0,   0,   0,   0,   0,   0,   0,   7,   7,   7,   7,   7,   7,  17,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 140,
+      7,   7,   7,  17,   7,   7,   7,   7,   7,   7,  87,   0, 167,   0,   0,   0,
+      7,   7,   7,   7,   0,   0,   7,   7,   7,   9,   7,   7,   7,   7,  50, 115,
+      7,   7,   7, 134,   7,   7,   7,   7, 147,   7, 169,   0,   0,   0,   0,   0,
+      7,   7,   7, 134,   4, 117,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   0,   7,   7,   7,   7,   7,   7, 147,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,  14,   0,   7,   7, 134,   0,   7,   0,   0,   0,
+    134,  67,   7,   7,   7,   7,  25, 211,   7,   7, 134,   0,   7,   7,  14,   0,
+      7,   7,   7,  14,   0,   0,   0,   0,   0,   0,   0,   0,   7,   7, 212,   0,
+      7,   7, 134,   0,   7,   7,   7,  74,   0,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7, 174,   0,   0,   0,   0,   0,   0,   0,   0,
+    213, 138, 102,   6,   7,   7, 147,  79,   0,   0,   0,   0,   7,   7,   7,  17,
+      7,   7,   7,  17,   0,   0,   0,   0,   7,   6,   7,   7, 214,   0,   0,   0,
+      7,   7,   7,   7,   7,   7, 134,   0,   7,   7, 134,   0,   7,   7,   9,   0,
+      7,   7,  74,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,  87,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   9,   0,   7,   7,   7,   7,   7,   7,   9,   0,
+    148,   7,   7,   7,   7,   7,   7,  19, 116,   0,   0,   0,  83,   4,   0,  72,
+    148,   7,   7,   7,   7,   7,  19, 215,   0,   0,   7,   7,   7,  87,   4, 117,
+    148,   7,   7,   7, 143,  19, 216,   4,   0,   0,   7,   7,   7,   7, 217,   0,
+    148,   7,   7,   7,   7,   7,  39,  19, 218, 219,   4, 220,   0,   0,   0,   0,
+      7,   7,  24,   7,   7, 146,  19,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     14, 170,   7,  25,   7,  87,   7,   7,   7,   7,   7, 143,  19, 115,   4, 117,
+     98,  65,  66,   7,   7,  67,  85,  69,  70,  80,  97, 172, 221, 124, 124,   0,
+      7,   7,   7,   7,   7,   7,  19,  19, 222,   0,   4, 117,   0,   0,   0,   0,
+      7,   7,   7,   7,   7, 143, 119,  19, 167,   0,   0, 187,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,  19,  19, 223,   0,   4, 117,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,  39,  19,   0,   4, 117,   0,   0,   0,   0,   0,   0,
+      0,   0,   0, 144,  19, 139,   4, 117,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   7,   7,   7,   7,   7,   7,   7,   7,   4, 117,   0, 107,
+      0,   0,   0,   0,   0,   0,   0,   0,   7,   7,   7,   7,   7,   7,   7,  87,
+      7,   7,   7,  74,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,  14,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7, 147,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,  14,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7,  14,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,  87,   7,   7,   7,  14,   4, 117,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   7,   7,   7, 134, 124,   0,
+      7,   7,   7,   7,   7,   7, 116,   0, 147,   0,   4, 117, 193,   7,   7, 172,
+      7,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7,  17,   0,  62,  19,  19,  19,  19, 116,
+      0,  72, 148,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    224,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   7,   9,   7,  17,
+      7,  87,   7, 225, 226,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 144, 227, 228, 229,
+    230, 139,   0,   0,   0, 231,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0, 219,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7,   7,   7,  20,   7,   7,   7,   7,   7,
+      7,   7,   7,  20, 232, 233,   7, 234, 102,   7,   7,   7,   7,   7,   7,   7,
+     25, 235,  20,  20,   7,   7,   7, 236, 155, 108,  67,   7,   7,   7,   7,   7,
+      7,   7,   7,   7, 134,   7,   7,   7,  67,   7,   7, 132,   7,   7,   7, 132,
+      7,   7,  20,   7,   7,   7,  20,   7,   7,  14,   7,   7,   7,  14,   7,   7,
+      7,  67,   7,   7,   7,  67,   7,   7, 132, 237,   4,   4,   4,   4,   4,   4,
+     19,  19,  19,  19,  19,  19, 116,  59,  19,  19,  19,  19,  19, 124, 140,   0,
+    238,   0,   0,  59,  30,  19,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      7,   7,   7,   7,   7,   7,   7,   7,  17,   0, 116,   0,   0,   0,   0,   0,
+    102,   7,   7,   7, 239,   6, 132, 240, 168, 241, 239, 154, 239, 132, 132,  82,
+      7,  24,   7, 147, 242,  24,   7, 147,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   7,   7,   7,  74,   7,   7,   7,  74,   7,   7,
+      7,  74,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 243, 244, 244, 244,
+    245,   0,   0,   0, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166,
+     19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,
+     19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,  19,   0,   0,
+};
+
+static RE_UINT8 re_word_break_stage_4[] = {
+      0,   0,   1,   2,   3,   4,   0,   5,   6,   6,   7,   0,   8,   9,   9,   9,
+     10,  11,  10,   0,   0,  12,  13,  14,   0,  15,  13,   0,   9,  10,  16,  17,
+     16,  18,   9,  19,   0,  20,  21,  21,   9,  22,  17,  23,   0,  24,  10,  22,
+     25,   9,   9,  25,  26,  21,  27,   9,  28,   0,  29,   0,  30,  21,  21,  31,
+     32,  31,  33,  33,  34,   0,  35,  36,  37,  38,   0,  39,  40,  41,  42,  21,
+     43,  44,  45,   9,   9,  46,  21,  47,  21,  48,  49,  27,  50,  51,   0,  52,
+     53,   9,  40,   8,   9,  54,  55,   0,  50,   9,  21,  16,  56,   0,  57,  21,
+     21,  58,  58,  59,  58,   0,  60,  21,  21,   9,  54,  61,  58,  21,  54,  62,
+     58,   8,   9,  51,  51,   9,  22,   9,  20,  17,  16,  61,  21,  63,  63,  64,
+      0,  60,   0,  25,  16,   0,  30,   8,  10,  65,  22,  66,  16,  49,  40,  60,
+     63,  59,  67,   0,   8,  20,   0,  62,  27,  68,  22,   8,  31,  59,  19,   0,
+      0,  69,  70,   8,  10,  17,  22,  16,  66,  22,  65,  19,  16,  69,  40,  69,
+     49,  59,  19,  60,  21,   8,  16,  46,  21,  49,   0,  32,   9,   8,   0,  13,
+     66,   0,  10,  46,  49,  64,   0,  65,  17,   9,  69,   8,   9,  28,  71,  60,
+     21,  72,  69,   0,  67,  21,  40,   0,  21,  40,  73,   0,  31,  74,  21,  59,
+     59,   0,   0,  75,  67,  69,   9,  58,  21,  74,   0,  71,  59,  69,  49,  63,
+     30,  74,  69,  21,  76,  59,   0,  28,  10,   9,  10,  30,   9,  16,  54,  74,
+     54,   0,  77,   0,   0,  21,  21,   0,   0,  67,  60,  78,  79,   0,   9,  42,
+      0,  30,  21,  45,   9,  21,   9,   0,  80,   9,  21,  27,  73,   8,  40,  21,
+     45,  53,  54,  81,  82,  82,   9,  20,  17,  22,   9,  17,   0,  83,  84,   0,
+      0,  85,  86,  87,   0,  11,  88,  89,   0,  88,  37,  90,  37,  37,  74,   0,
+     13,  65,   8,  16,  22,  25,  16,   9,   0,   8,  16,  13,   0,  17,  65,  42,
+     27,   0,  91,  92,  93,  94,  95,  95,  96,  95,  95,  96,  50,   0,  21,  97,
+     98,  98,  42,   9,  65,  28,   9,  59,  60,  59,  74,  69,  17,  99,   8,  10,
+     40,  59,  65,   9,   0, 100, 101,  33,  33,  34,  33, 102, 103, 101, 104,  89,
+     11,  88,   0, 105,   5, 106,   9, 107,   0, 108, 109,   0,   0, 110,  95, 111,
+     17,  19, 112,   0,  10,  25,  19,  51,  10,  16,  58,  32,   9,  99,  40,  14,
+     21, 113,  42,  13,  45,  19,  69,  74, 114,  19,  54,  69,  21,  25,  74,  19,
+     94,   0,  16,  32,  37,   0,  59,  30, 115,  37, 116,  21,  40,  30,  69,  59,
+     13,  66,   8,  22,  25,   8,  10,   8,  25,  10,   9,  62,   0,  74,  66,  51,
+     82,   0,  82,   8,   8,   8,   0, 117, 118, 118,  14,   0,
+};
+
+static RE_UINT8 re_word_break_stage_5[] = {
+     0,  0,  0,  0,  0,  0,  5,  6,  6,  4,  0,  0,  0,  0,  1,  0,
+     0,  0,  0,  2, 13,  0, 14,  0, 15, 15, 15, 15, 15, 15, 12, 13,
+     0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  0,  0,  0,  0, 16,
+     0,  6,  0,  0,  0,  0, 11,  0,  0,  9,  0,  0,  0, 11,  0, 12,
+    11, 11,  0,  0,  0,  0, 11, 11,  0,  0,  0, 12, 11,  0,  0,  0,
+    11,  0, 11,  0,  7,  7,  7,  7, 11,  0, 11, 11, 11, 11, 13, 11,
+     0,  0, 11, 12, 11, 11,  0, 11, 11, 11,  0,  7,  7,  7, 11, 11,
+     0, 11,  0,  0,  0, 13,  0,  0,  0,  7,  7,  7,  7,  7,  0,  7,
+     0,  7,  7,  0,  3,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3, 11,
+    12,  0,  0,  0,  9,  9,  9,  9,  9,  9,  0,  0, 13, 13,  0,  0,
+     7,  7,  7,  0,  9,  0,  0,  0, 11, 11, 11,  7, 15, 15,  0, 15,
+    13,  0, 11, 11,  7, 11, 11, 11,  0, 11,  7,  7,  7,  9,  0,  7,
+     7, 11, 11,  7,  7,  0,  7,  7, 15, 15, 11, 11, 11,  0,  0, 11,
+     0,  0,  0,  9, 11,  7, 11, 11, 11, 11,  7,  7,  7, 11,  0,  0,
+    13,  0, 11,  0,  7,  7, 11,  7, 11,  7,  7,  7,  7,  7,  0,  0,
+     0,  0,  0,  7,  7, 11,  7,  7,  0,  0, 15, 15,  7,  0,  0,  7,
+     7,  7, 11,  0,  0,  0,  0, 11,  0, 11, 11,  0,  0,  7,  0,  0,
+    11,  7,  0,  0,  0,  0,  7,  7,  0,  0,  7, 11,  0,  0,  7,  0,
+     7,  0,  7,  0, 15, 15,  0,  0,  7,  0,  0,  0,  0,  7,  0,  7,
+    15, 15,  7,  7, 11,  0,  7,  7,  7,  7,  9,  0, 11,  7, 11,  0,
+     7,  7,  7, 11,  7, 11, 11,  0,  0, 11,  0, 11,  7,  7,  9,  9,
+    14, 14,  0,  0, 14,  0,  0, 12,  6,  6,  9,  9,  9,  9,  9,  0,
+    16,  0,  0,  0, 13,  0,  0,  0,  9,  0,  9,  9,  0, 10, 10, 10,
+    10, 10,  0,  0,  0,  7,  7, 10, 10,  0,  0,  0, 10, 10, 10, 10,
+    10, 10, 10,  0,  7,  7,  0, 11, 11, 11,  7, 11, 11,  7,  7,  0,
+     0,  3,  7,  3,  3,  0,  3,  3,  3,  0,  3,  0,  3,  3,  0,  3,
+    13,  0,  0, 12,  0, 16, 16, 16, 13, 12,  0,  0, 11,  0,  0,  9,
+     0,  0,  0, 14,  0,  0, 12, 13,  0,  0, 10, 10, 10, 10,  7,  7,
+     0,  9,  9,  9,  7,  0, 15, 15, 15, 15, 11,  0,  7,  7,  7,  9,
+     9,  9,  9,  7,  0,  0,  8,  8,  8,  8,  8,  8,
+};
+
+/* Word_Break: 4424 bytes. */
+
+RE_UINT32 re_get_word_break(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_word_break_stage_1[f] << 5;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_word_break_stage_2[pos + f] << 4;
+    f = code >> 3;
+    code ^= f << 3;
+    pos = (RE_UINT32)re_word_break_stage_3[pos + f] << 1;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_word_break_stage_4[pos + f] << 2;
+    value = re_word_break_stage_5[pos + code];
+
+    return value;
+}
+
+/* Grapheme_Cluster_Break. */
+
+static RE_UINT8 re_grapheme_cluster_break_stage_1[] = {
+     0,  1,  2,  2,  2,  3,  4,  5,  6,  2,  2,  7,  2,  8,  9, 10,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    11,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  2,
+};
+
+static RE_UINT8 re_grapheme_cluster_break_stage_2[] = {
+     0,  1,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+    15, 16,  1, 17,  1,  1,  1, 18, 19, 20, 21, 22, 23, 24,  1,  1,
+    25,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 26, 27,  1,  1,
+    28,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1, 29,  1, 30, 31, 32, 33, 34, 35, 36, 37,
+    38, 39, 40, 34, 35, 36, 37, 38, 39, 40, 34, 35, 36, 37, 38, 39,
+    40, 34, 35, 36, 37, 38, 39, 40, 34, 35, 36, 37, 38, 39, 40, 34,
+    35, 36, 37, 38, 39, 40, 34, 41, 42, 42, 42, 42, 42, 42, 42, 42,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 43,  1,  1, 44, 45,
+     1, 46, 47, 48,  1,  1,  1,  1,  1,  1, 49,  1,  1,  1,  1,  1,
+    50, 51, 52, 53, 54, 55, 56, 57,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 58, 59,  1,  1,  1, 60,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 61,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1, 62, 63,  1,  1,  1,  1,  1,  1,  1, 64,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1, 65,  1,  1,  1,  1,  1,  1,  1,
+     1, 66,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    42, 67, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_grapheme_cluster_break_stage_3[] = {
+      0,   1,   2,   2,   2,   2,   2,   3,   1,   1,   4,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      5,   5,   5,   5,   5,   5,   5,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   6,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   7,   5,   8,   9,   2,   2,   2,
+     10,  11,   2,   2,  12,   5,   2,  13,   2,   2,   2,   2,   2,  14,  15,   2,
+      3,  16,   2,   5,  17,   2,   2,   2,   2,   2,  18,  13,   2,   2,  12,  19,
+      2,  20,  21,   2,   2,  22,   2,   2,   2,   2,   2,   2,   2,   2,  23,   5,
+     24,   2,   2,  25,  26,  27,  28,   2,  29,   2,   2,  30,  31,  32,  28,   2,
+     33,   2,   2,  34,  35,  16,   2,  36,  33,   2,   2,  34,  37,   2,  28,   2,
+     29,   2,   2,  38,  31,  39,  28,   2,  40,   2,   2,  41,  42,  32,   2,   2,
+     43,   2,   2,  44,  45,  46,  28,   2,  29,   2,   2,  47,  48,  46,  28,   2,
+     29,   2,   2,  41,  49,  32,  28,   2,  50,   2,   2,   2,  51,  52,   2,  50,
+      2,   2,   2,  53,  54,   2,   2,   2,   2,   2,   2,  55,  56,   2,   2,   2,
+      2,  57,   2,  58,   2,   2,   2,  59,  60,  61,   5,  62,  63,   2,   2,   2,
+      2,   2,  64,  65,   2,  66,  13,  67,  68,  69,   2,   2,   2,   2,   2,   2,
+     70,  70,  70,  70,  70,  70,  71,  71,  71,  71,  72,  73,  73,  73,  73,  73,
+      2,   2,   2,   2,   2,  64,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,  74,   2,  74,   2,  28,   2,  28,   2,   2,   2,  75,  76,  77,   2,   2,
+     78,   2,   2,   2,   2,   2,   2,   2,   2,   2,  79,   2,   2,   2,   2,   2,
+      2,   2,  80,  81,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,  82,   2,   2,   2,  83,  84,  85,   2,   2,   2,  86,   2,   2,   2,   2,
+     87,   2,   2,  88,  89,   2,  12,  19,  90,   2,  91,   2,   2,   2,  92,  93,
+      2,   2,  94,  95,   2,   2,   2,   2,   2,   2,   2,   2,   2,  96,  97,  98,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   5,   5,   5,  99,
+    100,   2, 101,   2,   2,   2,   1,   2,   2,   2,   2,   2,   2,   5,   5,  13,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 102, 103,
+      2,   2,   2,   2,   2,   2,   2, 102,   2,   2,   2,   2,   2,   2,   5,   5,
+      2,   2, 104,   2,   2,   2,   2,   2,   2, 105,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2, 102, 106,   2,  44,   2,   2,   2,   2,   2, 103,
+    107,   2, 108,   2,   2,   2,   2,   2, 109,   2,   2, 110, 111,   2,   5, 103,
+      2,   2, 112,   2, 113,  93,  70, 114,  24,   2,   2, 115, 116,   2, 117,   2,
+      2,   2, 118, 119, 120,   2,   2, 121,   2,   2,   2, 122,  16,   2, 123, 124,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 125,   2,
+    126, 127, 128, 129, 128, 130, 128, 126, 127, 128, 129, 128, 130, 128, 126, 127,
+    128, 129, 128, 130, 128, 126, 127, 128, 129, 128, 130, 128, 126, 127, 128, 129,
+    128, 130, 128, 126, 127, 128, 129, 128, 130, 128, 126, 127, 128, 129, 128, 130,
+    128, 126, 127, 128, 129, 128, 130, 128, 126, 127, 128, 129, 128, 130, 128, 126,
+    127, 128, 129, 128, 130, 128, 126, 127, 128, 129, 128, 130, 128, 126, 127, 128,
+    129, 128, 130, 128, 126, 127, 128, 129, 128, 130, 128, 126, 127, 128, 129, 128,
+    130, 128, 126, 127, 128, 129, 128, 130, 128, 126, 127, 128, 129, 128, 130, 128,
+    128, 129, 128, 130, 128, 126, 127, 128, 129, 128, 131,  71, 132,  73,  73, 133,
+      1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      2, 134,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      5,   2,   5,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   3,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,  44,   2,   2,   2,   2,   2, 135,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,  69,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,  13,   2,
+      2,   2,   2,   2,   2,   2,   2, 136,   2,   2,   2,   2,   2,   2,   2,   2,
+    137,   2,   2, 138,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,  46,   2,
+    139,   2,   2, 140, 141,   2,   2, 102,  90,   2,   2, 142,   2,   2,   2,   2,
+    143,   2, 144, 145,   2,   2,   2, 146,  90,   2,   2, 147, 148,   2,   2,   2,
+      2,   2, 149, 150,   2,   2,   2,   2,   2,   2,   2,   2,   2, 102, 151,   2,
+     93,   2,   2,  30, 152,  32, 153, 145,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 154, 155,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 102, 156,  13, 157,   2,   2,
+      2,   2,   2, 158,  13,   2,   2,   2,   2,   2, 159, 160,   2,   2,   2,   2,
+      2,  64, 161,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 145,
+      2,   2,   2, 141,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2, 162, 163, 164, 102, 143,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2, 165, 166,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2, 167, 168, 169,   2, 170,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,  74,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      5,   5,   5, 171,   5,   5,  62, 117, 172,  12,   7,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 141,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 173, 174,
+      5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   1,
+};
+
+static RE_UINT8 re_grapheme_cluster_break_stage_4[] = {
+     0,  0,  1,  2,  0,  0,  0,  0,  3,  3,  3,  3,  3,  3,  3,  4,
+     3,  3,  3,  5,  6,  6,  6,  6,  7,  6,  8,  3,  9,  6,  6,  6,
+     6,  6,  6, 10, 11, 10,  3,  3,  0, 12,  3,  3,  6,  6, 13, 14,
+     3,  3,  7,  6, 15,  3,  3,  3,  3, 16,  6, 17,  6, 18, 19,  8,
+    20,  3,  3,  3,  6,  6, 13,  3,  3, 16,  6,  6,  6,  3,  3,  3,
+     3, 16, 10,  6,  6,  9,  9,  8,  3,  3,  9,  3,  7,  6,  6,  6,
+    21,  3,  3,  3,  3,  3, 22, 23, 24,  6, 25, 26,  9,  6,  3,  3,
+    16,  3,  3,  3, 27,  3,  3,  3,  3,  3,  3, 28, 24, 29, 30, 31,
+     3,  7,  3,  3, 32,  3,  3,  3,  3,  3,  3, 23, 33,  7, 18,  8,
+     8, 20,  3,  3, 24, 10, 34, 31,  3,  3,  3, 19,  3, 16,  3,  3,
+    35,  3,  3,  3,  3,  3,  3, 22, 36, 37, 38, 31, 25,  3,  3,  3,
+     3,  3,  3, 16, 25, 39, 19,  8,  3, 11,  3,  3,  3,  3,  3, 40,
+    41, 42, 38,  8, 24, 23, 38, 31, 37,  3,  3,  3,  3,  3, 35,  7,
+    43, 44, 45, 46, 47,  6, 13,  3,  3,  7,  6, 13, 47,  6, 10, 15,
+     3,  3,  6,  8,  3,  3,  8,  3,  3, 48, 20, 37,  9,  6,  6, 21,
+     6, 19,  3,  9,  6,  6,  9,  6,  6,  6,  6, 15,  3, 35,  3,  3,
+     3,  3,  3,  9, 49,  6, 32, 33,  3, 37,  8, 16,  9, 15,  3,  3,
+    35, 33,  3, 20,  3,  3,  3, 20, 50, 50, 50, 50, 51, 51, 51, 51,
+    51, 51, 52, 52, 52, 52, 52, 52, 16, 15,  3,  3,  3, 53,  6, 54,
+    45, 41, 24,  6,  6,  3,  3, 20,  3,  3,  7, 55,  3,  3, 20,  3,
+    21, 46, 25,  3, 41, 45, 24,  3,  3,  7, 56,  3,  3, 57,  6, 13,
+    44,  9,  6, 25, 46,  6,  6, 18,  6,  6,  6, 13,  6, 58,  3,  3,
+     3, 49, 21, 25, 41, 58,  3,  3, 59,  3,  3,  3, 60, 54, 53,  8,
+     3, 22, 54, 61, 54,  3,  3,  3,  3, 45, 45,  6,  6, 43,  3,  3,
+    13,  6,  6,  6, 49,  6, 15, 20, 37, 15,  8,  3,  6,  8,  3,  6,
+     3,  3,  4, 62,  3,  3,  0, 63,  3,  3,  3,  7,  8,  3,  3,  3,
+     3,  3, 16,  6,  3,  3, 11,  3, 13,  6,  6,  8, 35, 35,  7,  3,
+    64, 65,  3,  3, 66,  3,  3,  3,  3, 45, 45, 45, 45, 15,  3,  3,
+     3, 16,  6,  8,  3,  7,  6,  6, 50, 50, 50, 67,  7, 43, 54, 25,
+    58,  3,  3,  3,  3, 20,  3,  3,  3,  3,  9, 21, 65, 33,  3,  3,
+     7,  3,  3, 68,  3,  3,  3, 15, 19, 18, 15, 16,  3,  3, 64, 54,
+     3, 69,  3,  3, 64, 26, 36, 31, 70, 71, 71, 71, 71, 71, 71, 70,
+    71, 71, 71, 71, 71, 71, 70, 71, 71, 70, 71, 71, 71,  3,  3,  3,
+    51, 72, 73, 52, 52, 52, 52,  3,  3,  3,  3, 35,  0,  0,  0,  3,
+     3, 16, 13,  3,  9, 11,  3,  6,  3,  3, 13,  7, 74,  3,  3,  3,
+     3,  3,  6,  6,  6, 13,  3,  3, 46, 21, 33,  5, 13,  3,  3,  3,
+     3,  7,  6, 24,  6, 15,  3,  3,  7,  3,  3,  3, 64, 43,  6, 21,
+    58,  3, 16, 15,  3,  3,  3, 46, 54, 49,  3,  3, 46,  6, 13,  3,
+    25, 30, 30, 66, 37, 16,  6, 15, 56,  6, 75, 61, 49,  3,  3,  3,
+    43,  8, 45, 53,  3,  3,  3,  8, 46,  6, 21, 61,  3,  3,  7, 26,
+     6, 53,  3,  3, 43, 53,  6,  3, 76, 45, 45, 45, 45, 45, 45, 45,
+    45, 45, 45, 77,  3,  3,  3, 11,  0,  3,  3,  3,  3, 78,  8, 60,
+    79,  0, 80,  6, 13,  9,  6,  3,  3,  3, 16,  8,  6, 13,  7,  6,
+     3, 15,  3,  3,  3, 81, 82, 82, 82, 82, 82, 82,
+};
+
+static RE_UINT8 re_grapheme_cluster_break_stage_5[] = {
+     3,  3,  3,  3,  3,  3,  2,  3,  3,  1,  3,  3,  0,  0,  0,  0,
+     0,  0,  0,  3,  0,  3,  0,  0,  4,  4,  4,  4,  0,  0,  0,  4,
+     4,  4,  0,  0,  0,  4,  4,  4,  4,  4,  0,  4,  0,  4,  4,  0,
+     3,  3,  0,  0,  4,  4,  4,  0,  3,  0,  0,  0,  4,  0,  0,  0,
+     0,  0,  4,  4,  4,  3,  0,  4,  4,  0,  0,  4,  4,  0,  4,  4,
+     0,  4,  0,  0,  4,  4,  4,  6,  0,  0,  4,  6,  4,  0,  6,  6,
+     6,  4,  4,  4,  4,  6,  6,  6,  6,  4,  6,  6,  0,  4,  6,  6,
+     4,  0,  4,  6,  4,  0,  0,  6,  6,  0,  0,  6,  6,  4,  0,  0,
+     0,  4,  4,  6,  6,  4,  4,  0,  4,  6,  0,  6,  0,  0,  4,  0,
+     4,  6,  6,  0,  0,  0,  6,  6,  6,  0,  6,  6,  6,  0,  4,  4,
+     4,  0,  6,  4,  6,  6,  4,  6,  6,  0,  4,  6,  6,  6,  4,  4,
+     4,  0,  4,  0,  6,  6,  6,  6,  6,  6,  6,  4,  0,  4,  0,  6,
+     0,  4,  0,  4,  4,  6,  4,  4,  7,  7,  7,  7,  8,  8,  8,  8,
+     9,  9,  9,  9,  4,  4,  6,  4,  4,  4,  6,  6,  4,  4,  3,  0,
+     4,  6,  6,  4,  0,  6,  4,  6,  6,  0,  0,  0,  4,  4,  6,  0,
+     0,  6,  4,  4,  6,  4,  6,  4,  4,  4,  3,  3,  3,  3,  3,  0,
+     0,  0,  0,  6,  6,  4,  4,  6,  6,  6,  0,  0,  7,  0,  0,  0,
+     4,  6,  0,  0,  0,  6,  4,  0, 10, 11, 11, 11, 11, 11, 11, 11,
+     8,  8,  8,  0,  0,  0,  0,  9,  6,  4,  6,  0,  4,  6,  4,  6,
+     0,  6,  6,  6,  6,  6,  6,  0,  0,  4,  6,  4,  4,  4,  4,  3,
+     3,  3,  3,  4,  0,  0,  5,  5,  5,  5,  5,  5,
+};
+
+/* Grapheme_Cluster_Break: 2640 bytes. */
+
+RE_UINT32 re_get_grapheme_cluster_break(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 13;
+    code = ch ^ (f << 13);
+    pos = (RE_UINT32)re_grapheme_cluster_break_stage_1[f] << 5;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_grapheme_cluster_break_stage_2[pos + f] << 4;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_grapheme_cluster_break_stage_3[pos + f] << 2;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_grapheme_cluster_break_stage_4[pos + f] << 2;
+    value = re_grapheme_cluster_break_stage_5[pos + code];
+
+    return value;
+}
+
+/* Sentence_Break. */
+
+static RE_UINT8 re_sentence_break_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  5,  5,  5,  6,  7,  5,  5,  8,  9, 10,
+    11, 12, 13, 14, 15,  9, 16,  9,  9,  9,  9, 17,  9, 18, 19, 20,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 21, 22, 23,  9,  9, 24,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    25,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+};
+
+static RE_UINT8 re_sentence_break_stage_2[] = {
+      0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
+     16,  17,  18,  19,  20,  17,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,
+     31,  32,  33,  34,  35,  33,  33,  36,  33,  37,  33,  33,  38,  39,  40,  33,
+     41,  42,  33,  33,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,
+     17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  43,  17,  17,
+     17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,
+     17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  44,
+     17,  17,  17,  17,  45,  17,  46,  47,  48,  49,  50,  51,  17,  17,  17,  17,
+     17,  17,  17,  17,  17,  17,  17,  52,  33,  33,  33,  33,  33,  33,  33,  33,
+     33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+     33,  33,  33,  33,  33,  33,  33,  33,  33,  17,  53,  54,  17,  55,  56,  57,
+     58,  59,  60,  61,  62,  63,  17,  64,  65,  66,  67,  68,  69,  33,  33,  33,
+     70,  71,  72,  73,  74,  75,  76,  77,  78,  33,  79,  33,  33,  33,  33,  33,
+     17,  17,  17,  80,  81,  82,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+     17,  17,  17,  17,  83,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+     33,  33,  33,  33,  17,  17,  84,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+     33,  33,  33,  33,  33,  33,  33,  33,  17,  17,  85,  86,  33,  33,  33,  87,
+     88,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  89,  33,  33,  33,
+     33,  90,  91,  33,  92,  93,  94,  95,  33,  33,  96,  33,  33,  33,  33,  33,
+     33,  33,  33,  33,  33,  33,  33,  33,  97,  33,  33,  33,  33,  33,  98,  33,
+     33,  99,  33,  33,  33,  33, 100,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+     17,  17,  17,  17,  17,  17, 101,  17,  17,  17,  17,  17,  17,  17,  17,  17,
+     17,  17,  17,  17,  17,  17,  17, 102, 103,  17,  17,  17,  17,  17,  17,  17,
+     17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17, 104,  33,
+     33,  33,  33,  33,  33,  33,  33,  33,  17,  17, 105,  33,  33,  33,  33,  33,
+    106, 107,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,  33,
+};
+
+static RE_UINT16 re_sentence_break_stage_3[] = {
+      0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
+      8,  16,  17,  18,  19,  20,  21,  22,  23,  23,  23,  24,  25,  26,  27,  28,
+     29,  30,  18,   8,  31,   8,  32,   8,   8,  33,  34,  35,  36,  37,  38,  39,
+     40,  41,  42,  43,  41,  41,  44,  45,  46,  47,  48,  41,  41,  49,  50,  51,
+     52,  53,  54,  55,  55,  56,  55,  57,  58,  59,  60,  61,  62,  63,  64,  65,
+     66,  67,  68,  69,  70,  71,  72,  73,  74,  71,  75,  76,  77,  78,  79,  80,
+     81,  82,  83,  84,  85,  86,  87,  88,  85,  89,  90,  91,  92,  93,  94,  95,
+     96,  97,  98,  55,  99, 100, 101,  55, 102, 103, 104, 105, 106, 107, 108,  55,
+     41, 109, 110, 111, 112,  29, 113, 114,  41,  41,  41,  41,  41,  41,  41,  41,
+     41,  41, 115,  41, 116, 117, 118,  41, 119,  41, 120, 121, 122,  29,  29, 123,
+     96,  41,  41,  41,  41,  41,  41,  41,  41,  41,  41, 124, 125,  41,  41, 126,
+    127, 128, 129, 130,  41, 131, 132, 133, 134,  41,  41, 135,  41, 136,  41, 137,
+    138, 139, 140, 141,  41, 142, 143,  55, 144,  41, 145, 146, 147, 148,  55,  55,
+    149, 131, 150, 151, 152, 153,  41, 154,  41, 155, 156, 157,  55,  55, 158, 159,
+     18,  18,  18,  18,  18,  18,  23, 160,   8,   8,   8,   8, 161,   8,   8,   8,
+    162, 163, 164, 165, 163, 166, 167, 168, 169, 170, 171, 172, 173,  55, 174, 175,
+    176, 177, 178,  30, 179,  55,  55,  55,  55,  55,  55,  55,  55,  55,  55,  55,
+    180, 181,  55,  55,  55,  55,  55,  55,  55,  55,  55,  55,  55, 182,  30, 183,
+     55,  55, 184, 185,  55,  55, 186, 187,  55,  55,  55,  55, 188,  55, 189, 190,
+     29, 191, 192, 193,   8,   8,   8, 194,  18, 195,  41, 196, 197, 198, 198,  23,
+    199, 200, 201,  55,  55,  55,  55,  55, 202, 203,  96,  41, 204,  96,  41, 114,
+    205, 206,  41,  41, 207, 208,  55, 209,  41,  41,  41,  41,  41, 137,  55,  55,
+     41,  41,  41,  41,  41,  41, 137,  55,  41,  41,  41,  41, 210,  55, 209, 211,
+    212, 213,   8, 214, 215,  41,  41, 216, 217, 218,   8, 219, 220, 221,  55, 222,
+    223, 224,  41, 225, 226, 131, 227, 228,  50, 229, 230, 231,  58, 232, 233, 234,
+     41, 235, 236, 237,  41, 238, 239, 240, 241, 242, 243, 244,  18,  18,  41, 245,
+     41,  41,  41,  41,  41, 246, 247, 248,  41,  41,  41, 249,  41,  41, 250,  55,
+    251, 252, 253,  41,  41, 254, 255,  41,  41, 256, 209,  41, 257,  41, 258, 259,
+    260, 261, 262, 263,  41,  41,  41, 264, 265,   2, 266, 267, 268, 138, 269, 270,
+    271, 272, 273,  55,  41,  41,  41, 208,  55,  55,  41,  56,  55,  55,  55, 274,
+     55,  55,  55,  55, 231,  41, 275, 276,  41, 209, 277, 278, 279,  41, 280,  55,
+     29, 281, 282,  41, 279, 133,  55,  55,  41, 283,  41, 284,  55,  55,  55,  55,
+     41, 197, 137, 258,  55,  55,  55,  55, 285, 286, 137, 197, 138,  55,  55, 287,
+    137, 250,  55,  55,  41, 288,  55,  55, 289, 290, 291, 231, 231,  55, 104, 292,
+     41, 137, 137, 293, 254,  55,  55,  55,  41,  41, 294,  55,  29, 295,  18, 296,
+    152, 297, 298, 299, 152, 300, 301, 302, 152, 303, 304, 305, 152, 232, 306,  55,
+    307, 308,  55,  55, 309, 310, 311, 312, 313,  71, 314, 315,  55,  55,  55,  55,
+     55,  55,  55,  55,  41,  47, 316,  55,  55,  55,  55,  55,  41, 317, 318,  55,
+     41,  47, 319,  55,  41, 320, 133,  55, 321, 322,  55,  55,  55,  55,  55,  55,
+     55,  55,  55,  55,  55,  29,  18, 323,  55,  55,  55,  55,  55,  55,  41, 324,
+     41,  41,  41,  41, 250,  55,  55,  55,  41,  41,  41, 207,  41,  41,  41,  41,
+     41,  41, 284,  55,  55,  55,  55,  55,  41, 207,  55,  55,  55,  55,  55,  55,
+     41,  41, 325,  55,  55,  55,  55,  55,  41, 324, 138, 326,  55,  55, 209, 327,
+     41, 328, 329, 330, 122,  55,  55,  55,  41,  41, 331, 332, 333,  55,  55,  55,
+    334,  55,  55,  55,  55,  55,  55,  55,  41,  41,  41, 335, 336, 337,  55,  55,
+     55,  55,  55, 338, 339, 340,  55,  55,  55,  55, 341,  55,  55,  55,  55,  55,
+    342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 342, 343, 355,
+    345, 356, 357, 358, 349, 359, 360, 361, 362, 363, 364, 191, 365, 366, 367, 368,
+     23, 369,  23, 370, 371, 372,  55,  55,  41,  41,  41,  41,  41,  41, 373,  55,
+    374, 375, 376, 377, 378, 379,  55,  55,  55, 380, 381, 381, 382,  55,  55,  55,
+     55,  55,  55, 383,  55,  55,  55,  55,  41,  41,  41,  41,  41,  41, 197,  55,
+     41,  56,  41,  41,  41,  41,  41,  41, 279,  41,  41,  41,  41,  41,  41,  41,
+     41,  41,  41,  41,  41, 334,  55,  55, 279,  55,  55,  55,  55,  55,  55,  55,
+    384, 385, 385, 385,  55,  55,  55,  55,  23,  23,  23,  23,  23,  23,  23, 386,
+};
+
+static RE_UINT8 re_sentence_break_stage_4[] = {
+      0,   0,   1,   2,   0,   0,   0,   0,   3,   4,   5,   6,   7,   7,   8,   9,
+     10,  11,  11,  11,  11,  11,  12,  13,  14,  15,  15,  15,  15,  15,  16,  13,
+      0,  17,   0,   0,   0,   0,   0,   0,  18,   0,  19,  20,   0,  21,  19,   0,
+     11,  11,  11,  11,  11,  22,  11,  23,  15,  15,  15,  15,  15,  24,  15,  15,
+     25,  25,  25,  25,  25,  25,  25,  25,  25,  25,  25,  25,  25,  25,  26,  26,
+     26,  26,  27,  25,  25,  25,  25,  25,  25,  25,  25,  25,  25,  25,  28,  29,
+     30,  31,  32,  33,  28,  31,  34,  28,  25,  31,  29,  31,  32,  26,  35,  34,
+     36,  28,  31,  26,  26,  26,  26,  27,  25,  25,  25,  25,  30,  31,  25,  25,
+     25,  25,  25,  25,  25,  15,  33,  30,  26,  23,  25,  25,  15,  15,  15,  15,
+     15,  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,  37,  15,  15,
+     15,  15,  15,  15,  15,  15,  38,  36,  39,  40,  36,  36,  41,   0,   0,   0,
+     15,  42,   0,  43,   0,   0,   0,   0,  44,  44,  44,  44,  44,  44,  44,  44,
+     44,  44,  44,  44,  25,  45,  46,  47,   0,  48,  22,  49,  32,  11,  11,  11,
+     50,  11,  11,  15,  15,  15,  15,  15,  15,  15,  15,  51,  33,  34,  25,  25,
+     25,  25,  25,  25,  15,  52,  30,  32,  11,  11,  11,  11,  11,  11,  11,  11,
+     11,  11,  11,  11,  15,  15,  15,  15,  53,  44,  54,  25,  25,  25,  25,  25,
+     28,  26,  26,  29,  25,  25,  25,  25,  25,  25,  25,  25,  10,  11,  11,  11,
+     11,  11,  11,  11,  11,  22,  55,  56,  14,  15,  15,  15,  15,  15,  15,  15,
+     15,  15,  57,   0,  58,  44,  44,  44,  44,  44,  44,  44,  44,  44,  44,  59,
+     60,  59,   0,   0,  36,  36,  36,  36,  36,  36,  61,   0,  36,   0,   0,   0,
+     62,  63,   0,  64,  44,  44,  65,  66,  36,  36,  36,  36,  36,  36,  36,  36,
+     36,  36,  67,  44,  44,  44,  44,  44,   7,   7,  68,  69,  70,  36,  36,  36,
+     36,  36,  36,  36,  36,  71,  44,  72,  44,  73,  74,  75,   7,   7,  76,  77,
+     78,   0,   0,  79,  80,  36,  36,  36,  36,  36,  36,  36,  44,  44,  44,  44,
+     44,  44,  65,  81,  36,  36,  36,  36,  36,  82,  44,  44,  83,   0,   0,   0,
+      7,   7,  76,  36,  36,  36,  36,  36,  36,  36,  67,  44,  44,  41,  84,   0,
+     36,  36,  36,  36,  36,  82,  85,  44,  44,  86,  86,  87,   0,   0,   0,   0,
+     36,  36,  36,  36,  36,  36,  86,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     36,  36,  36,  36,  36,  88,   0,   0,  89,  44,  44,  44,  44,  44,  44,  44,
+     44,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  82,  90,
+     44,  44,  44,  44,  86,  44,  36,  36,  82,  91,   7,   7,  81,  36,  36,  36,
+     86,  81,  36,  77,  77,  36,  36,  36,  36,  36,  92,  36,  43,  40,  41,  90,
+     44,  93,  93,  94,   0,  89,   0,  95,  82,  96,   7,   7,  41,   0,   0,   0,
+     58,  81,  61,  97,  77,  36,  36,  36,  36,  36,  92,  36,  92,  98,  41,  74,
+     65,  89,  93,  87,  99,   0,  81,  43,   0,  96,   7,   7,  75, 100,   0,   0,
+     58,  81,  36,  95,  95,  36,  36,  36,  36,  36,  92,  36,  92,  81,  41,  90,
+     44,  59,  59,  87,  88,   0,   0,   0,  82,  96,   7,   7,   0,   0,  55,   0,
+     58,  81,  36,  77,  77,  36,  36,  36,  44,  93,  93,  87,   0, 101,   0,  95,
+     82,  96,   7,   7,  55,   0,   0,   0, 102,  81,  61,  40,  92,  41,  98,  92,
+     97,  88,  61,  40,  36,  36,  41, 101,  65, 101,  74,  87,  88,  89,   0,   0,
+      0,  96,   7,   7,   0,   0,   0,   0,  44,  81,  36,  92,  92,  36,  36,  36,
+     36,  36,  92,  36,  36,  36,  41, 103,  44,  74,  74,  87,   0,  60,  61,   0,
+     82,  96,   7,   7,   0,   0,   0,   0,  58,  81,  36,  92,  92,  36,  36,  36,
+     36,  36,  92,  36,  36,  81,  41,  90,  44,  74,  74,  87,   0,  60,   0, 104,
+     82,  96,   7,   7,  98,   0,   0,   0,  36,  36,  36,  36,  36,  36,  61, 103,
+     44,  74,  74,  94,   0,  89,   0,  97,  82,  96,   7,   7,   0,   0,  40,  36,
+    101,  81,  36,  36,  36,  61,  40,  36,  36,  36,  36,  36,  95,  36,  36,  55,
+     36,  61, 105,  89,  44, 106,  44,  44,   0,  96,   7,   7, 101,   0,   0,   0,
+     81,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  80,  44,  65,   0,
+     36,  67,  44,  65,   7,   7, 107,   0,  98,  77,  43,  55,   0,  36,  81,  36,
+     81, 108,  40,  81,  80,  44,  59,  83,  36,  43,  44,  87,   7,   7, 107,  36,
+     88,   0,   0,   0,   0,   0,  87,   0,   7,   7, 107,   0,   0, 109, 110, 111,
+     36,  36,  81,  36,  36,  36,  36,  36,  36,  36,  36,  88,  58,  44,  44,  44,
+     44,  74,  36,  86,  44,  44,  58,  44,  44,  44,  44,  44,  44,  44,  44, 112,
+      0, 105,   0,   0,   0,   0,   0,   0,  36,  36,  67,  44,  44,  44,  44, 113,
+      7,   7, 114,   0,  36,  82,  75,  82,  90,  73,  44,  75,  86,  70,  36,  36,
+     82,  44,  44,  85,   7,   7, 115,  87,  11,  50,   0, 116,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  36,  61,  36,  36,  36,  92,  41,  36,  61,  92,  41,
+     36,  36,  92,  41,  36,  36,  36,  36,  36,  36,  36,  36,  92,  41,  36,  61,
+     92,  41,  36,  36,  36,  61,  36,  36,  36,  36,  36,  36,  92,  41,  36,  36,
+     36,  36,  36,  36,  36,  36,  61,  58, 117,   9, 118,   0,   0,   0,   0,   0,
+     36,  36,  36,  36,   0,   0,   0,   0,  11,  11,  11,  11,  11, 119,  15,  39,
+     36,  36,  36, 120,  36,  36,  36,  36, 121,  36,  36,  36,  36,  36, 122, 123,
+     36,  36,  61,  40,  36,  36,  88,   0,  36,  36,  36,  92,  82, 112,   0,   0,
+     36,  36,  36,  36,  82, 124,   0,   0,  36,  36,  36,  36,  82,   0,   0,   0,
+     36,  36,  36,  92, 125,   0,   0,   0,  36,  36,  36,  36,  36,  44,  44,  44,
+     44,  44,  44,  44,  44,  97,   0, 100,   7,   7, 107,   0,   0,   0,   0,   0,
+    126,   0, 127, 128,   7,   7, 107,   0,  36,  36,  36,  36,  36,  36,   0,   0,
+     36,  36, 129,   0,  36,  36,  36,  36,  36,  36,  36,  36,  36,  41,   0,   0,
+     36,  36,  36,  36,  36,  36,  36,  61,  44,  44,  44,   0,  44,  44,  44,   0,
+      0,  91,   7,   7,  36,  36,  36,  36,  36,  36,  36,  41,  36,  88,   0,   0,
+     36,  36,  36,   0,  36,  36,  36,  36,  36,  36,  41,   0,   7,   7, 107,   0,
+     36,  36,  36,  36,  36,  67,  44,   0,  36,  36,  36,  36,  36,  86,  44,  65,
+     44,  44,  44,  44,  44,  44,  44,  93,   7,   7, 107,   0,   7,   7, 107,   0,
+      0,  97, 130,   0,  44,  44,  44,  65,  44,  70,  36,  36,  36,  36,  36,  36,
+     44,  70,  36,   0,   7,   7, 114, 131,   0,   0,  89,  44,  44,   0,   0,   0,
+    113,  36,  36,  36,  36,  36,  36,  36,  86,  44,  44,  75,   7,   7,  76,  36,
+     36,  82,  44,  44,  44,   0,   0,   0,  36,  44,  44,  44,  44,  44,   9, 118,
+      7,   7, 107,  81,   7,   7,  76,  36,  36,  36,  36,  36,  36,  36,  36, 132,
+      0,   0,   0,   0,  65,  44,  44,  44,  44,  44,  70,  80,  82, 133,  87,   0,
+     44,  44,  44,  44,  44,  87,   0,  44,  25,  25,  25,  25,  25,  34,  15,  27,
+     15,  15,  11,  11,  15,  39,  11, 119,  15,  15,  11,  11,  15,  15,  11,  11,
+     15,  39,  11, 119,  15,  15, 134, 134,  15,  15,  11,  11,  15,  15,  15,  39,
+     15,  15,  11,  11,  15, 135,  11, 136,  46, 135,  11, 137,  15,  46,  11,   0,
+     15,  15,  11, 137,  46, 135,  11, 137, 138, 138, 139, 140, 141, 142, 143, 143,
+      0, 144, 145, 146,   0,   0, 147, 148,   0, 149, 148,   0,   0,   0,   0, 150,
+     62, 151,  62,  62,  21,   0,   0, 152,   0,   0,   0, 147,  15,  15,  15,  42,
+      0,   0,   0,   0,  44,  44,  44,  44,  44,  44,  44,  44, 112,   0,   0,   0,
+     48, 153, 154, 155,  23, 116,  10, 119,   0, 156,  49, 157,  11,  38, 158,  33,
+      0, 159,  39, 160,   0,   0,   0,   0, 161,  38,  88,   0,   0,   0,   0,   0,
+      0,   0, 143,   0,   0,   0,   0,   0,   0,   0, 147,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 162,  11,  11,  15,  15,  39,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   4, 143, 123,   0, 143, 143, 143,   5,   0,   0,
+      0, 147,   0,   0,   0,   0,   0,   0,   0, 163, 143, 143,   0,   0,   0,   0,
+      4, 143, 143, 143, 143, 143, 123,   0,   0,   0,   0,   0,   0,   0, 143,   0,
+      0,   0,   0,   0,   0,   0,   0,   5,  11,  11,  11,  22,  15,  15,  15,  15,
+     15,  15,  15,  15,  15,  15,  15,  24,  31, 164,  26,  32,  25,  29,  15,  33,
+     25,  42, 153, 165,  54,   0,   0,   0,  15, 166,   0,  21,  36,  36,  36,  36,
+     36,  36,   0,  97,   0,   0,   0,  89,  36,  36,  36,  36,  36,  61,   0,   0,
+     36,  61,  36,  61,  36,  61,  36,  61, 143, 143, 143,   5,   0,   0,   0,   5,
+    143, 143,   5, 167,   0,   0,   0, 118, 168,   0,   0,   0,   0,   0,   0,   0,
+    169,  81, 143, 143,   5, 143, 143, 170,  81,  36,  82,  44,  81,  41,  36,  88,
+     36,  36,  36,  36,  36,  61,  60,  81,   0,  81,  36,  36,  36,  36,  36,  36,
+     36,  36,  36,  41,  81,  36,  36,  36,  36,  36,  36,  61,   0,   0,   0,   0,
+     36,  36,  36,  36,  36,  36,  61,   0,   0,   0,   0,   0,  36,  36,  36,  36,
+     36,  36,  36,  88,   0,   0,   0,   0,  36,  36,  36,  36,  36,  36,  36, 171,
+     36,  36,  36, 172,  36,  36,  36,  36,   7,   7,  76,   0,   0,   0,   0,   0,
+     25,  25,  25, 173,  65,  44,  44, 174,  25,  25,  25,  25,  25,  25,  25, 175,
+     36,  36,  36,  36, 176,   9,   0,   0,   0,   0,   0,   0,   0,  97,  36,  36,
+    177,  25,  25,  25,  27,  25,  25,  25,  25,  25,  25,  25,  15,  15,  26,  30,
+     25,  25, 178, 179,  25,  27,  25,  25,  25,  25,  31, 119,  11,  25,   0,   0,
+      0,   0,   0,   0,   0,  97, 180,  36, 181, 181,  67,  36,  36,  36,  36,  36,
+     67,  44,   0,   0,   0,   0,   0,   0,  36,  36,  36,  36,  36, 131,   0,   0,
+     75,  36,  36,  36,  36,  36,  36,  36,  44, 112,   0, 131,   7,   7, 107,   0,
+     44,  44,  44,  44,  75,  36,  97,  55,  36,  82,  44, 176,  36,  36,  36,  36,
+     36,  67,  44,  44,  44,   0,   0,   0,  36,  36,  36,  36,  36,  36,  36,  88,
+     36,  36,  36,  36,  67,  44,  44,  44, 112,   0, 148,  97,   7,   7, 107,   0,
+     36,  80,  36,  36,   7,   7,  76,  61,  36,  36,  86,  44,  44,  65,   0,   0,
+     67,  36,  36,  87,   7,   7, 107, 182,  36,  36,  36,  36,  36,  61, 183,  75,
+     36,  36,  36,  36,  90,  73,  70,  82, 129,   0,   0,   0,   0,   0,  97,  41,
+     36,  36,  67,  44, 184, 185,   0,   0,  81,  61,  81,  61,  81,  61,   0,   0,
+     36,  61,  36,  61,  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,  24,  15,
+     15,  39,   0,   0,  15,  15,  15,  15,  67,  44, 186,  87,   7,   7, 107,   0,
+     36,   0,   0,   0,  36,  36,  36,  36,  36,  61,  97,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  36,  36,   0,  36,  36,  36,  41,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  36,  41,   0,  15,  24,   0,   0, 187,  15,   0, 188,
+     36,  36,  92,  36,  36,  61,  36,  43,  95,  92,  36,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  41,   0,   0,   0,   0,   0,   0,   0,  97,  36,  36,  36,
+     36,  36,  36,  36,  36,  36,  36, 189,  36,  36,  36,  36,  40,  36,  36,  36,
+     36,  36,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  36,  36,  36,   0,
+     44,  44,  44,  44, 190,   4, 123,   0,  44,  44,  44,  44, 191, 170, 143, 143,
+    143, 192, 123,   0,   6, 193, 194, 195, 141,   0,   0,   0,  36,  92,  36,  36,
+     36,  36,  36,  36,  36,  36,  36, 196,  57,   0,   5,   6,   0,   0, 197,   9,
+     14,  15,  15,  15,  15,  15,  16, 198, 199, 200,  36,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  36,  36,  82,  40,  36,  40,  36,  40,  36,  40,  88,
+      0,   0,   0,   0,   0,   0, 201,   0,  36,  36,  36,  81,  36,  36,  36,  36,
+     36,  61,  36,  36,  36,  36,  61,  95,  36,  36,  36,  41,  36,  36,  36,  41,
+      0,   0,   0,   0,   0,   0,   0,  99,  36,  36,  36,  36,  88,   0,   0,   0,
+    112,   0,   0,   0,   0,   0,   0,   0,  36,  36,  61,   0,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  82,  65,   0,  36,  36,  36,  36,  36,  36,  36,  41,
+     36,   0,  36,  36,  81,  41,   0,   0,  11,  11,  15,  15,  15,  15,  15,  15,
+     15,  15,  15,  15,  36,  36,  36,  36,  36,  36,   0,   0,  36,  36,  36,  36,
+     36,   0,   0,   0,   0,   0,   0,   0,  36,  41,  92,  36,  36,  36,  36,  36,
+     36,  36,  36,  36,  36,  95,  88,  77,  36,  36,  36,  36,  61,  41,   0,   0,
+     36,  36,  36,  36,  36,  36,   0,  40,  86,  60,   0,  44,  36,  81,  81,  36,
+     36,  36,  36,  36,  36,   0,  65,  89,   0,   0,   0,   0,   0, 131,   0,   0,
+     36, 185,   0,   0,   0,   0,   0,   0,  36,  36,  36,  36,  61,   0,   0,   0,
+     36,  36,  88,   0,   0,   0,   0,   0,  11,  11,  11,  11,  22,   0,   0,   0,
+     15,  15,  15,  15,  24,   0,   0,   0,  36,  36,  36,  36,  36,  36,  44,  44,
+     44, 186, 118,   0,   0,   0,   0,   0,   0,  96,   7,   7,   0,   0,   0,  89,
+     36,  36,  36,  36,  44,  44,  65, 202, 148,   0,   0,   0,  36,  36,  36,  36,
+     36,  36,  88,   0,   7,   7, 107,   0,  36,  67,  44,  44,  44, 203,   7,   7,
+    182,   0,   0,   0,  36,  36,  36,  36,  36,  36,  36,  36,  67, 104,   0,   0,
+     70, 204, 101, 205,   7,   7, 206, 172,  36,  36,  36,  36,  95,  36,  36,  36,
+     36,  36,  36,  44,  44,  44, 207, 118,  36,  61,  92,  95,  36,  36,  36,  95,
+     36,  36, 208,   0,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  67,
+     44,  44,  65,   0,   7,   7, 107,   0,  44,  81,  36,  77,  77,  36,  36,  36,
+     44,  93,  93,  87,  88,  89,   0,  81,  82, 101,  44, 112,  44, 112,   0,   0,
+     44,  95,   0,   0,   7,   7, 107,   0,  36,  36,  36,  67,  44,  87,  44,  44,
+    209,   0, 182, 130, 130, 130,  36,  87, 124,  88,   0,   0,   7,   7, 107,   0,
+     36,  36,  67,  44,  44,  44,   0,   0,  36,  36,  36,  36,  36,  36,  41,  58,
+     44,  44,  44,   0,   7,   7, 107,  78,   7,   7, 107,   0,   0,   0,   0,  97,
+     36,  36,  36,  36,  36,  36,  88,   0,  36,  61,   0,   0,   0,   0,   0,   0,
+      7,   7, 107, 131,   0,   0,   0,   0,  36,  36,  36,  41,  44, 205,   0,   0,
+     36,  36,  36,  36,  44, 186, 118,   0,  36, 118,   0,   0,   7,   7, 107,   0,
+     97,  36,  36,  36,  36,  36,   0,  81,  36,  88,   0,   0,  86,  44,  44,  44,
+     44,  44,  44,  44,  44,  44,  44,  65,   0,   0,   0,  89, 113,  36,  36,  36,
+     41,   0,   0,   0,   0,   0,   0,   0,  36,  36,  61,   0,  36,  36,  36,  88,
+     36,  36,  88,   0,  36,  36,  41, 210,  62,   0,   0,   0,   0,   0,   0,   0,
+      0,  58,  87,  58, 211,  62, 212,  44,  65,  58,  44,   0,   0,   0,   0,   0,
+      0,   0, 101,  87,   0,   0,   0,   0, 101, 112,   0,   0,   0,   0,   0,   0,
+     11,  11,  11,  11,  11,  11, 155,  15,  15,  15,  15,  15,  15,  11,  11,  11,
+     11,  11,  11, 155,  15, 135,  15,  15,  15,  15,  11,  11,  11,  11,  11,  11,
+    155,  15,  15,  15,  15,  15,  15,  49,  48, 213,  10,  49,  11, 155, 166,  14,
+     15,  14,  15,  15,  11,  11,  11,  11,  11,  11, 155,  15,  15,  15,  15,  15,
+     15,  50,  22,  10,  11,  49,  11, 214,  15,  15,  15,  15,  15,  15,  50,  22,
+     11, 156, 162,  11, 214,  15,  15,  15,  15,  15,  15,  11,  11,  11,  11,  11,
+     11, 155,  15,  15,  15,  15,  15,  15,  11,  11,  11, 155,  15,  15,  15,  15,
+    155,  15,  15,  15,  15,  15,  15,  11,  11,  11,  11,  11,  11, 155,  15,  15,
+     15,  15,  15,  15,  11,  11,  11,  11,  15,  39,  11,  11,  11,  11,  11,  11,
+    214,  15,  15,  15,  15,  15,  24,  15,  33,  11,  11,  11,  11,  11,  22,  15,
+     15,  15,  15,  15,  15, 135,  15,  11,  11,  11,  11,  11,  11, 214,  15,  15,
+     15,  15,  15,  24,  15,  33,  11,  11,  15,  15, 135,  15,  11,  11,  11,  11,
+     11,  11, 214,  15,  15,  15,  15,  15,  24,  15,  27,  96,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,  44,  44,  44,  44,  44,  65,  89,  44,
+     44,  44,  44, 112,   0,  99,   0,   0,   0, 112, 118,   0,   0,   0,  89,  44,
+     58,  44,  44,  44,   0,   0,   0,   0,  36,  88,   0,   0,  44,  65,   0,   0,
+     36,  81,  36,  36,  36,  36,  36,  36,  98,  77,  81,  36,  61,  36, 108,   0,
+    104,  97, 108,  81,  98,  77, 108, 108,  98,  77,  61,  36,  61,  36,  81,  43,
+     36,  36,  95,  36,  36,  36,  36,   0,  81,  81,  95,  36,  36,  36,  36,   0,
+      0,   0,   0,   0,  11,  11,  11,  11,  11,  11, 119,   0,  11,  11,  11,  11,
+     11,  11, 119,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 163, 123,   0,
+     20,   0,   0,   0,   0,   0,   0,   0,  62,  62,  62,  62,  62,  62,  62,  62,
+     44,  44,  44,  44,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_sentence_break_stage_5[] = {
+     0,  0,  0,  0,  0,  6,  2,  6,  6,  1,  0,  0,  6, 12, 13,  0,
+     0,  0,  0, 13, 13, 13,  0,  0, 14, 14, 11,  0, 10, 10, 10, 10,
+    10, 10, 14,  0,  0,  0,  0, 12,  0,  8,  8,  8,  8,  8,  8,  8,
+     8,  8,  8, 13,  0, 13,  0,  0,  0,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7, 13,  0,  4,  0,  0,  6,  0,  0,  0,  0,  0,  7, 13,
+     0,  5,  0,  0,  0,  7,  0,  0,  8,  8,  8,  0,  8,  8,  8,  7,
+     7,  7,  7,  0,  8,  7,  8,  7,  7,  8,  7,  8,  7,  7,  8,  7,
+     8,  8,  7,  8,  7,  8,  7,  7,  7,  8,  8,  7,  8,  7,  8,  8,
+     7,  8,  8,  8,  7,  7,  8,  8,  8,  7,  7,  7,  8,  7,  7,  9,
+     9,  9,  9,  9,  9,  7,  7,  7,  7,  9,  9,  9,  7,  7,  0,  0,
+     0,  0,  9,  9,  9,  9,  0,  0,  7,  0,  0,  0,  9,  0,  9,  0,
+     3,  3,  3,  3,  9,  0,  8,  7,  0,  0,  7,  7,  7,  7,  0,  8,
+     0,  0,  8,  0,  8,  0,  8,  8,  8,  8,  0,  8,  7,  7,  7,  8,
+     8,  7,  0,  8,  8,  7,  0,  3,  3,  3,  8,  7,  0,  9,  0,  0,
+     0, 14,  0,  0,  0, 12,  0,  0,  0,  3,  3,  3,  3,  3,  0,  3,
+     0,  3,  3,  0,  9,  9,  9,  0,  5,  5,  5,  5,  5,  5,  0,  0,
+    14, 14,  0,  0,  3,  3,  3,  0,  5,  0,  0, 12,  9,  9,  9,  3,
+    10, 10,  0, 10, 10,  0,  9,  9,  3,  9,  9,  9, 12,  9,  3,  3,
+     3,  5,  0,  3,  3,  9,  9,  3,  3,  0,  3,  3,  3,  3,  9,  9,
+    10, 10,  9,  9,  9,  0,  0,  9, 12, 12, 12,  0,  0,  0,  0,  5,
+     9,  3,  9,  9,  0,  9,  9,  9,  9,  9,  3,  3,  3,  9,  0,  0,
+    14, 12,  9,  0,  3,  3,  9,  3,  9,  3,  3,  3,  3,  3,  0,  0,
+     9,  0,  0,  0,  0,  0,  0,  3,  3,  9,  3,  3, 12, 12, 10, 10,
+     9,  0,  9,  9,  3,  0,  0,  3,  3,  3,  9,  0,  9,  9,  0,  9,
+     0,  0, 10, 10,  0,  0,  0,  9,  0,  9,  9,  0,  0,  3,  0,  0,
+     9,  3,  0,  0,  0,  0,  3,  3,  0,  0,  3,  9,  0,  9,  3,  3,
+     0,  0,  9,  0,  0,  0,  3,  0,  3,  0,  3,  0, 10, 10,  0,  0,
+     0,  9,  0,  9,  0,  3,  0,  3,  0,  3, 13, 13, 13, 13,  3,  3,
+     3,  0,  0,  0,  3,  3,  3,  9, 10, 10, 12, 12, 10, 10,  3,  3,
+     0,  8,  0,  0,  0,  0, 12,  0, 12,  0,  0,  0,  8,  8,  0,  0,
+     9,  0, 12,  9,  6,  9,  9,  9,  9,  9,  9, 13, 13,  0,  0,  0,
+     3, 12, 12,  0,  9,  0,  3,  3,  0,  0, 14, 12, 14, 12,  0,  3,
+     3,  3,  5,  0,  9,  3,  9,  0, 12, 12, 12, 12,  0,  0, 12, 12,
+     9,  9, 12, 12,  3,  9,  9,  0,  0,  8,  0,  8,  7,  0,  7,  7,
+     8,  0,  7,  0,  8,  0,  0,  0,  6,  6,  6,  6,  6,  6,  6,  5,
+     3,  3,  5,  5,  0,  0,  0, 14, 14,  0,  0,  0, 13, 13, 13, 13,
+    11,  0,  0,  0,  4,  4,  5,  5,  5,  5,  5,  6,  0, 13, 13,  0,
+    12, 12,  0,  0,  0, 13, 13, 12,  0,  0,  0,  6,  5,  0,  5,  5,
+     0, 13, 13,  7,  0,  0,  0,  8,  0,  0,  7,  8,  8,  8,  7,  7,
+     8,  0,  8,  0,  8,  8,  0,  7,  9,  7,  0,  0,  0,  8,  7,  7,
+     0,  0,  7,  0,  9,  9,  9,  8,  0,  0,  8,  8,  0,  0, 13, 13,
+     8,  7,  7,  8,  7,  8,  7,  3,  7,  7,  0,  7,  0,  0, 12,  9,
+     0,  0, 13,  0,  6, 14, 12,  0,  0, 13, 13, 13,  9,  9,  0, 12,
+     9,  0, 12, 12,  8,  7,  9,  3,  3,  3,  0,  9,  7,  7,  3,  3,
+     3,  3,  0, 12,  0,  0,  8,  7,  9,  0,  0,  8,  7,  8,  7,  9,
+     7,  7,  7,  9,  9,  9,  3,  9,  0, 12, 12, 12,  0,  0,  9,  3,
+    12, 12,  9,  9,  9,  3,  3,  0,  3,  3,  3, 12,  0,  0,  0,  7,
+     0,  9,  3,  9,  9,  9, 13, 13, 14, 14,  0, 14,  0, 14, 14,  0,
+    13,  0,  0, 13,  0, 14, 12, 12, 14, 13, 13, 13, 13, 13, 13,  0,
+     9,  0,  0,  5,  0,  0, 14,  0,  0, 13,  0, 13, 13, 12, 13, 13,
+    14,  0,  9,  9,  0,  5,  5,  5,  0,  5, 12, 12,  3,  0, 10, 10,
+     9, 12, 12,  0,  3, 12,  0,  0, 10, 10,  9,  0, 12, 12,  0, 12,
+     9, 12,  0,  0,  3,  0, 12, 12,  0,  3,  3, 12,  3,  3,  3,  5,
+     5,  5,  5,  3,  0,  8,  8,  0,  8,  0,  7,  7,
+};
+
+/* Sentence_Break: 6372 bytes. */
+
+RE_UINT32 re_get_sentence_break(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_sentence_break_stage_1[f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_sentence_break_stage_2[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_sentence_break_stage_3[pos + f] << 3;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_sentence_break_stage_4[pos + f] << 2;
+    value = re_sentence_break_stage_5[pos + code];
+
+    return value;
+}
+
+/* Math. */
+
+static RE_UINT8 re_math_stage_1[] = {
+    0, 1, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2,
+};
+
+static RE_UINT8 re_math_stage_2[] = {
+    0, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 6, 1, 1,
+};
+
+static RE_UINT8 re_math_stage_3[] = {
+     0,  1,  1,  2,  1,  1,  3,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     4,  5,  6,  7,  1,  8,  9, 10,  1,  6,  6, 11,  1,  1,  1,  1,
+     1,  1,  1, 12,  1,  1, 13, 14,  1,  1,  1,  1, 15, 16, 17, 18,
+     1,  1,  1,  1,  1,  1, 19,  1,
+};
+
+static RE_UINT8 re_math_stage_4[] = {
+     0,  1,  2,  3,  0,  4,  5,  5,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  6,  7,  8,  0,  0,  0,  0,  0,  0,  0,
+     9, 10, 11, 12, 13,  0, 14, 15, 16, 17, 18,  0, 19, 20, 21, 22,
+    23, 23, 23, 23, 23, 23, 23, 23, 24, 25,  0, 26, 27, 28, 29, 30,
+     0,  0,  0,  0,  0, 31, 32, 33, 34,  0, 35, 36,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 23, 23,  0, 19, 37,  0,  0,  0,  0,  0,
+     0, 38,  0,  0,  0,  0,  0,  0,  0,  0,  0, 39,  0,  0,  0,  0,
+     1,  3,  3,  0,  0,  0,  0, 40, 23, 23, 41, 23, 42, 43, 44, 23,
+    45, 46, 47, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 48, 23, 23,
+    23, 23, 23, 23, 23, 23, 49, 23, 44, 50, 51, 52, 53, 54,  0, 55,
+};
+
+static RE_UINT8 re_math_stage_5[] = {
+      0,   0,   0,   0,   0,   8,   0, 112,   0,   0,   0,  64,   0,   0,   0,  80,
+      0,  16,   2,   0,   0,   0, 128,   0,   0,   0,  39,   0,   0,   0, 115,   0,
+    192,   1,   0,   0,   0,   0,  64,   0,   0,   0,  28,   0,  17,   0,   4,   0,
+     30,   0,   0, 124,   0, 124,   0,   0,   0,   0, 255,  31,  98, 248,   0,   0,
+    132, 252,  47,  63,  16, 179, 251, 241, 255,  11,   0,   0,   0,   0, 255, 255,
+    255, 126, 195, 240, 255, 255, 255,  47,  48,   0, 240, 255, 255, 255, 255, 255,
+      0,  15,   0,   0,   3,   0,   0,   0,   0,   0,   0,  16,   0,   0,   0, 248,
+    255, 255, 191,   0,   0,   0,   1, 240,   7,   0,   0,   0,   3, 192, 255, 240,
+    195, 140,  15,   0, 148,  31,   0, 255,  96,   0,   0,   0,   5,   0,   0,   0,
+     15, 224,   0,   0, 159,  31,   0,   0,   0,   2,   0,   0, 126,   1,   0,   0,
+      4,  30,   0,   0, 255, 255, 223, 255, 255, 255, 255, 223, 100, 222, 255, 235,
+    239, 255, 255, 255, 191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,
+     63, 255, 255, 255, 255, 207, 255, 255, 150, 254, 247,  10, 132, 234, 150, 170,
+    150, 247, 247,  94, 255, 251, 255,  15, 238, 251, 255,  15,   0,   0,   3,   0,
+};
+
+/* Math: 538 bytes. */
+
+RE_UINT32 re_get_math(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_math_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_math_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_math_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_math_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_math_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Alphabetic. */
+
+static RE_UINT8 re_alphabetic_stage_1[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3,
+};
+
+static RE_UINT8 re_alphabetic_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 13, 13, 13, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 13, 13, 26, 27, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 28,  7, 29, 30,  7, 31, 13, 13, 13, 13, 13, 32,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_alphabetic_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1, 17, 18, 19,  1, 20, 21, 22, 23, 24, 25, 26, 27,  1, 28,
+    29, 30, 31, 31, 32, 31, 31, 31, 31, 31, 31, 31, 33, 34, 35, 31,
+    36, 37, 31, 31,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 38,  1,  1,  1,  1,  1,  1,  1,  1,  1, 39,
+     1,  1,  1,  1, 40,  1, 41, 42, 43, 44, 45, 46,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1, 47, 31, 31, 31, 31, 31, 31, 31, 31,
+    31,  1, 48, 49,  1, 50, 51, 52, 53, 54, 55, 56, 57, 58,  1, 59,
+    60, 61, 62, 63, 64, 31, 31, 31, 65, 66, 67, 68, 69, 70, 71, 72,
+    73, 31, 74, 31, 31, 31, 31, 31,  1,  1,  1, 75, 76, 77, 31, 31,
+     1,  1,  1,  1, 78, 31, 31, 31, 31, 31, 31, 31,  1,  1, 79, 31,
+     1,  1, 80, 81, 31, 31, 31, 82, 83, 31, 31, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 84, 31, 31, 31, 31, 31, 31, 31, 85, 86, 87, 88,
+    89, 31, 31, 31, 31, 31, 90, 31, 31, 91, 31, 31, 31, 31, 31, 31,
+     1,  1,  1,  1,  1,  1, 92,  1,  1,  1,  1,  1,  1,  1,  1, 93,
+    94,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 95, 31,
+     1,  1, 96, 31, 31, 31, 31, 31,
+};
+
+static RE_UINT8 re_alphabetic_stage_4[] = {
+      0,   0,   1,   1,   0,   2,   3,   3,   4,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   5,   6,   0,   0,   7,   8,   9,  10,   4,  11,
+      4,   4,   4,   4,  12,   4,   4,   4,   4,  13,  14,  15,  16,  17,  18,  19,
+     20,   4,  21,  22,   4,   4,  23,  24,  25,   4,  26,   4,   4,  27,  28,  29,
+     30,  31,  32,   0,   0,  33,   0,  34,   4,  35,  36,  37,  38,  39,  40,  41,
+     42,  43,  44,  45,  46,  47,  48,  49,  50,  47,  51,  52,  53,  54,  55,   0,
+     56,  57,  58,  59,  60,  61,  62,  63,  60,  64,  65,  66,  67,  68,  69,  70,
+     15,  71,  72,   0,  73,  74,  75,   0,  76,   0,  77,  78,  79,  80,   0,   0,
+      4,  81,  25,  82,  83,   4,  84,  85,   4,   4,  86,   4,  87,  88,  89,   4,
+     90,   4,  91,   0,  92,   4,   4,  93,  15,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,  94,   1,   4,   4,  95,  96,  97,  97,  98,   4,  99, 100,   0,
+      0,   4,   4, 101,   4, 102,   4, 103, 104, 105,  25, 106,   4, 107, 108,   0,
+    109,   4, 104, 110,   0, 111,   0,   0,   4, 112, 113,   0,   4, 114,   4, 115,
+      4, 103, 116, 117,   0,   0,   0, 118,   4,   4,   4,   4,   4,   4,   0, 119,
+     93,   4, 120, 117,   4, 121, 122, 123,   0,   0,   0, 124, 125,   0,   0,   0,
+    126, 127, 128,   4, 129,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 130,   4, 108,   4, 131, 104,   4,   4,   4,   4, 132,
+      4,  84,   4, 133, 134, 135, 135,   4,   0, 136,   0,   0,   0,   0,   0,   0,
+    137, 138,  15,   4, 139,  15,   4,  85, 140, 141,   4,   4, 142,  71,   0,  25,
+      4,   4,   4,   4,   4, 103,   0,   0,   4,   4,   4,   4,   4,   4, 103,   0,
+      4,   4,   4,   4,  31,   0,  25, 117, 143, 144,   4, 145,   4,   4,   4,  92,
+    146, 147,   4,   4, 148, 149,   0, 146, 150,  16,   4,  97,   4,   4,  59, 151,
+     28, 102, 152,  80,   4, 153, 136, 154,   4, 134, 155, 156,   4, 104, 157, 158,
+    159, 160,  85, 161,   4,   4,   4, 162,   4,   4,   4,   4,   4, 163, 164, 109,
+      4,   4,   4, 165,   4,   4, 166,   0, 167, 168, 169,   4,   4,  27, 170,   4,
+      4, 117,  25,   4, 171,   4,  16, 172,   0,   0,   0, 173,   4,   4,   4,  80,
+      0,   1,   1, 174,   4, 104, 175,   0, 176, 177, 178,   0,   4,   4,   4,  71,
+      0,   0,   4,  33,   0,   0,   0,   0,   0,   0,   0,   0,  80,   4, 179,   0,
+      4,  25, 102,  71, 117,   4, 180,   0,   4,   4,   4,   4, 117,   0,   0,   0,
+      4, 181,   4,  59,   0,   0,   0,   0,   4, 134, 103,  16,   0,   0,   0,   0,
+    182, 183, 103, 134, 104,   0,   0, 184, 103, 166,   0,   0,   4, 185,   0,   0,
+    186,  97,   0,  80,  80,   0,  77, 187,   4, 103, 103, 152,  27,   0,   0,   0,
+      4,   4, 129,   0,   4, 152,   4, 152,   4,   4, 188,   0, 147,  32,  25, 129,
+      4, 152,  25, 189,   4,   4, 190,   0, 191, 192,   0,   0, 193, 194,   4, 129,
+     38,  47, 195,  59,   0,   0,   0,   0,   0,   0,   0,   0,   4,   4, 196,   0,
+      0,   0,   0,   0,   4, 197, 198,   0,   4, 104, 199,   0,   4, 103,   0,   0,
+    200, 162,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   4,   4, 201,
+      0,   0,   0,   0,   0,   0,   4,  32,   4,   4,   4,   4, 166,   0,   0,   0,
+      4,   4,   4, 142,   4,   4,   4,   4,   4,   4,  59,   0,   0,   0,   0,   0,
+      4, 142,   0,   0,   0,   0,   0,   0,   4,   4, 202,   0,   0,   0,   0,   0,
+      4,  32, 104,   0,   0,   0,  25, 155,   4, 134,  59, 203,  92,   0,   0,   0,
+      4,   4, 204, 104, 170,   0,   0,   0, 205,   0,   0,   0,   0,   0,   0,   0,
+      4,   4,   4, 206, 207,   0,   0,   0,   4,   4, 208,   4, 209, 210, 211,   4,
+    212, 213, 214,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4, 215, 216,  85,
+    208, 208, 131, 131, 217, 217, 218,   0,   4,   4,   4,   4,   4,   4, 187,   0,
+    211, 219, 220, 221, 222, 223,   0,   0,   0,  25, 224, 224, 108,   0,   0,   0,
+      4,   4,   4,   4,   4,   4, 134,   0,   4,  33,   4,   4,   4,   4,   4,   4,
+    117,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4, 205,   0,   0,
+    117,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_alphabetic_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   4,  32,   4, 255, 255, 127, 255,
+    255, 255, 255, 255, 195, 255,   3,   0,  31,  80,   0,   0,  32,   0,   0,   0,
+      0,   0, 223, 188,  64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 191, 255,
+      3, 252, 255, 255, 255, 255, 254, 255, 255, 255, 127,   2, 254, 255, 255, 255,
+    255,   0,   0,   0,   0,   0, 255, 191, 182,   0, 255, 255, 255,   7,   7,   0,
+      0,   0, 255,   7, 255, 255, 255, 254,   0, 192, 255, 255, 255, 255, 239,  31,
+    254, 225,   0, 156,   0,   0, 255, 255,   0, 224, 255, 255, 255, 255,   3,   0,
+      0, 252, 255, 255, 255,   7,  48,   4, 255, 255, 255, 252, 255,  31,   0,   0,
+    255, 255, 255,   1, 255, 255,  31,   0, 248,   3, 255, 255, 255, 255, 255, 239,
+    255, 223, 225, 255,  15,   0, 254, 255, 239, 159, 249, 255, 255, 253, 197, 227,
+    159,  89, 128, 176,  15,   0,   3,   0, 238, 135, 249, 255, 255, 253, 109, 195,
+    135,  25,   2,  94,   0,   0,  63,   0, 238, 191, 251, 255, 255, 253, 237, 227,
+    191,  27,   1,   0,  15,   0,   0,   2, 238, 159, 249, 255, 159,  25, 192, 176,
+     15,   0,   2,   0, 236, 199,  61, 214,  24, 199, 255, 195, 199,  29, 129,   0,
+    239, 223, 253, 255, 255, 253, 255, 227, 223,  29,  96,   7,  15,   0,   0,   0,
+    238, 223, 253, 255, 255, 253, 239, 227, 223,  29,  96,  64,  15,   0,   6,   0,
+    255, 255, 255, 231, 223,  93, 128, 128,  15,   0,   0, 252, 236, 255, 127, 252,
+    255, 255, 251,  47, 127, 128,  95, 255,   0,   0,  12,   0, 255, 255, 255,   7,
+    127,  32,   0,   0, 150,  37, 240, 254, 174, 236, 255,  59,  95,  32,   0, 240,
+      1,   0,   0,   0, 255, 254, 255, 255, 255,  31, 254, 255,   3, 255, 255, 254,
+    255, 255, 255,  31, 255, 255, 127, 249, 231, 193, 255, 255, 127,  64,   0,  48,
+    191,  32, 255, 255, 255, 255, 255, 247, 255,  61, 127,  61, 255,  61, 255, 255,
+    255, 255,  61, 127,  61, 255, 127, 255, 255, 255,  61, 255, 255, 255, 255, 135,
+    255, 255,   0,   0, 255, 255,  63,  63, 255, 159, 255, 255, 255, 199, 255,   1,
+    255, 223,  15,   0, 255, 255,  15,   0, 255, 223,  13,   0, 255, 255, 207, 255,
+    255,   1, 128,  16, 255, 255, 255,   0, 255,   7, 255, 255, 255, 255,  63,   0,
+    255, 255, 255, 127, 255,  15, 255,   1, 255,  63,  31,   0, 255,  15, 255, 255,
+    255,   3,   0,   0, 255, 255, 255,  15, 254, 255,  31,   0, 128,   0,   0,   0,
+    255, 255, 239, 255, 239,  15,   0,   0, 255, 243,   0, 252, 191, 255,   3,   0,
+      0, 224,   0, 252, 255, 255, 255,  63,   0, 222, 111,   0, 128, 255,  31,   0,
+     63,  63, 255, 170, 255, 255, 223,  95, 220,  31, 207,  15, 255,  31, 220,  31,
+      0,   0,   2, 128,   0,   0, 255,  31, 132, 252,  47,  62,  80, 189, 255, 243,
+    224,  67,   0,   0, 255,   1,   0,   0,   0,   0, 192, 255, 255, 127, 255, 255,
+     31, 120,  12,   0, 255, 128,   0,   0, 255, 255, 127,   0, 127, 127, 127, 127,
+      0, 128,   0,   0, 224,   0,   0,   0, 254,   3,  62,  31, 255, 255, 127, 224,
+    224, 255, 255, 255, 255,  63, 254, 255, 255, 127,   0,   0, 255,  31, 255, 255,
+      0,  12,   0,   0, 255, 127, 240, 143,   0,   0, 128, 255, 252, 255, 255, 255,
+    255, 249, 255, 255, 255,  63, 255,   0, 187, 247, 255, 255,   0,   0, 252,  40,
+    255, 255,   7,   0, 255, 255, 247, 255, 223, 255,   0, 124, 255,  63,   0,   0,
+    255, 255, 127, 196,   5,   0,   0,  56, 255, 255,  60,   0, 126, 126, 126,   0,
+    127, 127, 255, 255,  63,   0, 255, 255, 255,   7,   0,   0,  15,   0, 255, 255,
+    127, 248, 255, 255, 255,  63, 255, 255, 255, 255, 255,   3, 127,   0, 248, 224,
+    255, 253, 127,  95, 219, 255, 255, 255,   0,   0, 248, 255, 255, 255, 252, 255,
+      0,   0, 255,  15,   0,   0, 223, 255, 192, 255, 255, 255, 252, 252, 252,  28,
+    255, 239, 255, 255, 127, 255, 255, 183, 255,  63, 255,  63, 255, 255,   1,   0,
+     15, 255,  62,   0, 255,   0, 255, 255,  63, 253, 255, 255, 255, 255, 191, 145,
+    255, 255,  55,   0, 255, 255, 255, 192, 111, 240, 239, 254,  31,   0,   0,   0,
+     63,   0,   0,   0, 255, 255,  71,   0,  30,   0,   0,  20, 255, 255, 251, 255,
+    255, 255, 159,   0, 127, 189, 255, 191, 255,   1, 255, 255, 159,  25, 129, 224,
+    179,   0,   0,   0, 255, 255,  63, 127,   0,   0,   0,  63,  17,   0,   0,   0,
+    255, 255, 255, 227,   0,   0,   0, 128, 127,   0,   0,   0, 248, 255, 255, 224,
+     31,   0, 255, 255,   3,   0,   0,   0, 255,   7, 255,  31, 255,   1, 255,  67,
+    255, 255, 223, 255, 255, 255, 255, 223, 100, 222, 255, 235, 239, 255, 255, 255,
+    191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,  63, 255, 255, 255,
+    253, 255, 255, 247, 255, 253, 255, 255, 247,  15,   0,   0, 150, 254, 247,  10,
+    132, 234, 150, 170, 150, 247, 247,  94, 255, 251, 255,  15, 238, 251, 255,  15,
+    255,   3, 255, 255,
+};
+
+/* Alphabetic: 2085 bytes. */
+
+RE_UINT32 re_get_alphabetic(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_alphabetic_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_alphabetic_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_alphabetic_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_alphabetic_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_alphabetic_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Lowercase. */
+
+static RE_UINT8 re_lowercase_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_lowercase_stage_2[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5,
+    6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static RE_UINT8 re_lowercase_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  7,  6,  6,  6,  6,  6,  6,  6,  6,  6,  8,  9, 10,
+    11, 12,  6,  6, 13,  6,  6,  6,  6,  6,  6,  6, 14, 15,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 16, 17,  6,  6,  6, 18,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 19,  6,  6,  6, 20,
+     6,  6,  6,  6, 21,  6,  6,  6,  6,  6,  6,  6, 22,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6, 23,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6, 24, 25, 26, 27,  6,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_lowercase_stage_4[] = {
+     0,  0,  0,  1,  0,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,
+     5, 13, 14, 15, 16, 17, 18, 19,  0,  0, 20, 21, 22, 23, 24, 25,
+     0, 26, 15,  5, 27,  5, 28,  5,  5, 29,  0, 30, 31,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 32,
+    15, 15, 15, 15, 15, 15,  0,  0,  5,  5,  5,  5, 33,  5,  5,  5,
+    34, 35, 36, 37, 35, 38, 39, 40,  0,  0,  0, 41, 42,  0,  0,  0,
+    43, 44, 45, 26, 46,  0,  0,  0,  0,  0,  0,  0,  0,  0, 26, 47,
+     0, 26, 48, 49,  5,  5,  5, 50, 15, 51,  0,  0,  0,  0,  0,  0,
+     0,  0,  5, 52, 53,  0,  0,  0,  0, 54,  5, 55, 56, 57,  0, 58,
+     0, 26, 59, 60, 15, 15,  0,  0, 61,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  1,  0,  0,  0,  0,  0,  0, 62, 63,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 15, 64,  0,  0,  0,  0,  0,  0, 15,  0,
+    65, 66, 67, 31, 68, 69, 70, 71, 72, 73, 74, 75, 76, 65, 66, 77,
+    31, 68, 78, 63, 71, 79, 80, 81, 82, 78, 83, 26, 84, 71, 85,  0,
+};
+
+static RE_UINT8 re_lowercase_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   4,  32,   4,   0,   0,   0, 128,
+    255, 255, 127, 255, 170, 170, 170, 170, 170, 170, 170,  85,  85, 171, 170, 170,
+    170, 170, 170, 212,  41,  49,  36,  78,  42,  45,  81, 230,  64,  82,  85, 181,
+    170, 170,  41, 170, 170, 170, 250, 147, 133, 170, 255, 255, 255, 255, 255, 255,
+    255, 255, 239, 255, 255, 255, 255,   1,   3,   0,   0,   0,  31,   0,   0,   0,
+     32,   0,   0,   0,   0,   0, 138,  60,   0,   0,   1,   0,   0, 240, 255, 255,
+    255, 127, 227, 170, 170, 170,  47,  25,   0,   0, 255, 255,   2, 168, 170, 170,
+     84, 213, 170, 170, 170, 170,   0,   0, 254, 255, 255, 255, 255,   0,   0,   0,
+      0,   0,   0,  63, 170, 170, 234, 191, 255,   0,  63,   0, 255,   0, 255,   0,
+     63,   0, 255,   0, 255,   0, 255,  63, 255,   0, 223,  64, 220,   0, 207,   0,
+    255,   0, 220,   0,   0,   0,   2, 128,   0,   0, 255,  31,   0, 196,   8,   0,
+      0, 128,  16,  50, 192,  67,   0,   0,  16,   0,   0,   0, 255,   3,   0,   0,
+    255, 255, 255, 127,  98,  21, 218,  63,  26,  80,   8,   0, 191,  32,   0,   0,
+    170,  42,   0,   0, 170, 170, 170,  58, 168, 170, 171, 170, 170, 170, 255, 149,
+    170,  80, 186, 170, 170,   2, 160,   0,   0,   0,   0,   7, 255, 255, 255, 247,
+     63,   0, 255, 255, 127,   0, 248,   0,   0, 255, 255, 255, 255, 255,   0,   0,
+    255, 255,   7,   0,   0,   0,   0, 252, 255, 255,  15,   0,   0, 192, 223, 255,
+    252, 255, 255,  15,   0,   0, 192, 235, 239, 255,   0,   0,   0, 252, 255, 255,
+     15,   0,   0, 192, 255, 255, 255,   0,   0,   0, 252, 255, 255,  15,   0,   0,
+    192, 255, 255, 255,   0, 192, 255, 255,   0,   0, 192, 255,  63,   0,   0,   0,
+    252, 255, 255, 247,   3,   0,   0, 240, 255, 255, 223,  15, 255, 127,  63,   0,
+    255, 253,   0,   0, 247,  11,   0,   0,
+};
+
+/* Lowercase: 777 bytes. */
+
+RE_UINT32 re_get_lowercase(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_lowercase_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_lowercase_stage_2[pos + f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_lowercase_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_lowercase_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_lowercase_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Uppercase. */
+
+static RE_UINT8 re_uppercase_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_uppercase_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  6,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  7,
+     8,  9,  1, 10,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 11,  1,  1,  1, 12,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_uppercase_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     7,  6,  6,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9, 10,
+     6, 11,  6,  6, 12,  6,  6,  6,  6,  6,  6,  6, 13,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 14, 15,  6,  6,  6,  6,  6,  6,  6, 16,
+     6,  6,  6,  6, 17,  6,  6,  6,  6,  6,  6,  6, 18,  6,  6,  6,
+    19,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 20, 21, 22, 23,
+     6, 24,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_uppercase_stage_4[] = {
+     0,  0,  1,  0,  0,  0,  2,  0,  3,  4,  5,  6,  7,  8,  9, 10,
+     3, 11, 12,  0,  0,  0,  0,  0,  0,  0,  0, 13, 14, 15, 16, 17,
+    18, 19,  0,  3, 20,  3, 21,  3,  3, 22, 23,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 18, 24,  0,
+     0,  0,  0,  0,  0, 18, 18, 25,  3,  3,  3,  3, 26,  3,  3,  3,
+    27, 28, 29, 30,  0, 31, 32, 33, 34, 35, 36, 19, 37,  0,  0,  0,
+     0,  0,  0,  0,  0, 38, 19,  0, 18, 39,  0, 40,  3,  3,  3, 41,
+     0,  0,  3, 42, 43,  0,  0,  0,  0, 44,  3, 45, 46, 47,  0,  0,
+     0,  1,  0,  0,  0,  0,  0,  0, 18, 48,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 18, 49,  0,  0,  0,  0,  0,  0,  0, 18,  0,  0,
+    50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 50, 51, 52,
+    53, 63, 25, 56, 57, 53, 64, 65, 66, 67, 38, 39, 56, 68, 69,  0,
+     0, 56, 70, 70, 57,  0,  0,  0,
+};
+
+static RE_UINT8 re_uppercase_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7, 255, 255, 127, 127,  85,  85,  85,  85,
+     85,  85,  85, 170, 170,  84,  85,  85,  85,  85,  85,  43, 214, 206, 219, 177,
+    213, 210, 174,  17, 144, 164, 170,  74,  85,  85, 210,  85,  85,  85,   5, 108,
+    122,  85,   0,   0,   0,   0,  69, 128,  64, 215, 254, 255, 251,  15,   0,   0,
+      0, 128,  28,  85,  85,  85, 144, 230, 255, 255, 255, 255, 255, 255,   0,   0,
+      1,  84,  85,  85, 171,  42,  85,  85,  85,  85, 254, 255, 255, 255, 127,   0,
+    191,  32,   0,   0, 255, 255,  63,   0,  85,  85,  21,  64,   0, 255,   0,  63,
+      0, 255,   0, 255,   0,  63,   0, 170,   0, 255,   0,   0,   0,   0,   0,  15,
+      0,  15,   0,  15,   0,  31,   0,  15, 132,  56,  39,  62,  80,  61,  15, 192,
+     32,   0,   0,   0,   8,   0,   0,   0,   0,   0, 192, 255, 255, 127,   0,   0,
+    157, 234,  37, 192,   5,  40,   4,   0,  85,  21,   0,   0,  85,  85,  85,   5,
+     84,  85,  84,  85,  85,  85,   0, 106,  85,  40,  69,  85,  85,  61,  95,   0,
+    255,   0,   0,   0, 255, 255,   7,   0, 255, 255, 255,   3,   0,   0, 240, 255,
+    255,  63,   0,   0,   0, 255, 255, 255,   3,   0,   0, 208, 100, 222,  63,   0,
+      0,   0, 255, 255, 255,   3,   0,   0, 176, 231, 223,  31,   0,   0,   0, 123,
+     95, 252,   1,   0,   0, 240, 255, 255,  63,   0,   0,   0,   3,   0,   0, 240,
+      1,   0,   0,   0, 252, 255, 255,   7,   0,   0,   0, 240, 255, 255,  31,   0,
+    255,   1,   0,   0,   0,   4,   0,   0, 255,   3, 255, 255,
+};
+
+/* Uppercase: 701 bytes. */
+
+RE_UINT32 re_get_uppercase(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_uppercase_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_uppercase_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_uppercase_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_uppercase_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_uppercase_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Cased. */
+
+static RE_UINT8 re_cased_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_cased_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  6,  7,  1,  1,  1,  1,  1,  1,  1,  1,  1,  8,
+     9, 10,  1, 11,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 12,  1,  1,  1, 13,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_cased_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     7,  6,  6,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9, 10, 11,
+    12, 13,  6,  6, 14,  6,  6,  6,  6,  6,  6,  6, 15, 16,  6,  6,
+     6,  6,  6,  6,  6,  6, 17, 18,  6,  6,  6, 19,  6,  6,  6,  6,
+     6,  6,  6, 20,  6,  6,  6, 21,  6,  6,  6,  6, 22,  6,  6,  6,
+     6,  6,  6,  6, 23,  6,  6,  6, 24,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6, 25, 26, 27, 28,  6, 29,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_cased_stage_4[] = {
+     0,  0,  1,  1,  0,  2,  3,  3,  4,  4,  4,  4,  4,  5,  6,  4,
+     4,  4,  4,  4,  7,  8,  9, 10,  0,  0, 11, 12, 13, 14,  4, 15,
+     4,  4,  4,  4, 16,  4,  4,  4,  4, 17, 18, 19, 20,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4, 21,  0,
+     0,  0,  0,  0,  0,  4,  4, 22,  4,  4,  4,  4,  4,  4,  0,  0,
+     4,  4,  4,  4,  4,  4,  4,  4, 22,  4, 23, 24,  4, 25, 26, 27,
+     0,  0,  0, 28, 29,  0,  0,  0, 30, 31, 32,  4, 33,  0,  0,  0,
+     0,  0,  0,  0,  0, 34,  4, 35,  4, 36, 37,  4,  4,  4,  4, 38,
+     4, 21,  0,  0,  0,  0,  0,  0,  0,  0,  4, 39, 24,  0,  0,  0,
+     0, 40,  4,  4, 41, 42,  0, 43,  0, 44,  5, 45,  4,  4,  0,  0,
+    46,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  0,  0,  0,
+     4,  4, 47,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4, 48,  4, 48,
+     0,  0,  0,  0,  0,  4,  4,  0,  4,  4, 49,  4, 50, 51, 52,  4,
+    53, 54, 55,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4, 56, 57,  5,
+    49, 49, 36, 36, 58, 58, 59,  0,  0, 44, 60, 60, 35,  0,  0,  0,
+};
+
+static RE_UINT8 re_cased_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   4,  32,   4, 255, 255, 127, 255,
+    255, 255, 255, 255, 255, 255, 255, 247, 240, 255, 255, 255, 255, 255, 239, 255,
+    255, 255, 255,   1,   3,   0,   0,   0,  31,   0,   0,   0,  32,   0,   0,   0,
+      0,   0, 207, 188,  64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 191, 255,
+      3, 252, 255, 255, 255, 255, 254, 255, 255, 255, 127,   0, 254, 255, 255, 255,
+    255,   0,   0,   0, 191,  32,   0,   0, 255, 255,  63,  63,  63,  63, 255, 170,
+    255, 255, 255,  63, 255, 255, 223,  95, 220,  31, 207,  15, 255,  31, 220,  31,
+      0,   0,   2, 128,   0,   0, 255,  31, 132, 252,  47,  62,  80, 189,  31, 242,
+    224,  67,   0,   0,  24,   0,   0,   0,   0,   0, 192, 255, 255,   3,   0,   0,
+    255, 127, 255, 255, 255, 255, 255, 127,  31, 120,  12,   0, 255,  63,   0,   0,
+    252, 255, 255, 255, 255, 120, 255, 255, 255,  63, 255,   0,   0,   0,   0,   7,
+      0,   0, 255, 255,  63,   0, 255, 255, 127,   0, 248,   0, 255, 255,   0,   0,
+    255, 255,   7,   0, 255, 255, 223, 255, 255, 255, 255, 223, 100, 222, 255, 235,
+    239, 255, 255, 255, 191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,
+     63, 255, 255, 255, 253, 255, 255, 247, 255, 253, 255, 255, 247,  15,   0,   0,
+    255,   3, 255, 255,
+};
+
+/* Cased: 709 bytes. */
+
+RE_UINT32 re_get_cased(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_cased_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_cased_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_cased_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_cased_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_cased_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Case_Ignorable. */
+
+static RE_UINT8 re_case_ignorable_stage_1[] = {
+    0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4,
+    4, 4,
+};
+
+static RE_UINT8 re_case_ignorable_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  8,  9,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10,
+    11, 12, 13,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 14,  7,  7,
+     7,  7,  7,  7,  7,  7,  7, 15,  7,  7, 16, 17,  7, 18, 19,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    20,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+};
+
+static RE_UINT8 re_case_ignorable_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1,  1, 17,  1,  1,  1, 18, 19, 20, 21, 22, 23, 24,  1, 25,
+    26,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 28, 29,  1,
+    30,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    31,  1,  1,  1, 32,  1, 33, 34, 35, 36, 37, 38,  1,  1,  1,  1,
+     1,  1,  1, 39,  1,  1, 40, 41,  1, 42, 43, 44,  1,  1,  1,  1,
+     1,  1, 45,  1,  1,  1,  1,  1, 46, 47, 48, 49, 50, 51, 52, 53,
+     1,  1, 54, 55,  1,  1,  1, 56,  1,  1,  1,  1, 57,  1,  1,  1,
+     1, 58, 59,  1,  1,  1,  1,  1,  1,  1, 60,  1,  1,  1,  1,  1,
+    61,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 62,  1,  1,  1,  1,
+    63, 64,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_case_ignorable_stage_4[] = {
+      0,   1,   2,   3,   0,   4,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   5,   6,   6,   6,   6,   6,   7,   8,   0,   0,   0,
+      0,   0,   0,   0,   9,   0,   0,   0,   0,   0,  10,   0,  11,  12,  13,  14,
+     15,   0,  16,  17,   0,   0,  18,  19,  20,   5,  21,   0,   0,  22,   0,  23,
+     24,  25,  26,   0,   0,   0,   0,  27,  28,  29,  30,  31,  32,  33,  34,  35,
+     36,  33,  37,  38,  36,  33,  39,  35,  32,  40,  41,  35,  42,   0,  43,   0,
+      3,  44,  45,  35,  32,  40,  46,  35,  32,   0,  34,  35,   0,   0,  47,   0,
+      0,  48,  49,   0,   0,  50,  51,   0,  52,  53,   0,  54,  55,  56,  57,   0,
+      0,  58,  59,  60,  61,   0,   0,  33,   0,   0,  62,   0,   0,   0,   0,   0,
+     63,  63,  64,  64,   0,  65,  66,   0,  67,   0,  68,   0,   0,  69,   0,   0,
+      0,  70,   0,   0,   0,   0,   0,   0,  71,   0,  72,  73,   0,  74,   0,   0,
+     75,  76,  42,  77,  78,  79,   0,  80,   0,  81,   0,  82,   0,   0,  83,  84,
+      0,  85,   6,  86,  87,   6,   6,  88,   0,   0,   0,   0,   0,  89,  90,  91,
+     92,  93,   0,  94,  95,   0,   5,  96,   0,   0,   0,  97,   0,   0,   0,  98,
+      0,   0,   0,  99,   0,   0,   0,   6,   0, 100,   0,   0,   0,   0,   0,   0,
+    101, 102,   0,   0, 103,   0,   0, 104, 105,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  82, 106,   0,   0, 107, 108,   0,   0, 109,
+      6,  78,   0,  17, 110,   0,   0,  52, 111, 112,   0,   0,   0,   0, 113, 114,
+      0, 115, 116,   0,  28, 117, 100, 112,   0, 118, 119, 120,   0, 121, 122, 123,
+      0,   0,  87,   0,   0,   0,   0, 124,   2,   0,   0,   0,   0, 125,  78,   0,
+    126, 127, 128,   0,   0,   0,   0, 129,   1,   2,   3,  17,  44,   0,   0, 130,
+      0,   0,   0,   0,   0,   0,   0, 131,   0,   0,   0,   0,   0,   0,   0,   3,
+      0,   0,   0, 132,   0,   0,   0,   0, 133, 134,   0,   0,   0,   0,   0, 112,
+     32, 135, 136, 129,  78, 137,   0,   0,  28, 138,   0, 139,  78, 140, 141,   0,
+      0, 142,   0,   0,   0,   0, 129, 143,  78,  33,   3, 144,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 145, 146,   0,   0,   0,   0,   0,   0, 147, 148,   0,
+      0, 149,   3,   0,   0, 150,   0,   0,  62, 151,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 152,   0, 153,  75,   0,   0,   0,   0,   0,
+      0,   0,   0,   0, 154,   0,   0,   0,   0,   0,   0,   0, 155,  75,   0,   0,
+      0,   0,   0, 156, 157, 158,   0,   0,   0,   0, 159,   0,   0,   0,   0,   0,
+      6, 160,   6, 161, 162, 163,   0,   0,   0,   0,   0,   0,   0,   0, 153,   0,
+      0,   0,   0,   0,   0,   0,   0,  87,  32,   6,   6,   6,   0,   0,   0,   0,
+      6,   6,   6,   6,   6,   6,   6, 127,
+};
+
+static RE_UINT8 re_case_ignorable_stage_5[] = {
+      0,   0,   0,   0, 128,  64,   0,   4,   0,   0,   0,  64,   1,   0,   0,   0,
+      0, 161, 144,   1,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255,  48,   4,
+    176,   0,   0,   0, 248,   3,   0,   0,   0,   0,   0,   2,   0,   0, 254, 255,
+    255, 255, 255, 191, 182,   0,   0,   0,   0,   0,  16,   0,  63,   0, 255,  23,
+      1, 248, 255, 255,   0,   0,   1,   0,   0,   0, 192, 191, 255,  61,   0,   0,
+      0, 128,   2,   0, 255,   7,   0,   0, 192, 255,   1,   0,   0, 248,  63,   4,
+      0,   0, 192, 255, 255,  63,   0,   0,   0,   0,   0,  14, 248, 255, 255, 255,
+      7,   0,   0,   0,   0,   0,   0,  20, 254,  33, 254,   0,  12,   0,   2,   0,
+      2,   0,   0,   0,   0,   0,   0,  16,  30,  32,   0,   0,  12,   0,   0,   0,
+      6,   0,   0,   0, 134,  57,   2,   0,   0,   0,  35,   0, 190,  33,   0,   0,
+      0,   0,   0, 144,  30,  32,  64,   0,   4,   0,   0,   0,   1,  32,   0,   0,
+      0,   0,   0, 192, 193,  61,  96,   0,  64,  48,   0,   0,   0,   4,  92,   0,
+      0,   0, 242,   7, 192, 127,   0,   0,   0,   0, 242,  27,  64,  63,   0,   0,
+      0,   0,   0,   3,   0,   0, 160,   2,   0,   0, 254, 127, 223, 224, 255, 254,
+    255, 255, 255,  31,  64,   0,   0,   0,   0, 224, 253, 102,   0,   0,   0, 195,
+      1,   0,  30,   0, 100,  32,   0,  32,   0,   0,   0, 224,   0,   0,  28,   0,
+      0,   0,  12,   0,   0,   0, 176,  63,  64, 254, 143,  32,   0, 120,   0,   0,
+      8,   0,   0,   0,   0,   2,   0,   0, 135,   1,   4,  14,   0,   0, 128,   9,
+      0,   0,  64, 127, 229,  31, 248, 159, 128,   0, 255, 127,  15,   0,   0,   0,
+      0,   0, 208,  23,   0, 248,  15,   0,   3,   0,   0,   0,  60,  59,   0,   0,
+     64, 163,   3,   0,   0, 240, 207,   0,   0,   0,   0,  63,   0,   0, 247, 255,
+    253,  33,  16,   3,   0, 240, 255, 255, 255,   7,   0,   1,   0,   0,   0, 248,
+    255, 255,  63, 240,   0,   0,   0, 160,   3, 224,   0, 224,   0, 224,   0,  96,
+      0, 248,   0,   3, 144, 124,   0,   0, 223, 255,   2, 128,   0,   0, 255,  31,
+    255, 255,   1,   0,   0,   0,   0,  48,   0, 128,   3,   0,   0, 128,   0, 128,
+      0, 128,   0,   0,  32,   0,   0,   0,   0,  60,  62,   8,   0,   0,   0, 126,
+      0,   0,   0, 112,   0,   0,  32,   0,   0,  16,   0,   0,   0, 128, 247, 191,
+      0,   0,   0, 240,   0,   0,   3,   0,   0,   7,   0,   0,  68,   8,   0,   0,
+     96,   0,   0,   0,  16,   0,   0,   0, 255, 255,   3,   0, 192,  63,   0,   0,
+    128, 255,   3,   0,   0,   0, 200,  19,   0, 126, 102,   0,   8,  16,   0,   0,
+      0,   0,   1,  16,   0,   0, 157, 193,   2,   0,   0,  32,   0,  48,  88,   0,
+     32,  33,   0,   0,   0,   0, 252, 255, 255, 255,   8,   0, 255, 255,   0,   0,
+      0,   0,  36,   0,   0,   0,   0, 128,   8,   0,   0,  14,   0,   0,   0,  32,
+      0,   0, 192,   7, 110, 240,   0,   0,   0,   0,   0, 135,   0,   0,   0, 255,
+    127,   0,   0,   0,   0,   0, 120,  38, 128, 239,  31,   0,   0,   0,   8,   0,
+      0,   0, 192, 127,   0,  28,   0,   0,   0, 128, 211,   0, 248,   7,   0,   0,
+    192,  31,  31,   0,   0,   0, 248, 133,  13,   0,   0,   0,   0,   0,  60, 176,
+      1,   0,   0,  48,   0,   0, 248, 167,   0,  40, 191,   0, 188,  15,   0,   0,
+      0,   0,  31,   0,   0,   0, 127,   0,   0, 128, 255, 255,   0,   0,   0,  96,
+    128,   3, 248, 255, 231,  15,   0,   0,   0,  60,   0,   0,  28,   0,   0,   0,
+    255, 255, 127, 248, 255,  31,  32,   0,  16,   0,   0, 248, 254, 255,   0,   0,
+};
+
+/* Case_Ignorable: 1474 bytes. */
+
+RE_UINT32 re_get_case_ignorable(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_case_ignorable_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_case_ignorable_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_case_ignorable_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_case_ignorable_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_case_ignorable_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Changes_When_Lowercased. */
+
+static RE_UINT8 re_changes_when_lowercased_stage_1[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3,
+};
+
+static RE_UINT8 re_changes_when_lowercased_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  6,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  7,
+     8,  9,  1, 10,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_changes_when_lowercased_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     7,  6,  6,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9, 10,
+     6, 11,  6,  6, 12,  6,  6,  6,  6,  6,  6,  6, 13,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 14, 15,  6,  6,  6,  6,  6,  6,  6, 16,
+     6,  6,  6,  6, 17,  6,  6,  6,  6,  6,  6,  6, 18,  6,  6,  6,
+    19,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_changes_when_lowercased_stage_4[] = {
+     0,  0,  1,  0,  0,  0,  2,  0,  3,  4,  5,  6,  7,  8,  9, 10,
+     3, 11, 12,  0,  0,  0,  0,  0,  0,  0,  0, 13, 14, 15, 16, 17,
+    18, 19,  0,  3, 20,  3, 21,  3,  3, 22, 23,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 18, 24,  0,
+     0,  0,  0,  0,  0, 18, 18, 25,  3,  3,  3,  3, 26,  3,  3,  3,
+    27, 28, 29, 30, 28, 31, 32, 33,  0, 34,  0, 19, 35,  0,  0,  0,
+     0,  0,  0,  0,  0, 36, 19,  0, 18, 37,  0, 38,  3,  3,  3, 39,
+     0,  0,  3, 40, 41,  0,  0,  0,  0, 42,  3, 43, 44, 45,  0,  0,
+     0,  1,  0,  0,  0,  0,  0,  0, 18, 46,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 18, 47,  0,  0,  0,  0,  0,  0,  0, 18,  0,  0,
+};
+
+static RE_UINT8 re_changes_when_lowercased_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7, 255, 255, 127, 127,  85,  85,  85,  85,
+     85,  85,  85, 170, 170,  84,  85,  85,  85,  85,  85,  43, 214, 206, 219, 177,
+    213, 210, 174,  17, 176, 173, 170,  74,  85,  85, 214,  85,  85,  85,   5, 108,
+    122,  85,   0,   0,   0,   0,  69, 128,  64, 215, 254, 255, 251,  15,   0,   0,
+      0, 128,   0,  85,  85,  85, 144, 230, 255, 255, 255, 255, 255, 255,   0,   0,
+      1,  84,  85,  85, 171,  42,  85,  85,  85,  85, 254, 255, 255, 255, 127,   0,
+    191,  32,   0,   0, 255, 255,  63,   0,  85,  85,  21,  64,   0, 255,   0,  63,
+      0, 255,   0, 255,   0,  63,   0, 170,   0, 255,   0,   0,   0, 255,   0,  31,
+      0,  31,   0,  15,   0,  31,   0,  31,  64,  12,   4,   0,   8,   0,   0,   0,
+      0,   0, 192, 255, 255, 127,   0,   0, 157, 234,  37, 192,   5,  40,   4,   0,
+     85,  21,   0,   0,  85,  85,  85,   5,  84,  85,  84,  85,  85,  85,   0, 106,
+     85,  40,  69,  85,  85,  61,  95,   0, 255,   0,   0,   0, 255, 255,   7,   0,
+};
+
+/* Changes_When_Lowercased: 538 bytes. */
+
+RE_UINT32 re_get_changes_when_lowercased(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_changes_when_lowercased_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_changes_when_lowercased_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_changes_when_lowercased_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_changes_when_lowercased_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_changes_when_lowercased_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Changes_When_Uppercased. */
+
+static RE_UINT8 re_changes_when_uppercased_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_changes_when_uppercased_stage_2[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5,
+    6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static RE_UINT8 re_changes_when_uppercased_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  7,  6,  6,  6,  6,  6,  6,  6,  6,  6,  8,  9, 10,
+     6, 11,  6,  6, 12,  6,  6,  6,  6,  6,  6,  6, 13, 14,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 15, 16,  6,  6,  6, 17,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 18,  6,  6,  6, 19,
+     6,  6,  6,  6, 20,  6,  6,  6,  6,  6,  6,  6, 21,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6, 22,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_changes_when_uppercased_stage_4[] = {
+     0,  0,  0,  1,  0,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,
+     5, 13, 14, 15, 16,  0,  0,  0,  0,  0, 17, 18, 19, 20, 21, 22,
+     0, 23, 24,  5, 25,  5, 26,  5,  5, 27,  0, 28, 29,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 30,
+     0,  0,  0, 31,  0,  0,  0,  0,  5,  5,  5,  5, 32,  5,  5,  5,
+    33, 34, 35, 36, 24, 37, 38, 39,  0,  0, 40, 23, 41,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 23, 42,  0, 23, 43, 44,  5,  5,  5, 45,
+    24, 46,  0,  0,  0,  0,  0,  0,  0,  0,  5, 47, 48,  0,  0,  0,
+     0, 49,  5, 50, 51, 52,  0,  0,  0,  0, 53, 23, 24, 24,  0,  0,
+    54,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,
+     0, 55, 56,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 24, 57,
+     0,  0,  0,  0,  0,  0, 24,  0,
+};
+
+static RE_UINT8 re_changes_when_uppercased_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   0,  32,   0,   0,   0,   0, 128,
+    255, 255, 127, 255, 170, 170, 170, 170, 170, 170, 170,  84,  85, 171, 170, 170,
+    170, 170, 170, 212,  41,  17,  36,  70,  42,  33,  81, 162,  96,  91,  85, 181,
+    170, 170,  45, 170, 168, 170,  10, 144, 133, 170, 223,  26, 107, 155,  38,  32,
+    137,  31,   4,  96,  32,   0,   0,   0,   0,   0, 138,  56,   0,   0,   1,   0,
+      0, 240, 255, 255, 255, 127, 227, 170, 170, 170,  47,   9,   0,   0, 255, 255,
+    255, 255, 255, 255,   2, 168, 170, 170,  84, 213, 170, 170, 170, 170,   0,   0,
+    254, 255, 255, 255, 255,   0,   0,   0,   0,   0,   0,  63,   0,   0,   0,  34,
+    170, 170, 234,  15, 255,   0,  63,   0, 255,   0, 255,   0,  63,   0, 255,   0,
+    255,   0, 255,  63, 255, 255, 223,  80, 220,  16, 207,   0, 255,   0, 220,  16,
+      0,  64,   0,   0,  16,   0,   0,   0, 255,   3,   0,   0, 255, 255, 255, 127,
+     98,  21,  72,   0,  10,  80,   8,   0, 191,  32,   0,   0, 170,  42,   0,   0,
+    170, 170, 170,  10, 168, 170, 168, 170, 170, 170,   0, 148, 170,  16, 138, 170,
+    170,   2, 160,   0,   0,   0,   8,   0, 127,   0, 248,   0,   0, 255, 255, 255,
+    255, 255,   0,   0, 255, 255,   7,   0,
+};
+
+/* Changes_When_Uppercased: 609 bytes. */
+
+RE_UINT32 re_get_changes_when_uppercased(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_changes_when_uppercased_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_changes_when_uppercased_stage_2[pos + f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_changes_when_uppercased_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_changes_when_uppercased_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_changes_when_uppercased_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Changes_When_Titlecased. */
+
+static RE_UINT8 re_changes_when_titlecased_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_changes_when_titlecased_stage_2[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5,
+    6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static RE_UINT8 re_changes_when_titlecased_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  7,  6,  6,  6,  6,  6,  6,  6,  6,  6,  8,  9, 10,
+     6, 11,  6,  6, 12,  6,  6,  6,  6,  6,  6,  6, 13, 14,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 15, 16,  6,  6,  6, 17,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 18,  6,  6,  6, 19,
+     6,  6,  6,  6, 20,  6,  6,  6,  6,  6,  6,  6, 21,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6, 22,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_changes_when_titlecased_stage_4[] = {
+     0,  0,  0,  1,  0,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,
+     5, 13, 14, 15, 16,  0,  0,  0,  0,  0, 17, 18, 19, 20, 21, 22,
+     0, 23, 24,  5, 25,  5, 26,  5,  5, 27,  0, 28, 29,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 30,
+     0,  0,  0, 31,  0,  0,  0,  0,  5,  5,  5,  5, 32,  5,  5,  5,
+    33, 34, 35, 36, 34, 37, 38, 39,  0,  0, 40, 23, 41,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 23, 42,  0, 23, 43, 44,  5,  5,  5, 45,
+    24, 46,  0,  0,  0,  0,  0,  0,  0,  0,  5, 47, 48,  0,  0,  0,
+     0, 49,  5, 50, 51, 52,  0,  0,  0,  0, 53, 23, 24, 24,  0,  0,
+    54,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,
+     0, 55, 56,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 24, 57,
+     0,  0,  0,  0,  0,  0, 24,  0,
+};
+
+static RE_UINT8 re_changes_when_titlecased_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   0,  32,   0,   0,   0,   0, 128,
+    255, 255, 127, 255, 170, 170, 170, 170, 170, 170, 170,  84,  85, 171, 170, 170,
+    170, 170, 170, 212,  41,  17,  36,  70,  42,  33,  81, 162, 208,  86,  85, 181,
+    170, 170,  43, 170, 168, 170,  10, 144, 133, 170, 223,  26, 107, 155,  38,  32,
+    137,  31,   4,  96,  32,   0,   0,   0,   0,   0, 138,  56,   0,   0,   1,   0,
+      0, 240, 255, 255, 255, 127, 227, 170, 170, 170,  47,   9,   0,   0, 255, 255,
+    255, 255, 255, 255,   2, 168, 170, 170,  84, 213, 170, 170, 170, 170,   0,   0,
+    254, 255, 255, 255, 255,   0,   0,   0,   0,   0,   0,  63,   0,   0,   0,  34,
+    170, 170, 234,  15, 255,   0,  63,   0, 255,   0, 255,   0,  63,   0, 255,   0,
+    255,   0, 255,  63, 255,   0, 223,  64, 220,   0, 207,   0, 255,   0, 220,   0,
+      0,  64,   0,   0,  16,   0,   0,   0, 255,   3,   0,   0, 255, 255, 255, 127,
+     98,  21,  72,   0,  10,  80,   8,   0, 191,  32,   0,   0, 170,  42,   0,   0,
+    170, 170, 170,  10, 168, 170, 168, 170, 170, 170,   0, 148, 170,  16, 138, 170,
+    170,   2, 160,   0,   0,   0,   8,   0, 127,   0, 248,   0,   0, 255, 255, 255,
+    255, 255,   0,   0, 255, 255,   7,   0,
+};
+
+/* Changes_When_Titlecased: 609 bytes. */
+
+RE_UINT32 re_get_changes_when_titlecased(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_changes_when_titlecased_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_changes_when_titlecased_stage_2[pos + f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_changes_when_titlecased_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_changes_when_titlecased_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_changes_when_titlecased_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Changes_When_Casefolded. */
+
+static RE_UINT8 re_changes_when_casefolded_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_changes_when_casefolded_stage_2[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5,
+    6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static RE_UINT8 re_changes_when_casefolded_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     7,  6,  6,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9, 10,
+     6, 11,  6,  6, 12,  6,  6,  6,  6,  6,  6,  6, 13,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 14, 15,  6,  6,  6, 16,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 17,  6,  6,  6, 18,
+     6,  6,  6,  6, 19,  6,  6,  6,  6,  6,  6,  6, 20,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6, 21,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_changes_when_casefolded_stage_4[] = {
+     0,  0,  1,  0,  0,  2,  3,  0,  4,  5,  6,  7,  8,  9, 10, 11,
+     4, 12, 13,  0,  0,  0,  0,  0,  0,  0, 14, 15, 16, 17, 18, 19,
+    20, 21,  0,  4, 22,  4, 23,  4,  4, 24, 25,  0, 26,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 27,  0,
+     0,  0,  0,  0,  0,  0,  0, 28,  4,  4,  4,  4, 29,  4,  4,  4,
+    30, 31, 32, 33, 20, 34, 35, 36,  0, 37,  0, 21, 38,  0,  0,  0,
+     0,  0,  0,  0,  0, 39, 21,  0, 20, 40,  0, 41,  4,  4,  4, 42,
+     0,  0,  4, 43, 44,  0,  0,  0,  0, 45,  4, 46, 47, 48,  0,  0,
+     0,  0,  0, 49, 20, 20,  0,  0, 50,  0,  0,  0,  0,  0,  0,  0,
+     0,  1,  0,  0,  0,  0,  0,  0, 20, 51,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 20, 52,  0,  0,  0,  0,  0,  0,  0, 20,  0,  0,
+};
+
+static RE_UINT8 re_changes_when_casefolded_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   0,  32,   0, 255, 255, 127, 255,
+     85,  85,  85,  85,  85,  85,  85, 170, 170,  86,  85,  85,  85,  85,  85, 171,
+    214, 206, 219, 177, 213, 210, 174,  17, 176, 173, 170,  74,  85,  85, 214,  85,
+     85,  85,   5, 108, 122,  85,   0,   0,  32,   0,   0,   0,   0,   0,  69, 128,
+     64, 215, 254, 255, 251,  15,   0,   0,   4, 128,  99,  85,  85,  85, 179, 230,
+    255, 255, 255, 255, 255, 255,   0,   0,   1,  84,  85,  85, 171,  42,  85,  85,
+     85,  85, 254, 255, 255, 255, 127,   0, 128,   0,   0,   0, 191,  32,   0,   0,
+      0,   0,   0,  63,  85,  85,  21,  76,   0, 255,   0,  63,   0, 255,   0, 255,
+      0,  63,   0, 170,   0, 255,   0,   0, 255, 255, 156,  31, 156,  31,   0,  15,
+      0,  31, 156,  31,  64,  12,   4,   0,   8,   0,   0,   0,   0,   0, 192, 255,
+    255, 127,   0,   0, 157, 234,  37, 192,   5,  40,   4,   0,  85,  21,   0,   0,
+     85,  85,  85,   5,  84,  85,  84,  85,  85,  85,   0, 106,  85,  40,  69,  85,
+     85,  61,  95,   0,   0,   0, 255, 255, 127,   0, 248,   0, 255,   0,   0,   0,
+    255, 255,   7,   0,
+};
+
+/* Changes_When_Casefolded: 581 bytes. */
+
+RE_UINT32 re_get_changes_when_casefolded(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_changes_when_casefolded_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_changes_when_casefolded_stage_2[pos + f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_changes_when_casefolded_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_changes_when_casefolded_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_changes_when_casefolded_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Changes_When_Casemapped. */
+
+static RE_UINT8 re_changes_when_casemapped_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_changes_when_casemapped_stage_2[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5,
+    6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static RE_UINT8 re_changes_when_casemapped_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     7,  6,  6,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9, 10, 11,
+     6, 12,  6,  6, 13,  6,  6,  6,  6,  6,  6,  6, 14, 15,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 16, 17,  6,  6,  6, 18,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 19,  6,  6,  6, 20,
+     6,  6,  6,  6, 21,  6,  6,  6,  6,  6,  6,  6, 22,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6, 23,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_changes_when_casemapped_stage_4[] = {
+     0,  0,  1,  1,  0,  2,  3,  3,  4,  5,  4,  4,  6,  7,  8,  4,
+     4,  9, 10, 11, 12,  0,  0,  0,  0,  0, 13, 14, 15, 16, 17, 18,
+     4,  4,  4,  4, 19,  4,  4,  4,  4, 20, 21, 22, 23,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4, 24,  0,
+     0,  0,  0,  0,  0,  4,  4, 25,  0,  0,  0, 26,  0,  0,  0,  0,
+     4,  4,  4,  4, 27,  4,  4,  4, 25,  4, 28, 29,  4, 30, 31, 32,
+     0, 33, 34,  4, 35,  0,  0,  0,  0,  0,  0,  0,  0, 36,  4, 37,
+     4, 38, 39, 40,  4,  4,  4, 41,  4, 24,  0,  0,  0,  0,  0,  0,
+     0,  0,  4, 42, 43,  0,  0,  0,  0, 44,  4, 45, 46, 47,  0,  0,
+     0,  0, 48, 49,  4,  4,  0,  0, 50,  0,  0,  0,  0,  0,  0,  0,
+     0,  1,  1,  0,  0,  0,  0,  0,  4,  4, 51,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  4, 52,  4, 52,  0,  0,  0,  0,  0,  4,  4,  0,
+};
+
+static RE_UINT8 re_changes_when_casemapped_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   0,  32,   0, 255, 255, 127, 255,
+    255, 255, 255, 255, 255, 255, 255, 254, 255, 223, 255, 247, 255, 243, 255, 179,
+    240, 255, 255, 255, 253, 255,  15, 252, 255, 255, 223,  26, 107, 155,  38,  32,
+    137,  31,   4,  96,  32,   0,   0,   0,   0,   0, 207, 184,  64, 215, 255, 255,
+    251, 255, 255, 255, 255, 255, 227, 255, 255, 255, 191, 239,   3, 252, 255, 255,
+    255, 255, 254, 255, 255, 255, 127,   0, 254, 255, 255, 255, 255,   0,   0,   0,
+    191,  32,   0,   0, 255, 255,  63,  63,   0,   0,   0,  34, 255, 255, 255,  79,
+     63,  63, 255, 170, 255, 255, 255,  63, 255, 255, 223,  95, 220,  31, 207,  15,
+    255,  31, 220,  31,  64,  12,   4,   0,   0,  64,   0,   0,  24,   0,   0,   0,
+      0,   0, 192, 255, 255,   3,   0,   0, 255, 127, 255, 255, 255, 255, 255, 127,
+    255, 255, 109, 192,  15, 120,  12,   0, 255,  63,   0,   0, 255, 255, 255,  15,
+    252, 255, 252, 255, 255, 255,   0, 254, 255,  56, 207, 255, 255,  63, 255,   0,
+      0,   0,   8,   0,   0,   0, 255, 255, 127,   0, 248,   0, 255, 255,   0,   0,
+    255, 255,   7,   0,
+};
+
+/* Changes_When_Casemapped: 597 bytes. */
+
+RE_UINT32 re_get_changes_when_casemapped(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_changes_when_casemapped_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_changes_when_casemapped_stage_2[pos + f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_changes_when_casemapped_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_changes_when_casemapped_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_changes_when_casemapped_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* ID_Start. */
+
+static RE_UINT8 re_id_start_stage_1[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3,
+};
+
+static RE_UINT8 re_id_start_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 13, 13, 13, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 13, 13, 26, 13, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 27,  7, 28, 29,  7, 30, 13, 13, 13, 13, 13, 31,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_id_start_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1, 17, 18, 19,  1, 20, 21, 22, 23, 24, 25, 26, 27,  1, 28,
+    29, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 31, 31,
+    34, 35, 31, 31,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 36,  1,  1,  1,  1,  1,  1,  1,  1,  1, 37,
+     1,  1,  1,  1, 38,  1, 39, 40, 41, 42, 43, 44,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1, 45, 31, 31, 31, 31, 31, 31, 31, 31,
+    31,  1, 46, 47,  1, 48, 49, 50, 51, 52, 53, 54, 55, 56,  1, 57,
+    58, 59, 60, 61, 62, 31, 31, 31, 63, 64, 65, 66, 67, 68, 69, 70,
+    71, 31, 72, 31, 31, 31, 31, 31,  1,  1,  1, 73, 74, 75, 31, 31,
+     1,  1,  1,  1, 76, 31, 31, 31, 31, 31, 31, 31,  1,  1, 77, 31,
+     1,  1, 78, 79, 31, 31, 31, 80, 81, 31, 31, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 82, 31, 31, 31, 31, 31, 31, 31, 83, 84, 85, 86,
+    87, 31, 31, 31, 31, 31, 88, 31,  1,  1,  1,  1,  1,  1, 89,  1,
+     1,  1,  1,  1,  1,  1,  1, 90, 91,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1, 92, 31,  1,  1, 93, 31, 31, 31, 31, 31,
+};
+
+static RE_UINT8 re_id_start_stage_4[] = {
+      0,   0,   1,   1,   0,   2,   3,   3,   4,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   5,   6,   0,   0,   0,   7,   8,   9,   4,  10,
+      4,   4,   4,   4,  11,   4,   4,   4,   4,  12,  13,  14,  15,   0,  16,  17,
+      0,   4,  18,  19,   4,   4,  20,  21,  22,  23,  24,   4,   4,  25,  26,  27,
+     28,  29,  30,   0,   0,  31,   0,   0,  32,  33,  34,  35,  36,  37,  38,  39,
+     40,  41,  42,  43,  44,  45,  46,  47,  48,  45,  49,  50,  51,  52,  46,   0,
+     53,  54,  55,  56,  53,  57,  58,  59,  53,  60,  61,  62,  63,  64,  65,   0,
+     14,  66,  65,   0,  67,  68,  69,   0,  70,   0,  71,  72,  73,   0,   0,   0,
+      4,  74,  75,  76,  77,   4,  78,  79,   4,   4,  80,   4,  81,  82,  83,   4,
+     84,   4,  85,   0,  23,   4,   4,  86,  14,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,  87,   1,   4,   4,  88,  89,  90,  90,  91,   4,  92,  93,   0,
+      0,   4,   4,  94,   4,  95,   4,  96,  97,   0,  16,  98,   4,  99, 100,   0,
+    101,   4,  31,   0,   0, 102,   0,   0, 103,  92, 104,   0, 105, 106,   4, 107,
+      4, 108, 109, 110,   0,   0,   0, 111,   4,   4,   4,   4,   4,   4,   0,   0,
+     86,   4, 112, 110,   4, 113, 114, 115,   0,   0,   0, 116, 117,   0,   0,   0,
+    118, 119, 120,   4, 121,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      4, 122,  97,   4,   4,   4,   4, 123,   4,  78,   4, 124, 101, 125, 125,   0,
+    126, 127,  14,   4, 128,  14,   4,  79, 103, 129,   4,   4, 130,  85,   0,  16,
+      4,   4,   4,   4,   4,  96,   0,   0,   4,   4,   4,   4,   4,   4,  96,   0,
+      4,   4,   4,   4,  72,   0,  16, 110, 131, 132,   4, 133, 110,   4,   4,  23,
+    134, 135,   4,   4, 136, 137,   0, 134, 138, 139,   4,  92, 135,  92,   0, 140,
+     26, 141,  65, 142,  32, 143, 144, 145,   4, 121, 146, 147,   4, 148, 149, 150,
+    151, 152,  79, 141,   4,   4,   4, 139,   4,   4,   4,   4,   4, 153, 154, 155,
+      4,   4,   4, 156,   4,   4, 157,   0, 158, 159, 160,   4,   4,  90, 161,   4,
+      4, 110,  16,   4, 162,   4,  15, 163,   0,   0,   0, 164,   4,   4,   4, 142,
+      0,   1,   1, 165,   4,  97, 166,   0, 167, 168, 169,   0,   4,   4,   4,  85,
+      0,   0,   4,  31,   0,   0,   0,   0,   0,   0,   0,   0, 142,   4, 170,   0,
+      4,  16, 171,  96, 110,   4, 172,   0,   4,   4,   4,   4, 110,   0,   0,   0,
+      4, 173,   4, 108,   0,   0,   0,   0,   4, 101,  96,  15,   0,   0,   0,   0,
+    174, 175,  96, 101,  97,   0,   0, 176,  96, 157,   0,   0,   4, 177,   0,   0,
+    178,  92,   0, 142, 142,   0,  71, 179,   4,  96,  96, 143,  90,   0,   0,   0,
+      4,   4, 121,   0,   4, 143,   4, 143, 105,  94,   0,   0, 105,  23,  16, 121,
+    105,  65,  16, 180, 105, 143, 181,   0, 182, 183,   0,   0, 184, 185,  97,   0,
+     48,  45, 186,  56,   0,   0,   0,   0,   0,   0,   0,   0,   4,  23, 187,   0,
+      0,   0,   0,   0,   4, 130, 188,   0,   4,  23, 189,   0,   4,  18,   0,   0,
+    157,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   4,   4, 190,
+      0,   0,   0,   0,   0,   0,   4,  30,   4,   4,   4,   4, 157,   0,   0,   0,
+      4,   4,   4, 130,   4,   4,   4,   4,   4,   4, 108,   0,   0,   0,   0,   0,
+      4, 130,   0,   0,   0,   0,   0,   0,   4,   4,  65,   0,   0,   0,   0,   0,
+      4,  30,  97,   0,   0,   0,  16, 191,   4,  23, 108, 192,  23,   0,   0,   0,
+      4,   4, 193,   0, 161,   0,   0,   0,  56,   0,   0,   0,   0,   0,   0,   0,
+      4,   4,   4, 194, 195,   0,   0,   0,   4,   4, 196,   4, 197, 198, 199,   4,
+    200, 201, 202,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4, 203, 204,  79,
+    196, 196, 122, 122, 205, 205, 146,   0,   4,   4,   4,   4,   4,   4, 179,   0,
+    199, 206, 207, 208, 209, 210,   0,   0,   4,   4,   4,   4,   4,   4, 101,   0,
+      4,  31,   4,   4,   4,   4,   4,   4, 110,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,  56,   0,   0, 110,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_id_start_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   4,  32,   4, 255, 255, 127, 255,
+    255, 255, 255, 255, 195, 255,   3,   0,  31,  80,   0,   0,   0,   0, 223, 188,
+     64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 191, 255,   3, 252, 255, 255,
+    255, 255, 254, 255, 255, 255, 127,   2, 254, 255, 255, 255, 255,   0,   0,   0,
+      0,   0, 255, 255, 255,   7,   7,   0, 255,   7,   0,   0,   0, 192, 254, 255,
+    255, 255,  47,   0,  96, 192,   0, 156,   0,   0, 253, 255, 255, 255,   0,   0,
+      0, 224, 255, 255,  63,   0,   2,   0,   0, 252, 255, 255, 255,   7,  48,   4,
+    255, 255,  63,   4,  16,   1,   0,   0, 255, 255, 255,   1, 255, 255,  31,   0,
+    240, 255, 255, 255, 255, 255, 255,  35,   0,   0,   1, 255,   3,   0, 254, 255,
+    225, 159, 249, 255, 255, 253, 197,  35,   0,  64,   0, 176,   3,   0,   3,   0,
+    224, 135, 249, 255, 255, 253, 109,   3,   0,   0,   0,  94,   0,   0,  28,   0,
+    224, 191, 251, 255, 255, 253, 237,  35,   0,   0,   1,   0,   3,   0,   0,   2,
+    224, 159, 249, 255,   0,   0,   0, 176,   3,   0,   2,   0, 232, 199,  61, 214,
+     24, 199, 255,   3, 224, 223, 253, 255, 255, 253, 255,  35,   0,   0,   0,   7,
+      3,   0,   0,   0, 255, 253, 239,  35,   0,   0,   0,  64,   3,   0,   6,   0,
+    255, 255, 255,  39,   0,  64,   0, 128,   3,   0,   0, 252, 224, 255, 127, 252,
+    255, 255, 251,  47, 127,   0,   0,   0, 255, 255,  13,   0, 150,  37, 240, 254,
+    174, 236,  13,  32,  95,   0,   0, 240,   1,   0,   0,   0, 255, 254, 255, 255,
+    255,  31,   0,   0,   0,  31,   0,   0, 255,   7,   0, 128,   0,   0,  63,  60,
+     98, 192, 225, 255,   3,  64,   0,   0, 191,  32, 255, 255, 255, 255, 255, 247,
+    255,  61, 127,  61, 255,  61, 255, 255, 255, 255,  61, 127,  61, 255, 127, 255,
+    255, 255,  61, 255, 255, 255, 255,   7, 255, 255,  63,  63, 255, 159, 255, 255,
+    255, 199, 255,   1, 255, 223,   3,   0, 255, 255,   3,   0, 255, 223,   1,   0,
+    255, 255,  15,   0,   0,   0, 128,  16, 255, 255, 255,   0, 255,   5, 255, 255,
+    255, 255,  63,   0, 255, 255, 255, 127, 255,  63,  31,   0, 255,  15, 255, 255,
+    255,   3,   0,   0, 255, 255, 127,   0, 128,   0,   0,   0, 224, 255, 255, 255,
+    224,  15,   0,   0, 248, 255, 255, 255,   1, 192,   0, 252,  63,   0,   0,   0,
+     15,   0,   0,   0,   0, 224,   0, 252, 255, 255, 255,  63,   0, 222,  99,   0,
+     63,  63, 255, 170, 255, 255, 223,  95, 220,  31, 207,  15, 255,  31, 220,  31,
+      0,   0,   2, 128,   0,   0, 255,  31, 132, 252,  47,  63,  80, 253, 255, 243,
+    224,  67,   0,   0, 255,   1,   0,   0, 255, 127, 255, 255,  31, 120,  12,   0,
+    255, 128,   0,   0, 127, 127, 127, 127, 224,   0,   0,   0, 254,   3,  62,  31,
+    255, 255, 127, 248, 255,  63, 254, 255, 255, 127,   0,   0, 255,  31, 255, 255,
+      0,  12,   0,   0, 255, 127,   0, 128,   0,   0, 128, 255, 252, 255, 255, 255,
+    255, 249, 255, 255, 255,  63, 255,   0, 187, 247, 255, 255,   7,   0,   0,   0,
+      0,   0, 252,  40,  63,   0, 255, 255, 255, 255, 255,  31, 255, 255,   7,   0,
+      0, 128,   0,   0, 223, 255,   0, 124, 247,  15,   0,   0, 255, 255, 127, 196,
+    255, 255,  98,  62,   5,   0,   0,  56, 255,   7,  28,   0, 126, 126, 126,   0,
+    127, 127, 255, 255,  15,   0, 255, 255, 127, 248, 255, 255, 255, 255, 255,  15,
+    255,  63, 255, 255, 255, 255, 255,   3, 127,   0, 248, 160, 255, 253, 127,  95,
+    219, 255, 255, 255,   0,   0, 248, 255, 255, 255, 252, 255,   0,   0, 255,  15,
+      0,   0, 223, 255, 192, 255, 255, 255, 252, 252, 252,  28, 255, 239, 255, 255,
+    127, 255, 255, 183, 255,  63, 255,  63, 255, 255,   1,   0, 255,   7, 255, 255,
+     15, 255,  62,   0, 255,   0, 255, 255,  63, 253, 255, 255, 255, 255, 191, 145,
+    255, 255,  55,   0, 255, 255, 255, 192,   1,   0, 239, 254,  31,   0,   0,   0,
+    255, 255,  71,   0,  30,   0,   0,  20, 255, 255, 251, 255, 255,  15,   0,   0,
+    127, 189, 255, 191, 255,   1, 255, 255,   0,   0,   1, 224, 176,   0,   0,   0,
+      0,   0,   0,  15,  16,   0,   0,   0,   0,   0,   0, 128, 255,  63,   0,   0,
+    248, 255, 255, 224,  31,   0,   1,   0, 255,   7, 255,  31, 255,   1, 255,   3,
+    255, 255, 223, 255, 255, 255, 255, 223, 100, 222, 255, 235, 239, 255, 255, 255,
+    191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,  63, 255, 255, 255,
+    253, 255, 255, 247, 255, 253, 255, 255, 150, 254, 247,  10, 132, 234, 150, 170,
+    150, 247, 247,  94, 255, 251, 255,  15, 238, 251, 255,  15,
+};
+
+/* ID_Start: 1997 bytes. */
+
+RE_UINT32 re_get_id_start(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_id_start_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_id_start_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_id_start_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_id_start_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_id_start_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* ID_Continue. */
+
+static RE_UINT8 re_id_continue_stage_1[] = {
+    0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6,
+    6, 6,
+};
+
+static RE_UINT8 re_id_continue_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 13, 13, 13, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 26, 13, 27, 13, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 28,  7, 29, 30,  7, 31, 13, 13, 13, 13, 13, 32,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    33, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_id_continue_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1, 17, 18, 19,  1, 20, 21, 22, 23, 24, 25, 26, 27,  1, 28,
+    29, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 31, 31,
+    34, 35, 31, 31,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 36,  1,  1,  1,  1,  1,  1,  1,  1,  1, 37,
+     1,  1,  1,  1, 38,  1, 39, 40, 41, 42, 43, 44,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1, 45, 31, 31, 31, 31, 31, 31, 31, 31,
+    31,  1, 46, 47,  1, 48, 49, 50, 51, 52, 53, 54, 55, 56,  1, 57,
+    58, 59, 60, 61, 62, 31, 31, 31, 63, 64, 65, 66, 67, 68, 69, 70,
+    71, 31, 72, 31, 31, 31, 31, 31,  1,  1,  1, 73, 74, 75, 31, 31,
+     1,  1,  1,  1, 76, 31, 31, 31, 31, 31, 31, 31,  1,  1, 77, 31,
+     1,  1, 78, 79, 31, 31, 31, 80, 81, 31, 31, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 82, 31, 31, 31, 31, 83, 84, 31, 85, 86, 87, 88,
+    31, 31, 89, 31, 31, 31, 31, 31, 90, 31, 31, 31, 31, 31, 91, 31,
+     1,  1,  1,  1,  1,  1, 92,  1,  1,  1,  1,  1,  1,  1,  1, 93,
+    94,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 95, 31,
+     1,  1, 96, 31, 31, 31, 31, 31, 31, 97, 31, 31, 31, 31, 31, 31,
+};
+
+static RE_UINT8 re_id_continue_stage_4[] = {
+      0,   1,   2,   3,   0,   4,   5,   5,   6,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6,   6,   7,   8,   6,   6,   6,   9,  10,  11,   6,  12,
+      6,   6,   6,   6,  13,   6,   6,   6,   6,  14,  15,  16,  17,  18,  19,  20,
+     21,   6,   6,  22,   6,   6,  23,  24,  25,   6,  26,   6,   6,  27,   6,  28,
+      6,  29,  30,   0,   0,  31,   0,  32,   6,   6,   6,  33,  34,  35,  36,  37,
+     38,  39,  40,  41,  42,  43,  44,  45,  46,  43,  47,  48,  49,  50,  51,  52,
+     53,  54,  55,  56,  57,  58,  59,  60,  57,  61,  62,  63,  64,  65,  66,  67,
+     16,  68,  69,   0,  70,  71,  72,   0,  73,  74,  75,  76,  77,  78,  79,   0,
+      6,   6,  80,   6,  81,   6,  82,  83,   6,   6,  84,   6,  85,  86,  87,   6,
+     88,   6,  61,  89,  90,   6,   6,  91,  16,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,  92,   3,   6,   6,  93,  94,  31,  95,  96,   6,   6,  97,  98,
+     99,   6,   6, 100,   6, 101,   6, 102, 103, 104, 105, 106,   6, 107, 108,   0,
+     30,   6, 103, 109, 110, 111,   0,   0,   6,   6, 112, 113,   6,   6,   6,  95,
+      6, 100, 114,  81,   0,   0, 115, 116,   6,   6,   6,   6,   6,   6,   6, 117,
+     91,   6, 118,  81,   6, 119, 120, 121,   0, 122, 123, 124, 125,   0, 125, 126,
+    127, 128, 129,   6, 130,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      6, 131, 103,   6,   6,   6,   6, 132,   6,  82,   6, 133, 134, 135, 135,   6,
+    136, 137,  16,   6, 138,  16,   6,  83, 139, 140,   6,   6, 141,  68,   0,  25,
+      6,   6,   6,   6,   6, 102,   0,   0,   6,   6,   6,   6,   6,   6, 102,   0,
+      6,   6,   6,   6, 142,   0,  25,  81, 143, 144,   6, 145,   6,   6,   6,  27,
+    146, 147,   6,   6, 148, 149,   0, 146,   6, 150,   6,  95,   6,   6, 151, 152,
+      6, 153,  95,  78,   6,   6, 154, 103,   6, 134, 155, 156,   6,   6, 157, 158,
+    159, 160,  83, 161,   6,   6,   6, 162,   6,   6,   6,   6,   6, 163, 164,  30,
+      6,   6,   6, 153,   6,   6, 165,   0, 166, 167, 168,   6,   6,  27, 169,   6,
+      6,  81,  25,   6, 170,   6, 150, 171,  90, 172, 173, 174,   6,   6,   6,  78,
+      1,   2,   3, 105,   6, 103, 175,   0, 176, 177, 178,   0,   6,   6,   6,  68,
+      0,   0,   6,  31,   0,   0,   0, 179,   0,   0,   0,   0,  78,   6, 180, 181,
+      6,  25, 101,  68,  81,   6, 182,   0,   6,   6,   6,   6,  81,  98,   0,   0,
+      6, 183,   6, 184,   0,   0,   0,   0,   6, 134, 102, 150,   0,   0,   0,   0,
+    185, 186, 102, 134, 103,   0,   0, 187, 102, 165,   0,   0,   6, 188,   0,   0,
+    189, 190,   0,  78,  78,   0,  75, 191,   6, 102, 102, 192,  27,   0,   0,   0,
+      6,   6, 130,   0,   6, 192,   6, 192,   6,   6, 191, 193,   6,  68,  25, 194,
+      6, 195,  25, 196,   6,   6, 197,   0, 198, 100,   0,   0, 199, 200,   6, 201,
+     34,  43, 202, 203,   0,   0,   0,   0,   0,   0,   0,   0,   6,   6, 204,   0,
+      0,   0,   0,   0,   6, 205, 206,   0,   6,   6, 207,   0,   6, 100,  98,   0,
+    208, 112,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   6,   6, 209,
+      0,   0,   0,   0,   0,   0,   6, 210,   6,   6,   6,   6, 165,   0,   0,   0,
+      6,   6,   6, 141,   6,   6,   6,   6,   6,   6, 184,   0,   0,   0,   0,   0,
+      6, 141,   0,   0,   0,   0,   0,   0,   6,   6, 191,   0,   0,   0,   0,   0,
+      6, 210, 103,  98,   0,   0,  25, 106,   6, 134, 211, 212,  90,   0,   0,   0,
+      6,   6, 213, 103, 214,   0,   0,   0, 215,   0,   0,   0,   0,   0,   0,   0,
+      6,   6,   6, 216, 217,   0,   0,   0,   0,   0,   0, 218, 219, 220,   0,   0,
+      0,   0, 221,   0,   0,   0,   0,   0,   6,   6, 195,   6, 222, 223, 224,   6,
+    225, 226, 227,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6, 228, 229,  83,
+    195, 195, 131, 131, 230, 230, 231,   6,   6, 232,   6, 233, 234, 235,   0,   0,
+      6,   6,   6,   6,   6,   6, 236,   0, 224, 237, 238, 239, 240, 241,   0,   0,
+      6,   6,   6,   6,   6,   6, 134,   0,   6,  31,   6,   6,   6,   6,   6,   6,
+     81,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6, 215,   0,   0,
+     81,   0,   0,   0,   0,   0,   0,   0,   6,   6,   6,   6,   6,   6,   6,  90,
+};
+
+static RE_UINT8 re_id_continue_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 254, 255, 255, 135, 254, 255, 255,   7,
+      0,   4, 160,   4, 255, 255, 127, 255, 255, 255, 255, 255, 195, 255,   3,   0,
+     31,  80,   0,   0, 255, 255, 223, 188, 192, 215, 255, 255, 251, 255, 255, 255,
+    255, 255, 191, 255, 251, 252, 255, 255, 255, 255, 254, 255, 255, 255, 127,   2,
+    254, 255, 255, 255, 255,   0, 254, 255, 255, 255, 255, 191, 182,   0, 255, 255,
+    255,   7,   7,   0,   0,   0, 255,   7, 255, 195, 255, 255, 255, 255, 239, 159,
+    255, 253, 255, 159,   0,   0, 255, 255, 255, 231, 255, 255, 255, 255,   3,   0,
+    255, 255,  63,   4, 255,  63,   0,   0, 255, 255, 255,  15, 255, 255,  31,   0,
+    248, 255, 255, 255, 207, 255, 254, 255, 239, 159, 249, 255, 255, 253, 197, 243,
+    159, 121, 128, 176, 207, 255,   3,   0, 238, 135, 249, 255, 255, 253, 109, 211,
+    135,  57,   2,  94, 192, 255,  63,   0, 238, 191, 251, 255, 255, 253, 237, 243,
+    191,  59,   1,   0, 207, 255,   0,   2, 238, 159, 249, 255, 159,  57, 192, 176,
+    207, 255,   2,   0, 236, 199,  61, 214,  24, 199, 255, 195, 199,  61, 129,   0,
+    192, 255,   0,   0, 239, 223, 253, 255, 255, 253, 255, 227, 223,  61,  96,   7,
+    207, 255,   0,   0, 238, 223, 253, 255, 255, 253, 239, 243, 223,  61,  96,  64,
+    207, 255,   6,   0, 255, 255, 255, 231, 223, 125, 128, 128, 207, 255,   0, 252,
+    236, 255, 127, 252, 255, 255, 251,  47, 127, 132,  95, 255, 192, 255,  12,   0,
+    255, 255, 255,   7, 255, 127, 255,   3, 150,  37, 240, 254, 174, 236, 255,  59,
+     95,  63, 255, 243,   1,   0,   0,   3, 255,   3, 160, 194, 255, 254, 255, 255,
+    255,  31, 254, 255, 223, 255, 255, 254, 255, 255, 255,  31,  64,   0,   0,   0,
+    255,   3, 255, 255, 255, 255, 255,  63, 191,  32, 255, 255, 255, 255, 255, 247,
+    255,  61, 127,  61, 255,  61, 255, 255, 255, 255,  61, 127,  61, 255, 127, 255,
+    255, 255,  61, 255,   0, 254,   3,   0, 255, 255,   0,   0, 255, 255,  63,  63,
+    255, 159, 255, 255, 255, 199, 255,   1, 255, 223,  31,   0, 255, 255,  15,   0,
+    255, 223,  13,   0, 255, 255, 143,  48, 255,   3,   0,   0,   0,  56, 255,   3,
+    255, 255, 255,   0, 255,   7, 255, 255, 255, 255,  63,   0, 255, 255, 255, 127,
+    255,  15, 255,  15, 192, 255, 255, 255, 255,  63,  31,   0, 255,  15, 255, 255,
+    255,   3, 255,   7, 255, 255, 255, 159, 255,   3, 255,   3, 128,   0, 255,  63,
+    255,  15, 255,   3,   0, 248,  15,   0, 255, 227, 255, 255,   0,   0, 247, 255,
+    255, 255, 127,   3, 255, 255,  63, 240,  63,  63, 255, 170, 255, 255, 223,  95,
+    220,  31, 207,  15, 255,  31, 220,  31,   0,   0,   0, 128,   1,   0,  16,   0,
+      0,   0,   2, 128,   0,   0, 255,  31, 226, 255,   1,   0, 132, 252,  47,  63,
+     80, 253, 255, 243, 224,  67,   0,   0, 255,   1,   0,   0, 255, 127, 255, 255,
+     31, 248,  15,   0, 255, 128,   0, 128, 255, 255, 127,   0, 127, 127, 127, 127,
+    224,   0,   0,   0, 254, 255,  62,  31, 255, 255, 127, 254, 224, 255, 255, 255,
+    255,  63, 254, 255, 255, 127,   0,   0, 255,  31,   0,   0, 255,  31, 255, 255,
+    255,  15,   0,   0, 255, 255, 240, 191,   0,   0, 128, 255, 252, 255, 255, 255,
+    255, 249, 255, 255, 255,  63, 255,   0, 255,   0,   0,   0,  31,   0, 255,   3,
+    255, 255, 255,  40, 255,  63, 255, 255,   1, 128, 255,   3, 255,  63, 255,   3,
+    255, 255, 127, 252,   7,   0,   0,  56, 255, 255, 124,   0, 126, 126, 126,   0,
+    127, 127, 255, 255,  63,   0, 255, 255, 255,  55, 255,   3,  15,   0, 255, 255,
+    127, 248, 255, 255, 255, 255, 255,   3, 127,   0, 248, 224, 255, 253, 127,  95,
+    219, 255, 255, 255,   0,   0, 248, 255, 255, 255, 252, 255,   0,   0, 255,  15,
+    255, 255,  24,   0,   0, 224,   0,   0,   0,   0, 223, 255, 252, 252, 252,  28,
+    255, 239, 255, 255, 127, 255, 255, 183, 255,  63, 255,  63,   0,   0,   0,  32,
+    255, 255,   1,   0,   1,   0,   0,   0,  15, 255,  62,   0, 255,   0, 255, 255,
+     15,   0,   0,   0,  63, 253, 255, 255, 255, 255, 191, 145, 255, 255,  55,   0,
+    255, 255, 255, 192, 111, 240, 239, 254, 255, 255,  15, 135, 127,   0,   0,   0,
+    255, 255,   7,   0, 192, 255,   0, 128, 255,   1, 255,   3, 255, 255, 223, 255,
+    255, 255,  79,   0,  31,  28, 255,  23, 255, 255, 251, 255, 127, 189, 255, 191,
+    255,   1, 255, 255, 255,   7, 255,   3, 159,  57, 129, 224, 207,  31,  31,   0,
+    191,   0, 255,   3, 255, 255,  63, 255,   1,   0,   0,  63,  17,   0, 255,   3,
+    255, 255, 255, 227, 255,   3,   0, 128, 255, 255, 255,   1,  15,   0, 255,   3,
+    248, 255, 255, 224,  31,   0, 255, 255,   0, 128, 255, 255,   3,   0,   0,   0,
+    255,   7, 255,  31, 255,   1, 255,  99, 224, 227,   7, 248, 231,  15,   0,   0,
+      0,  60,   0,   0,  28,   0,   0,   0, 255, 255, 255, 223, 100, 222, 255, 235,
+    239, 255, 255, 255, 191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,
+     63, 255, 255, 255, 253, 255, 255, 247, 255, 253, 255, 255, 247, 207, 255, 255,
+    255, 255, 127, 248, 255,  31,  32,   0,  16,   0,   0, 248, 254, 255,   0,   0,
+     31,   0, 127,   0, 150, 254, 247,  10, 132, 234, 150, 170, 150, 247, 247,  94,
+    255, 251, 255,  15, 238, 251, 255,  15,
+};
+
+/* ID_Continue: 2186 bytes. */
+
+RE_UINT32 re_get_id_continue(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_id_continue_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_id_continue_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_id_continue_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_id_continue_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_id_continue_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* XID_Start. */
+
+static RE_UINT8 re_xid_start_stage_1[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3,
+};
+
+static RE_UINT8 re_xid_start_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 13, 13, 13, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 13, 13, 26, 13, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 27,  7, 28, 29,  7, 30, 13, 13, 13, 13, 13, 31,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_xid_start_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1, 17, 18, 19,  1, 20, 21, 22, 23, 24, 25, 26, 27,  1, 28,
+    29, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 31, 31,
+    34, 35, 31, 31,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 36,  1,  1,  1,  1,  1,  1,  1,  1,  1, 37,
+     1,  1,  1,  1, 38,  1, 39, 40, 41, 42, 43, 44,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1, 45, 31, 31, 31, 31, 31, 31, 31, 31,
+    31,  1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,  1, 58,
+    59, 60, 61, 62, 63, 31, 31, 31, 64, 65, 66, 67, 68, 69, 70, 71,
+    72, 31, 73, 31, 31, 31, 31, 31,  1,  1,  1, 74, 75, 76, 31, 31,
+     1,  1,  1,  1, 77, 31, 31, 31, 31, 31, 31, 31,  1,  1, 78, 31,
+     1,  1, 79, 80, 31, 31, 31, 81, 82, 31, 31, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 83, 31, 31, 31, 31, 31, 31, 31, 84, 85, 86, 87,
+    88, 31, 31, 31, 31, 31, 89, 31,  1,  1,  1,  1,  1,  1, 90,  1,
+     1,  1,  1,  1,  1,  1,  1, 91, 92,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1, 93, 31,  1,  1, 94, 31, 31, 31, 31, 31,
+};
+
+static RE_UINT8 re_xid_start_stage_4[] = {
+      0,   0,   1,   1,   0,   2,   3,   3,   4,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   5,   6,   0,   0,   0,   7,   8,   9,   4,  10,
+      4,   4,   4,   4,  11,   4,   4,   4,   4,  12,  13,  14,  15,   0,  16,  17,
+      0,   4,  18,  19,   4,   4,  20,  21,  22,  23,  24,   4,   4,  25,  26,  27,
+     28,  29,  30,   0,   0,  31,   0,   0,  32,  33,  34,  35,  36,  37,  38,  39,
+     40,  41,  42,  43,  44,  45,  46,  47,  48,  45,  49,  50,  51,  52,  46,   0,
+     53,  54,  55,  56,  53,  57,  58,  59,  53,  60,  61,  62,  63,  64,  65,   0,
+     14,  66,  65,   0,  67,  68,  69,   0,  70,   0,  71,  72,  73,   0,   0,   0,
+      4,  74,  75,  76,  77,   4,  78,  79,   4,   4,  80,   4,  81,  82,  83,   4,
+     84,   4,  85,   0,  23,   4,   4,  86,  14,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,  87,   1,   4,   4,  88,  89,  90,  90,  91,   4,  92,  93,   0,
+      0,   4,   4,  94,   4,  95,   4,  96,  97,   0,  16,  98,   4,  99, 100,   0,
+    101,   4,  31,   0,   0, 102,   0,   0, 103,  92, 104,   0, 105, 106,   4, 107,
+      4, 108, 109, 110,   0,   0,   0, 111,   4,   4,   4,   4,   4,   4,   0,   0,
+     86,   4, 112, 110,   4, 113, 114, 115,   0,   0,   0, 116, 117,   0,   0,   0,
+    118, 119, 120,   4, 121,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      4, 122,  97,   4,   4,   4,   4, 123,   4,  78,   4, 124, 101, 125, 125,   0,
+    126, 127,  14,   4, 128,  14,   4,  79, 103, 129,   4,   4, 130,  85,   0,  16,
+      4,   4,   4,   4,   4,  96,   0,   0,   4,   4,   4,   4,   4,   4,  96,   0,
+      4,   4,   4,   4,  72,   0,  16, 110, 131, 132,   4, 133, 110,   4,   4,  23,
+    134, 135,   4,   4, 136, 137,   0, 134, 138, 139,   4,  92, 135,  92,   0, 140,
+     26, 141,  65, 142,  32, 143, 144, 145,   4, 121, 146, 147,   4, 148, 149, 150,
+    151, 152,  79, 141,   4,   4,   4, 139,   4,   4,   4,   4,   4, 153, 154, 155,
+      4,   4,   4, 156,   4,   4, 157,   0, 158, 159, 160,   4,   4,  90, 161,   4,
+      4,   4, 110,  32,   4,   4,   4,   4,   4, 110,  16,   4, 162,   4,  15, 163,
+      0,   0,   0, 164,   4,   4,   4, 142,   0,   1,   1, 165, 110,  97, 166,   0,
+    167, 168, 169,   0,   4,   4,   4,  85,   0,   0,   4,  31,   0,   0,   0,   0,
+      0,   0,   0,   0, 142,   4, 170,   0,   4,  16, 171,  96, 110,   4, 172,   0,
+      4,   4,   4,   4, 110,   0,   0,   0,   4, 173,   4, 108,   0,   0,   0,   0,
+      4, 101,  96,  15,   0,   0,   0,   0, 174, 175,  96, 101,  97,   0,   0, 176,
+     96, 157,   0,   0,   4, 177,   0,   0, 178,  92,   0, 142, 142,   0,  71, 179,
+      4,  96,  96, 143,  90,   0,   0,   0,   4,   4, 121,   0,   4, 143,   4, 143,
+    105,  94,   0,   0, 105,  23,  16, 121, 105,  65,  16, 180, 105, 143, 181,   0,
+    182, 183,   0,   0, 184, 185,  97,   0,  48,  45, 186,  56,   0,   0,   0,   0,
+      0,   0,   0,   0,   4,  23, 187,   0,   0,   0,   0,   0,   4, 130, 188,   0,
+      4,  23, 189,   0,   4,  18,   0,   0, 157,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   4,   4, 190,   0,   0,   0,   0,   0,   0,   4,  30,
+      4,   4,   4,   4, 157,   0,   0,   0,   4,   4,   4, 130,   4,   4,   4,   4,
+      4,   4, 108,   0,   0,   0,   0,   0,   4, 130,   0,   0,   0,   0,   0,   0,
+      4,   4,  65,   0,   0,   0,   0,   0,   4,  30,  97,   0,   0,   0,  16, 191,
+      4,  23, 108, 192,  23,   0,   0,   0,   4,   4, 193,   0, 161,   0,   0,   0,
+     56,   0,   0,   0,   0,   0,   0,   0,   4,   4,   4, 194, 195,   0,   0,   0,
+      4,   4, 196,   4, 197, 198, 199,   4, 200, 201, 202,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4, 203, 204,  79, 196, 196, 122, 122, 205, 205, 146,   0,
+      4,   4,   4,   4,   4,   4, 179,   0, 199, 206, 207, 208, 209, 210,   0,   0,
+      4,   4,   4,   4,   4,   4, 101,   0,   4,  31,   4,   4,   4,   4,   4,   4,
+    110,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,  56,   0,   0,
+    110,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_xid_start_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255,   7,   0,   4,  32,   4, 255, 255, 127, 255,
+    255, 255, 255, 255, 195, 255,   3,   0,  31,  80,   0,   0,   0,   0, 223, 184,
+     64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 191, 255,   3, 252, 255, 255,
+    255, 255, 254, 255, 255, 255, 127,   2, 254, 255, 255, 255, 255,   0,   0,   0,
+      0,   0, 255, 255, 255,   7,   7,   0, 255,   7,   0,   0,   0, 192, 254, 255,
+    255, 255,  47,   0,  96, 192,   0, 156,   0,   0, 253, 255, 255, 255,   0,   0,
+      0, 224, 255, 255,  63,   0,   2,   0,   0, 252, 255, 255, 255,   7,  48,   4,
+    255, 255,  63,   4,  16,   1,   0,   0, 255, 255, 255,   1, 255, 255,  31,   0,
+    240, 255, 255, 255, 255, 255, 255,  35,   0,   0,   1, 255,   3,   0, 254, 255,
+    225, 159, 249, 255, 255, 253, 197,  35,   0,  64,   0, 176,   3,   0,   3,   0,
+    224, 135, 249, 255, 255, 253, 109,   3,   0,   0,   0,  94,   0,   0,  28,   0,
+    224, 191, 251, 255, 255, 253, 237,  35,   0,   0,   1,   0,   3,   0,   0,   2,
+    224, 159, 249, 255,   0,   0,   0, 176,   3,   0,   2,   0, 232, 199,  61, 214,
+     24, 199, 255,   3, 224, 223, 253, 255, 255, 253, 255,  35,   0,   0,   0,   7,
+      3,   0,   0,   0, 255, 253, 239,  35,   0,   0,   0,  64,   3,   0,   6,   0,
+    255, 255, 255,  39,   0,  64,   0, 128,   3,   0,   0, 252, 224, 255, 127, 252,
+    255, 255, 251,  47, 127,   0,   0,   0, 255, 255,   5,   0, 150,  37, 240, 254,
+    174, 236,   5,  32,  95,   0,   0, 240,   1,   0,   0,   0, 255, 254, 255, 255,
+    255,  31,   0,   0,   0,  31,   0,   0, 255,   7,   0, 128,   0,   0,  63,  60,
+     98, 192, 225, 255,   3,  64,   0,   0, 191,  32, 255, 255, 255, 255, 255, 247,
+    255,  61, 127,  61, 255,  61, 255, 255, 255, 255,  61, 127,  61, 255, 127, 255,
+    255, 255,  61, 255, 255, 255, 255,   7, 255, 255,  63,  63, 255, 159, 255, 255,
+    255, 199, 255,   1, 255, 223,   3,   0, 255, 255,   3,   0, 255, 223,   1,   0,
+    255, 255,  15,   0,   0,   0, 128,  16, 255, 255, 255,   0, 255,   5, 255, 255,
+    255, 255,  63,   0, 255, 255, 255, 127, 255,  63,  31,   0, 255,  15, 255, 255,
+    255,   3,   0,   0, 255, 255, 127,   0, 128,   0,   0,   0, 224, 255, 255, 255,
+    224,  15,   0,   0, 248, 255, 255, 255,   1, 192,   0, 252,  63,   0,   0,   0,
+     15,   0,   0,   0,   0, 224,   0, 252, 255, 255, 255,  63,   0, 222,  99,   0,
+     63,  63, 255, 170, 255, 255, 223,  95, 220,  31, 207,  15, 255,  31, 220,  31,
+      0,   0,   2, 128,   0,   0, 255,  31, 132, 252,  47,  63,  80, 253, 255, 243,
+    224,  67,   0,   0, 255,   1,   0,   0, 255, 127, 255, 255,  31, 120,  12,   0,
+    255, 128,   0,   0, 127, 127, 127, 127, 224,   0,   0,   0, 254,   3,  62,  31,
+    255, 255, 127, 224, 255,  63, 254, 255, 255, 127,   0,   0, 255,  31, 255, 255,
+      0,  12,   0,   0, 255, 127,   0, 128,   0,   0, 128, 255, 252, 255, 255, 255,
+    255, 249, 255, 255, 255,  63, 255,   0, 187, 247, 255, 255,   7,   0,   0,   0,
+      0,   0, 252,  40,  63,   0, 255, 255, 255, 255, 255,  31, 255, 255,   7,   0,
+      0, 128,   0,   0, 223, 255,   0, 124, 247,  15,   0,   0, 255, 255, 127, 196,
+    255, 255,  98,  62,   5,   0,   0,  56, 255,   7,  28,   0, 126, 126, 126,   0,
+    127, 127, 255, 255,  15,   0, 255, 255, 127, 248, 255, 255, 255, 255, 255,  15,
+    255,  63, 255, 255, 255, 255, 255,   3, 127,   0, 248, 160, 255, 253, 127,  95,
+    219, 255, 255, 255,   0,   0, 248, 255, 255, 255, 252, 255,   0,   0, 255,   3,
+      0,   0, 138, 170, 192, 255, 255, 255, 252, 252, 252,  28, 255, 239, 255, 255,
+    127, 255, 255, 183, 255,  63, 255,  63, 255, 255,   1,   0, 255,   7, 255, 255,
+     15, 255,  62,   0, 255,   0, 255, 255,  63, 253, 255, 255, 255, 255, 191, 145,
+    255, 255,  55,   0, 255, 255, 255, 192,   1,   0, 239, 254,  31,   0,   0,   0,
+    255, 255,  71,   0,  30,   0,   0,  20, 255, 255, 251, 255, 255,  15,   0,   0,
+    127, 189, 255, 191, 255,   1, 255, 255,   0,   0,   1, 224, 176,   0,   0,   0,
+      0,   0,   0,  15,  16,   0,   0,   0,   0,   0,   0, 128, 255,  63,   0,   0,
+    248, 255, 255, 224,  31,   0,   1,   0, 255,   7, 255,  31, 255,   1, 255,   3,
+    255, 255, 223, 255, 255, 255, 255, 223, 100, 222, 255, 235, 239, 255, 255, 255,
+    191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,  63, 255, 255, 255,
+    253, 255, 255, 247, 255, 253, 255, 255, 150, 254, 247,  10, 132, 234, 150, 170,
+    150, 247, 247,  94, 255, 251, 255,  15, 238, 251, 255,  15,
+};
+
+/* XID_Start: 2005 bytes. */
+
+RE_UINT32 re_get_xid_start(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_xid_start_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_xid_start_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_xid_start_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_xid_start_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_xid_start_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* XID_Continue. */
+
+static RE_UINT8 re_xid_continue_stage_1[] = {
+    0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6,
+    6, 6,
+};
+
+static RE_UINT8 re_xid_continue_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 13, 13, 13, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 26, 13, 27, 13, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 28,  7, 29, 30,  7, 31, 13, 13, 13, 13, 13, 32,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    33, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_xid_continue_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1, 17, 18, 19,  1, 20, 21, 22, 23, 24, 25, 26, 27,  1, 28,
+    29, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 31, 31,
+    34, 35, 31, 31,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 36,  1,  1,  1,  1,  1,  1,  1,  1,  1, 37,
+     1,  1,  1,  1, 38,  1, 39, 40, 41, 42, 43, 44,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1, 45, 31, 31, 31, 31, 31, 31, 31, 31,
+    31,  1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,  1, 58,
+    59, 60, 61, 62, 63, 31, 31, 31, 64, 65, 66, 67, 68, 69, 70, 71,
+    72, 31, 73, 31, 31, 31, 31, 31,  1,  1,  1, 74, 75, 76, 31, 31,
+     1,  1,  1,  1, 77, 31, 31, 31, 31, 31, 31, 31,  1,  1, 78, 31,
+     1,  1, 79, 80, 31, 31, 31, 81, 82, 31, 31, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 83, 31, 31, 31, 31, 84, 85, 31, 86, 87, 88, 89,
+    31, 31, 90, 31, 31, 31, 31, 31, 91, 31, 31, 31, 31, 31, 92, 31,
+     1,  1,  1,  1,  1,  1, 93,  1,  1,  1,  1,  1,  1,  1,  1, 94,
+    95,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 96, 31,
+     1,  1, 97, 31, 31, 31, 31, 31, 31, 98, 31, 31, 31, 31, 31, 31,
+};
+
+static RE_UINT8 re_xid_continue_stage_4[] = {
+      0,   1,   2,   3,   0,   4,   5,   5,   6,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6,   6,   7,   8,   6,   6,   6,   9,  10,  11,   6,  12,
+      6,   6,   6,   6,  13,   6,   6,   6,   6,  14,  15,  16,  17,  18,  19,  20,
+     21,   6,   6,  22,   6,   6,  23,  24,  25,   6,  26,   6,   6,  27,   6,  28,
+      6,  29,  30,   0,   0,  31,   0,  32,   6,   6,   6,  33,  34,  35,  36,  37,
+     38,  39,  40,  41,  42,  43,  44,  45,  46,  43,  47,  48,  49,  50,  51,  52,
+     53,  54,  55,  56,  57,  58,  59,  60,  57,  61,  62,  63,  64,  65,  66,  67,
+     16,  68,  69,   0,  70,  71,  72,   0,  73,  74,  75,  76,  77,  78,  79,   0,
+      6,   6,  80,   6,  81,   6,  82,  83,   6,   6,  84,   6,  85,  86,  87,   6,
+     88,   6,  61,  89,  90,   6,   6,  91,  16,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,  92,   3,   6,   6,  93,  94,  31,  95,  96,   6,   6,  97,  98,
+     99,   6,   6, 100,   6, 101,   6, 102, 103, 104, 105, 106,   6, 107, 108,   0,
+     30,   6, 103, 109, 110, 111,   0,   0,   6,   6, 112, 113,   6,   6,   6,  95,
+      6, 100, 114,  81,   0,   0, 115, 116,   6,   6,   6,   6,   6,   6,   6, 117,
+     91,   6, 118,  81,   6, 119, 120, 121,   0, 122, 123, 124, 125,   0, 125, 126,
+    127, 128, 129,   6, 130,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      6, 131, 103,   6,   6,   6,   6, 132,   6,  82,   6, 133, 134, 135, 135,   6,
+    136, 137,  16,   6, 138,  16,   6,  83, 139, 140,   6,   6, 141,  68,   0,  25,
+      6,   6,   6,   6,   6, 102,   0,   0,   6,   6,   6,   6,   6,   6, 102,   0,
+      6,   6,   6,   6, 142,   0,  25,  81, 143, 144,   6, 145,   6,   6,   6,  27,
+    146, 147,   6,   6, 148, 149,   0, 146,   6, 150,   6,  95,   6,   6, 151, 152,
+      6, 153,  95,  78,   6,   6, 154, 103,   6, 134, 155, 156,   6,   6, 157, 158,
+    159, 160,  83, 161,   6,   6,   6, 162,   6,   6,   6,   6,   6, 163, 164,  30,
+      6,   6,   6, 153,   6,   6, 165,   0, 166, 167, 168,   6,   6,  27, 169,   6,
+      6,   6,  81, 170,   6,   6,   6,   6,   6,  81,  25,   6, 171,   6, 150,   1,
+     90, 172, 173, 174,   6,   6,   6,  78,   1,   2,   3, 105,   6, 103, 175,   0,
+    176, 177, 178,   0,   6,   6,   6,  68,   0,   0,   6,  31,   0,   0,   0, 179,
+      0,   0,   0,   0,  78,   6, 180, 181,   6,  25, 101,  68,  81,   6, 182,   0,
+      6,   6,   6,   6,  81,  98,   0,   0,   6, 183,   6, 184,   0,   0,   0,   0,
+      6, 134, 102, 150,   0,   0,   0,   0, 185, 186, 102, 134, 103,   0,   0, 187,
+    102, 165,   0,   0,   6, 188,   0,   0, 189, 190,   0,  78,  78,   0,  75, 191,
+      6, 102, 102, 192,  27,   0,   0,   0,   6,   6, 130,   0,   6, 192,   6, 192,
+      6,   6, 191, 193,   6,  68,  25, 194,   6, 195,  25, 196,   6,   6, 197,   0,
+    198, 100,   0,   0, 199, 200,   6, 201,  34,  43, 202, 203,   0,   0,   0,   0,
+      0,   0,   0,   0,   6,   6, 204,   0,   0,   0,   0,   0,   6, 205, 206,   0,
+      6,   6, 207,   0,   6, 100,  98,   0, 208, 112,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   6,   6, 209,   0,   0,   0,   0,   0,   0,   6, 210,
+      6,   6,   6,   6, 165,   0,   0,   0,   6,   6,   6, 141,   6,   6,   6,   6,
+      6,   6, 184,   0,   0,   0,   0,   0,   6, 141,   0,   0,   0,   0,   0,   0,
+      6,   6, 191,   0,   0,   0,   0,   0,   6, 210, 103,  98,   0,   0,  25, 106,
+      6, 134, 211, 212,  90,   0,   0,   0,   6,   6, 213, 103, 214,   0,   0,   0,
+    215,   0,   0,   0,   0,   0,   0,   0,   6,   6,   6, 216, 217,   0,   0,   0,
+      0,   0,   0, 218, 219, 220,   0,   0,   0,   0, 221,   0,   0,   0,   0,   0,
+      6,   6, 195,   6, 222, 223, 224,   6, 225, 226, 227,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6, 228, 229,  83, 195, 195, 131, 131, 230, 230, 231,   6,
+      6, 232,   6, 233, 234, 235,   0,   0,   6,   6,   6,   6,   6,   6, 236,   0,
+    224, 237, 238, 239, 240, 241,   0,   0,   6,   6,   6,   6,   6,   6, 134,   0,
+      6,  31,   6,   6,   6,   6,   6,   6,  81,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6, 215,   0,   0,  81,   0,   0,   0,   0,   0,   0,   0,
+      6,   6,   6,   6,   6,   6,   6,  90,
+};
+
+static RE_UINT8 re_xid_continue_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 254, 255, 255, 135, 254, 255, 255,   7,
+      0,   4, 160,   4, 255, 255, 127, 255, 255, 255, 255, 255, 195, 255,   3,   0,
+     31,  80,   0,   0, 255, 255, 223, 184, 192, 215, 255, 255, 251, 255, 255, 255,
+    255, 255, 191, 255, 251, 252, 255, 255, 255, 255, 254, 255, 255, 255, 127,   2,
+    254, 255, 255, 255, 255,   0, 254, 255, 255, 255, 255, 191, 182,   0, 255, 255,
+    255,   7,   7,   0,   0,   0, 255,   7, 255, 195, 255, 255, 255, 255, 239, 159,
+    255, 253, 255, 159,   0,   0, 255, 255, 255, 231, 255, 255, 255, 255,   3,   0,
+    255, 255,  63,   4, 255,  63,   0,   0, 255, 255, 255,  15, 255, 255,  31,   0,
+    248, 255, 255, 255, 207, 255, 254, 255, 239, 159, 249, 255, 255, 253, 197, 243,
+    159, 121, 128, 176, 207, 255,   3,   0, 238, 135, 249, 255, 255, 253, 109, 211,
+    135,  57,   2,  94, 192, 255,  63,   0, 238, 191, 251, 255, 255, 253, 237, 243,
+    191,  59,   1,   0, 207, 255,   0,   2, 238, 159, 249, 255, 159,  57, 192, 176,
+    207, 255,   2,   0, 236, 199,  61, 214,  24, 199, 255, 195, 199,  61, 129,   0,
+    192, 255,   0,   0, 239, 223, 253, 255, 255, 253, 255, 227, 223,  61,  96,   7,
+    207, 255,   0,   0, 238, 223, 253, 255, 255, 253, 239, 243, 223,  61,  96,  64,
+    207, 255,   6,   0, 255, 255, 255, 231, 223, 125, 128, 128, 207, 255,   0, 252,
+    236, 255, 127, 252, 255, 255, 251,  47, 127, 132,  95, 255, 192, 255,  12,   0,
+    255, 255, 255,   7, 255, 127, 255,   3, 150,  37, 240, 254, 174, 236, 255,  59,
+     95,  63, 255, 243,   1,   0,   0,   3, 255,   3, 160, 194, 255, 254, 255, 255,
+    255,  31, 254, 255, 223, 255, 255, 254, 255, 255, 255,  31,  64,   0,   0,   0,
+    255,   3, 255, 255, 255, 255, 255,  63, 191,  32, 255, 255, 255, 255, 255, 247,
+    255,  61, 127,  61, 255,  61, 255, 255, 255, 255,  61, 127,  61, 255, 127, 255,
+    255, 255,  61, 255,   0, 254,   3,   0, 255, 255,   0,   0, 255, 255,  63,  63,
+    255, 159, 255, 255, 255, 199, 255,   1, 255, 223,  31,   0, 255, 255,  15,   0,
+    255, 223,  13,   0, 255, 255, 143,  48, 255,   3,   0,   0,   0,  56, 255,   3,
+    255, 255, 255,   0, 255,   7, 255, 255, 255, 255,  63,   0, 255, 255, 255, 127,
+    255,  15, 255,  15, 192, 255, 255, 255, 255,  63,  31,   0, 255,  15, 255, 255,
+    255,   3, 255,   7, 255, 255, 255, 159, 255,   3, 255,   3, 128,   0, 255,  63,
+    255,  15, 255,   3,   0, 248,  15,   0, 255, 227, 255, 255,   0,   0, 247, 255,
+    255, 255, 127,   3, 255, 255,  63, 240,  63,  63, 255, 170, 255, 255, 223,  95,
+    220,  31, 207,  15, 255,  31, 220,  31,   0,   0,   0, 128,   1,   0,  16,   0,
+      0,   0,   2, 128,   0,   0, 255,  31, 226, 255,   1,   0, 132, 252,  47,  63,
+     80, 253, 255, 243, 224,  67,   0,   0, 255,   1,   0,   0, 255, 127, 255, 255,
+     31, 248,  15,   0, 255, 128,   0, 128, 255, 255, 127,   0, 127, 127, 127, 127,
+    224,   0,   0,   0, 254, 255,  62,  31, 255, 255, 127, 230, 224, 255, 255, 255,
+    255,  63, 254, 255, 255, 127,   0,   0, 255,  31,   0,   0, 255,  31, 255, 255,
+    255,  15,   0,   0, 255, 255, 240, 191,   0,   0, 128, 255, 252, 255, 255, 255,
+    255, 249, 255, 255, 255,  63, 255,   0, 255,   0,   0,   0,  31,   0, 255,   3,
+    255, 255, 255,  40, 255,  63, 255, 255,   1, 128, 255,   3, 255,  63, 255,   3,
+    255, 255, 127, 252,   7,   0,   0,  56, 255, 255, 124,   0, 126, 126, 126,   0,
+    127, 127, 255, 255,  63,   0, 255, 255, 255,  55, 255,   3,  15,   0, 255, 255,
+    127, 248, 255, 255, 255, 255, 255,   3, 127,   0, 248, 224, 255, 253, 127,  95,
+    219, 255, 255, 255,   0,   0, 248, 255, 240, 255, 255, 255, 255, 255, 252, 255,
+    255, 255,  24,   0,   0, 224,   0,   0,   0,   0, 138, 170, 252, 252, 252,  28,
+    255, 239, 255, 255, 127, 255, 255, 183, 255,  63, 255,  63,   0,   0,   0,  32,
+    255, 255,   1,   0,   1,   0,   0,   0,  15, 255,  62,   0, 255,   0, 255, 255,
+     15,   0,   0,   0,  63, 253, 255, 255, 255, 255, 191, 145, 255, 255,  55,   0,
+    255, 255, 255, 192, 111, 240, 239, 254, 255, 255,  15, 135, 127,   0,   0,   0,
+    255, 255,   7,   0, 192, 255,   0, 128, 255,   1, 255,   3, 255, 255, 223, 255,
+    255, 255,  79,   0,  31,  28, 255,  23, 255, 255, 251, 255, 127, 189, 255, 191,
+    255,   1, 255, 255, 255,   7, 255,   3, 159,  57, 129, 224, 207,  31,  31,   0,
+    191,   0, 255,   3, 255, 255,  63, 255,   1,   0,   0,  63,  17,   0, 255,   3,
+    255, 255, 255, 227, 255,   3,   0, 128, 255, 255, 255,   1,  15,   0, 255,   3,
+    248, 255, 255, 224,  31,   0, 255, 255,   0, 128, 255, 255,   3,   0,   0,   0,
+    255,   7, 255,  31, 255,   1, 255,  99, 224, 227,   7, 248, 231,  15,   0,   0,
+      0,  60,   0,   0,  28,   0,   0,   0, 255, 255, 255, 223, 100, 222, 255, 235,
+    239, 255, 255, 255, 191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,
+     63, 255, 255, 255, 253, 255, 255, 247, 255, 253, 255, 255, 247, 207, 255, 255,
+    255, 255, 127, 248, 255,  31,  32,   0,  16,   0,   0, 248, 254, 255,   0,   0,
+     31,   0, 127,   0, 150, 254, 247,  10, 132, 234, 150, 170, 150, 247, 247,  94,
+    255, 251, 255,  15, 238, 251, 255,  15,
+};
+
+/* XID_Continue: 2194 bytes. */
+
+RE_UINT32 re_get_xid_continue(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_xid_continue_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_xid_continue_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_xid_continue_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_xid_continue_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_xid_continue_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Default_Ignorable_Code_Point. */
+
+static RE_UINT8 re_default_ignorable_code_point_stage_1[] = {
+    0, 1, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2,
+    2, 2,
+};
+
+static RE_UINT8 re_default_ignorable_code_point_stage_2[] = {
+    0, 1, 2, 3, 4, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 7, 1, 1, 8, 1, 1, 1, 1, 1,
+    9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_default_ignorable_code_point_stage_3[] = {
+     0,  1,  1,  2,  1,  1,  3,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  4,  1,  1,  1,  1,  1,  5,  6,  1,  1,  1,  1,  1,  1,  1,
+     7,  1,  1,  1,  1,  1,  1,  1,  1,  8,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  9, 10,  1,  1,  1,  1, 11,  1,  1,  1,
+     1, 12,  1,  1,  1,  1,  1,  1, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_default_ignorable_code_point_stage_4[] = {
+     0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  2,  0,  0,  0,  0,  0,  3,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  4,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,  0,
+     7,  0,  0,  0,  0,  0,  0,  0,  8,  9,  0, 10,  0,  0,  0,  0,
+     0,  0,  0, 11,  0,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0,  4,
+     0,  0,  0,  0,  0,  5,  0, 12,  0,  0,  0,  0,  0, 13,  0,  0,
+     0,  0,  0, 14,  0,  0,  0,  0, 15, 15, 15, 15, 15, 15, 15, 15,
+};
+
+static RE_UINT8 re_default_ignorable_code_point_stage_5[] = {
+      0,   0,   0,   0,   0,  32,   0,   0,   0, 128,   0,   0,   0,   0,   0,  16,
+      0,   0,   0, 128,   1,   0,   0,   0,   0,   0,  48,   0,   0, 120,   0,   0,
+      0, 248,   0,   0,   0, 124,   0,   0, 255, 255,   0,   0,  16,   0,   0,   0,
+      0,   0, 255,   1,  15,   0,   0,   0,   0,   0, 248,   7, 255, 255, 255, 255,
+};
+
+/* Default_Ignorable_Code_Point: 370 bytes. */
+
+RE_UINT32 re_get_default_ignorable_code_point(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_default_ignorable_code_point_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_default_ignorable_code_point_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_default_ignorable_code_point_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_default_ignorable_code_point_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_default_ignorable_code_point_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Grapheme_Extend. */
+
+static RE_UINT8 re_grapheme_extend_stage_1[] = {
+    0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4,
+    4, 4,
+};
+
+static RE_UINT8 re_grapheme_extend_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  8,  9,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10,
+    11, 12, 13,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 14,  7,  7,
+     7,  7,  7,  7,  7,  7,  7, 15,  7,  7, 16, 17,  7, 18,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    19,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+};
+
+static RE_UINT8 re_grapheme_extend_stage_3[] = {
+     0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,
+    14,  0,  0, 15,  0,  0,  0, 16, 17, 18, 19, 20, 21, 22,  0,  0,
+    23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 24, 25,  0,  0,
+    26,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 27,  0, 28, 29, 30, 31,  0,  0,  0,  0,
+     0,  0,  0, 32,  0,  0, 33, 34,  0, 35, 36, 37,  0,  0,  0,  0,
+     0,  0, 38,  0,  0,  0,  0,  0, 39, 40, 41, 42, 43, 44, 45, 46,
+     0,  0, 47, 48,  0,  0,  0, 49,  0,  0,  0,  0, 50,  0,  0,  0,
+     0, 51, 52,  0,  0,  0,  0,  0,  0,  0, 53,  0,  0,  0,  0,  0,
+    54,  0,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_grapheme_extend_stage_4[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   2,   0,   0,   0,   0,
+      0,   0,   0,   0,   3,   0,   0,   0,   0,   0,   0,   0,   4,   5,   6,   0,
+      7,   0,   8,   9,   0,   0,  10,  11,  12,  13,  14,   0,   0,  15,   0,  16,
+     17,  18,  19,   0,   0,   0,   0,  20,  21,  22,  23,  24,  25,  26,  27,  24,
+     28,  29,  30,  31,  28,  29,  32,  24,  25,  33,  34,  24,  35,  36,  37,   0,
+     38,  39,  40,  24,  25,  41,  42,  24,  25,  36,  27,  24,   0,   0,  43,   0,
+      0,  44,  45,   0,   0,  46,  47,   0,  48,  49,   0,  50,  51,  52,  53,   0,
+      0,  54,  55,  56,  57,   0,   0,   0,   0,   0,  58,   0,   0,   0,   0,   0,
+     59,  59,  60,  60,   0,  61,  62,   0,  63,   0,   0,   0,   0,  64,   0,   0,
+      0,  65,   0,   0,   0,   0,   0,   0,  66,   0,  67,  68,   0,  69,   0,   0,
+     70,  71,  35,  16,  72,  73,   0,  74,   0,  75,   0,   0,   0,   0,  76,  77,
+      0,   0,   0,   0,   0,   0,   1,  78,  79,   0,   0,   0,   0,   0,  13,  80,
+      0,   0,   0,   0,   0,   0,   0,  81,   0,   0,   0,  82,   0,   0,   0,   1,
+      0,  83,   0,   0,  84,   0,   0,   0,   0,   0,   0,  85,  39,   0,   0,  86,
+     87,  88,   0,   0,   0,   0,  89,  90,   0,  91,  92,   0,  21,  93,   0,  94,
+      0,  95,  96,  29,   0,  97,  25,  98,   0,   0,   0,   0,   0,   0,   0,  99,
+     36,   0,   0,   0,   0,   0,   0,   0,   2,   2,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  39,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 100,
+      0,   0,   0,   0,   0,   0,   0,  38,   0,   0,   0, 101,   0,   0,   0,   0,
+    102, 103,   0,   0,   0,   0,   0,  88,  25, 104, 105,  82,  72, 106,   0,   0,
+     21, 107,   0, 108,  72, 109, 110,   0,   0, 111,   0,   0,   0,   0,  82, 112,
+     72,  26, 113, 114,   0,   0,   0,   0,   0,   0,   0,   0,   0, 115, 116,   0,
+      0,   0,   0,   0,   0, 117, 118,   0,   0, 119,  38,   0,   0, 120,   0,   0,
+     58, 121,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 122,
+      0, 123,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 124,   0,   0,   0,
+      0,   0,   0,   0, 125,   0,   0,   0,   0,   0,   0, 126, 127, 128,   0,   0,
+      0,   0, 129,   0,   0,   0,   0,   0,   1, 130,   1, 131, 132, 133,   0,   0,
+      0,   0,   0,   0,   0,   0, 123,   0,   1,   1,   1,   1,   1,   1,   1,   2,
+};
+
+static RE_UINT8 re_grapheme_extend_stage_5[] = {
+      0,   0,   0,   0, 255, 255, 255, 255, 255, 255,   0,   0, 248,   3,   0,   0,
+      0,   0, 254, 255, 255, 255, 255, 191, 182,   0,   0,   0,   0,   0, 255,   7,
+      0, 248, 255, 255,   0,   0,   1,   0,   0,   0, 192, 159, 159,  61,   0,   0,
+      0,   0,   2,   0,   0,   0, 255, 255, 255,   7,   0,   0, 192, 255,   1,   0,
+      0, 248,  15,   0,   0,   0, 192, 251, 239,  62,   0,   0,   0,   0,   0,  14,
+    248, 255, 255, 255,   7,   0,   0,   0,   0,   0,   0,  20, 254,  33, 254,   0,
+     12,   0,   0,   0,   2,   0,   0,   0,   0,   0,   0,  80,  30,  32, 128,   0,
+      6,   0,   0,   0,   0,   0,   0,  16, 134,  57,   2,   0,   0,   0,  35,   0,
+    190,  33,   0,   0,   0,   0,   0, 208,  30,  32, 192,   0,   4,   0,   0,   0,
+      0,   0,   0,  64,   1,  32, 128,   0,   1,   0,   0,   0,   0,   0,   0, 192,
+    193,  61,  96,   0,   0,   0,   0, 144,  68,  48,  96,   0,   0, 132,  92, 128,
+      0,   0, 242,   7, 128, 127,   0,   0,   0,   0, 242,  27,   0,  63,   0,   0,
+      0,   0,   0,   3,   0,   0, 160,   2,   0,   0, 254, 127, 223, 224, 255, 254,
+    255, 255, 255,  31,  64,   0,   0,   0,   0, 224, 253, 102,   0,   0,   0, 195,
+      1,   0,  30,   0, 100,  32,   0,  32,   0,   0,   0, 224,   0,   0,  28,   0,
+      0,   0,  12,   0,   0,   0, 176,  63,  64, 254,  15,  32,   0,  56,   0,   0,
+      0,   2,   0,   0, 135,   1,   4,  14,   0,   0, 128,   9,   0,   0,  64, 127,
+    229,  31, 248, 159,   0,   0, 255, 127,  15,   0,   0,   0,   0,   0, 208,  23,
+      3,   0,   0,   0,  60,  59,   0,   0,  64, 163,   3,   0,   0, 240, 207,   0,
+      0,   0, 247, 255, 253,  33,  16,   3, 255, 255,  63, 240,   0,  48,   0,   0,
+    255, 255,   1,   0,   0, 128,   3,   0,   0,   0,   0, 128,   0, 252,   0,   0,
+      0,   0,   0,   6,   0, 128, 247,  63,   0,   0,   3,   0,  68,   8,   0,   0,
+     96,   0,   0,   0,  16,   0,   0,   0, 255, 255,   3,   0, 192,  63,   0,   0,
+    128, 255,   3,   0,   0,   0, 200,  19,  32,   0,   0,   0,   0, 126, 102,   0,
+      8,  16,   0,   0,   0,   0, 157, 193,   0,  48,  64,   0,  32,  33,   0,   0,
+      0,   0,   0,  32,   0,   0, 192,   7, 110, 240,   0,   0,   0,   0,   0, 135,
+      0,   0,   0, 255, 127,   0,   0,   0,   0,   0, 120,   6, 128, 239,  31,   0,
+      0,   0,   8,   0,   0,   0, 192, 127,   0,  28,   0,   0,   0, 128, 211,   0,
+    248,   7,   0,   0,   1,   0, 128,   0, 192,  31,  31,   0,   0,   0, 249, 165,
+     13,   0,   0,   0,   0, 128,  60, 176,   1,   0,   0,  48,   0,   0, 248, 167,
+      0,  40, 191,   0, 188,  15,   0,   0,   0,   0,  31,   0,   0,   0, 127,   0,
+      0, 128,   7,   0,   0,   0,   0,  96, 160, 195,   7, 248, 231,  15,   0,   0,
+      0,  60,   0,   0,  28,   0,   0,   0, 255, 255, 127, 248, 255,  31,  32,   0,
+     16,   0,   0, 248, 254, 255,   0,   0,
+};
+
+/* Grapheme_Extend: 1274 bytes. */
+
+RE_UINT32 re_get_grapheme_extend(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_grapheme_extend_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_grapheme_extend_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_grapheme_extend_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_grapheme_extend_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_grapheme_extend_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Grapheme_Base. */
+
+static RE_UINT8 re_grapheme_base_stage_1[] = {
+    0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6,
+};
+
+static RE_UINT8 re_grapheme_base_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 13, 13,
+    13, 13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 15, 13, 16, 17, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 21,
+    22, 23, 24, 25, 26, 27, 28, 19, 29, 30, 19, 19, 13, 31, 19, 19,
+    19, 32, 19, 19, 19, 19, 19, 19, 19, 19, 33, 34, 19, 19, 19, 19,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 35, 19, 19, 36,
+    19, 19, 19, 19, 37, 38, 39, 19, 19, 19, 40, 41, 42, 43, 44, 19,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 45, 13, 13, 13, 46, 47, 13,
+    13, 13, 13, 48, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 49, 19,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+};
+
+static RE_UINT8 re_grapheme_base_stage_3[] = {
+      0,   1,   2,   2,   2,   2,   3,   4,   2,   5,   6,   7,   8,   9,  10,  11,
+     12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
+     28,  29,   2,   2,  30,  31,  32,  33,   2,   2,   2,   2,   2,  34,  35,  36,
+     37,  38,  39,  40,  41,  42,  43,  44,  45,  46,   2,  47,   2,   2,  48,  49,
+     50,  51,   2,  52,   2,   2,   2,  53,  54,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,  55,  56,  57,  58,  59,  60,  61,  62,   2,  63,
+     64,  65,  66,  67,  68,  69,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,  70,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,  71,
+      2,  72,   2,   2,  73,  74,   2,  75,  76,  77,  78,  79,  80,  81,  82,  83,
+      2,   2,   2,   2,   2,   2,   2,  84,  85,  85,  85,  85,  85,  85,  85,  85,
+     85,  85,   2,   2,  86,  87,  88,  89,   2,   2,  90,  91,  92,  93,  94,  95,
+     96,  53,  97,  98,  85,  99, 100, 101,   2, 102, 103,  85,   2,   2, 104,  85,
+    105, 106, 107, 108, 109, 110, 111, 112, 113, 114,  85,  85, 115,  85,  85,  85,
+    116, 117, 118, 119, 120, 121, 122,  85,  85, 123,  85, 124, 125, 126, 127,  85,
+     85, 128,  85,  85,  85, 129,  85,  85,   2,   2,   2,   2,   2,   2,   2, 130,
+    131,   2, 132,  85,  85,  85,  85,  85, 133,  85,  85,  85,  85,  85,  85,  85,
+      2,   2,   2,   2, 134,  85,  85,  85,   2,   2,   2,   2, 135, 136, 137, 138,
+     85,  85,  85,  85,  85,  85, 139, 140, 141,  85,  85,  85,  85,  85,  85,  85,
+    142, 143,  85,  85,  85,  85,  85,  85,   2, 144, 145, 146, 147,  85, 148,  85,
+    149, 150, 151,   2,   2, 152,   2, 153,   2,   2,   2,   2, 154, 155,  85,  85,
+      2, 156,  85,  85,  85,  85,  85,  85,  85,  85,  85,  85, 157, 158,  85,  85,
+    159, 160, 161, 162, 163,  85,   2,   2,   2,   2, 164, 165,   2, 166, 167, 168,
+    169, 170, 171, 172,  85,  85,  85,  85,   2,   2,   2,   2,   2, 173,   2,   2,
+      2,   2,   2,   2,   2,   2, 174,   2, 175,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2, 176,  85,  85,   2,   2,   2,   2, 177,  85,  85,  85,
+};
+
+static RE_UINT8 re_grapheme_base_stage_4[] = {
+      0,   0,   1,   1,   1,   1,   1,   2,   0,   0,   3,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,   0,   0,   0,   0,   0,   0,   0,   4,
+      5,   1,   6,   1,   1,   1,   1,   1,   7,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   8,   1,   9,   8,   1,  10,   0,   0,  11,  12,   1,  13,  14,
+     15,  16,   1,   1,  13,   0,   1,   8,   1,   1,   1,   1,   1,  17,  18,   1,
+     19,  20,   1,   0,  21,   1,   1,   1,   1,   1,  22,  23,   1,   1,  13,  24,
+      1,  25,  26,   2,   1,  27,   0,   0,   0,   0,   1,  14,   0,   0,   0,   0,
+     28,   1,   1,  29,  30,  31,  32,   1,  33,  34,  35,  36,  37,  38,  39,  40,
+     41,  34,  35,  42,  43,  44,  15,  45,  46,   6,  35,  47,  48,  43,  39,  49,
+     50,  34,  35,  51,  52,  38,  39,  53,  54,  55,  56,  57,  58,  43,  15,  13,
+     59,  20,  35,  60,  61,  62,  39,  63,  64,  20,  35,  65,  66,  11,  39,  67,
+     64,  20,   1,  68,  69,  70,  39,  71,  72,  73,   1,  74,  75,  76,  15,  45,
+      8,   1,   1,  77,  78,  40,   0,   0,  79,  80,  81,  82,  83,  84,   0,   0,
+      1,   4,   1,  85,  86,   1,  87,  70,  88,   0,   0,  89,  90,  13,   0,   0,
+      1,   1,  87,  91,   1,  92,   8,  93,  94,   3,   1,   1,  95,   1,   1,   1,
+      1,   1,   1,   1,  96,  97,   1,   1,  96,   1,   1,  98,  99, 100,   1,   1,
+      1,  99,   1,   1,   1,  13,   1,  87,   1, 101,   1,   1,   1,   1,   1, 102,
+      1,  87,   1,   1,   1,   1,   1, 103,   3, 104,   1, 105,   1, 104,   3,  43,
+      1,   1,   1, 106, 107, 108, 101, 101,  13, 101,   1,   1,   1,   1,   1,  53,
+      1,   1, 109,   1,   1,   1,   1,  22,   1,   2, 110, 111, 112,   1,  19,  14,
+      1,   1,  40,   1, 101, 113,   1,   1,   1, 114,   1,   1,   1, 115, 116, 117,
+    101, 101,  19,   0,   0,   0,   0,   0, 118,   1,   1, 119, 120,   1,  13, 108,
+    121,   1, 122,   1,   1,   1, 123, 124,   1,   1,  40, 125, 126,   1,   1,   1,
+      0,   0,   0,   0,  53, 127, 128, 129,   1,   1,   1,   1,   0,   0,   0,   0,
+      1, 102,   1,   1, 102, 130,   1,  19,   1,   1,   1, 131, 131, 132,   1, 133,
+     13,   1, 134,   1,   1,   1,   0,  32,   2,  87,   1,   2,   0,   0,   0,   0,
+     40,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,  13,
+      1,   1,  75,   0,  13,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1, 135,
+      1, 136,   1, 126,  35, 104, 137,   0,   1,   1,   2,   1,   1,   2,   1,   1,
+      1,   1,   1,   1,   1,   1,   2, 138,   1,   1,  95,   1,   1,   1, 134,  43,
+      1,  75, 139, 139, 139, 139,   0,   0,   1,   1,   1,   1, 117,   0,   0,   0,
+      1, 140,   1,   1,   1,   1,   1, 141,   1,   1,   1,   1,   1,  22,   0,  40,
+      1,   1, 101,   1,   8,   1,   1,   1,   1, 142,   1,   1,   1,   1,   1,   1,
+    143,   1,  19,   8,   1,   1,   1,   1,   2,   1,   1,  13,   1,   1, 141,   1,
+      1,   2,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   2,
+      1,   1,   1,  22,   1,   1,   1,   1,   1,   1,   1,   1,   1,  22,   0,   0,
+     87,   1,   1,   1,  75,   1,   1,   1,   1,   1,  40,   0,   1,   1,   2, 144,
+      1,  19,   1,   1,   1,   1,   1, 145,   1,   1,  19,  53,   0,   0,   0, 146,
+    147,   1, 148, 101,   1,   1,   1,  53,   1,   1,   1,   1, 149, 101,   0, 150,
+      1,   1, 151,   1,  75, 152,   1,  87,  28,   1,   1, 153, 154, 155, 131,   2,
+      1,   1, 156, 157, 158,  84,   1, 159,   1,   1,   1, 160, 161, 162, 163,  22,
+    164, 165, 139,   1,   1,   1,  22,   1,   1,   1,   1,   1,   1,   1, 166, 101,
+      1,   1, 141,   1, 142,   1,   1,  40,   0,   0,   0,   0,   0,   0,   0,   0,
+      1,   1,   1,   1,   1,   1,  19,   1,   1,   1,   1,   1,   1, 101,   0,   0,
+     75, 167,   1, 168, 169,   1,   1,   1,   1,   1,   1,   1, 104,  28,   1,   1,
+      1,   1,   1,   1,   0,   1,   1,   1,   1, 121,   1,   1,  53,   0,   0,  19,
+      0, 101,   0,   1,   1, 170, 171, 131,   1,   1,   1,   1,   1,   1,   1,  87,
+      8,   1,   1,   1,   1,   1,   1,   1,   1,  19,   1,   2, 172, 173, 139, 174,
+    159,   1, 100, 175,  19,  19,   0,   0, 176,   1,   1, 177,   1,   1,   1,   1,
+     87,  40,  43,   0,   0,   1,   1,  87,   1,  87,   1,   1,   1,  43,   8,  40,
+      1,   1, 141,   1,  13,   1,   1,  22,   1, 154,   1,   1, 178,  22,   0,   0,
+      1,  19, 101,   0,   0,   0,   0,   0,   1,   1,  53,   1,   1,   1, 179,   0,
+      1,   1,   1,  75,   1,  22,  53,   0, 180,   1,   1, 181,   1, 182,   1,   1,
+      1,   2, 146,   0,   0,   0,   1, 183,   1, 184,   1,  57,   0,   0,   0,   0,
+      1,   1,   1, 185,   1, 121,   1,   1,  43, 186,   1, 141,  53, 103,   1,   1,
+      1,   1,   0,   0,   1,   1, 187,  75,   1,   1,   1,  71,   1, 136,   1, 188,
+      1, 189, 190,   0,   0,   0,   0,   0,   1,   1,   1,   1, 103,   0,   0,   0,
+      1,   1,   1, 117,   1,   1,   1,   7,   0,   0,   0,   0,   0,   0,   1,   2,
+     20,   1,   1,  53, 191, 121,   1,   0, 121,   1,   1, 192, 104,   1, 103, 101,
+     28,   1, 193,  15, 141,   1,   1, 194, 121,   1,   1, 195,  60,   1,   8,  14,
+      1,   6,   2, 196,   0,   0,   0,   0, 197, 154, 101,   1,   1,   2, 117, 101,
+     50,  34,  35, 198, 199, 200, 141,   0,   1,   1,   1, 201, 202, 101,   0,   0,
+      1,   1,   2, 203,   8,  40,   0,   0,   1,   1,   1, 204,  61, 101,   0,   0,
+      1,   1, 205, 206, 101,   0,   0,   0,   1, 101, 207,   1,   0,   0,   0,   0,
+      0,   0,   1,   1,   1,   1,   1, 208,   0,   0,   0,   0,   1,   1,   1, 103,
+      1, 101,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,   2,  14,
+      1,   1,   1,   1, 141,   0,   0,   0,   1,   1,   2,   0,   0,   0,   0,   0,
+      1,   1,   1,   1,  75,   0,   0,   0,   1,   1,   1, 103,   1,   2, 155,   0,
+      0,   0,   0,   0,   0,   1,  19, 209,   1,   1,   1, 146,  22, 140,   6, 210,
+      1,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,  14,   1,   1,   2,
+      0,  28,   0,   0,   0,   0,   0,   0, 104,   0,   0,   0,   0,   0,   0,   0,
+      1,   1,   1,   1,   1,   1,  13,  87, 103, 211,   0,   0,   0,   0,   0,   0,
+      1,   1,   1,   1,   1,   1,   1,  22,   1,   1,   9,   1,   1,   1, 212,   0,
+    213,   1, 155,   1,   1,   1, 103,   0,   1,   1,   1,   1, 214,   0,   0,   0,
+      1,   1,   1,   1,   1,  75,   1, 104,   1,   1,   1,   1,   1, 131,   1,   1,
+      1,   3, 215,  29, 216,   1,   1,   1, 217, 218,   1, 219, 220,  20,   1,   1,
+      1,   1, 136,   1,   1,   1,   1,   1,   1,   1,   1,   1, 163,   1,   1,   1,
+      0,   0,   0, 221,   0,   0,  21, 131, 222,   0,   0,   0,   0,   0,   0,   0,
+      1,   1,   1,   1, 223,   0,   0,   0, 216,   1, 224, 225, 226, 227, 228, 229,
+    140,  40, 230,  40,   0,   0,   0, 104,   1,   1,  40,   1,   1,   1,   1,   1,
+      1, 141,   2,   8,   8,   8,   1,  22,  87,   1,   2,   1,   1,   1,  40,   1,
+      1,  13,   0,   0,   0,   0,  15,   1, 117,   1,   1,  13, 103, 104,   0,   0,
+      1,   1,   1,   1,   1,   1,   1, 140,   1,   1, 216,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,  43,  87, 141,   1,   1,   1,   1,   1,   1,   1, 141,
+      1,   1,   1,   1,   1,  14,   0,   0,  40,   1,   1,   1,  53, 101,   1,   1,
+     53,   1,  19,   0,   0,   0,   0,   0,   0, 103,   0,   0,   0,   0,   0,   0,
+     14,   0,   0,   0,  43,   0,   0,   0,   1,   1,   1,   1,   1,  75,   0,   0,
+      1,   1,   1,  14,   1,   1,   1,   1,   1,  19,   1,   1,   1,   1,   1,   1,
+      1,   1, 104,   0,   0,   0,   0,   0,   1,  19,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_grapheme_base_stage_5[] = {
+      0,   0, 255, 255, 255, 127, 255, 223, 255, 252, 240, 215, 251, 255,   7, 252,
+    254, 255, 127, 254, 255, 230,   0,  64,  73,   0, 255,   7,  31,   0, 192, 255,
+      0, 200,  63,  64,  96, 194, 255,  63, 253, 255,   0, 224,  63,   0,   2,   0,
+    240,   7,  63,   4,  16,   1, 255,  65, 248, 255, 255, 235,   1, 222,   1, 255,
+    243, 255, 237, 159, 249, 255, 255, 253, 197, 163, 129,  89,   0, 176, 195, 255,
+    255,  15, 232, 135, 109, 195,   1,   0,   0,  94,  28,   0, 232, 191, 237, 227,
+      1,  26,   3,   2, 236, 159, 237,  35, 129,  25, 255,   0, 232, 199,  61, 214,
+     24, 199, 255, 131, 198,  29, 238, 223, 255,  35,  30,   0,   0,   7,   0, 255,
+    236, 223, 239,  99, 155,  13,   6,   0, 255, 167, 193,  93,   0, 128,  63, 254,
+    236, 255, 127, 252, 251,  47, 127,   0,   3, 127,  13, 128, 127, 128, 150,  37,
+    240, 254, 174, 236,  13,  32,  95,   0, 255, 243,  95, 253, 255, 254, 255,  31,
+     32,  31,   0, 192, 191, 223,   2, 153, 255,  60, 225, 255, 155, 223, 191,  32,
+    255,  61, 127,  61,  61, 127,  61, 255, 127, 255, 255,   3,  63,  63, 255,   1,
+      3,   0,  99,   0,  79, 192, 191,   1, 240,  31, 255,   5, 120,  14, 251,   1,
+    241, 255, 255, 199, 127, 198, 191,   0,  26, 224,   7,   0, 240, 255,  47, 232,
+    251,  15, 252, 255, 195, 196, 191,  92,  12, 240,  48, 248, 255, 227,   8,   0,
+      2, 222, 111,   0, 255, 170, 223, 255, 207, 239, 220, 127, 255, 128, 207, 255,
+     63, 255,   0, 240,  12, 254, 127, 127, 255, 251,  15,   0, 127, 248, 224, 255,
+      8, 192, 252,   0, 128, 255, 187, 247, 159,  15,  15, 192, 252,  63,  63, 192,
+     12, 128,  55, 236, 255, 191, 255, 195, 255, 129,  25,   0, 247,  47, 255, 239,
+     98,  62,   5,   0,   0, 248, 255, 207, 126, 126, 126,   0, 223,  30, 248, 160,
+    127,  95, 219, 255, 247, 255, 127,  15, 252, 252, 252,  28,   0,  48, 255, 183,
+    135, 255, 143, 255,  15, 255,  15, 128,  63, 253, 191, 145, 191, 255,  55, 248,
+    255, 143, 255, 240, 239, 254,  31, 248,   7, 255,   3,  30,   0, 254, 128,  63,
+    135, 217, 127,  16, 119,   0,  63, 128,  44,  63, 127, 189, 237, 163, 158,  57,
+      1, 224,   6,  90, 242,   0,   3,  79,   7,  88, 255, 215,  64,   0,  67,   0,
+      7, 128,  32,   0, 255, 224, 255, 147,  95,  60,  24, 240,  35,   0, 100, 222,
+    239, 255, 191, 231, 223, 223, 255, 123,  95, 252, 128,   7, 239,  15, 159, 255,
+    150, 254, 247,  10, 132, 234, 150, 170, 150, 247, 247,  94, 238, 251,
+};
+
+/* Grapheme_Base: 2544 bytes. */
+
+RE_UINT32 re_get_grapheme_base(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_grapheme_base_stage_1[f] << 5;
+    f = code >> 10;
+    code ^= f << 10;
+    pos = (RE_UINT32)re_grapheme_base_stage_2[pos + f] << 3;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_grapheme_base_stage_3[pos + f] << 3;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_grapheme_base_stage_4[pos + f] << 4;
+    pos += code;
+    value = (re_grapheme_base_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Grapheme_Link. */
+
+static RE_UINT8 re_grapheme_link_stage_1[] = {
+    0, 1, 2, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1,
+};
+
+static RE_UINT8 re_grapheme_link_stage_2[] = {
+     0,  0,  1,  2,  3,  4,  5,  0,  0,  0,  0,  6,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,
+     0,  0,  8,  0,  9, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_grapheme_link_stage_3[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  2,  3,  0,  0,  4,  5,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  6,  7,  0,  0,  0,  0,  8,  0,  9, 10,
+     0,  0, 11,  0,  0,  0,  0,  0, 12,  9, 13, 14,  0, 15,  0, 16,
+     0,  0,  0,  0, 17,  0,  0,  0, 18, 19, 20, 14, 21, 22,  1,  0,
+     0, 23,  0, 17, 17, 24, 25,  0,
+};
+
+static RE_UINT8 re_grapheme_link_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  2,  0,  0,  3,  0,  0,
+     4,  0,  0,  0,  0,  5,  0,  0,  6,  6,  0,  0,  0,  0,  7,  0,
+     0,  0,  0,  8,  0,  0,  4,  0,  0,  9,  0, 10,  0,  0,  0, 11,
+    12,  0,  0,  0,  0,  0, 13,  0,  0,  0,  8,  0,  0,  0,  0, 14,
+     0,  0,  0,  1,  0, 11,  0,  0,  0,  0, 12, 11,  0, 15,  0,  0,
+     0, 16,  0,  0,  0, 17,  0,  0,  0,  0,  0,  2,  0,  0, 18,  0,
+     0, 14,  0,  0,  0, 19,  0,  0,
+};
+
+static RE_UINT8 re_grapheme_link_stage_5[] = {
+      0,   0,   0,   0,   0,  32,   0,   0,   0,   4,   0,   0,   0,   0,   0,   4,
+     16,   0,   0,   0,   0,   0,   0,   6,   0,   0,  16,   0,   0,   0,   4,   0,
+      1,   0,   0,   0,   0,  12,   0,   0,   0,   0,  12,   0,   0,   0,   0, 128,
+     64,   0,   0,   0,   0,   0,   8,   0,   0,   0,  64,   0,   0,   0,   0,   2,
+      0,   0,  24,   0,   0,   0,  32,   0,   4,   0,   0,   0,   0,   8,   0,   0,
+};
+
+/* Grapheme_Link: 404 bytes. */
+
+RE_UINT32 re_get_grapheme_link(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 14;
+    code = ch ^ (f << 14);
+    pos = (RE_UINT32)re_grapheme_link_stage_1[f] << 4;
+    f = code >> 10;
+    code ^= f << 10;
+    pos = (RE_UINT32)re_grapheme_link_stage_2[pos + f] << 3;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_grapheme_link_stage_3[pos + f] << 2;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_grapheme_link_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_grapheme_link_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* White_Space. */
+
+static RE_UINT8 re_white_space_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_white_space_stage_2[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_white_space_stage_3[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
+    3, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_white_space_stage_4[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 3, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 1, 1, 1,
+    3, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_white_space_stage_5[] = {
+      0,  62,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     32,   0,   0,   0,   1,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,
+    255,   7,   0,   0,   0, 131,   0,   0,   0,   0,   0, 128,   0,   0,   0,   0,
+};
+
+/* White_Space: 169 bytes. */
+
+RE_UINT32 re_get_white_space(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_white_space_stage_1[f] << 3;
+    f = code >> 13;
+    code ^= f << 13;
+    pos = (RE_UINT32)re_white_space_stage_2[pos + f] << 4;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_white_space_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_white_space_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_white_space_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Bidi_Control. */
+
+static RE_UINT8 re_bidi_control_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_bidi_control_stage_2[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_bidi_control_stage_3[] = {
+    0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    2, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_bidi_control_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+    2, 3, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_bidi_control_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  16,   0,   0,   0,   0,
+      0, 192,   0,   0,   0, 124,   0,   0,   0,   0,   0,   0, 192,   3,   0,   0,
+};
+
+/* Bidi_Control: 129 bytes. */
+
+RE_UINT32 re_get_bidi_control(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_bidi_control_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_bidi_control_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_bidi_control_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_bidi_control_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_bidi_control_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Join_Control. */
+
+static RE_UINT8 re_join_control_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_join_control_stage_2[] = {
+    0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_join_control_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_join_control_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_join_control_stage_5[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0, 48,  0,  0,  0,  0,  0,  0,
+};
+
+/* Join_Control: 97 bytes. */
+
+RE_UINT32 re_get_join_control(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_join_control_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_join_control_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_join_control_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_join_control_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_join_control_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Dash. */
+
+static RE_UINT8 re_dash_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_dash_stage_2[] = {
+    0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static RE_UINT8 re_dash_stage_3[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 3, 1, 4, 1, 1, 1,
+    5, 6, 1, 1, 1, 1, 1, 7, 8, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9,
+};
+
+static RE_UINT8 re_dash_stage_4[] = {
+     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  2,  1,  3,  1,  1,  1,  1,  1,  1,  1,
+     4,  1,  1,  1,  1,  1,  1,  1,  5,  6,  7,  1,  1,  1,  1,  1,
+     8,  1,  1,  1,  1,  1,  1,  1,  9,  3,  1,  1,  1,  1,  1,  1,
+    10,  1, 11,  1,  1,  1,  1,  1, 12, 13,  1,  1, 14,  1,  1,  1,
+};
+
+static RE_UINT8 re_dash_stage_5[] = {
+      0,   0,   0,   0,   0,  32,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   4,   0,   0,   0,   0,   0,  64,   1,   0,   0,   0,   0,   0,   0,   0,
+     64,   0,   0,   0,   0,   0,   0,   0,   0,   0,  63,   0,   0,   0,   0,   0,
+      0,   0,   8,   0,   0,   0,   0,   8,   0,   8,   0,   0,   0,   0,   0,   0,
+      0,   0,   4,   0,   0,   0,   0,   0,   0,   0, 128,   4,   0,   0,   0,  12,
+      0,   0,   0,  16,   0,   0,   1,   0,   0,   0,   0,   0,   1,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   6,   0,   0,   0,   0,   1,   8,   0,   0,   0,
+      0,  32,   0,   0,   0,   0,   0,   0,
+};
+
+/* Dash: 297 bytes. */
+
+RE_UINT32 re_get_dash(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_dash_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_dash_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_dash_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_dash_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_dash_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Hyphen. */
+
+static RE_UINT8 re_hyphen_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_hyphen_stage_2[] = {
+    0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static RE_UINT8 re_hyphen_stage_3[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1,
+    4, 1, 1, 1, 1, 1, 1, 5, 6, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7,
+};
+
+static RE_UINT8 re_hyphen_stage_4[] = {
+    0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 1, 1,
+    4, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 6, 1, 1, 1, 1, 1, 7, 1, 1, 8, 9, 1, 1,
+};
+
+static RE_UINT8 re_hyphen_stage_5[] = {
+      0,   0,   0,   0,   0,  32,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   4,   0,   0,   0,   0,   0,   0,  64,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   3,   0,   0,   0,   0,   0,   0,   0, 128,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   8,   0,   0,   0,   0,   8,   0,   0,   0,
+      0,  32,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  32,   0,   0,   0,
+};
+
+/* Hyphen: 241 bytes. */
+
+RE_UINT32 re_get_hyphen(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_hyphen_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_hyphen_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_hyphen_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_hyphen_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_hyphen_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Quotation_Mark. */
+
+static RE_UINT8 re_quotation_mark_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_quotation_mark_stage_2[] = {
+    0, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_quotation_mark_stage_3[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 1, 1, 1, 1, 1, 1, 3, 4, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 5,
+};
+
+static RE_UINT8 re_quotation_mark_stage_4[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    3, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1,
+    5, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 7, 8, 1, 1,
+};
+
+static RE_UINT8 re_quotation_mark_stage_5[] = {
+      0,   0,   0,   0, 132,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   8,   0,   8,   0,   0,   0, 255,   0,   0,   0,   6,
+      4,   0,   0,   0,   0,   0,   0,   0,   0, 240,   0, 224,   0,   0,   0,   0,
+     30,   0,   0,   0,   0,   0,   0,   0, 132,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  12,   0,   0,   0,
+};
+
+/* Quotation_Mark: 209 bytes. */
+
+RE_UINT32 re_get_quotation_mark(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_quotation_mark_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_quotation_mark_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_quotation_mark_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_quotation_mark_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_quotation_mark_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Terminal_Punctuation. */
+
+static RE_UINT8 re_terminal_punctuation_stage_1[] = {
+    0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4,
+};
+
+static RE_UINT8 re_terminal_punctuation_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  9, 10, 11,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9, 12, 13,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 14,
+    15,  9, 16,  9, 17, 18,  9,  9,  9, 19,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 20,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 21,
+     9,  9,  9,  9,  9,  9, 22,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+};
+
+static RE_UINT8 re_terminal_punctuation_stage_3[] = {
+     0,  1,  1,  1,  1,  1,  2,  3,  1,  1,  1,  4,  5,  6,  7,  8,
+     9,  1, 10,  1,  1,  1,  1,  1,  1,  1,  1,  1, 11,  1, 12,  1,
+    13,  1,  1,  1,  1,  1, 14,  1,  1,  1,  1,  1, 15, 16, 17, 18,
+    19,  1, 20,  1,  1, 21, 22,  1, 23,  1,  1,  1,  1,  1,  1,  1,
+    24,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1, 25,  1,  1,  1, 26,  1,  1,  1,  1,  1,  1,  1,
+     1, 27,  1,  1, 28, 29,  1,  1, 30, 31, 32, 33, 34, 35,  1, 36,
+     1,  1,  1,  1, 37,  1, 38,  1,  1,  1,  1,  1,  1,  1,  1, 39,
+    40,  1, 41,  1, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  1,  1,
+     1,  1,  1, 52, 53,  1, 54,  1, 55,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1, 56, 57, 58,  1,  1, 41,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 59,  1,  1,
+};
+
+static RE_UINT8 re_terminal_punctuation_stage_4[] = {
+     0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  3,  0,  0,  0,
+     4,  0,  5,  0,  6,  0,  0,  0,  0,  0,  7,  0,  8,  0,  0,  0,
+     0,  0,  0,  9,  0, 10,  2,  0,  0,  0,  0, 11,  0,  0, 12,  0,
+    13,  0,  0,  0,  0,  0, 14,  0,  0,  0,  0, 15,  0,  0,  0, 16,
+     0,  0,  0, 17,  0, 18,  0,  0,  0,  0, 19,  0, 20,  0,  0,  0,
+     0,  0, 11,  0,  0, 21,  0,  0,  0,  0, 22,  0,  0, 23,  0, 24,
+     0, 25, 26,  0,  0, 27, 28,  0, 29,  0,  0,  0,  0,  0,  0, 24,
+    30,  0,  0,  0,  0,  0,  0, 31,  0,  0,  0, 32,  0,  0, 33,  0,
+     0, 34,  0,  0,  0,  0, 26,  0,  0,  0, 35,  0,  0,  0, 36, 37,
+     0,  0,  0, 38,  0,  0, 39,  0,  1,  0,  0, 40, 36,  0, 41,  0,
+     0,  0, 42,  0, 36,  0,  0,  0,  0,  0, 32,  0,  0,  0,  0, 43,
+     0, 44,  0,  0, 45,  0,  0,  0,  0,  0, 46,  0,  0, 24, 47,  0,
+     0,  0, 48,  0,  0,  0, 49,  0,  0, 50,  0,  0,  0,  4,  0,  0,
+     0,  0, 51,  0,  0,  0, 29,  0,  0, 52,  0,  0,  0,  0,  0, 53,
+     0,  0,  0, 33,  0,  0,  0, 54,  0, 55, 56,  0, 57,  0,  0,  0,
+};
+
+static RE_UINT8 re_terminal_punctuation_stage_5[] = {
+      0,   0,   0,   0,   2,  80,   0, 140,   0,   0,   0,  64, 128,   0,   0,   0,
+      0,   2,   0,   0,   8,   0,   0,   0,   0,  16,   0, 136,   0,   0,  16,   0,
+    255,  23,   0,   0,   0,   0,   0,   3,   0,   0, 255, 127,  48,   0,   0,   0,
+      0,   0,   0,  12,   0, 225,   7,   0,   0,  12,   0,   0, 254,   1,   0,   0,
+      0,  96,   0,   0,   0,  56,   0,   0,   0,   0,  96,   0,   0,   0, 112,   4,
+     60,   3,   0,   0,   0,  15,   0,   0,   0,   0,   0, 236,   0,   0,   0, 248,
+      0,   0,   0, 192,   0,   0,   0,  48, 128,   3,   0,   0,   0,  64,   0,  16,
+      2,   0,   0,   0,   6,   0,   0,   0,   0, 224,   0,   0,   0,   0, 248,   0,
+      0,   0, 192,   0,   0, 192,   0,   0,   0, 128,   0,   0,   0,   0,   0, 224,
+      0,   0,   0, 128,   0,   0,   3,   0,   0,   8,   0,   0,   0,   0, 247,   0,
+     18,   0,   0,   0,   0,   0,   1,   0,   0,   0, 128,   0,   0,   0,  63,   0,
+      0,   0,   0, 252,   0,   0,   0,  30, 128,  63,   0,   0,   3,   0,   0,   0,
+     14,   0,   0,   0,  96,  32,   0, 192,   0,   0,   0,  31,  60, 254, 255,   0,
+      0,   0,   0, 112,   0,   0,  31,   0,   0,   0,  32,   0,   0,   0, 128,   3,
+     16,   0,   0,   0, 128,   7,   0,   0,
+};
+
+/* Terminal_Punctuation: 850 bytes. */
+
+RE_UINT32 re_get_terminal_punctuation(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_terminal_punctuation_stage_1[f] << 5;
+    f = code >> 10;
+    code ^= f << 10;
+    pos = (RE_UINT32)re_terminal_punctuation_stage_2[pos + f] << 3;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_terminal_punctuation_stage_3[pos + f] << 2;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_terminal_punctuation_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_terminal_punctuation_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Other_Math. */
+
+static RE_UINT8 re_other_math_stage_1[] = {
+    0, 1, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2,
+};
+
+static RE_UINT8 re_other_math_stage_2[] = {
+    0, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 6, 1, 1,
+};
+
+static RE_UINT8 re_other_math_stage_3[] = {
+     0,  1,  1,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     3,  4,  1,  5,  1,  6,  7,  8,  1,  9,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1, 10, 11,  1,  1,  1,  1, 12, 13, 14, 15,
+     1,  1,  1,  1,  1,  1, 16,  1,
+};
+
+static RE_UINT8 re_other_math_stage_4[] = {
+     0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  2,  3,  4,  5,  6,  7,  8,  0,  9, 10,
+    11, 12, 13,  0, 14, 15, 16, 17, 18,  0,  0,  0,  0, 19, 20, 21,
+     0,  0,  0,  0,  0, 22, 23, 24, 25,  0, 26, 27,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 25, 28,  0,  0,  0,  0, 29,  0, 30, 31,
+     0,  0,  0, 32,  0,  0,  0,  0,  0, 33,  0,  0,  0,  0,  0,  0,
+    34, 34, 35, 34, 36, 37, 38, 34, 39, 40, 41, 34, 34, 34, 34, 34,
+    34, 34, 34, 34, 34, 42, 43, 44, 35, 35, 45, 45, 46, 46, 47, 34,
+    38, 48, 49, 50, 51, 52,  0,  0,
+};
+
+static RE_UINT8 re_other_math_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,  64,   0,   0,  39,   0,   0,   0,  51,   0,
+      0,   0,  64,   0,   0,   0,  28,   0,   1,   0,   0,   0,  30,   0,   0,  96,
+      0,  96,   0,   0,   0,   0, 255,  31,  98, 248,   0,   0, 132, 252,  47,  62,
+     16, 179, 251, 241, 224,   3,   0,   0,   0,   0, 224, 243, 182,  62, 195, 240,
+    255,  63, 235,  47,  48,   0,   0,   0,   0,  15,   0,   0,   0,   0, 176,   0,
+      0,   0,   1,   0,   4,   0,   0,   0,   3, 192, 127, 240, 193, 140,  15,   0,
+    148,  31,   0,   0,  96,   0,   0,   0,   5,   0,   0,   0,  15,  96,   0,   0,
+    192, 255,   0,   0, 248, 255, 255,   1,   0,   0,   0,  15,   0,   0,   0,  48,
+     10,   1,   0,   0,   0,   0,   0,  80, 255, 255, 255, 255, 255, 255, 223, 255,
+    255, 255, 255, 223, 100, 222, 255, 235, 239, 255, 255, 255, 191, 231, 223, 223,
+    255, 255, 255, 123,  95, 252, 253, 255,  63, 255, 255, 255, 253, 255, 255, 247,
+    255, 255, 255, 247, 255, 127, 255, 255, 255, 253, 255, 255, 247, 207, 255, 255,
+    150, 254, 247,  10, 132, 234, 150, 170, 150, 247, 247,  94, 255, 251, 255,  15,
+    238, 251, 255,  15,
+};
+
+/* Other_Math: 502 bytes. */
+
+RE_UINT32 re_get_other_math(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_other_math_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_other_math_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_other_math_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_other_math_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_other_math_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Hex_Digit. */
+
+static RE_UINT8 re_hex_digit_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_hex_digit_stage_2[] = {
+    0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_hex_digit_stage_3[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 2,
+};
+
+static RE_UINT8 re_hex_digit_stage_4[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 2, 1,
+};
+
+static RE_UINT8 re_hex_digit_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 126,   0,   0,   0, 126,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0, 255,   3, 126,   0,   0,   0, 126,   0,   0,   0,   0,   0,   0,   0,
+};
+
+/* Hex_Digit: 129 bytes. */
+
+RE_UINT32 re_get_hex_digit(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_hex_digit_stage_1[f] << 3;
+    f = code >> 13;
+    code ^= f << 13;
+    pos = (RE_UINT32)re_hex_digit_stage_2[pos + f] << 3;
+    f = code >> 10;
+    code ^= f << 10;
+    pos = (RE_UINT32)re_hex_digit_stage_3[pos + f] << 3;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_hex_digit_stage_4[pos + f] << 7;
+    pos += code;
+    value = (re_hex_digit_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* ASCII_Hex_Digit. */
+
+static RE_UINT8 re_ascii_hex_digit_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_ascii_hex_digit_stage_2[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_ascii_hex_digit_stage_3[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_ascii_hex_digit_stage_4[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_ascii_hex_digit_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 126,   0,   0,   0, 126,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+
+/* ASCII_Hex_Digit: 97 bytes. */
+
+RE_UINT32 re_get_ascii_hex_digit(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_ascii_hex_digit_stage_1[f] << 3;
+    f = code >> 13;
+    code ^= f << 13;
+    pos = (RE_UINT32)re_ascii_hex_digit_stage_2[pos + f] << 3;
+    f = code >> 10;
+    code ^= f << 10;
+    pos = (RE_UINT32)re_ascii_hex_digit_stage_3[pos + f] << 3;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_ascii_hex_digit_stage_4[pos + f] << 7;
+    pos += code;
+    value = (re_ascii_hex_digit_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Other_Alphabetic. */
+
+static RE_UINT8 re_other_alphabetic_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_other_alphabetic_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  7,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9,
+    10, 11, 12,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 13,  6,  6,
+     6,  6,  6,  6,  6,  6,  6, 14,  6,  6,  6,  6,  6,  6, 15,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_other_alphabetic_stage_3[] = {
+     0,  0,  0,  1,  0,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,
+    13,  0,  0, 14,  0,  0,  0, 15, 16, 17, 18, 19, 20, 21,  0,  0,
+     0,  0,  0,  0, 22,  0,  0,  0,  0,  0,  0,  0,  0, 23,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 24,  0,
+    25, 26, 27, 28,  0,  0,  0,  0,  0,  0,  0, 29,  0,  0,  0,  0,
+     0,  0,  0, 30,  0,  0,  0,  0,  0,  0, 31,  0,  0,  0,  0,  0,
+    32, 33, 34, 35, 36, 37, 38, 39,  0,  0,  0, 40,  0,  0,  0, 41,
+     0,  0,  0,  0, 42,  0,  0,  0,  0, 43,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_other_alphabetic_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  2,  3,  0,  4,  0,  5,  6,  0,  0,  7,  8,
+     9, 10,  0,  0,  0, 11,  0,  0, 12, 13,  0,  0,  0,  0,  0, 14,
+    15, 16, 17, 18, 19, 20, 21, 18, 19, 20, 22, 23, 19, 20, 24, 18,
+    19, 20, 25, 18, 26, 20, 27,  0, 15, 20, 28, 18, 19, 20, 28, 18,
+    19, 20, 29, 18, 18,  0, 30, 31,  0, 32, 33,  0,  0, 34, 33,  0,
+     0,  0,  0, 35, 36, 37,  0,  0,  0, 38, 39, 40, 41,  0,  0,  0,
+     0,  0, 42,  0,  0,  0,  0,  0, 31, 31, 31, 31,  0, 43, 44,  0,
+     0,  0,  0,  0,  0, 45,  0,  0,  0, 46,  0,  0,  0,  0,  0,  0,
+    47,  0, 48, 49,  0,  0,  0,  0, 50, 51, 15,  0, 52, 53,  0, 54,
+     0, 55,  0,  0,  0,  0,  0, 31,  0,  0,  0,  0,  0,  0,  0, 56,
+     0,  0,  0,  0,  0, 43, 57, 58,  0,  0,  0,  0,  0,  0,  0, 57,
+     0,  0,  0, 59, 20,  0,  0,  0,  0, 60,  0,  0, 61, 62, 15,  0,
+     0, 63, 64,  0, 15, 62,  0,  0,  0, 65, 66,  0,  0, 67,  0, 68,
+     0,  0,  0,  0,  0,  0,  0, 69, 70,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0, 71,  0,  0,  0,  0, 72,  0,  0,  0,  0,  0,  0,  0,
+    52, 73, 74,  0, 26, 75,  0,  0, 52, 64,  0,  0, 52, 76,  0,  0,
+     0, 77,  0,  0,  0,  0, 42, 44, 15, 20, 21, 18,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 10, 61,  0,  0,  0,  0,  0,  0, 78, 79,  0,
+     0, 80, 81,  0,  0, 82,  0,  0, 83, 84,  0,  0,  0,  0,  0,  0,
+     0, 85,  0,  0,  0,  0,  0,  0,  0,  0, 35, 86,  0,  0,  0,  0,
+     0,  0,  0,  0, 70,  0,  0,  0,  0, 10, 87, 87, 58,  0,  0,  0,
+};
+
+static RE_UINT8 re_other_alphabetic_stage_5[] = {
+      0,   0,   0,   0,  32,   0,   0,   0,   0,   0, 255, 191, 182,   0,   0,   0,
+      0,   0, 255,   7,   0, 248, 255, 254,   0,   0,   1,   0,   0,   0, 192,  31,
+    158,  33,   0,   0,   0,   0,   2,   0,   0,   0, 255, 255, 192, 255,   1,   0,
+      0,   0, 192, 248, 239,  30,   0,   0, 248,   3, 255, 255,  15,   0,   0,   0,
+      0,   0,   0, 204, 255, 223, 224,   0,  12,   0,   0,   0,  14,   0,   0,   0,
+      0,   0,   0, 192, 159,  25, 128,   0, 135,  25,   2,   0,   0,   0,  35,   0,
+    191,  27,   0,   0, 159,  25, 192,   0,   4,   0,   0,   0, 199,  29, 128,   0,
+    223,  29,  96,   0, 223,  29, 128,   0,   0, 128,  95, 255,   0,   0,  12,   0,
+      0,   0, 242,   7,   0,  32,   0,   0,   0,   0, 242,  27,   0,   0, 254, 255,
+      3, 224, 255, 254, 255, 255, 255,  31,   0, 248, 127, 121,   0,   0, 192, 195,
+    133,   1,  30,   0, 124,   0,   0,  48,   0,   0,   0, 128,   0,   0, 192, 255,
+    255,   1,   0,   0,   0,   2,   0,   0, 255,  15, 255,   1,   0,   0, 128,  15,
+      0,   0, 224, 127, 254, 255,  31,   0,  31,   0,   0,   0,   0,   0, 224, 255,
+      7,   0,   0,   0, 254,  51,   0,   0, 128, 255,   3,   0, 240, 255,  63,   0,
+    128, 255,  31,   0, 255, 255, 255, 255, 255,   3,   0,   0,   0,   0, 240,  15,
+    248,   0,   0,   0,   3,   0,   0,   0,   0,   0, 240, 255, 192,   7,   0,   0,
+    128, 255,   7,   0,   0, 254, 127,   0,   8,  48,   0,   0,   0,   0, 157,  65,
+      0, 248,  32,   0, 248,   7,   0,   0,   0,   0,   0,  64,   0,   0, 192,   7,
+    110, 240,   0,   0,   0,   0,   0, 255,  63,   0,   0,   0,   0,   0, 255,   1,
+      0,   0, 248, 255,   0, 240, 159,   0,   0, 128,  63, 127,   0,   0,   0,  48,
+      0,   0, 255, 127,   1,   0,   0,   0,   0, 248,  63,   0,   0,   0,   0, 224,
+    255,   7,   0,   0,   0,   0, 127,   0, 255, 255, 255, 127, 255,   3, 255, 255,
+};
+
+/* Other_Alphabetic: 945 bytes. */
+
+RE_UINT32 re_get_other_alphabetic(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_other_alphabetic_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_other_alphabetic_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_other_alphabetic_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_other_alphabetic_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_other_alphabetic_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Ideographic. */
+
+static RE_UINT8 re_ideographic_stage_1[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_ideographic_stage_2[] = {
+     0,  0,  0,  0,  0,  0,  1,  2,  2,  3,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  2,  6,  2,  7,  8,  2,  9,  0,  0,  0,  0,  0, 10,
+};
+
+static RE_UINT8 re_ideographic_stage_3[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  4,  0,  2,  5,  0,  0,  0,  0,  0,
+     2,  2,  2,  2,  2,  2,  6,  2,  2,  2,  2,  2,  2,  2,  2,  7,
+     8,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  9,  0,
+     2,  2, 10,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_ideographic_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  0,  0,  0,  0,  0,  0,
+     3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  4,  0,  0,
+     3,  3,  3,  3,  3,  3,  4,  0,  3,  3,  3,  5,  3,  3,  6,  0,
+     3,  3,  3,  3,  3,  3,  7,  0,  3,  8,  3,  3,  3,  3,  3,  3,
+     9,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3, 10,  0,  0,
+     9,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_ideographic_stage_5[] = {
+      0,   0,   0,   0, 192,   0,   0,   0, 254,   3,   0,   7, 255, 255, 255, 255,
+    255, 255,  63,   0, 255,  63, 255, 255, 255, 255, 255,   3, 255, 255, 127,   0,
+    255, 255,  31,   0, 255, 255, 255,  63,   3,   0,   0,   0,
+};
+
+/* Ideographic: 333 bytes. */
+
+RE_UINT32 re_get_ideographic(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_ideographic_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_ideographic_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_ideographic_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_ideographic_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_ideographic_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Diacritic. */
+
+static RE_UINT8 re_diacritic_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_diacritic_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  7,  8,  4,  4,  4,  4,  4,  4,  4,  4,  4,  9,
+    10, 11, 12,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4, 13,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4, 14,  4,  4, 15,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+};
+
+static RE_UINT8 re_diacritic_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1,  1,  1,  1,  1,  1, 17,  1, 18, 19, 20, 21, 22,  1, 23,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 24,  1, 25,  1,
+    26,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 27, 28,
+    29, 30, 31, 32,  1,  1,  1,  1,  1,  1,  1, 33,  1,  1, 34, 35,
+     1,  1, 36,  1,  1,  1,  1,  1,  1,  1, 37,  1,  1,  1,  1,  1,
+    38, 39, 40, 41, 42, 43, 44, 45,  1,  1, 46,  1,  1,  1,  1, 47,
+     1, 48,  1,  1,  1,  1,  1,  1, 49,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_diacritic_stage_4[] = {
+     0,  0,  1,  2,  0,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  4,  5,  5,  5,  5,  6,  7,  8,  0,  0,  0,
+     0,  0,  0,  0,  9,  0,  0,  0,  0,  0, 10,  0, 11, 12, 13,  0,
+     0,  0, 14,  0,  0,  0, 15, 16,  0,  4, 17,  0,  0, 18,  0, 19,
+    20,  0,  0,  0,  0,  0,  0, 21,  0, 22, 23, 24,  0, 22, 25,  0,
+     0, 22, 25,  0,  0, 22, 25,  0,  0, 22, 25,  0,  0,  0, 25,  0,
+     0,  0, 25,  0,  0, 22, 25,  0,  0,  0, 25,  0,  0,  0, 26,  0,
+     0,  0, 27,  0,  0,  0, 28,  0, 20, 29,  0,  0, 30,  0, 31,  0,
+     0, 32,  0,  0, 33,  0,  0,  0,  0,  0,  0,  0,  0,  0, 34,  0,
+     0, 35,  0,  0,  0,  0,  0,  0,  0,  0,  0, 36,  0, 37,  0,  0,
+     0, 38, 39, 40,  0, 41,  0,  0,  0, 42,  0, 43,  0,  0,  4, 44,
+     0, 45,  5, 17,  0,  0, 46, 47,  0,  0,  0,  0,  0, 48, 49, 50,
+     0,  0,  0,  0,  0,  0,  0, 51,  0, 52,  0,  0,  0,  0,  0,  0,
+     0, 53,  0,  0, 54,  0,  0, 22,  0,  0,  0, 55, 56,  0,  0, 57,
+    58, 59,  0,  0, 60,  0,  0, 20,  0,  0,  0,  0,  0,  0, 39, 61,
+     0, 62, 63,  0,  0, 63,  2, 64,  0,  0,  0, 65,  0, 15, 66, 67,
+     0,  0, 68,  0,  0,  0,  0, 69,  1,  0,  0,  0,  0,  0,  0,  0,
+     0, 70,  0,  0,  0,  0,  0,  0,  0,  1,  2, 71, 72,  0,  0, 73,
+     0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0, 74,
+     0,  0,  0,  0,  0, 75,  0,  0,  0, 76,  0, 63,  0,  0, 77,  0,
+     0, 78,  0,  0,  0,  0,  0, 79,  0, 22, 25, 80,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 81,  0,  0,  0,  0,  0,  0, 15,  2,  0,
+     0, 15,  0,  0,  0, 42,  0,  0,  0, 82,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0, 83,  0,  0,  0,  0, 84,  0,  0,  0,
+     0,  0,  0, 85, 86, 87,  0,  0,  0,  0,  0,  0,  0,  0, 88,  0,
+};
+
+static RE_UINT8 re_diacritic_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,  64,   1,   0,   0,   0,   0, 129, 144,   1,
+      0,   0, 255, 255, 255, 255, 255, 255, 255, 127, 255, 224,   7,   0,  48,   4,
+     48,   0,   0,   0, 248,   0,   0,   0,   0,   0,   0,   2,   0,   0, 254, 255,
+    251, 255, 255, 191,  22,   0,   0,   0,   0, 248, 135,   1,   0,   0,   0, 128,
+     97,  28,   0,   0, 255,   7,   0,   0, 192, 255,   1,   0,   0, 248,  63,   0,
+      0,   0,   0,   3, 248, 255, 255, 127,   0,   0,   0,  16,   0,  32,  30,   0,
+      0,   0,   2,   0,   0,  32,   0,   0,   0,   4,   0,   0, 128,  95,   0,   0,
+      0,  31,   0,   0,   0,   0, 160, 194, 220,   0,   0,   0,  64,   0,   0,   0,
+      0,   0, 128,   6, 128, 191,   0,  12,   0, 254,  15,  32,   0,   0,   0,  14,
+      0,   0, 224, 159,   0,   0, 255,  63,   0,   0,  16,   0,  16,   0,   0,   0,
+      0, 248,  15,   0,   0,  12,   0,   0,   0,   0, 192,   0,   0,   0,   0,  63,
+    255,  33,  16,   3,   0, 240, 255, 255, 240, 255,   0,   0,   0,   0,  32, 224,
+      0,   0,   0, 160,   3, 224,   0, 224,   0, 224,   0,  96,   0, 128,   3,   0,
+      0, 128,   0,   0,   0, 252,   0,   0,   0,   0,   0,  30,   0, 128,   0, 176,
+      0,   0,   0,  48,   0,   0,   3,   0,   0,   0, 128, 255,   3,   0,   0,   0,
+      0,   1,   0,   0, 255, 255,   3,   0,   0, 120,   0,   0,   0,   0,   8,   0,
+     32,   0,   0,   0,   0,   0,   0,  56,   7,   0,   0,   0,   0,   0,  64,   0,
+      0,   0,   0, 248,   0,  48,   0,   0, 255, 255,   0,   0,   0,   0,   1,   0,
+      0,   0,   0, 192,   8,   0,   0,   0,  96,   0,   0,   0,   0,   0,   0,   6,
+      0,   0,  24,   0,   1,  28,   0,   0,   0,   0,  96,   0,   0,   6,   0,   0,
+    192,  31,  31,   0,  12,   0,   0,   0,   0,   8,   0,   0,   0,   0,  31,   0,
+      0, 128, 255, 255, 128, 227,   7, 248, 231,  15,   0,   0,   0,  60,   0,   0,
+      0,   0, 127,   0,
+};
+
+/* Diacritic: 997 bytes. */
+
+RE_UINT32 re_get_diacritic(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_diacritic_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_diacritic_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_diacritic_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_diacritic_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_diacritic_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Extender. */
+
+static RE_UINT8 re_extender_stage_1[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3,
+};
+
+static RE_UINT8 re_extender_stage_2[] = {
+    0, 1, 2, 3, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7,
+    2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_extender_stage_3[] = {
+     0,  1,  2,  1,  1,  1,  3,  4,  1,  1,  1,  1,  1,  1,  5,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  6,  1,  7,  1,  8,  1,  1,  1,
+     9,  1,  1,  1,  1,  1,  1,  1, 10,  1,  1,  1,  1,  1, 11,  1,
+     1, 12, 13,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 14,
+     1,  1,  1, 15,  1, 16,  1,  1,  1,  1,  1, 17,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_extender_stage_4[] = {
+     0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  3,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  4,  0,  0,  5,  0,  0,  0,  5,  0,
+     6,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  0,  0,
+     0,  9,  0, 10,  0,  0,  0,  0, 11, 12,  0,  0, 13,  0,  0, 14,
+    15,  0,  0,  0,  0,  0,  0,  0, 16,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 17,  5,  0,  0,  0, 18,  0,  0, 19, 20,
+     0,  0,  0, 18,  0,  0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 21,  0,  0,  0, 22,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_extender_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 128,   0,   0,   0,   3,   0,   1,   0,   0,   0,
+      0,   0,   0,   4,  64,   0,   0,   0,   0,   4,   0,   0,   8,   0,   0,   0,
+    128,   0,   0,   0,   0,   0,  64,   0,   0,   0,   0,   8,  32,   0,   0,   0,
+      0,   0,  62,   0,   0,   0,   0,  96,   0,   0,   0, 112,   0,   0,  32,   0,
+      0,  16,   0,   0,   0, 128,   0,   0,   0,   0,   1,   0,   0,   0,   0,  32,
+      0,   0,  24,   0, 192,   1,   0,   0,  12,   0,   0,   0,
+};
+
+/* Extender: 414 bytes. */
+
+RE_UINT32 re_get_extender(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_extender_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_extender_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_extender_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_extender_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_extender_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Other_Lowercase. */
+
+static RE_UINT8 re_other_lowercase_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_other_lowercase_stage_2[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static RE_UINT8 re_other_lowercase_stage_3[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2,
+    4, 2, 5, 2, 2, 2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 7, 2, 8, 2, 2,
+};
+
+static RE_UINT8 re_other_lowercase_stage_4[] = {
+     0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  2,  3,  0,  4,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  6,  7,  0,
+     0,  8,  9,  0,  0, 10,  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,
+     0, 12,  0,  0,  0,  0,  0,  0,  0,  0, 13,  0,  0, 14,  0, 15,
+     0,  0,  0,  0,  0, 16,  0,  0,
+};
+
+static RE_UINT8 re_other_lowercase_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   4,   0,   4,
+      0,   0,   0,   0,   0,   0, 255,   1,   3,   0,   0,   0,  31,   0,   0,   0,
+     32,   0,   0,   0,   0,   0,   0,   4,   0,   0,   0,   0,   0, 240, 255, 255,
+    255, 255, 255, 255, 255,   7,   0,   1,   0,   0,   0, 248, 255, 255, 255, 255,
+      0,   0,   0,   0,   0,   0,   2, 128,   0,   0, 255,  31,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 255, 255,   0,   0, 255, 255, 255,   3,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  48,   0,   0,   0,  48,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   3,
+      0,   0,   0, 240,   0,   0,   0,   0,
+};
+
+/* Other_Lowercase: 297 bytes. */
+
+RE_UINT32 re_get_other_lowercase(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_other_lowercase_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_other_lowercase_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_other_lowercase_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_other_lowercase_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_other_lowercase_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Other_Uppercase. */
+
+static RE_UINT8 re_other_uppercase_stage_1[] = {
+    0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1,
+};
+
+static RE_UINT8 re_other_uppercase_stage_2[] = {
+    0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
+};
+
+static RE_UINT8 re_other_uppercase_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0,
+    0, 3, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_other_uppercase_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 2, 1, 0, 0, 3, 4, 4, 5, 0, 0, 0,
+};
+
+static RE_UINT8 re_other_uppercase_stage_5[] = {
+      0,   0,   0,   0, 255, 255,   0,   0,   0,   0, 192, 255,   0,   0, 255, 255,
+    255,   3, 255, 255, 255,   3,   0,   0,
+};
+
+/* Other_Uppercase: 162 bytes. */
+
+RE_UINT32 re_get_other_uppercase(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_other_uppercase_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_other_uppercase_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_other_uppercase_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_other_uppercase_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_other_uppercase_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Noncharacter_Code_Point. */
+
+static RE_UINT8 re_noncharacter_code_point_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_noncharacter_code_point_stage_2[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+};
+
+static RE_UINT8 re_noncharacter_code_point_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
+    0, 0, 0, 0, 0, 0, 0, 2,
+};
+
+static RE_UINT8 re_noncharacter_code_point_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+    0, 0, 0, 0, 0, 0, 0, 2,
+};
+
+static RE_UINT8 re_noncharacter_code_point_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255, 255, 255, 255,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 192,
+};
+
+/* Noncharacter_Code_Point: 121 bytes. */
+
+RE_UINT32 re_get_noncharacter_code_point(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_noncharacter_code_point_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_noncharacter_code_point_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_noncharacter_code_point_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_noncharacter_code_point_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_noncharacter_code_point_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Other_Grapheme_Extend. */
+
+static RE_UINT8 re_other_grapheme_extend_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_other_grapheme_extend_stage_2[] = {
+    0, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+    1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_other_grapheme_extend_stage_3[] = {
+    0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 6, 0, 7, 8, 0, 0, 0, 0, 0,
+    9, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_other_grapheme_extend_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,
+     0,  0,  0,  0,  1,  2,  1,  2,  0,  0,  0,  3,  1,  2,  0,  4,
+     5,  0,  0,  0,  0,  0,  0,  0,  6,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  1,  2,  0,  0,
+     0,  0,  8,  0,  0,  0,  9,  0,  0,  0,  0,  0,  0, 10,  0,  0,
+};
+
+static RE_UINT8 re_other_grapheme_extend_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  64,
+      0,   0, 128,   0,   0,   0,   0,   0,   4,   0,  96,   0,   0,   0,   0,   0,
+      0, 128,   0, 128,   0,   0,   0,   0,   0,  48,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 192,   0,   0,   0,   0,   0, 192,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   1,  32,   0,   0,   0,   0,   0, 128,   0,   0,
+      0,   0,   0,   0,  32, 192,   7,   0,
+};
+
+/* Other_Grapheme_Extend: 289 bytes. */
+
+RE_UINT32 re_get_other_grapheme_extend(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_other_grapheme_extend_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_other_grapheme_extend_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_other_grapheme_extend_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_other_grapheme_extend_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_other_grapheme_extend_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* IDS_Binary_Operator. */
+
+static RE_UINT8 re_ids_binary_operator_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_ids_binary_operator_stage_2[] = {
+    0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_ids_binary_operator_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+static RE_UINT8 re_ids_binary_operator_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+static RE_UINT8 re_ids_binary_operator_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 243,  15,
+};
+
+/* IDS_Binary_Operator: 97 bytes. */
+
+RE_UINT32 re_get_ids_binary_operator(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_ids_binary_operator_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_ids_binary_operator_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_ids_binary_operator_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_ids_binary_operator_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_ids_binary_operator_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* IDS_Trinary_Operator. */
+
+static RE_UINT8 re_ids_trinary_operator_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_ids_trinary_operator_stage_2[] = {
+    0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_ids_trinary_operator_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+static RE_UINT8 re_ids_trinary_operator_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+static RE_UINT8 re_ids_trinary_operator_stage_5[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12,  0,
+};
+
+/* IDS_Trinary_Operator: 97 bytes. */
+
+RE_UINT32 re_get_ids_trinary_operator(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_ids_trinary_operator_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_ids_trinary_operator_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_ids_trinary_operator_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_ids_trinary_operator_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_ids_trinary_operator_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Radical. */
+
+static RE_UINT8 re_radical_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_radical_stage_2[] = {
+    0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_radical_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+static RE_UINT8 re_radical_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 1, 2, 2, 3, 2, 2, 2, 2, 2, 2, 4, 0,
+};
+
+static RE_UINT8 re_radical_stage_5[] = {
+      0,   0,   0,   0, 255, 255, 255, 251, 255, 255, 255, 255, 255, 255,  15,   0,
+    255, 255,  63,   0,
+};
+
+/* Radical: 117 bytes. */
+
+RE_UINT32 re_get_radical(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_radical_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_radical_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_radical_stage_3[pos + f] << 4;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_radical_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_radical_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Unified_Ideograph. */
+
+static RE_UINT8 re_unified_ideograph_stage_1[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_unified_ideograph_stage_2[] = {
+    0, 0, 0, 1, 2, 3, 3, 3, 3, 4, 0, 0, 0, 0, 0, 5,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 7, 8, 0, 0, 0,
+};
+
+static RE_UINT8 re_unified_ideograph_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 4, 0, 0,
+    1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 6, 7, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 8,
+};
+
+static RE_UINT8 re_unified_ideograph_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 3,
+    4, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 5, 1, 1, 1, 1,
+    1, 1, 1, 1, 6, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 8, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_unified_ideograph_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255,  63,   0, 255, 255,  63,   0,   0,   0,   0,   0,
+      0, 192,  26, 128, 154,   3,   0,   0, 255, 255, 127,   0,   0,   0,   0,   0,
+    255, 255, 255, 255, 255, 255,  31,   0, 255, 255, 255,  63, 255, 255, 255, 255,
+    255, 255, 255, 255,   3,   0,   0,   0,
+};
+
+/* Unified_Ideograph: 281 bytes. */
+
+RE_UINT32 re_get_unified_ideograph(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_unified_ideograph_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_unified_ideograph_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_unified_ideograph_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_unified_ideograph_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_unified_ideograph_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Other_Default_Ignorable_Code_Point. */
+
+static RE_UINT8 re_other_default_ignorable_code_point_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+    1,
+};
+
+static RE_UINT8 re_other_default_ignorable_code_point_stage_2[] = {
+    0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static RE_UINT8 re_other_default_ignorable_code_point_stage_3[] = {
+    0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0,
+    4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+    7, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static RE_UINT8 re_other_default_ignorable_code_point_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,
+     0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  3,  0,
+     0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  0,  0,
+     0,  0,  0,  0,  0,  0,  6,  7,  8,  0,  9,  9,  0,  0,  0, 10,
+     9,  9,  9,  9,  9,  9,  9,  9,
+};
+
+static RE_UINT8 re_other_default_ignorable_code_point_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0, 128,   0,   0,   0,   0,   0,   0,
+      0,   0,   0, 128,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,  48,   0,
+      0,   0,   0,   0,  32,   0,   0,   0,   0,   0,   0,   0,  16,   0,   0,   0,
+      0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,   1,
+    253, 255, 255, 255,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255,
+      0,   0,   0,   0,   0,   0, 255, 255,
+};
+
+/* Other_Default_Ignorable_Code_Point: 281 bytes. */
+
+RE_UINT32 re_get_other_default_ignorable_code_point(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_other_default_ignorable_code_point_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_other_default_ignorable_code_point_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_other_default_ignorable_code_point_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_other_default_ignorable_code_point_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_other_default_ignorable_code_point_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Deprecated. */
+
+static RE_UINT8 re_deprecated_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
+    1, 1,
+};
+
+static RE_UINT8 re_deprecated_stage_2[] = {
+    0, 1, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+static RE_UINT8 re_deprecated_stage_3[] = {
+    0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+    0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0,
+    5, 0, 0, 6, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_deprecated_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+    0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0,
+    0, 6, 0, 0, 0, 0, 0, 0, 7, 0, 0, 8, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_deprecated_stage_5[] = {
+      0,   0,   0,   0,   0,   2,   0,   0,   0,   0,   8,   0,   0,   0, 128,   2,
+     24,   0,   0,   0,   0, 252,   0,   0,   0,   6,   0,   0,   2,   0,   0,   0,
+      0,   0,   0, 128,
+};
+
+/* Deprecated: 230 bytes. */
+
+RE_UINT32 re_get_deprecated(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_deprecated_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_deprecated_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_deprecated_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_deprecated_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_deprecated_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Soft_Dotted. */
+
+static RE_UINT8 re_soft_dotted_stage_1[] = {
+    0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1,
+};
+
+static RE_UINT8 re_soft_dotted_stage_2[] = {
+    0, 1, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_soft_dotted_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+     5,  5,  5,  5,  5,  6,  7,  5,  8,  9,  5,  5,  5,  5,  5,  5,
+     5,  5,  5,  5, 10,  5,  5,  5,  5,  5,  5,  5, 11, 12, 13,  5,
+};
+
+static RE_UINT8 re_soft_dotted_stage_4[] = {
+     0,  0,  0,  1,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,
+     0,  0,  3,  4,  5,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,
+     0,  0,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  9, 10, 11,  0,  0,  0, 12,  0,  0,  0,  0, 13,  0,
+     0,  0,  0, 14,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,
+     0,  0,  0, 16,  0,  0,  0,  0,  0, 17, 18,  0, 19, 20,  0, 21,
+     0, 22, 23,  0, 24,  0, 17, 18,  0, 19, 20,  0, 21,  0,  0,  0,
+};
+
+static RE_UINT8 re_soft_dotted_stage_5[] = {
+      0,   0,   0,   0,   0,   6,   0,   0,   0, 128,   0,   0,   0,   2,   0,   0,
+      0,   1,   0,   0,   0,   0,   0,  32,   0,   0,   4,   0,   0,   0,   8,   0,
+      0,   0,  64,   1,   4,   0,   0,   0,   0,   0,  64,   0,  16,   1,   0,   0,
+      0,  32,   0,   0,   0,   8,   0,   0,   0,   0,   2,   0,   0,   3,   0,   0,
+      0,   0,   0,  16,  12,   0,   0,   0,   0,   0, 192,   0,   0,  12,   0,   0,
+      0,   0,   0, 192,   0,   0,  12,   0, 192,   0,   0,   0,   0,   0,   0,  12,
+      0, 192,   0,   0,
+};
+
+/* Soft_Dotted: 342 bytes. */
+
+RE_UINT32 re_get_soft_dotted(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_soft_dotted_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_soft_dotted_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_soft_dotted_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_soft_dotted_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_soft_dotted_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Logical_Order_Exception. */
+
+static RE_UINT8 re_logical_order_exception_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_logical_order_exception_stage_2[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_logical_order_exception_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0,
+};
+
+static RE_UINT8 re_logical_order_exception_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_logical_order_exception_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,  31,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 224,   4,   0,   0,   0,   0,   0,   0,  96,  26,
+};
+
+/* Logical_Order_Exception: 145 bytes. */
+
+RE_UINT32 re_get_logical_order_exception(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_logical_order_exception_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_logical_order_exception_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_logical_order_exception_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_logical_order_exception_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_logical_order_exception_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Other_ID_Start. */
+
+static RE_UINT8 re_other_id_start_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_other_id_start_stage_2[] = {
+    0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_other_id_start_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_other_id_start_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+    0, 0, 2, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_other_id_start_stage_5[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0, 64,  0,  0,
+     0,  0,  0, 24,  0,  0,  0,  0,
+};
+
+/* Other_ID_Start: 113 bytes. */
+
+RE_UINT32 re_get_other_id_start(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_other_id_start_stage_1[f] << 3;
+    f = code >> 13;
+    code ^= f << 13;
+    pos = (RE_UINT32)re_other_id_start_stage_2[pos + f] << 4;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_other_id_start_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_other_id_start_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_other_id_start_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Other_ID_Continue. */
+
+static RE_UINT8 re_other_id_continue_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_other_id_continue_stage_2[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_other_id_continue_stage_3[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 4, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_other_id_continue_stage_4[] = {
+    0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 4,
+};
+
+static RE_UINT8 re_other_id_continue_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 128,   0,
+    128,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 254,   3,   0,
+      0,   0,   0,   4,   0,   0,   0,   0,
+};
+
+/* Other_ID_Continue: 145 bytes. */
+
+RE_UINT32 re_get_other_id_continue(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_other_id_continue_stage_1[f] << 3;
+    f = code >> 13;
+    code ^= f << 13;
+    pos = (RE_UINT32)re_other_id_continue_stage_2[pos + f] << 4;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_other_id_continue_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_other_id_continue_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_other_id_continue_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* STerm. */
+
+static RE_UINT8 re_sterm_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_sterm_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  8,  9,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10,
+     7, 11, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 13,  7,  7,
+     7,  7,  7,  7,  7,  7,  7, 14,  7,  7,  7, 15,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+};
+
+static RE_UINT8 re_sterm_stage_3[] = {
+     0,  1,  1,  1,  1,  2,  3,  4,  1,  5,  1,  1,  1,  1,  1,  1,
+     6,  1,  1,  7,  1,  1,  8,  9, 10, 11, 12, 13, 14,  1,  1,  1,
+    15,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 16,  1,
+    17,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1, 18,  1, 19,  1, 20, 21, 22, 23,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1, 24, 25,  1,  1, 26,  1,  1,  1,  1,  1,
+    27, 28, 29,  1,  1, 30, 31, 32,  1,  1, 33, 34,  1,  1,  1,  1,
+     1,  1,  1,  1, 35,  1,  1,  1,  1,  1, 36,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_sterm_stage_4[] = {
+     0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  2,  0,  0,  0,  3,  0,  0,  0,  0,  0,  4,  0,
+     5,  0,  0,  0,  0,  0,  0,  6,  0,  0,  0,  7,  0,  0,  0,  0,
+     0,  0,  8,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,
+     0,  0,  0, 10,  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,
+    12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 13,  0,  0,  0,  0, 14,  0,  0,  0,  0,  0,
+     0, 15,  0, 16,  0,  0,  0,  0,  0, 17, 18,  0,  0,  0,  0,  0,
+     0, 19,  0,  0,  0,  0,  0,  0, 20,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  3, 21,  0,  0,  0,  0,  0,  0, 22,
+     0,  0,  0, 23,  0,  0, 21,  0,  0, 24,  0,  0,  0,  0, 25,  0,
+     0,  0, 26,  0,  0,  0,  0, 27,  0,  0,  0,  0,  0,  0,  0, 28,
+     0,  0, 29,  0,  0,  0,  0,  0,  1,  0,  0, 30,  0,  0,  0,  0,
+     0,  0, 23,  0,  0,  0,  0,  0,  0,  0, 31,  0,  0, 16, 32,  0,
+     0,  0, 33,  0,  0,  0, 34,  0,  0, 35,  0,  0,  0,  2,  0,  0,
+     0,  0,  0,  0,  0,  0, 36,  0,  0,  0, 37,  0,  0,  0,  0,  0,
+     0, 38,  0,  0,  0,  0,  0,  0,  0,  0,  0, 21,  0,  0,  0, 39,
+     0, 40, 41,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,  0,  0,  0,
+     0,  0,  0,  0, 42,  0,  0,  0,
+};
+
+static RE_UINT8 re_sterm_stage_5[] = {
+      0,   0,   0,   0,   2,  64,   0, 128,   0,   2,   0,   0,   0,   0,   0, 128,
+      0,   0,  16,   0,   7,   0,   0,   0,   0,   0,   0,   2,  48,   0,   0,   0,
+      0,  12,   0,   0, 132,   1,   0,   0,   0,  64,   0,   0,   0,   0,  96,   0,
+      8,   2,   0,   0,   0,  15,   0,   0,   0,   0,   0, 204,   0,   0,   0,  24,
+      0,   0,   0, 192,   0,   0,   0,  48, 128,   3,   0,   0,   0,  64,   0,  16,
+      4,   0,   0,   0,   0, 192,   0,   0,   0,   0, 136,   0,   0,   0, 192,   0,
+      0, 128,   0,   0,   0,   3,   0,   0,   0,   0,   0, 224,   0,   0,   3,   0,
+      0,   8,   0,   0,   0,   0, 196,   0,   2,   0,   0,   0, 128,   1,   0,   0,
+      3,   0,   0,   0,  14,   0,   0,   0,  96,  32,   0, 192,   0,   0,   0,  27,
+     12, 254, 255,   0,   6,   0,   0,   0,   0,   0,   0, 112,   0,   0,  32,   0,
+      0,   0, 128,   1,  16,   0,   0,   0,   0,   1,   0,   0,
+};
+
+/* STerm: 709 bytes. */
+
+RE_UINT32 re_get_sterm(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_sterm_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_sterm_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_sterm_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_sterm_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_sterm_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Variation_Selector. */
+
+static RE_UINT8 re_variation_selector_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+    1,
+};
+
+static RE_UINT8 re_variation_selector_stage_2[] = {
+    0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_variation_selector_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_variation_selector_stage_4[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+    2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 4,
+};
+
+static RE_UINT8 re_variation_selector_stage_5[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,  56,   0,   0,   0,   0,   0,   0,
+    255, 255,   0,   0,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255,   0,   0,
+};
+
+/* Variation_Selector: 169 bytes. */
+
+RE_UINT32 re_get_variation_selector(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_variation_selector_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_variation_selector_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_variation_selector_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_variation_selector_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_variation_selector_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Pattern_White_Space. */
+
+static RE_UINT8 re_pattern_white_space_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_pattern_white_space_stage_2[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_pattern_white_space_stage_3[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_pattern_white_space_stage_4[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    3, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_pattern_white_space_stage_5[] = {
+      0,  62,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     32,   0,   0,   0,   0,   0,   0,   0,   0, 192,   0,   0,   0,   3,   0,   0,
+};
+
+/* Pattern_White_Space: 129 bytes. */
+
+RE_UINT32 re_get_pattern_white_space(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_pattern_white_space_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_pattern_white_space_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_pattern_white_space_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_pattern_white_space_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_pattern_white_space_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Pattern_Syntax. */
+
+static RE_UINT8 re_pattern_syntax_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_pattern_syntax_stage_2[] = {
+    0, 1, 1, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_pattern_syntax_stage_3[] = {
+     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     2,  3,  4,  4,  5,  4,  4,  6,  4,  4,  4,  4,  1,  1,  7,  1,
+     8,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  9, 10,  1,
+};
+
+static RE_UINT8 re_pattern_syntax_stage_4[] = {
+     0,  1,  2,  2,  0,  3,  4,  4,  0,  0,  0,  0,  0,  0,  0,  0,
+     5,  6,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  8,  8,  8,
+     8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,
+     8,  8,  8,  9, 10,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,
+    11, 12,  0,  0,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,  0,  0,
+     0,  0, 14,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_pattern_syntax_stage_5[] = {
+      0,   0,   0,   0, 254, 255,   0, 252,   1,   0,   0, 120, 254,  90,  67, 136,
+      0,   0, 128,   0,   0,   0, 255, 255, 255,   0, 255, 127, 254, 255, 239, 127,
+    255, 255, 255, 255, 255, 255,  63,   0,   0,   0, 240, 255,  14, 255, 255, 255,
+      1,   0,   1,   0,   0,   0,   0, 192,  96,   0,   0,   0,
+};
+
+/* Pattern_Syntax: 277 bytes. */
+
+RE_UINT32 re_get_pattern_syntax(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_pattern_syntax_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_pattern_syntax_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_pattern_syntax_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_pattern_syntax_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_pattern_syntax_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Hangul_Syllable_Type. */
+
+static RE_UINT8 re_hangul_syllable_type_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_hangul_syllable_type_stage_2[] = {
+    0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_hangul_syllable_type_stage_3[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  1,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  3,  0,  0,  0,  0,  0,  4,  5,  6,  7,  8,  9, 10,  4,
+     5,  6,  7,  8,  9, 10,  4,  5,  6,  7,  8,  9, 10,  4,  5,  6,
+     7,  8,  9, 10,  4,  5,  6,  7,  8,  9, 10,  4,  5,  6,  7,  8,
+     9, 10,  4,  5,  6,  7,  8,  9, 10,  4,  5,  6,  7,  8,  9, 10,
+     4,  5,  6,  7,  8,  9, 10,  4,  5,  6,  7,  8,  9, 10,  4,  5,
+     6,  7,  8,  9, 10,  4,  5,  6,  7,  8,  9, 10,  4,  5,  6, 11,
+};
+
+static RE_UINT8 re_hangul_syllable_type_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  4,
+     5,  6,  6,  7,  6,  6,  6,  5,  6,  6,  7,  6,  6,  6,  5,  6,
+     6,  7,  6,  6,  6,  5,  6,  6,  7,  6,  6,  6,  5,  6,  6,  7,
+     6,  6,  6,  5,  6,  6,  7,  6,  6,  6,  5,  6,  6,  7,  6,  6,
+     6,  5,  6,  6,  7,  6,  6,  6,  5,  6,  6,  7,  6,  6,  6,  5,
+     6,  6,  7,  6,  6,  6,  5,  6,  6,  7,  6,  6,  6,  5,  6,  6,
+     7,  6,  6,  6,  5,  6,  6,  7,  6,  6,  6,  5,  6,  6,  7,  6,
+     6,  6,  5,  6,  6,  7,  6,  6,  6,  5,  6,  6,  7,  6,  6,  6,
+     6,  5,  6,  6,  8,  0,  2,  2,  9, 10,  3,  3,  3,  3,  3, 11,
+};
+
+static RE_UINT8 re_hangul_syllable_type_stage_5[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+    1, 1, 1, 1, 1, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5,
+    5, 5, 5, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0,
+    0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0,
+};
+
+/* Hangul_Syllable_Type: 497 bytes. */
+
+RE_UINT32 re_get_hangul_syllable_type(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_hangul_syllable_type_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_hangul_syllable_type_stage_2[pos + f] << 4;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_hangul_syllable_type_stage_3[pos + f] << 4;
+    f = code >> 3;
+    code ^= f << 3;
+    pos = (RE_UINT32)re_hangul_syllable_type_stage_4[pos + f] << 3;
+    value = re_hangul_syllable_type_stage_5[pos + code];
+
+    return value;
+}
+
+/* Bidi_Class. */
+
+static RE_UINT8 re_bidi_class_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  6,  5,  5,  5,  5,  7,
+     8,  9,  5,  5,  5,  5, 10,  5,  5,  5,  5, 11,  5, 12, 13, 14,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+    16,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 15,
+};
+
+static RE_UINT8 re_bidi_class_stage_2[] = {
+      0,   1,   2,   2,   2,   3,   4,   5,   2,   6,   2,   7,   8,   9,  10,  11,
+     12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
+     28,  29,   2,   2,   2,   2,  30,  31,  32,   2,   2,   2,   2,  33,  34,  35,
+     36,  37,  38,  39,  40,  41,  42,  43,  44,  45,   2,  46,   2,   2,   2,  47,
+     48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  53,  53,  53,  58,  53,  53,
+      2,   2,  53,  53,  53,  53,  59,  60,   2,  61,  62,  63,  64,  65,  53,  66,
+     67,  68,   2,  69,  70,  71,  72,  73,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,  74,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,  75,   2,   2,  76,  77,  78,  79,
+     80,  81,  82,  83,  84,  85,   2,  86,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,  87,  88,  88,  88,  89,  90,  91,  92,  93,  94,
+      2,   2,  95,  96,   2,  97,  98,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+     99,  99, 100,  99, 101, 102, 103,  99,  99,  99,  99,  99, 104,  99,  99,  99,
+    105, 106, 107, 108, 109, 110, 111,   2,   2, 112,   2, 113, 114, 115, 116,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2, 117, 118,   2,   2,   2,   2,   2,   2,   2,   2, 119,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2, 120,   2,   2,   2,   2,   2,   2,
+      2,   2, 121, 122, 123,   2, 124,   2,   2,   2,   2,   2,   2, 125, 126, 127,
+      2,   2,   2,   2, 128, 129,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+     99, 130,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  88, 131,  99,  99,
+    132, 133, 134,   2,   2,   2,  53,  53,  53,  53, 135, 136,  53, 137, 138, 139,
+    140, 141, 142, 143,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 144,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 144,
+    145, 145, 146, 147, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+    145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+};
+
+static RE_UINT8 re_bidi_class_stage_3[] = {
+      0,   1,   2,   3,   4,   5,   4,   6,   7,   8,   9,  10,  11,  12,  11,  12,
+     11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  13,  14,  14,  15,  16,
+     17,  17,  17,  17,  17,  17,  17,  18,  19,  11,  11,  11,  11,  11,  11,  20,
+     21,  11,  11,  11,  11,  11,  11,  11,  22,  23,  17,  24,  25,  26,  26,  26,
+     27,  28,  29,  29,  30,  17,  31,  32,  29,  29,  29,  29,  29,  33,  34,  35,
+     29,  36,  29,  17,  28,  29,  29,  29,  29,  29,  37,  32,  26,  26,  38,  39,
+     26,  40,  41,  26,  26,  42,  26,  26,  26,  26,  29,  29,  29,  29,  43,  17,
+     44,  11,  11,  45,  46,  47,  48,  11,  49,  11,  11,  50,  51,  11,  48,  52,
+     53,  11,  11,  50,  54,  49,  11,  55,  53,  11,  11,  50,  56,  11,  48,  57,
+     49,  11,  11,  58,  51,  59,  48,  11,  60,  11,  11,  11,  61,  11,  11,  62,
+     63,  11,  11,  64,  65,  66,  48,  67,  49,  11,  11,  50,  68,  11,  48,  11,
+     49,  11,  11,  11,  51,  11,  48,  11,  11,  11,  11,  11,  69,  70,  11,  11,
+     11,  11,  11,  71,  72,  11,  11,  11,  11,  11,  11,  73,  74,  11,  11,  11,
+     11,  75,  11,  76,  11,  11,  11,  77,  78,  79,  17,  80,  59,  11,  11,  11,
+     11,  11,  81,  82,  11,  83,  63,  84,  85,  86,  11,  11,  11,  11,  11,  11,
+     11,  11,  11,  11,  11,  81,  11,  11,  11,  87,  11,  11,  11,  11,  11,  11,
+      4,  11,  11,  11,  11,  11,  11,  11,  88,  89,  11,  11,  11,  11,  11,  11,
+     11,  90,  11,  90,  11,  48,  11,  48,  11,  11,  11,  91,  92,  93,  11,  87,
+     94,  11,  11,  11,  11,  11,  11,  11,  11,  11,  95,  11,  11,  11,  11,  11,
+     11,  11,  96,  97,  98,  11,  11,  11,  11,  11,  11,  11,  11,  99,  16,  16,
+     11, 100,  11,  11,  11, 101, 102, 103,  11,  11,  11, 104,  11,  11,  11,  11,
+    105,  11,  11, 106,  60,  11, 107, 105, 108,  11, 109,  11,  11,  11, 110, 108,
+     11,  11, 111, 112,  11,  11,  11,  11,  11,  11,  11,  11,  11, 113, 114, 115,
+     11,  11,  11,  11,  17,  17,  17, 116,  11,  11,  11, 117, 118, 119, 119, 120,
+    121,  16, 122, 123, 124, 125, 126, 127, 128,  11, 129, 129, 129,  17,  17,  63,
+    130, 131, 132, 133, 134,  16,  11,  11, 135,  16,  16,  16,  16,  16,  16,  16,
+     16, 136,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,
+     16,  16,  16, 137,  11,  11,  11,   5,  16, 138,  16,  16,  16,  16,  16, 139,
+     16,  16, 140,  11, 139,  11,  16,  16, 141, 142,  11,  11,  11,  11, 143,  16,
+     16,  16, 144,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16, 145,
+     16, 146,  16, 147, 148, 149, 150,  11,  11,  11,  11,  11,  11,  11, 151, 152,
+     11,  11,  11,  11,  11,  11,  11, 153,  11,  11,  11,  11,  11,  11,  17,  17,
+     16,  16,  16,  16, 154,  11,  11,  11,  16, 155,  16,  16,  16,  16,  16, 156,
+     16,  16,  16,  16,  16, 137,  11, 157, 158,  16, 159, 160,  11,  11,  11,  11,
+     11, 161,   4,  11,  11,  11,  11, 162,  11,  11,  11,  11,  16,  16, 156,  11,
+     11, 120,  11,  11,  11,  16,  11, 163,  11,  11,  11, 164, 150,  11,  11,  11,
+     11,  11,  11,  11,  11,  11,  11, 165,  11,  11,  11,  11,  11,  99,  11, 166,
+     11,  11,  11,  11,  16,  16,  16,  16,  11,  16,  16,  16, 140,  11,  11,  11,
+    119,  11,  11,  11,  11,  11, 153, 167,  11,  64,  11,  11,  11,  11,  11, 108,
+     16,  16, 149,  11,  11,  11,  11,  11, 168,  11,  11,  11,  11,  11,  11,  11,
+    169,  11, 170, 171,  11,  11,  11, 172,  11,  11,  11,  11, 173,  11,  17, 108,
+     11,  11, 174,  11, 175, 108,  11,  11,  44,  11,  11, 176,  11,  11, 177,  11,
+     11,  11, 178, 179, 180,  11,  11,  50,  11,  11,  11, 181,  49,  11,  68,  59,
+     11,  11,  11,  11,  11,  11, 182,  11,  11, 183, 184,  26,  26,  29,  29,  29,
+     29,  29,  29,  29,  29,  29,  29,  29,  29,  29,  29, 185,  29,  29,  29,  29,
+     29,  29,  29,  29,  29,   8,   8, 186,  17,  87,  17,  16,  16, 187, 188,  29,
+     29,  29,  29,  29,  29,  29,  29, 189, 190,   3,   4,   5,   4,   5, 137,  11,
+     11,  11,  11,  11,  11,  11, 191, 192, 193,  11,  11,  11,  16,  16,  16,  16,
+    194, 157,   4,  11,  11,  11,  11,  86,  11,  11,  11,  11,  11,  11, 195, 142,
+     11,  11,  11,  11,  11,  11,  11, 196,  26,  26,  26,  26,  26,  26,  26,  26,
+     26, 197,  26,  26,  26,  26,  26,  26, 198,  26,  26, 199,  26,  26,  26,  26,
+     26,  26,  26,  26,  26,  26, 200,  26,  26,  26,  26, 201,  26,  26,  26,  26,
+     26,  26,  26,  26,  26,  26, 202, 203,  49,  11,  11, 204, 205,  14, 137, 153,
+    108,  11,  11, 206,  11,  11,  11,  11,  44,  11, 207, 208,  11,  11,  11, 209,
+    108,  11,  11, 210, 211,  11,  11,  11,  11,  11, 153, 212,  11,  11,  11,  11,
+     11,  11,  11,  11,  11, 153, 213,  11, 108,  11,  11,  50,  63,  11, 214, 208,
+     11,  11,  11, 215, 216,  11,  11,  11,  11,  11,  11, 217,  63,  68,  11,  11,
+     11,  11,  11, 218,  63,  11,  11,  11,  11,  11, 219, 220,  11,  11,  11,  11,
+     11,  81, 221,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11, 208,
+     11,  11,  11, 205,  11,  11,  11,  11, 153,  44,  11,  11,  11,  11,  11,  11,
+     11, 222, 223,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11,  11, 224, 225,
+    226,  11, 227,  11,  11,  11,  11,  11,  16,  16,  16,  16, 228,  11,  11,  11,
+     16,  16,  16,  16,  16, 140,  11,  11,  11,  11,  11,  11,  11, 162,  11,  11,
+     11, 229,  11,  11, 166,  11,  11,  11, 230,  11,  11,  11, 231, 232, 232, 232,
+     17,  17,  17, 233,  17,  17,  80, 177, 173, 107, 234,  11,  11,  11,  11,  11,
+     26,  26,  26,  26,  26, 235,  26,  26,  29,  29,  29,  29,  29,  29,  29, 236,
+     16,  16, 157,  16,  16,  16,  16,  16,  16, 156, 237, 164, 164, 164,  16, 137,
+    238,  11,  11,  11,  11,  11, 133,  11,  16,  16,  16,  16,  16,  16,  16, 155,
+     16,  16, 239,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,   4, 194, 156,
+     16,  16,  16,  16,  16,  16,  16, 156,  16,  16,  16,  16,  16, 240,  11,  11,
+    157,  16,  16,  16, 241,  87,  16,  16, 241,  16, 242,  11,  11,  11,  11,  11,
+     11, 243,  11,  11,  11,  11,  11,  11, 240,  11,  11,  11,   4,  11,  11,  11,
+     11,  11,  11,  11,  11,  11,  11, 244,   8,   8,   8,   8,   8,   8,   8,   8,
+     17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,   8,
+};
+
+static RE_UINT8 re_bidi_class_stage_4[] = {
+      0,   0,   1,   2,   0,   0,   0,   3,   4,   5,   6,   7,   8,   8,   9,  10,
+     11,  12,  12,  12,  12,  12,  13,  10,  12,  12,  13,  14,   0,  15,   0,   0,
+      0,   0,   0,   0,  16,   5,  17,  18,  19,  20,  21,  10,  12,  12,  12,  12,
+     12,  13,  12,  12,  12,  12,  22,  12,  23,  10,  10,  10,  12,  24,  10,  17,
+     10,  10,  10,  10,  25,  25,  25,  25,  12,  26,  12,  27,  12,  17,  12,  12,
+     12,  27,  12,  12,  28,  25,  29,  12,  12,  12,  27,  30,  31,  25,  25,  25,
+     25,  25,  25,  32,  33,  32,  34,  34,  34,  34,  34,  34,  35,  36,  37,  38,
+     25,  25,  39,  40,  40,  40,  40,  40,  40,  40,  41,  25,  35,  35,  42,  43,
+     44,  40,  40,  40,  40,  45,  25,  46,  25,  47,  48,  49,   8,   8,  50,  40,
+     51,  40,  40,  40,  40,  45,  25,  25,  34,  34,  52,  25,  25,  53,  54,  34,
+     34,  55,  32,  25,  25,  31,  31,  56,  34,  34,  31,  34,  41,  25,  25,  25,
+     57,  12,  12,  12,  12,  12,  58,  59,  60,  25,  59,  61,  60,  25,  12,  12,
+     62,  12,  12,  12,  61,  12,  12,  12,  12,  12,  12,  59,  60,  59,  12,  61,
+     63,  12,  64,  12,  65,  12,  12,  12,  65,  28,  66,  29,  29,  61,  12,  12,
+     60,  67,  59,  61,  68,  12,  12,  12,  12,  12,  12,  66,  12,  58,  12,  12,
+     58,  12,  12,  12,  59,  12,  12,  61,  13,  10,  69,  12,  59,  12,  12,  12,
+     12,  12,  12,  62,  59,  62,  70,  29,  12,  65,  12,  12,  12,  12,  10,  71,
+     12,  12,  12,  29,  12,  12,  58,  12,  62,  72,  12,  12,  61,  25,  57,  64,
+     12,  28,  25,  57,  61,  25,  67,  59,  12,  12,  25,  29,  12,  12,  29,  12,
+     12,  73,  74,  26,  60,  25,  25,  57,  25,  70,  12,  60,  25,  25,  60,  25,
+     25,  25,  25,  59,  12,  12,  12,  60,  70,  25,  65,  65,  12,  12,  29,  62,
+     60,  59,  12,  12,  58,  65,  12,  61,  12,  12,  12,  61,  10,  10,  26,  12,
+     75,  12,  12,  12,  12,  12,  13,  11,  62,  59,  12,  12,  12,  67,  25,  29,
+     12,  58,  60,  25,  25,  12,  64,  61,  10,  10,  76,  77,  12,  12,  61,  12,
+     57,  28,  59,  12,  58,  12,  60,  12,  11,  26,  12,  12,  12,  12,  12,  23,
+     12,  28,  66,  12,  12,  58,  25,  57,  72,  60,  25,  59,  28,  25,  25,  66,
+     25,  25,  25,  57,  25,  12,  12,  12,  12,  70,  57,  59,  12,  12,  28,  25,
+     29,  12,  12,  12,  62,  29,  67,  29,  12,  58,  29,  73,  12,  12,  12,  25,
+     25,  62,  12,  12,  57,  25,  25,  25,  70,  25,  59,  61,  12,  59,  29,  12,
+     25,  29,  12,  25,  12,  12,  12,  78,  26,  12,  12,  24,  12,  12,  12,  24,
+     12,  12,  12,  22,  79,  79,  80,  81,  10,  10,  82,  83,  84,  85,  10,  10,
+     10,  86,  10,  10,  10,  10,  10,  87,   0,  88,  89,   0,  90,   8,  91,  71,
+      8,   8,  91,  71,  84,  84,  84,  84,  17,  71,  26,  12,  12,  20,  11,  23,
+     10,  78,  92,  93,  12,  12,  23,  12,  10,  11,  23,  26,  12,  12,  24,  12,
+     94,  10,  10,  10,  10,  26,  12,  12,  10,  20,  10,  10,  10,  10,  71,  12,
+     10,  71,  12,  12,  10,  10,   8,   8,   8,   8,   8,  12,  12,  12,  23,  10,
+     10,  10,  10,  24,  10,  23,  10,  10,  10,  26,  10,  10,  10,  10,  26,  24,
+     10,  10,  20,  10,  26,  12,  12,  12,  12,  12,  12,  10,  12,  24,  71,  28,
+     29,  12,  24,  10,  12,  12,  12,  28,  71,  12,  12,  12,  10,  10,  17,  10,
+     10,  12,  12,  12,  10,  10,  10,  12,  95,  11,  10,  10,  11,  12,  62,  29,
+     11,  23,  12,  24,  12,  12,  96,  11,  12,  12,  13,  12,  12,  12,  12,  71,
+     24,  10,  10,  10,  12,  13,  71,  12,  12,  12,  12,  13,  97,  25,  25,  98,
+     12,  12,  11,  12,  58,  58,  28,  12,  12,  65,  10,  12,  12,  12,  99,  12,
+     12,  10,  12,  12,  12,  59,  12,  12,  12,  62,  25,  29,  12,  28,  25,  25,
+     28,  62,  29,  59,  12,  61,  12,  12,  12,  12,  60,  57,  65,  65,  12,  12,
+     28,  12,  12,  59,  70,  66,  59,  62,  12,  61,  59,  61,  12,  12,  12, 100,
+     34,  34, 101,  34,  40,  40,  40, 102,  40,  40,  40, 103, 104, 105,  10, 106,
+    107,  71, 108,  12,  40,  40,  40, 109,  30,   5,   6,   7,   5, 110,  10,  71,
+      0,   0, 111, 112,  92,  12,  12,  12,  10,  10,  10,  11, 113,   8,   8,   8,
+     12,  62,  57,  12,  34,  34,  34, 114,  31,  33,  34,  25,  34,  34, 115,  52,
+     34,  33,  34,  34,  34,  34, 116,  10,  35,  35,  35,  35,  35,  35,  35, 117,
+     12,  12,  25,  25,  25,  57,  12,  12,  28,  57,  65,  12,  12,  28,  25,  60,
+     25,  59,  12,  12,  28,  12,  12,  12,  12,  62,  25,  57,  12,  12,  62,  59,
+     29,  70,  12,  12,  28,  25,  57,  12,  12,  62,  25,  59,  28,  25,  72,  28,
+     70,  12,  12,  12,  62,  29,  12,  67,  28,  25,  57,  73,  12,  12,  28,  61,
+     25,  67,  12,  12,  62,  67,  25,  12,  12,  12,  12,  65,   0,  12,  12,  12,
+     12,  28,  29,  12, 118,   0, 119,  25,  57,  60,  25,  12,  12,  12,  62,  29,
+    120, 121,  12,  12,  12,  92,  12,  12,  12,  12,  92,  12,  13,  12,  12, 122,
+      8,   8,   8,   8,  25,  57,  28,  25,  60,  25,  25,  25,  25, 115,  34,  34,
+    123,  40,  40,  40,  10,  10,  10,  71,   8,   8, 124,  11,  10,  24,  10,  10,
+     10,  11,  12,  12,  10,  10,  12,  12,  10,  10,  10,  26,  10,  10,  11,  12,
+     12,  12,  12, 125,
+};
+
+static RE_UINT8 re_bidi_class_stage_5[] = {
+    11, 11, 11, 11, 11,  8,  7,  8,  9,  7, 11, 11,  7,  7,  7,  8,
+     9, 10, 10,  4,  4,  4, 10, 10, 10, 10, 10,  3,  6,  3,  6,  6,
+     2,  2,  2,  2,  2,  2,  6, 10, 10, 10, 10, 10, 10,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0, 10, 10, 10, 10, 11, 11,  7, 11, 11,
+     6, 10,  4,  4, 10, 10,  0, 10, 10, 11, 10, 10,  4,  4,  2,  2,
+    10,  0, 10, 10, 10,  2,  0, 10,  0, 10, 10,  0,  0,  0, 10, 10,
+     0, 10, 10, 10, 12, 12, 12, 12, 10, 10,  0,  0,  0,  0, 10,  0,
+     0,  0,  0, 12, 12, 12,  0,  0,  0, 10, 10,  4,  1, 12, 12, 12,
+    12, 12,  1, 12,  1, 12, 12,  1,  1,  1,  1,  1,  5,  5,  5,  5,
+     5,  5, 10, 10, 13,  4,  4, 13,  6, 13, 10, 10, 12, 12, 12, 13,
+    13, 13, 13, 13, 13, 13, 13, 12,  5,  5,  4,  5,  5, 13, 13, 13,
+    12, 13, 13, 13, 13, 13, 12, 12, 12,  5, 10, 12, 12, 13, 13, 12,
+    12, 10, 12, 12, 12, 12, 13, 13,  2,  2, 13, 13, 13, 12, 13, 13,
+     1,  1,  1, 12,  1,  1, 10, 10, 10, 10,  1,  1,  1,  1, 12, 12,
+    12, 12,  1,  1, 12, 12, 12,  0,  0,  0, 12,  0, 12,  0,  0,  0,
+     0, 12, 12, 12,  0, 12,  0,  0,  0,  0, 12, 12,  0,  0,  4,  4,
+     0,  0,  0,  4,  0, 12, 12,  0, 12,  0,  0, 12, 12, 12,  0, 12,
+     0,  4,  0,  0, 10,  4, 10,  0, 12,  0, 12, 12, 10, 10, 10,  0,
+    12,  0, 12,  0,  0, 12,  0, 12,  0, 12, 10, 10,  9,  0,  0,  0,
+    10, 10, 10, 12, 12, 12, 11,  0,  0, 10,  0, 10,  9,  9,  9,  9,
+     9,  9,  9, 11, 11, 11,  0,  1,  9,  7, 16, 17, 18, 14, 15,  6,
+     4,  4,  4,  4,  4, 10, 10, 10,  6, 10, 10, 10, 10, 10, 10,  9,
+    11, 11, 19, 20, 21, 22, 11, 11,  2,  0,  0,  0,  2,  2,  3,  3,
+     0, 10,  0,  0,  0,  0,  4,  0, 10, 10,  3,  4,  9, 10, 10, 10,
+     0, 12, 12, 10, 12, 12, 12, 10, 12, 12, 10, 10,  4,  4,  0,  0,
+     0,  1, 12,  1,  1,  3,  1,  1, 13, 13, 10, 10, 13, 10, 13, 13,
+     6, 10,  6,  0, 10,  6, 10, 10, 10, 10, 10,  4, 10, 10,  3,  3,
+    10,  4,  4, 10, 13, 13, 13, 11, 10,  4,  4,  0, 11, 10, 10, 10,
+    10, 10, 11, 11, 12,  2,  2,  2,  1,  1,  1, 10, 12, 12, 12,  1,
+     1, 10, 10, 10,  5,  5,  5,  1,  0,  0,  0, 11, 11, 11, 11, 12,
+    10, 10, 12, 12, 12, 10,  0,  0,  0,  0,  2,  2, 10, 10, 13, 13,
+     2,  2,  2, 10,  0,  0, 11, 11,
+};
+
+/* Bidi_Class: 3484 bytes. */
+
+RE_UINT32 re_get_bidi_class(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_bidi_class_stage_1[f] << 5;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_bidi_class_stage_2[pos + f] << 3;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_bidi_class_stage_3[pos + f] << 2;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_bidi_class_stage_4[pos + f] << 2;
+    value = re_bidi_class_stage_5[pos + code];
+
+    return value;
+}
+
+/* Canonical_Combining_Class. */
+
+static RE_UINT8 re_canonical_combining_class_stage_1[] = {
+    0, 1, 2, 2, 2, 3, 2, 4, 5, 2, 2, 6, 2, 7, 8, 9,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_canonical_combining_class_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0, 10, 11, 12, 13,  0,
+    14,  0,  0,  0,  0,  0, 15,  0, 16,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0, 17, 18, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,  0, 21,
+    22, 23,  0,  0,  0, 24,  0,  0, 25, 26, 27, 28,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 29,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 30,  0,
+     0,  0,  0,  0,  0,  0,  0,  0, 31, 32,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 33,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_canonical_combining_class_stage_3[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   3,   4,   0,   0,   0,   0,
+      0,   0,   0,   0,   5,   0,   0,   0,   0,   0,   0,   0,   6,   7,   8,   0,
+      9,   0,  10,  11,   0,   0,  12,  13,  14,  15,  16,   0,   0,   0,   0,  17,
+     18,  19,  20,   0,   0,   0,   0,  21,   0,  22,  23,   0,   0,  22,  24,   0,
+      0,  22,  24,   0,   0,  22,  24,   0,   0,  22,  24,   0,   0,   0,  24,   0,
+      0,   0,  25,   0,   0,  22,  24,   0,   0,   0,  24,   0,   0,   0,  26,   0,
+      0,  27,  28,   0,   0,  29,  30,   0,  31,  32,   0,  33,  34,   0,  35,   0,
+      0,  36,   0,   0,  37,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  38,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,  39,  39,   0,   0,   0,   0,  40,   0,
+      0,   0,   0,   0,   0,  41,   0,   0,   0,  42,   0,   0,   0,   0,   0,   0,
+     43,   0,   0,  44,   0,  45,   0,   0,   0,  46,  47,  48,   0,  49,   0,  50,
+      0,  51,   0,   0,   0,   0,  52,  53,   0,   0,   0,   0,   0,   0,  54,  55,
+      0,   0,   0,   0,   0,   0,  56,  57,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  58,   0,   0,   0,  59,   0,   0,   0,  60,
+      0,  61,   0,   0,  62,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,  63,  64,   0,   0,  65,   0,   0,   0,   0,   0,   0,   0,   0,
+     66,   0,   0,   0,   0,   0,  47,  67,   0,  68,  69,   0,   0,  70,  71,   0,
+      0,   0,   0,   0,   0,  72,  73,  74,   0,   0,   0,   0,   0,   0,   0,  24,
+      0,   0,   0,   0,   0,   0,   0,   0,  75,   0,   0,   0,   0,   0,   0,   0,
+      0,  76,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  77,
+      0,   0,   0,   0,   0,   0,   0,  78,   0,   0,   0,  79,   0,   0,   0,   0,
+     80,  81,   0,   0,   0,   0,   0,  82,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,  66,  59,   0,  83,   0,   0,  84,  85,   0,  70,   0,   0,  86,   0,
+      0,  87,   0,   0,   0,   0,   0,  88,   0,  22,  24,  89,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,  90,   0,   0,   0,   0,   0,   0,  59,  91,   0,
+      0,  59,   0,   0,   0,  92,   0,   0,   0,  93,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  94,   0,  95,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  96,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  97,  98,  99,   0,   0,
+      0,   0, 100,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 101,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_canonical_combining_class_stage_4[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   2,   3,   4,
+      5,   6,   7,   4,   4,   8,   9,  10,   1,  11,  12,  13,  14,  15,  16,  17,
+     18,   1,   1,   1,   0,   0,   0,   0,  19,   1,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  20,  21,  22,   1,  23,   4,  21,  24,  25,  26,  27,  28,
+     29,  30,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,  31,   0,
+      0,   0,  32,  33,  34,  35,   1,  36,   0,   0,   0,   0,  37,   0,   0,   0,
+      0,   0,   0,   0,   0,  38,   1,  39,  14,  39,  40,  41,   0,   0,   0,   0,
+      0,   0,   0,   0,  42,   0,   0,   0,   0,   0,   0,   0,  43,  36,  44,  45,
+     21,  45,  46,   0,   0,   0,   0,   0,   0,   0,  19,   1,  21,   0,   0,   0,
+      0,   0,   0,   0,   0,  38,  47,   1,   1,  48,  48,  49,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,  50,   0,  51,  21,  43,  52,  53,  21,  35,   1,
+      0,   0,   0,   0,   0,   0,   0,  54,   0,   0,   0,  55,  56,  57,   0,   0,
+      0,   0,   0,  55,   0,   0,   0,   0,   0,   0,   0,  55,   0,  58,   0,   0,
+      0,   0,  59,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  60,   0,
+      0,   0,  61,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  62,   0,
+      0,   0,  63,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  64,   0,
+      0,   0,   0,   0,   0,  65,  66,   0,   0,   0,   0,   0,  67,  68,  69,  70,
+     71,  72,   0,   0,   0,   0,   0,   0,   0,  73,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,  74,  75,   0,   0,   0,   0,  76,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  48,   0,   0,   0,   0,   0,  77,   0,   0,
+      0,   0,   0,   0,  59,   0,   0,  78,   0,   0,  79,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,  80,   0,   0,   0,   0,   0,   0,  19,  81,   0,
+     77,   0,   0,   0,   0,  48,   1,  82,   0,   0,   0,   0,   1,  52,  15,  41,
+      0,   0,   0,   0,   0,  54,   0,   0,   0,  77,   0,   0,   0,   0,   0,   0,
+      0,   0,  19,  10,   1,   0,   0,   0,   0,   0,  83,   0,   0,   0,   0,   0,
+      0,  84,   0,   0,  83,   0,   0,   0,   0,   0,   0,   0,   0,  74,   0,   0,
+      0,   0,   0,   0,  85,   9,  12,   4,  86,   8,  87,  76,   0,  57,  49,   0,
+     21,   1,  21,  88,  89,   1,   1,   1,   1,   1,   1,   1,   1,  49,   0,  90,
+      0,   0,   0,   0,  91,   1,  92,  57,  78,  93,  94,   4,  57,   0,   0,   0,
+      0,   0,   0,  19,  49,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  95,
+      1,   1,   1,   1,   1,   1,   1,   1,   0,   0,  96,  97,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,  98,   0,   0,   0,   0,  19,   0,   1,   1,  49,
+      0,   0,   0,   0,   0,   0,   0,  38,   0,   0,   0,   0,  49,   0,   0,   0,
+      0,  59,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,  49,   0,   0,   0,
+      0,   0,  51,  64,   0,   0,   0,   0,   0,   0,   0,   0,  95,   0,   0,   0,
+      0,   0,   0,   0,  74,   0,   0,   0,  77,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  99, 100,  57,  38,  78,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,  59,   0,   0,   0,   0,   0,   0,   0,   0,   0, 101,
+      1,  14,   4,  12,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  76,
+     81,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  38,  85,   0,
+      0,   0,   0, 102,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 103,  95,
+      0, 104,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 105,   0,
+     85,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  95,  77,   0,   0,
+     77,   0,  84,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 105,   0,   0,
+      0,   0, 106,   0,   0,   0,   0,   0,   0,  38,   1,  57,   1,  57,   0,   0,
+    107,   0,   0,   0,   0,   0,   0,   0,  54,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 107,   0,   0,   0,   0,  95,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   8,  87,   0,   0,   0,   0,   0,   0,   1,  85,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 108,   0, 109, 110, 111, 112,   0,  51,   4,
+    113,  48,  23,   0,   0,   0,   0,   0,   0,   0,  38,  49,   0,   0,   0,   0,
+     38,  57,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   4, 113,   0,   0,
+};
+
+static RE_UINT8 re_canonical_combining_class_stage_5[] = {
+     0,  0,  0,  0, 50, 50, 50, 50, 50, 51, 45, 45, 45, 45, 51, 43,
+    45, 45, 45, 45, 45, 41, 41, 45, 45, 45, 45, 41, 41, 45, 45, 45,
+     1,  1,  1,  1,  1, 45, 45, 45, 45, 50, 50, 50, 50, 54, 50, 45,
+    45, 45, 50, 50, 50, 45, 45,  0, 50, 50, 50, 45, 45, 45, 45, 50,
+    51, 45, 45, 50, 52, 53, 53, 52, 53, 53, 52, 50,  0,  0,  0, 50,
+     0, 45, 50, 50, 50, 50, 45, 50, 50, 50, 46, 45, 50, 50, 45, 45,
+    50, 46, 49, 50,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 14, 15,
+    16, 17,  0, 18,  0, 19, 20,  0, 50, 45,  0, 13, 25, 26, 27,  0,
+     0,  0,  0, 22, 23, 24, 25, 26, 27, 28, 29, 50, 50, 45, 45, 50,
+    45, 50, 50, 45, 30,  0,  0,  0,  0,  0, 50, 50, 50,  0,  0, 50,
+    50,  0, 45, 50, 50, 45,  0,  0,  0, 31,  0,  0, 50, 45, 50, 50,
+    45, 45, 50, 45, 45, 50, 45, 50, 45, 50, 50,  0, 50, 50,  0, 50,
+     0, 50, 50, 50, 50, 50,  0,  0,  0, 45, 45, 45,  0,  0,  0, 45,
+    50, 45, 45, 45, 22, 23, 24, 50,  2,  0,  0,  0,  0,  4,  0,  0,
+     0, 50, 45, 50, 50,  0,  0,  0,  0, 32, 33,  0,  0,  0,  4,  0,
+    34, 34,  4,  0, 35, 35, 35, 35, 36, 36,  0,  0, 37, 37, 37, 37,
+    45, 45,  0,  0,  0, 45,  0, 45,  0, 43,  0,  0,  0, 38, 39,  0,
+    40,  0,  0,  0,  0,  0, 39, 39, 39, 39,  0,  0, 39,  0, 50, 50,
+     4,  0, 50, 50,  0,  0, 45,  0,  0,  0,  0,  2,  0,  4,  4,  0,
+     0, 45,  0,  0,  4,  0,  0,  0,  0, 50,  0,  0,  0, 49,  0,  0,
+     0, 46, 50, 45, 45,  0,  0,  0, 50,  0,  0, 45,  0,  0,  4,  4,
+     0,  0,  2,  0, 50, 50, 50,  0, 50,  0,  1,  1,  1,  0,  0,  0,
+    50, 53, 42, 45, 41, 50, 50, 50, 52, 45, 50, 45, 50, 50,  1,  1,
+     1,  1,  1, 50,  0,  1,  1, 50, 45, 50,  1,  1,  0,  0,  0,  4,
+     0,  0, 44, 49, 51, 46, 47, 47,  0,  3,  3,  0, 50,  0, 50, 50,
+    45,  0,  0, 50,  0,  0, 21,  0,  0, 45,  0, 50, 50,  1, 45,  0,
+     0, 50, 45,  0,  0,  4,  2,  0,  0,  2,  4,  0,  0,  0,  4,  2,
+     0,  0,  1,  0,  0, 43, 43,  1,  1,  1,  0,  0,  0, 48, 43, 43,
+    43, 43, 43,  0, 45, 45, 45,  0,
+};
+
+/* Canonical_Combining_Class: 2112 bytes. */
+
+RE_UINT32 re_get_canonical_combining_class(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 13;
+    code = ch ^ (f << 13);
+    pos = (RE_UINT32)re_canonical_combining_class_stage_1[f] << 4;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_canonical_combining_class_stage_2[pos + f] << 4;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_canonical_combining_class_stage_3[pos + f] << 3;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_canonical_combining_class_stage_4[pos + f] << 2;
+    value = re_canonical_combining_class_stage_5[pos + code];
+
+    return value;
+}
+
+/* Decomposition_Type. */
+
+static RE_UINT8 re_decomposition_type_stage_1[] = {
+    0, 1, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 2, 2, 7, 8,
+    2, 2, 2, 2, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_decomposition_type_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  9, 10, 11, 12, 13, 14,
+    15,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 16,  7, 17, 18, 19,
+    20, 21, 22, 23, 24,  7,  7,  7,  7,  7, 25,  7, 26, 27, 28, 29,
+    30, 31, 32, 33,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7, 34, 35,  7,  7,  7, 36, 37, 37, 37, 37,
+    37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+    37, 37, 37, 37, 37, 37, 37, 38,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7, 37, 39, 40, 41, 42, 43, 44,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    45, 46,  7, 47, 48, 49,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7, 50,  7,  7, 51, 52, 53, 54,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 55,  7,
+     7, 56, 57,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7, 37, 37, 58,  7,  7,  7,  7,  7,
+};
+
+static RE_UINT8 re_decomposition_type_stage_3[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   3,   4,   3,   5,
+      6,   7,   8,   9,  10,  11,   8,  12,   0,   0,  13,  14,  15,  16,  17,  18,
+      6,  19,  20,  21,   0,   0,   0,   0,   0,   0,   0,  22,   0,  23,  24,   0,
+      0,   0,   0,   0,  25,   0,   0,  26,  27,  14,  28,  14,  29,  30,   0,  31,
+     32,  33,   0,  33,   0,  32,   0,  34,   0,   0,   0,   0,  35,  36,  37,  38,
+      0,   0,   0,   0,   0,   0,   0,   0,  39,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,  40,   0,   0,   0,   0,  41,   0,   0,   0,   0,  42,  43,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,  33,  44,   0,  45,   0,   0,   0,   0,   0,   0,  46,  47,   0,   0,
+      0,   0,   0,  48,   0,  49,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  50,  51,   0,   0,   0,  52,   0,   0,  53,   0,   0,   0,
+      0,   0,   0,   0,  54,   0,   0,   0,   0,   0,   0,   0,  55,   0,   0,   0,
+      0,   0,   0,   0,  53,   0,   0,   0,   0,   0,   0,   0,   0,  56,   0,   0,
+      0,   0,   0,  57,   0,   0,   0,   0,   0,   0,   0,  57,   0,  58,   0,   0,
+     59,   0,   0,   0,  60,  61,  33,  62,  63,  60,  61,  33,   0,   0,   0,   0,
+      0,   0,  64,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  65,
+     66,  67,   0,  68,  69,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,  70,  71,  72,  73,  74,  75,   0,  76,  73,  73,   0,   0,   0,   0,
+      6,   6,   6,   6,   6,   6,   6,   6,   6,  77,   6,   6,   6,   6,   6,  78,
+      6,  79,   6,   6,  79,  80,   6,  81,   6,   6,   6,  82,  83,  84,   6,  85,
+     86,  87,  88,  89,  90,  91,   0,  92,  93,  94,  95,   0,   0,   0,   0,   0,
+     96,  97,  98,  99, 100, 101, 102, 102, 103, 104, 105,   0, 106,   0,   0,   0,
+    107,   0, 108, 109, 110,   0, 111, 112, 112,   0, 113,   0,   0,   0, 114,   0,
+      0,   0, 115,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 116, 117, 102, 102, 102, 118, 116, 116, 119,   0,
+    120,   0,   0,   0,   0,   0,   0, 121,   0,   0,   0,   0,   0, 122,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 123,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 124,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0, 125,   0,   0,   0,   0,   0,  57,
+    102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 126,   0,   0,
+    127,   0,   0, 128, 129, 130, 131, 132,   0, 133, 129, 130, 131, 132,   0, 134,
+      0,   0,   0, 135, 102, 102, 102, 102, 136, 137,   0,   0,   0,   0,   0,   0,
+    102, 136, 102, 102, 138, 139, 116, 140, 116, 116, 116, 116, 141, 116, 116, 140,
+    142, 142, 142, 142, 142, 143, 102, 144, 142, 142, 142, 142, 142, 142, 102, 145,
+      0,   0,   0,   0,   0,   0,   0,   0,   0, 146,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 147,   0,   0,   0,   0,   0,   0,   0, 148,
+      0,   0,   0,   0,   0, 149,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6,   6,   6,   6,   6,   6,  21,   0,   0,   0,   0,   0,
+     81, 150, 151,   6,   6,   6,  81,   6,   6,   6,   6,   6,   6,  78,   0,   0,
+    152, 153, 154, 155, 156, 157, 158, 158, 159, 158, 160, 161,   0, 162, 163, 164,
+    165, 165, 165, 165, 165, 165, 166, 167, 167, 168, 169, 169, 169, 170, 171, 172,
+    165, 173, 174, 175,   0, 176, 177, 178, 179, 180, 167, 181, 182,   0,   0, 183,
+      0, 184,   0, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 194, 195, 196,
+    197, 198, 198, 198, 198, 198, 199, 200, 200, 200, 200, 201, 202, 203, 204,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0, 205, 206,   0,   0,   0,   0,   0,
+      0,   0, 207,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  46,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 208,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 104,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 207, 209,   0,   0,   0,   0, 210,  14,   0,   0,   0,
+    211, 211, 211, 211, 211, 212, 211, 211, 211, 213, 214, 215, 216, 211, 211, 211,
+    217, 218, 211, 219, 220, 221, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
+    211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 222, 211, 211, 211, 211, 211,
+    211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 223, 211, 211, 211,
+    216, 211, 224, 225, 226, 227, 228, 229, 230, 231, 232, 231,   0,   0,   0,   0,
+    233, 102, 234, 142, 142,   0, 235,   0,   0, 236,   0,   0,   0,   0,   0,   0,
+    237, 142, 142, 238, 239, 240,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      6,  81,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_decomposition_type_stage_4[] = {
+      0,   0,   0,   0,   1,   0,   2,   3,   4,   5,   6,   7,   8,   9,   8,   8,
+     10,  11,  10,  12,  10,  11,  10,   9,   8,   8,   8,   8,  13,   8,   8,   8,
+      8,  12,   8,   8,  14,   8,  10,  15,  16,   8,  17,   8,  12,   8,   8,   8,
+      8,   8,   8,  15,  12,   0,   0,  18,  19,   0,   0,   0,   0,  20,  20,  21,
+      8,   8,   8,  22,   8,  13,   8,   8,  23,  12,   8,   8,   8,   8,   8,  13,
+      0,  13,   8,   8,   8,   0,   0,   0,  24,  24,  25,   0,   0,   0,  20,   5,
+     24,  25,   0,   0,   9,  19,   0,   0,   0,  19,  26,  27,   0,  21,  11,  22,
+      0,   0,  13,   8,   0,   0,  13,  11,  28,  29,   0,   0,  30,   5,  31,   0,
+      9,  18,   0,  11,   0,   0,  32,   0,   0,  13,   0,   0,  33,   0,   0,   0,
+      8,  13,  13,   8,  13,   8,  13,   8,   8,  12,  12,   0,   0,   3,   0,   0,
+     13,  11,   0,   0,   0,  34,  35,   0,  36,   0,   0,   0,  18,   0,   0,   0,
+     32,  19,   0,   0,   0,   0,   8,   8,   0,   0,  18,  19,   0,   0,   0,   9,
+     18,  27,   0,   0,   0,   0,  10,  27,   0,   0,  37,  19,   0,   0,   0,  12,
+      0,  19,   0,   0,   0,   0,  13,  19,   0,   0,  19,   0,  19,  18,  22,   0,
+      0,   0,  27,  11,   3,   0,   0,   0,   0,   0,   0,   5,   0,   0,   0,   1,
+     18,   0,   0,  32,  27,  18,   0,  19,  18,  38,  17,   0,  32,   0,   0,   0,
+      0,  27,   0,   0,   0,   0,   0,  25,   0,  27,  36,  36,  27,   0,   0,   0,
+      0,   0,  18,  32,   9,   0,   0,   0,   0,   0,   0,  39,  24,  24,  39,  24,
+     24,  24,  24,  40,  24,  24,  24,  24,  41,  42,  43,   0,   0,   0,  25,   0,
+      0,   0,  44,  24,   8,   8,  45,   0,   8,   8,  12,   0,   8,  12,   8,  12,
+      8,   8,  46,  46,   8,   8,   8,  12,   8,  22,   8,  47,  21,  22,   8,   8,
+      8,  13,   8,  10,  13,  22,   8,  48,  49,  50,  30,   0,  51,   3,   0,   0,
+      0,  30,   0,  52,   3,  53,   0,  54,   0,   3,   5,   0,   0,   3,   0,   3,
+     55,  24,  24,  24,  42,  42,  42,  43,  42,  42,  42,  56,   0,   0,  35,   0,
+     57,  34,  58,  59,  59,  60,  61,  62,  63,  64,  65,  66,  66,  67,  68,  59,
+     69,  61,  62,   0,  70,  70,  70,  70,  20,  20,  20,  20,   0,   0,  71,   0,
+      0,   0,  13,   0,   0,   0,   0,  27,   0,   0,   0,  10,   0,  19,  32,  19,
+      0,  36,   0,  72,  35,   0,   0,   0,  32,  37,  32,   0,  36,   0,   0,  10,
+     12,  12,  12,   0,   0,   0,   0,   8,   8,   0,  13,  12,   0,   0,  33,   0,
+     73,  73,  73,  73,  73,  20,  20,  20,  20,  74,  73,  73,  73,  73,  75,   0,
+      0,   0,   0,  35,   0,  30,   0,   0,   0,   0,   0,  19,   0,   0,   0,  76,
+      0,   0,   0,  44,   0,   0,   0,   3,  20,   5,   0,   0,  77,   0,   0,   0,
+      0,  26,  30,   0,   0,   0,   0,  36,  36,  36,  36,  36,  36,  46,  32,   0,
+      9,  22,  33,  12,   0,  19,   3,  78,   0,  37,  11,  79,  34,  20,  20,  20,
+     20,  20,  20,  30,   4,  24,  24,  24,  20,  73,   0,   0,  80,  73,  73,  73,
+     73,  73,  73,  75,  20,  20,  20,  81,  81,  81,  81,  81,  81,  81,  20,  20,
+     82,  81,  81,  81,  20,  20,  20,  83,   0,   0,   0,  55,  25,   0,   0,   0,
+      0,   0,  55,   0,   0,   0,   0,  24,  36,  10,   8,  11,  36,  33,  13,   8,
+     20,  30,   0,   0,   3,  20,   0,  46,  59,  59,  84,   8,   8,  11,   8,  36,
+      9,  22,   8,  15,  85,  86,  86,  86,  86,  86,  86,  86,  86,  85,  85,  85,
+     87,  85,  86,  86,  88,   0,   0,   0,  89,  90,  91,  92,  85,  87,  86,  85,
+     85,  85,  93,  87,  94,  94,  94,  94,  94,  95,  95,  95,  95,  95,  95,  95,
+     95,  96,  97,  97,  97,  97,  97,  97,  97,  97,  97,  98,  99,  99,  99,  99,
+     99, 100,  94,  94, 101,  95,  95,  95,  95,  95,  95, 102,  97,  99,  99, 103,
+    104,  97, 105, 106, 107, 105, 108, 105, 104,  96,  95, 105,  96, 109, 110,  97,
+    111, 106, 112, 105,  95, 106, 113,  95,  96, 106,   0,   0,  94,  94,  94, 114,
+    115, 115, 116,   0, 115, 115, 115, 115, 115, 117, 118,  20, 119, 120, 120, 120,
+    120, 119, 120,   0, 121, 122, 123, 123, 124,  91, 125, 126,  90, 125, 127, 127,
+    127, 127, 126,  91, 125, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126,
+    125, 126,  91, 128, 129, 130, 130, 130, 130, 130, 130, 130, 131, 132, 132, 132,
+    132, 132, 132, 132, 132, 132, 132, 133, 134, 132, 134, 132, 134, 132, 134, 135,
+    130, 136, 132, 133,   0,   0,  27,  19,   0,   0,  18,   0,   0,   0,   0,  13,
+      0,   0,  18,  36,   8,  19,   0,   0,   0,   0,  18,   8,  59,  59,  59,  59,
+     59, 137,  59,  59,  59,  59,  59, 137, 138, 139,  61, 137,  59,  59,  66,  61,
+     59,  61,  59,  59,  59,  66, 140,  61,  59, 137,  59, 137,  59,  59,  66, 140,
+     59, 141, 142,  59, 137,  59,  59,  59,  59,  62,  59,  59,  59,  59,  59, 142,
+    139, 143,  61,  59, 140,  59, 144,   0, 138, 145, 144,  61, 139, 143, 144, 144,
+    139, 143, 140,  59, 140,  59,  61, 141,  59,  59,  66,  59,  59,  59,  59,   0,
+     61,  61,  66,  59,  20,  20,  30,   0,  20,  20, 146,  75,   0,   0,   4,   0,
+    147,   0,   0,   0, 148,   0,   0,   0,  81,  81, 148,   0,  20,  20,  35,   0,
+    149,   0,   0,   0,
+};
+
+static RE_UINT8 re_decomposition_type_stage_5[] = {
+     0,  0,  0,  0,  4,  0,  0,  0,  2,  0, 10,  0,  0,  0,  0,  2,
+     0,  0, 10, 10,  2,  2,  0,  0,  2, 10, 10,  0, 17, 17, 17,  0,
+     1,  1,  1,  1,  1,  1,  0,  1,  0,  1,  1,  1,  1,  1,  1,  0,
+     1,  1,  0,  0,  0,  0,  1,  1,  1,  0,  2,  2,  1,  1,  1,  2,
+     2,  0,  0,  1,  1,  2,  0,  0,  0,  0,  0,  1,  1,  0,  0,  0,
+     2,  2,  2,  2,  2,  1,  1,  1,  1,  0,  1,  1,  1,  2,  2,  2,
+    10, 10, 10, 10, 10,  0,  0,  0,  0,  0,  2,  0,  0,  0,  1,  0,
+     2,  2,  2,  1,  1,  2,  2,  0,  2,  2,  2,  0,  0,  2,  0,  0,
+     0,  1,  0,  0,  0,  1,  1,  0,  0,  2,  2,  2,  2,  0,  0,  0,
+     1,  0,  1,  0,  1,  0,  0,  1,  0,  1,  1,  2, 10, 10, 10,  0,
+    10, 10,  0, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,  0,
+     0,  0,  0, 10,  1,  1,  2,  1,  0,  1,  0,  1,  1,  2,  1,  2,
+     1,  1,  2,  0,  1,  1,  2,  2,  2,  2,  2,  4,  0,  4,  0,  0,
+     0,  0,  0,  4,  2,  0,  2,  2,  2,  0,  2,  0, 10, 10,  0,  0,
+    11,  0,  0,  0,  2,  2,  3,  2,  0,  2,  3,  3,  3,  3,  3,  3,
+     0,  3,  2,  0,  0,  3,  3,  3,  3,  3,  0,  0, 10,  2, 10,  0,
+     3,  0,  1,  0,  3,  0,  1,  1,  3,  3,  0,  3,  3,  2,  2,  2,
+     2,  3,  0,  2,  3,  0,  0,  0, 17, 17, 17, 17,  0, 17,  0,  0,
+     2,  2,  0,  2,  9,  9,  9,  9,  2,  2,  9,  9,  9,  9,  9,  0,
+    11, 10,  0,  0, 13,  0,  0,  0,  2,  0,  1, 12,  0,  0,  1, 12,
+    16,  9,  9,  9, 16, 16, 16, 16,  2, 16, 16, 16,  2,  2,  2, 16,
+     3,  3,  1,  1,  8,  7,  8,  7,  5,  6,  8,  7,  8,  7,  5,  6,
+     8,  7,  0,  0,  0,  0,  0,  8,  7,  5,  6,  8,  7,  8,  7,  8,
+     7,  8,  8,  7,  5,  8,  7,  5,  8,  8,  8,  8,  7,  7,  7,  7,
+     7,  7,  7,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,
+     6,  8,  8,  8,  8,  7,  7,  7,  7,  5,  5,  5,  7,  8,  0,  0,
+     5,  7,  5,  5,  7,  5,  7,  7,  5,  5,  7,  7,  5,  5,  7,  5,
+     5,  7,  7,  5,  7,  7,  5,  7,  5,  5,  5,  7,  0,  0,  5,  5,
+     5,  7,  7,  7,  5,  7,  5,  7,  8,  0,  0,  0, 12, 12, 12, 12,
+    12, 12,  0,  0, 12,  0,  0, 12, 12,  2,  2,  2, 15, 15, 15,  0,
+    15, 15, 15, 15,  8,  6,  8,  0,  8,  0,  8,  6,  8,  6,  8,  6,
+     8,  8,  7,  8,  7,  8,  7,  5,  6,  8,  7,  8,  6,  8,  7,  5,
+     7,  0,  0,  0,  0, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14,  0,  0,  0, 14, 14, 14,  0,  0,  0,
+    13, 13, 13,  0,  3,  0,  3,  3,  0,  0,  3,  0,  0,  3,  3,  0,
+     3,  3,  3,  0,  3,  0,  3,  0,  0,  0,  3,  3,  3,  0,  0,  3,
+     0,  3,  0,  3,  0,  0,  0,  3,  2,  2,  2,  9, 16,  0,  0,  0,
+    16, 16, 16,  0,  9,  9,  0,  0,
+};
+
+/* Decomposition_Type: 2964 bytes. */
+
+RE_UINT32 re_get_decomposition_type(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 13;
+    code = ch ^ (f << 13);
+    pos = (RE_UINT32)re_decomposition_type_stage_1[f] << 5;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_decomposition_type_stage_2[pos + f] << 4;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_decomposition_type_stage_3[pos + f] << 2;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_decomposition_type_stage_4[pos + f] << 2;
+    value = re_decomposition_type_stage_5[pos + code];
+
+    return value;
+}
+
+/* East_Asian_Width. */
+
+static RE_UINT8 re_east_asian_width_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  6,  5,  5,  7,  8,  9,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 10, 10, 10, 12,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 13,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 13,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    14, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+     8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8, 15,
+     8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8, 15,
+};
+
+static RE_UINT8 re_east_asian_width_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+     5,  6,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+     7,  8,  9, 10, 11, 12, 13, 14,  5, 15,  5, 16,  5,  5, 17, 18,
+    19, 20, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 22, 22,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    22, 22, 22, 22, 24,  5,  5,  5,  5, 25,  5,  5, 22, 22, 22, 22,
+    22, 22, 22, 22, 22, 22, 22, 26,  5,  5,  5,  5,  5,  5,  5,  5,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 22, 22,  5,  5,  5, 28, 29,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    30,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+     5, 31, 32,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 33,
+     5, 34,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 35,
+};
+
+static RE_UINT8 re_east_asian_width_stage_3[] = {
+     0,  0,  1,  1,  1,  1,  1,  2,  0,  0,  3,  4,  5,  6,  7,  8,
+     9, 10, 11, 12, 13, 14, 11,  0,  0,  0,  0,  0, 15, 16,  0,  0,
+     0,  0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0, 17, 18,  0,  0,
+    19, 19, 19, 19, 19, 19, 19,  0,  0, 20, 21, 20, 21,  0,  0,  0,
+     9, 19, 19, 19, 19,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    22, 22, 22, 22, 22, 22,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0, 23, 24, 25,  0,  0,  0, 26, 27,  0, 28,  0,  0,  0,  0,  0,
+    29, 30, 31,  0,  0, 32, 33, 34, 35, 34,  0, 36,  0, 37, 38,  0,
+    39, 40, 41, 42, 43, 44, 45,  0, 46, 47, 48, 49,  0,  0,  0,  0,
+     0, 44, 50,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19, 51, 19,
+    19, 19, 19, 19, 33, 19, 19, 52, 19, 53, 21, 54, 55, 56, 57,  0,
+    58, 59,  0,  0, 60,  0, 61,  0,  0, 62,  0, 62, 63, 19, 64, 19,
+     0,  0,  0, 65,  0, 38,  0, 66,  0,  0,  0,  0,  0,  0, 67,  0,
+     0,  0,  0,  0,  0,  0,  0,  0, 68,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 69,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0, 22, 70, 22, 22, 22, 22, 22, 71,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 72,  0, 73,
+    74, 22, 22, 75, 76, 22, 22, 22, 22, 77, 22, 22, 22, 22, 22, 22,
+    78, 22, 79, 76, 22, 22, 22, 22, 75, 22, 22, 80, 22, 22, 71, 22,
+    22, 75, 22, 22, 81, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 75,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,  0,  0,  0,  0,
+    22, 22, 22, 22, 22, 22, 22, 22, 82, 22, 22, 22, 83,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 22, 82,  0,  0,  0,  0,  0,  0,  0,  0,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 71,  0,  0,  0,  0,  0,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+    19, 84,  0, 22, 22, 85, 86,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    87, 88, 88, 88, 88, 88, 89, 90, 90, 90, 90, 91, 92, 93, 94, 65,
+    95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    96, 19, 97, 19, 19, 19, 34, 19, 19, 96,  0,  0,  0,  0,  0,  0,
+    98, 22, 22, 80, 99, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 79,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 97,
+};
+
+static RE_UINT8 re_east_asian_width_stage_4[] = {
+     0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  2,  3,  4,  5,  6,
+     7,  8,  9,  7,  0, 10,  0,  0, 11, 12, 11, 13, 14, 10,  9, 14,
+     8, 12,  9,  5, 15,  0,  0,  0, 16,  0, 12,  0,  0, 13, 12,  0,
+    17,  0, 11, 12,  9, 11,  7, 15, 13,  0,  0,  0,  0,  0,  0, 10,
+     5,  5,  5, 11,  0, 18, 17, 15, 11,  0,  7, 16,  7,  7,  7,  7,
+    17,  7,  7,  7, 19,  7, 14,  0, 20, 20, 20, 20, 18,  9, 14, 14,
+     9,  7,  0,  0,  8, 15, 12, 10,  0, 11,  0, 12, 17, 11,  0,  0,
+     0,  0, 21, 11, 12, 15, 15,  0, 12, 10,  0,  0, 22, 10, 12,  0,
+    12, 11, 12,  9,  7,  7,  7,  0,  7,  7, 14,  0,  0,  0, 15,  0,
+     0,  0, 14,  0, 10, 11,  0,  0,  0, 12,  0,  0,  8, 12, 18, 12,
+    15, 15, 10, 17, 18, 16,  7,  5,  0,  7,  0, 14,  0,  0, 11, 11,
+    10,  0,  0,  0, 14,  7, 13, 13, 13, 13,  0,  0,  0, 15, 15,  0,
+     0, 15,  0,  0,  0,  0,  0, 12,  0,  0, 23,  0,  7,  7, 19,  7,
+     7,  0,  0,  0, 13, 14,  0,  0, 13, 13,  0, 14, 14, 13, 18, 13,
+    14,  0,  0,  0, 13, 14,  0, 12,  0, 22, 15, 13,  0, 14,  0,  5,
+     5,  0,  0,  0, 19, 19,  9, 19,  0,  0,  0, 13,  0,  7,  7, 19,
+    19,  0,  7,  7,  0,  0,  0, 15,  0, 13,  7,  7,  0, 24,  1, 25,
+     0, 26,  0,  0,  0, 17, 14,  0, 20, 20, 27, 20, 20,  0,  0,  0,
+    20, 28,  0,  0, 20, 20, 20,  0, 29, 20, 20, 20, 20, 20, 20, 30,
+    31, 20, 20, 20, 20, 30, 31, 20,  0, 31, 20, 20, 20, 20, 20, 28,
+    20, 20, 30,  0, 20, 20,  7,  7, 20, 20, 20, 32, 20, 30,  0,  0,
+    20, 20, 28,  0, 30, 20, 20, 20, 20, 30, 20,  0, 33, 34, 34, 34,
+    34, 34, 34, 34, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37,
+    38, 36, 38, 36, 38, 36, 38, 39, 34, 40, 36, 37, 28,  0,  0,  0,
+     7,  7,  9,  0,  7,  7,  7, 14, 30,  0,  0,  0, 20, 20, 32,  0,
+};
+
+static RE_UINT8 re_east_asian_width_stage_5[] = {
+    0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 0, 1, 5, 5,
+    1, 5, 5, 1, 1, 0, 1, 0, 5, 1, 1, 5, 1, 1, 1, 1,
+    1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0,
+    0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
+    0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1,
+    3, 3, 3, 3, 0, 2, 0, 0, 0, 1, 1, 0, 0, 3, 3, 0,
+    0, 0, 5, 5, 5, 5, 0, 0, 0, 5, 5, 0, 3, 3, 0, 3,
+    3, 3, 0, 0, 4, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3,
+    3, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 0, 0, 0,
+    4, 4, 4, 0,
+};
+
+/* East_Asian_Width: 1668 bytes. */
+
+RE_UINT32 re_get_east_asian_width(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_east_asian_width_stage_1[f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_east_asian_width_stage_2[pos + f] << 4;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_east_asian_width_stage_3[pos + f] << 2;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_east_asian_width_stage_4[pos + f] << 2;
+    value = re_east_asian_width_stage_5[pos + code];
+
+    return value;
+}
+
+/* Joining_Group. */
+
+static RE_UINT8 re_joining_group_stage_1[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1,
+};
+
+static RE_UINT8 re_joining_group_stage_2[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_joining_group_stage_3[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0,
+    0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static RE_UINT8 re_joining_group_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  0,  0,  0,  7,  8,  9,
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,  0,  0, 21,  0, 22,
+     0,  0, 23, 24, 25, 26,  0,  0,  0, 27, 28, 29, 30, 31, 32, 33,
+     0,  0,  0,  0, 34, 35, 36,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0, 37, 38, 39, 40, 41, 42,  0,  0,
+};
+
+static RE_UINT8 re_joining_group_stage_5[] = {
+     0,  0,  0,  0,  0,  0,  0,  0, 45,  0,  3,  3, 43,  3, 45,  3,
+     4, 41,  4,  4, 13, 13, 13,  6,  6, 31, 31, 35, 35, 33, 33, 39,
+    39,  1,  1, 11, 11, 55, 55, 55,  0,  9, 29, 19, 22, 24, 26, 16,
+    43, 45, 45,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4, 29,
+     0,  3,  3,  3,  0,  3, 43, 43, 45,  4,  4,  4,  4,  4,  4,  4,
+     4, 13, 13, 13, 13, 13, 13, 13,  6,  6,  6,  6,  6,  6,  6,  6,
+     6, 31, 31, 31, 31, 31, 31, 31, 31, 31, 35, 35, 35, 33, 33, 39,
+     1,  9,  9,  9,  9,  9,  9, 29, 29, 11, 38, 11, 19, 19, 19, 11,
+    11, 11, 11, 11, 11, 22, 22, 22, 22, 26, 26, 26, 26, 56, 21, 13,
+    41, 17, 17, 14, 43, 43, 43, 43, 43, 43, 43, 43, 55, 47, 55, 43,
+    45, 45, 46, 46,  0, 41,  0,  0,  0,  0,  0,  0,  0,  0,  6, 31,
+     0,  0, 35, 33,  1,  0,  0, 21,  2,  0,  5, 12, 12,  7,  7, 15,
+    44, 50, 18, 42, 42, 48, 49, 20, 23, 25, 27, 36, 10,  8, 28, 32,
+    34, 30,  7, 37, 40,  5, 12,  7,  0,  0,  0,  0,  0, 51, 52, 53,
+     4,  4,  4,  4,  4,  4,  4, 13, 13,  6,  6, 31, 35,  1,  1,  1,
+     9,  9, 11, 11, 11, 24, 24, 26, 26, 26, 22, 31, 31, 35, 13, 13,
+    35, 31, 13,  3,  3, 55, 55, 45, 43, 43, 54, 54, 13, 35, 35, 19,
+     4,  4, 13, 39,  9, 29, 22, 24, 45, 45, 31, 43, 57,  0,  6, 33,
+    11, 58, 31,  1, 19,  0,  0,  0, 59, 61, 61, 65, 65, 62,  0, 83,
+     0, 85, 85,  0,  0, 66, 80, 84, 68, 68, 68, 69, 63, 81, 70, 71,
+    77, 60, 60, 73, 73, 76, 74, 74, 74, 75,  0,  0, 78,  0,  0,  0,
+     0,  0,  0, 72, 64, 79, 82, 67,
+};
+
+/* Joining_Group: 586 bytes. */
+
+RE_UINT32 re_get_joining_group(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_joining_group_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_joining_group_stage_2[pos + f] << 4;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_joining_group_stage_3[pos + f] << 4;
+    f = code >> 3;
+    code ^= f << 3;
+    pos = (RE_UINT32)re_joining_group_stage_4[pos + f] << 3;
+    value = re_joining_group_stage_5[pos + code];
+
+    return value;
+}
+
+/* Joining_Type. */
+
+static RE_UINT8 re_joining_type_stage_1[] = {
+     0,  1,  2,  3,  4,  4,  4,  4,  4,  4,  5,  4,  4,  4,  4,  6,
+     7,  8,  4,  4,  4,  4,  9,  4,  4,  4,  4, 10,  4, 11, 12,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    13,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+};
+
+static RE_UINT8 re_joining_type_stage_2[] = {
+     0,  1,  0,  0,  0,  0,  2,  0,  0,  3,  0,  4,  5,  6,  7,  8,
+     9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26,  0,  0,  0,  0, 27,  0,  0,  0,  0,  0,  0,  0, 28, 29,
+    30, 31, 32,  0, 33, 34, 35, 36, 37, 38,  0, 39,  0,  0,  0,  0,
+    40, 41,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0, 42, 43, 44,  0,  0,  0,  0,
+    45, 46,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 47, 48,  0,  0,
+    49, 50, 51, 52, 53, 54,  0, 55,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 56,  0,  0,  0,  0,  0, 57, 43,  0, 58,
+     0,  0,  0, 59,  0, 60, 61,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 62, 63,  0, 64,  0,  0,  0,  0,  0,  0,  0,  0,
+    65, 66, 67, 68, 69, 70, 71,  0,  0, 72,  0, 73, 74, 75, 76,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 77, 78,  0,  0,  0,  0,  0,  0,  0,  0, 79,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0, 80,  0,  0,  0,  0,  0,  0,
+     0,  0, 81, 82, 83,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 84, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0, 86,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    87,  0, 88,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_joining_type_stage_3[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,
+      2,   2,   2,   2,   2,   2,   2,   0,   3,   0,   0,   0,   0,   0,   0,   0,
+      0,   4,   2,   5,   6,   0,   0,   0,   0,   7,   8,   9,  10,   2,  11,  12,
+     13,  14,  15,  15,  16,  17,  18,  19,  20,  21,  22,   2,  23,  24,  25,  26,
+      0,   0,  27,  28,  29,  15,  30,  31,   0,  32,  33,   0,  34,  35,   0,   0,
+      0,   0,  36,  37,   0,   0,  38,   2,  39,   0,   0,  40,  41,  42,  43,   0,
+     44,   0,   0,  45,  46,   0,  43,   0,  47,   0,   0,  45,  48,  44,   0,  49,
+     47,   0,   0,  45,  50,   0,  43,   0,  44,   0,   0,  51,  46,  52,  43,   0,
+     53,   0,   0,   0,  54,   0,   0,   0,  28,   0,   0,  55,  56,  57,  43,   0,
+     44,   0,   0,  51,  58,   0,  43,   0,  44,   0,   0,   0,  46,   0,  43,   0,
+      0,   0,   0,   0,  59,  60,   0,   0,   0,   0,   0,  61,  62,   0,   0,   0,
+      0,   0,   0,  63,  64,   0,   0,   0,   0,  65,   0,  66,   0,   0,   0,  67,
+     68,  69,   2,  70,  52,   0,   0,   0,   0,   0,  71,  72,   0,  73,  28,  74,
+     75,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  71,   0,   0,
+      0,  76,   0,  76,   0,  43,   0,  43,   0,   0,   0,  77,  78,  79,   0,   0,
+     80,   0,  15,  15,  15,  15,  15,  81,  82,  15,  83,   0,   0,   0,   0,   0,
+      0,   0,  84,  85,   0,   0,   0,   0,   0,  86,   0,   0,   0,  87,  88,  89,
+      0,   0,   0,  90,   0,   0,   0,   0,  91,   0,   0,  92,  53,   0,  93,  91,
+     94,   0,  95,   0,   0,   0,  96,  94,   0,   0,  97,  98,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,  99, 100, 101,   0,   0,   0,   0,   2,   2,   2, 102,
+    103,   0, 104,   0,   0,   0, 105,   0,   0,   0,   0,   0,   0,   2,   2,  28,
+      0,   0,   0,   0,   0,   0,  20,  94,   0,   0,   0,   0,   0,   0,   0,  20,
+      0,   0,   0,   0,   0,   0,   2,   2,   0,   0, 106,   0,   0,   0,   0,   0,
+      0, 107,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  20, 108,
+      0,  55,   0,   0,   0,   0,   0,  94, 109,   0,  57,   0,  15,  15,  15, 110,
+      0,   0,   0,   0, 111,   0,   2,  94,   0,   0, 112,   0, 113,  94,   0,   0,
+     39,   0,   0, 114,   0,   0, 115,   0,   0,   0, 116, 117, 118,   0,   0,  45,
+      0,   0,   0, 119,  44,   0, 120,  52,   0,   0,   0,   0,   0,   0, 121,   0,
+      0, 122,   0,   0,   0,   0,   0,   0,   2,   0,   2,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 123,   0,   0,   0,   0,   0,   0,   0,   1,
+      0,   0,   0,   0,   0,   0,  28,   0,   0,   0,   0,   0,   0,   0,   0, 124,
+    125,   0,   0, 126,   0,   0,   0,   0,   0,   0,   0,   0, 127, 128, 129,   0,
+    130, 131, 132,   0,   0,   0,   0,   0,  44,   0,   0, 133, 134,   0,   0,  20,
+     94,   0,   0, 135,   0,   0,   0,   0,  39,   0, 136, 137,   0,   0,   0, 138,
+     94,   0,   0, 139, 140,   0,   0,   0,   0,   0,  20, 141,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,  20, 142,   0,  94,   0,   0,  45,  28,   0, 143, 137,
+      0,   0,   0, 144, 145,   0,   0,   0,   0,   0,   0, 146,  28, 120,   0,   0,
+      0,   0,   0, 147,  28,   0,   0,   0,   0,   0, 148, 149,   0,   0,   0,   0,
+      0,  71, 150,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 137,
+      0,   0,   0, 134,   0,   0,   0,   0,  20,  39,   0,   0,   0,   0,   0,   0,
+      0, 151,  91,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 152,  38,
+    153,   0, 106,   0,   0,   0,   0,   0,   0,   0,   0,   0,  76,   0,   0,   0,
+      2,   2,   2, 154,   2,   2,  70, 115, 111,  93,   4,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 134,   0,   0,  44,   0,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+};
+
+static RE_UINT8 re_joining_type_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  1,  2,  2,  2,  2,  3,  2,  4,  0,
+     5,  2,  2,  2,  2,  2,  2,  6,  7,  6,  0,  0,  2,  2,  8,  9,
+    10, 11, 12, 13, 14, 15, 15, 15, 16, 15, 17,  2,  0,  0,  0, 18,
+    19, 20, 15, 15, 15, 15, 21, 21, 21, 21, 22, 15, 15, 15, 15, 15,
+    23, 21, 21, 24, 25, 26,  2, 27,  2, 27, 28, 29,  0,  0, 18, 30,
+     0,  0,  0,  3, 31, 32, 22, 33, 15, 15, 34, 23,  2,  2,  8, 35,
+    15, 15, 32, 15, 15, 15, 13, 36, 24, 36, 22, 15,  0, 37,  2,  2,
+     9,  0,  0,  0,  0,  0, 18, 15, 15, 15, 38,  2,  2,  0, 39,  0,
+     0, 37,  6,  2,  2,  5,  5,  4, 36, 25, 12, 15, 15, 40,  5,  0,
+    15, 15, 25, 41, 42, 43,  0,  0,  3,  2,  2,  2,  8,  0,  0,  0,
+     0,  0, 44,  9,  5,  2,  9,  1,  5,  2,  0,  0, 37,  0,  0,  0,
+     1,  0,  0,  0,  0,  0,  0,  9,  5,  9,  0,  1,  7,  0,  0,  0,
+     7,  3, 27,  4,  4,  1,  0,  0,  5,  6,  9,  1,  0,  0,  0, 27,
+     0, 44,  0,  0, 44,  0,  0,  0,  9,  0,  0,  1,  0,  0,  0, 37,
+     9, 37, 28,  4,  0,  7,  0,  0,  0, 44,  0,  4,  0,  0, 44,  0,
+    37, 45,  0,  0,  1,  2,  8,  0,  0,  3,  2,  8,  1,  2,  6,  9,
+     0,  0,  2,  4,  0,  0,  4,  0,  0, 46,  1,  0,  5,  2,  2,  8,
+     2, 28,  0,  5,  2,  2,  5,  2,  2,  2,  2,  9,  0,  0,  0,  5,
+    28,  2,  7,  7,  0,  0,  4, 37,  5,  9,  0,  0, 44,  7,  0,  1,
+    37,  9,  0,  0,  0,  6,  2,  4,  0, 44,  5,  2,  2,  0,  0,  1,
+     0, 47, 48,  4, 15, 15,  0,  0,  0, 47, 15, 15, 15, 15, 49,  0,
+     8,  3,  9,  0, 44,  0,  5,  0,  0,  3, 27,  0,  0, 44,  2,  8,
+    45,  5,  2,  9,  3,  2,  2, 27,  2,  2,  2,  8,  2,  0,  0,  0,
+     0, 28,  8,  9,  0,  0,  3,  2,  4,  0,  0,  0, 37,  4,  6,  4,
+     0, 44,  4, 46,  0,  0,  0,  2,  2, 37,  0,  0,  8,  2,  2,  2,
+    28,  2,  9,  1,  0,  9,  4,  0,  2,  4,  0,  2,  0,  0,  3, 50,
+     0,  0, 37,  8,  2,  9, 37,  2,  0,  0, 37,  4,  0,  0,  7,  0,
+     8,  2,  2,  4, 44, 44,  3,  0, 51,  0,  0,  0,  0,  9,  0,  0,
+     0, 37,  2,  4,  0,  3,  2,  2,  3, 37,  4,  9,  0,  1,  0,  0,
+     0,  0,  5,  8,  7,  7,  0,  0,  3,  0,  0,  9, 28, 27,  9, 37,
+     0,  0,  0,  4,  0,  1,  9,  1,  0,  0,  0, 44,  0,  0,  5,  0,
+     0, 37,  8,  0,  5,  7,  0,  2,  0,  0,  8,  3, 15, 52, 53, 54,
+    14, 55, 15, 12, 56, 57, 47, 13, 24, 22, 12, 58, 56,  0,  0,  0,
+     0,  0, 20, 59,  0,  0,  2,  2,  2,  8,  0,  0,  3,  8,  7,  1,
+     0,  3,  2,  5,  2,  9,  0,  0,  3,  0,  0,  0,  0, 37,  2,  8,
+     0,  0, 37,  9,  4, 28,  0,  0,  3,  2,  8,  0,  0, 37,  2,  9,
+     3,  2, 45,  3, 28,  0,  0,  0, 37,  4,  0,  6,  3,  2,  8, 46,
+     0,  0,  3,  1,  2,  6,  0,  0, 37,  6,  2,  0,  0,  0,  0,  7,
+     0,  3,  4,  0,  8,  5,  2,  0,  2,  8,  3,  2,
+};
+
+static RE_UINT8 re_joining_type_stage_5[] = {
+    0, 0, 0, 0, 0, 5, 0, 0, 5, 5, 5, 5, 0, 0, 0, 5,
+    5, 5, 0, 0, 0, 5, 5, 5, 5, 5, 0, 5, 0, 5, 5, 0,
+    5, 5, 5, 0, 5, 0, 0, 0, 2, 0, 3, 3, 3, 3, 2, 3,
+    2, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2,
+    1, 2, 2, 2, 3, 2, 2, 5, 0, 0, 2, 2, 5, 3, 3, 3,
+    0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 2, 2, 3,
+    2, 3, 2, 3, 2, 2, 3, 3, 0, 3, 5, 5, 5, 0, 0, 5,
+    5, 0, 5, 5, 5, 5, 3, 3, 2, 0, 0, 2, 3, 5, 2, 2,
+    2, 3, 3, 3, 2, 2, 3, 2, 3, 2, 3, 2, 0, 3, 2, 2,
+    3, 2, 2, 2, 0, 0, 5, 5, 2, 2, 2, 5, 0, 0, 1, 0,
+    3, 2, 0, 0, 3, 0, 3, 2, 2, 3, 3, 2, 2, 0, 0, 0,
+    0, 0, 5, 0, 5, 0, 5, 0, 0, 5, 0, 5, 0, 0, 0, 2,
+    0, 0, 1, 5, 2, 5, 2, 0, 0, 1, 5, 5, 2, 2, 4, 0,
+    2, 3, 0, 3, 0, 3, 3, 0, 0, 4, 3, 3, 2, 2, 2, 4,
+    2, 3, 0, 0, 3, 5, 5, 0, 3, 2, 3, 3, 3, 2, 2, 0,
+};
+
+/* Joining_Type: 2292 bytes. */
+
+RE_UINT32 re_get_joining_type(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_joining_type_stage_1[f] << 5;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_joining_type_stage_2[pos + f] << 3;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_joining_type_stage_3[pos + f] << 2;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_joining_type_stage_4[pos + f] << 2;
+    value = re_joining_type_stage_5[pos + code];
+
+    return value;
+}
+
+/* Line_Break. */
+
+static RE_UINT8 re_line_break_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  6,  7,  8,  9, 10, 11,
+    12, 13, 14, 15, 16, 10, 17, 10, 10, 10, 10, 18, 10, 19, 20, 21,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22,
+     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    23, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+};
+
+static RE_UINT8 re_line_break_stage_2[] = {
+      0,   1,   2,   2,   2,   3,   4,   5,   2,   6,   7,   8,   9,  10,  11,  12,
+     13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,
+     29,  30,  31,  32,  33,  34,  35,  36,  37,   2,   2,   2,   2,  38,  39,  40,
+     41,  42,  43,  44,  45,  46,  47,  48,  49,  50,   2,  51,   2,   2,  52,  53,
+     54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
+      2,   2,   2,  70,   2,   2,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,
+     81,  82,  83,  84,  85,  86,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,
+     79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,
+     79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,
+     79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  87,  79,  79,  79,  79,
+     79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,
+     79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,
+     88,  79,  79,  79,  79,  79,  79,  79,  79,  89,   2,   2,  90,  91,   2,  92,
+     93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 101,
+    102, 103, 104, 105, 106, 107, 101, 102, 103, 104, 105, 106, 107, 101, 102, 103,
+    104, 105, 106, 107, 101, 102, 103, 104, 105, 106, 107, 101, 102, 103, 104, 105,
+    106, 107, 101, 102, 103, 104, 105, 106, 107, 101, 102, 103, 104, 105, 106, 107,
+    101, 102, 103, 104, 105, 106, 107, 101, 102, 103, 104, 105, 106, 107, 101, 102,
+    103, 104, 105, 106, 107, 101, 102, 103, 104, 105, 106, 107, 101, 102, 103, 108,
+    109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+    110, 110,  79,  79,  79,  79, 111, 112,   2,   2, 113, 114, 115, 116, 117, 118,
+    119, 120, 121, 122, 110, 123, 124, 125,   2, 126, 127, 110,   2,   2, 128, 110,
+    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 110, 110, 139, 110, 110, 110,
+    140, 141, 142, 143, 144, 145, 146, 110, 110, 147, 110, 148, 149, 150, 151, 110,
+    110, 152, 110, 110, 110, 153, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      2,   2,   2,   2,   2,   2,   2, 154, 155,   2, 156, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      2,   2,   2,   2, 157, 158, 159,   2, 160, 110, 110, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110,   2,   2,   2, 161, 162, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      2,   2,   2,   2, 163, 164, 165, 166, 110, 110, 110, 110, 110, 110, 167, 168,
+    169, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 170, 171, 110, 110, 110, 110, 110, 110,
+      2, 172, 173, 174, 175, 110, 176, 110, 177, 178, 179,   2,   2, 180,   2, 181,
+      2,   2,   2,   2, 182, 183, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      2, 184, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 185, 186, 110, 110,
+    187, 188, 189, 190, 191, 110,  79, 192,  79, 193, 194, 195, 196, 197, 198, 199,
+    200, 201, 202, 203, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+     79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,
+     79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79,  79, 204,
+    205, 110, 206, 207, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+    110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+};
+
+static RE_UINT16 re_line_break_stage_3[] = {
+      0,   1,   2,   3,   4,   5,   4,   6,   7,   1,   8,   9,   4,  10,   4,  10,
+      4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,  11,  12,   4,   4,
+      1,   1,   1,   1,  13,  14,  15,  16,  17,   4,  18,   4,   4,   4,   4,   4,
+     19,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,  20,   4,  21,  20,   4,
+     22,  23,   1,  24,  25,  26,  27,  28,  29,  30,   4,   4,  31,   1,  32,  33,
+      4,   4,   4,   4,   4,  34,  35,  36,  37,  38,   4,   1,  39,   4,   4,   4,
+      4,   4,  40,  41,  36,   4,  31,  42,   4,  43,  44,  45,   4,  46,  47,  47,
+     47,  47,   4,  48,  47,  47,  49,   1,  50,   4,   4,  51,   1,  52,  53,   4,
+     54,  55,  56,  57,  58,  59,  60,  61,  62,  55,  56,  63,  64,  65,  66,  67,
+     68,  18,  56,  69,  70,  71,  60,  72,  73,  55,  56,  69,  74,  75,  60,  76,
+     77,  78,  79,  80,  81,  82,  66,  83,  84,  85,  56,  86,  87,  88,  60,  89,
+     90,  85,  56,  91,  87,  92,  60,  93,  90,  85,   4,  94,  95,  96,  60,  97,
+     98,  99,   4, 100, 101, 102,  66, 103, 104, 105, 105, 106, 107, 108,  47,  47,
+    109, 110, 111, 112, 113, 114,  47,  47, 115, 116,  36, 117, 118,   4, 119, 120,
+    121, 122,   1, 123, 124, 125,  47,  47, 105, 105, 105, 105, 126, 105, 105, 105,
+    105, 127,   4,   4, 128,   4,   4,   4, 129, 129, 129, 129, 129, 129, 130, 130,
+    130, 130, 131, 132, 132, 132, 132, 132,   4,   4,   4,   4, 133, 134,   4,   4,
+    133,   4,   4, 135, 136, 137,   4,   4,   4, 136,   4,   4,   4, 138, 139, 119,
+      4, 140,   4,   4,   4,   4,   4, 141, 142,   4,   4,   4,   4,   4,   4,   4,
+    142, 143,   4,   4,   4,   4, 144, 145, 146, 147,   4, 148,   4, 149, 146, 150,
+    105, 105, 105, 105, 105, 151, 152, 140, 153, 152,   4,   4,   4,   4,   4,  76,
+      4,   4, 154,   4,   4,   4,   4, 155,   4,  45, 156, 156, 157, 105, 158, 159,
+    105, 105, 160, 105, 161, 162,   4,   4,   4, 163, 105, 105, 105, 164, 105, 165,
+    152, 152, 158, 166,  47,  47,  47,  47, 167,   4,   4, 168, 169, 170, 171, 172,
+    173,   4, 174,  36,   4,   4,  40, 175,   4,   4, 168, 176, 177,  36,   4, 178,
+     47,  47,  47,  47,  76, 179, 180, 181,   4,   4,   4,   4,   1,   1,   1, 182,
+      4, 141,   4,   4, 141, 183,   4, 184,   4,   4,   4, 185, 185, 186,   4, 187,
+    188, 189, 190, 191, 192, 193, 194, 195, 196, 119, 197, 198, 199,   1,   1, 200,
+    201, 202, 203,   4,   4, 204, 205, 206, 207, 206,   4,   4,   4, 208,   4,   4,
+    209, 210, 211, 212, 213, 214, 215,   4, 216, 217, 218, 219,   4,   4, 220,   4,
+    221, 222, 223,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4, 224,
+      4,   4, 225,  47, 226,  47, 227, 227, 227, 227, 227, 227, 227, 227, 227, 228,
+    227, 227, 227, 227, 205, 227, 227, 229, 227, 230, 231, 232, 233, 234, 235,   4,
+    236, 237,   4, 238, 239,   4, 240, 241,   4, 242,   4, 243, 244, 245, 246, 247,
+    248,   4,   4,   4,   4, 249, 250, 251, 227, 252,   4,   4, 253,   4, 254,   4,
+    255, 256,   4,   4,   4, 221,   4, 257,   4,   4,   4,   4,   4, 258,   4, 259,
+      4, 260,   4, 261,  56, 262, 263,  47,   4,   4,  45,   4,   4,  45,   4,   4,
+      4,   4,   4,   4,   4,   4, 264, 265,   4,   4, 128,   4,   4,   4, 266, 267,
+      4, 225, 268, 268, 268, 268,   1,   1, 269, 270, 271, 272, 273,  47,  47,  47,
+    274, 275, 274, 274, 274, 274, 274, 276, 274, 274, 274, 274, 274, 274, 274, 274,
+    274, 274, 274, 274, 274, 277,  47, 278, 279, 280, 281, 282, 283, 274, 284, 274,
+    285, 286, 287, 274, 284, 274, 285, 288, 289, 274, 290, 291, 274, 274, 274, 274,
+    292, 274, 274, 293, 274, 274, 276, 294, 274, 292, 274, 274, 295, 274, 274, 274,
+    274, 274, 274, 274, 274, 274, 274, 292, 274, 274, 274, 274,   4,   4,   4,   4,
+    274, 296, 274, 274, 274, 274, 274, 274, 297, 274, 274, 274, 298,   4,   4, 178,
+    299,   4, 300,  47,   4,   4, 264, 301,   4, 302,   4,   4,   4,   4,   4, 303,
+      4,   4, 184,  76,  47,  47,  47, 304, 305,   4, 306, 307,   4,   4,   4, 308,
+    309,   4,   4, 168, 310, 152,   1, 311,  36,   4, 312,   4, 313, 314, 129, 315,
+     50,   4,   4, 316, 317, 318, 105, 319,   4,   4, 320, 321, 322, 323, 105, 105,
+    105, 105, 105, 105, 324, 325,  31, 326, 327, 328, 268,   4,   4,   4, 155,   4,
+      4,   4,   4,   4,   4,   4, 329, 152, 330, 331, 332, 333, 332, 334, 332, 330,
+    331, 332, 333, 332, 334, 332, 330, 331, 332, 333, 332, 334, 332, 330, 331, 332,
+    333, 332, 334, 332, 330, 331, 332, 333, 332, 334, 332, 330, 331, 332, 333, 332,
+    334, 332, 330, 331, 332, 333, 332, 334, 332, 330, 331, 332, 333, 332, 334, 332,
+    333, 332, 335, 130, 336, 132, 132, 337, 338, 338, 338, 338, 338, 338, 338, 338,
+     47,  47,  47,  47,  47,  47,  47,  47, 225, 339, 340, 341, 342,   4,   4,   4,
+      4,   4,   4,   4, 262, 343,   4,   4,   4,   4,   4, 344,  47,   4,   4,   4,
+      4, 345,   4,   4,  76,  47,  47, 346,   1, 347,   1, 348, 349, 350, 351, 185,
+      4,   4,   4,   4,   4,   4,   4, 352, 353, 354, 274, 355, 274, 356, 357, 358,
+      4, 359,   4,  45, 360, 361, 362, 363, 364,   4, 137, 365, 184, 184,  47,  47,
+      4,   4,   4,   4,   4,   4,   4, 226, 366,   4,   4, 367,   4,   4,   4,   4,
+    119, 368,  71,  47,  47,   4,   4, 369,   4, 119,   4,   4,   4,  71,  33, 368,
+      4,   4, 370,   4, 226,   4,   4, 371,   4, 372,   4,   4, 373, 374,  47,  47,
+      4, 184, 152,  47,  47,  47,  47,  47,   4,   4,  76,   4,   4,   4, 375,  47,
+      4,   4,   4, 225,   4, 155,  76,  47, 376,   4,   4, 377,   4, 378,   4,   4,
+      4,  45, 304,  47,  47,  47,   4, 379,   4, 380,   4, 381,  47,  47,  47,  47,
+      4,   4,   4, 382,   4, 345,   4,   4, 383, 384,   4, 385,  76, 386,   4,   4,
+      4,   4,  47,  47,   4,   4, 387, 388,   4,   4,   4, 389,   4, 260,   4, 390,
+      4, 391, 392,  47,  47,  47,  47,  47,   4,   4,   4,   4, 145,  47,  47,  47,
+      4,   4,   4, 393,   4,   4,   4, 394,  47,  47,  47,  47,  47,  47,   4,  45,
+    173,   4,   4, 395, 396, 345, 397, 398, 173,   4,   4, 399, 400,   4, 145, 152,
+    173,   4, 313, 401, 402,   4,   4, 403, 173,   4,   4, 316, 404, 405,  20,  48,
+      4,  18, 406, 407,  47,  47,  47,  47, 408,  37, 409,   4,   4, 264, 410, 152,
+    411,  55,  56,  69,  74, 412, 413, 414,   4,   4,   4,   1, 415, 152,  47,  47,
+      4,   4, 264, 416, 417, 418,  47,  47,   4,   4,   4,   1, 419, 152,  47,  47,
+      4,   4,  31, 420, 152,  47,  47,  47, 105, 421, 160, 422,  47,  47,  47,  47,
+     47,  47,   4,   4,   4,   4,  36, 423,  47,  47,  47,  47,   4,   4,   4, 145,
+      4, 140,  47,  47,  47,  47,  47,  47,   4,   4,   4,   4,   4,   4,  45, 424,
+      4,   4,   4,   4, 370,  47,  47,  47,   4,   4,   4,   4,   4, 425,   4,   4,
+    426,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4, 427,
+      4,   4,  45,  47,  47,  47,  47,  47,   4,   4,   4,   4, 428,   4,   4,   4,
+      4,   4,   4,   4, 225,  47,  47,  47,   4,   4,   4, 145,   4,  45, 429,  47,
+     47,  47,  47,  47,  47,   4, 184, 430,   4,   4,   4, 431, 432, 433,  18, 434,
+      4,  47,  47,  47,  47,  47,  47,  47,   4,   4,   4,   4,  48, 435,   1, 166,
+    398, 173,  47,  47,  47,  47,  47,  47, 436,  47,  47,  47,  47,  47,  47,  47,
+      4,   4,   4,   4,   4,   4, 226, 119, 145, 437, 438,  47,  47,  47,  47,  47,
+      4,   4,   4,   4,   4,   4,   4, 155,   4,   4,  21,   4,   4,   4, 439,   1,
+    440,   4, 441,   4,   4,   4, 145,  47,   4,   4,   4,   4, 442,  47,  47,  47,
+      4,   4,   4,   4,   4, 225,   4, 262,   4,   4,   4,   4,   4, 185,   4,   4,
+      4, 146, 443, 444, 445,   4,   4,   4, 446, 447,   4, 448, 449,  85,   4,   4,
+      4,   4, 260,   4,   4,   4,   4,   4,   4,   4,   4,   4, 450, 451, 451, 451,
+      1,   1,   1, 452,   1,   1, 453, 454, 455, 456,  23,  47,  47,  47,  47,  47,
+      4,   4,   4,   4, 457, 321,  47,  47, 445,   4, 458, 459, 460, 461, 462, 463,
+    464, 368, 465, 368,  47,  47,  47, 262, 274, 274, 278, 274, 274, 274, 274, 274,
+    274, 276, 292, 291, 291, 291, 274, 277, 466, 227, 467, 227, 227, 227, 468, 227,
+    227, 469,  47,  47,  47,  47, 470, 471, 472, 274, 274, 293, 473, 436,  47,  47,
+    274, 474, 274, 475, 274, 274, 274, 476, 274, 274, 477, 478, 274, 274, 274, 274,
+    479, 480, 481, 482, 483, 274, 274, 275, 274, 274, 484, 274, 274, 485, 274, 486,
+    274, 274, 274, 274, 274,   4,   4, 487, 274, 274, 274, 274, 274, 488, 297, 276,
+      4,   4,   4,   4,   4,   4,   4, 370,   4,   4,   4,   4,   4,  48,  47,  47,
+    368,   4,   4,   4,  76, 140,   4,   4,  76,   4, 184,  47,  47,  47,  47,  47,
+     47, 473,  47,  47,  47,  47,  47,  47, 489,  47,  47,  47, 488,  47,  47,  47,
+    274, 274, 274, 274, 274, 274, 274, 290, 490,  47,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,  47,
+};
+
+static RE_UINT8 re_line_break_stage_4[] = {
+      0,   0,   0,   0,   1,   2,   3,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      4,   5,   6,   7,   8,   9,  10,  11,  12,  12,  12,  12,  12,  13,  14,  15,
+     14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  16,  17,  14,
+     14,  14,  14,  14,  14,  16,  18,  19,   0,   0,  20,   0,   0,   0,   0,   0,
+     21,  22,  23,  24,  25,  26,  27,  14,  22,  28,  29,  28,  28,  26,  28,  30,
+     14,  14,  14,  24,  14,  14,  14,  14,  14,  14,  14,  24,  31,  28,  31,  14,
+     25,  14,  14,  14,  28,  28,  24,  32,   0,   0,   0,   0,   0,   0,   0,  33,
+      0,   0,   0,   0,   0,   0,  34,  34,  34,  35,   0,   0,   0,   0,   0,   0,
+     14,  14,  14,  14,  36,  14,  14,  37,  36,  36,  14,  14,  14,  38,  38,  14,
+     14,  39,  14,  14,  14,  14,  14,  14,  14,  19,   0,   0,   0,  14,  14,  14,
+     39,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  38,  39,  14,  14,  14,
+     14,  14,  14,  14,  40,  41,  39,   9,  42,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  43,  19,  44,   0,  45,  36,  36,  36,  36,
+     46,  46,  46,  46,  46,  46,  46,  46,  46,  46,  46,  46,  46,  47,  36,  36,
+     46,  48,  38,  36,  36,  36,  36,  36,  14,  14,  14,  14,  49,  50,  13,  14,
+      0,   0,   0,   0,   0,  51,  52,  53,  14,  14,  14,  14,  14,  19,   0,   0,
+     12,  12,  12,  12,  12,  54,  55,  14,  44,  14,  14,  14,  14,  14,  14,  14,
+     14,  14,  56,   0,   0,   0,  44,  19,   0,   0,  44,  19,  44,   0,   0,  14,
+     12,  12,  12,  12,  12,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  39,
+     19,  14,  14,  14,  14,  14,  14,  14,   0,   0,   0,   0,   0,  52,  39,  14,
+     14,  14,  14,   0,   0,   0,   0,   0,  44,  36,  36,  36,  36,  36,  36,  36,
+      0,   0,  14,  14,  57,  38,  36,  36,  14,  14,  14,   0,   0,  19,   0,   0,
+      0,   0,  19,   0,  19,   0,   0,  36,  14,  14,  14,  14,  14,  14,  14,  38,
+     14,  14,  14,  14,  19,   0,  36,  38,  36,  36,  36,  36,  36,  36,  36,  36,
+     14,  14,  38,  36,  36,  36,  36,  36,  36,  42,   0,   0,   0,   0,   0,   0,
+      0,   0,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,   0,  44,   0,
+     19,   0,   0,   0,  14,  14,  14,  14,  14,   0,  58,  12,  12,  12,  12,  12,
+     19,   0,  39,  14,  14,  14,  38,  39,  38,  39,  14,  14,  14,  14,  14,  14,
+     14,  14,  14,  14,  38,  14,  14,  14,  38,  38,  36,  14,  14,  36,  44,   0,
+      0,   0,  52,  42,  52,  42,   0,  38,  36,  36,  36,  42,  36,  36,  14,  39,
+     14,   0,  36,  12,  12,  12,  12,  12,  14,  50,  14,  14,  49,   9,  36,  36,
+     42,   0,  39,  14,  14,  38,  36,  39,  38,  14,  39,  38,  14,  36,  52,   0,
+      0,  52,  36,  42,  52,  42,   0,  36,  42,  36,  36,  36,  39,  14,  38,  38,
+     36,  36,  36,  12,  12,  12,  12,  12,   0,  14,  19,  36,  36,  36,  36,  36,
+     42,   0,  39,  14,  14,  14,  14,  39,  38,  14,  39,  14,  14,  36,  44,   0,
+      0,   0,   0,  42,   0,  42,   0,  36,  38,  36,  36,  36,  36,  36,  36,  36,
+      9,  36,  36,  36,  39,  36,  36,  36,  42,   0,  39,  14,  14,  14,  38,  39,
+      0,   0,  52,  42,  52,  42,   0,  36,  36,  36,  36,   0,  36,  36,  14,  39,
+     14,  14,  14,  14,  36,  36,  36,  36,  36,  44,  39,  14,  14,  38,  36,  14,
+     38,  14,  14,  36,  39,  38,  38,  14,  36,  39,  38,  36,  14,  38,  36,  14,
+     14,  14,  14,  14,  14,  36,  36,   0,   0,  52,  36,   0,  52,   0,   0,  36,
+     38,  36,  36,  42,  36,  36,  36,  36,  14,  14,  14,  14,   9,  38,  36,  36,
+      0,   0,  39,  14,  14,  14,  38,  14,  38,  14,  14,  14,  14,  14,  14,  14,
+     14,  14,  14,  14,  14,  36,  39,   0,   0,   0,  52,   0,  52,   0,   0,  36,
+     36,  36,  42,  52,  14,  38,  36,  36,  36,  36,  36,  36,  14,  14,  14,  14,
+     42,   0,  39,  14,  14,  14,  38,  14,  14,  14,  39,  14,  14,  36,  44,   0,
+     36,  36,  42,  52,  36,  36,  36,  38,  39,  38,  36,  36,  36,  36,  36,  36,
+     14,  14,  14,  14,  14,  38,  39,   0,   0,   0,  52,   0,  52,   0,   0,  38,
+     36,  36,  36,  42,  36,  36,  36,  39,  14,  14,  14,  36,  59,  14,  14,  14,
+     36,   0,  39,  14,  14,  14,  14,  14,  14,  14,  14,  38,  36,  14,  14,  14,
+     14,  39,  14,  14,  14,  14,  39,  36,  14,  14,  14,  38,  36,  52,  36,  42,
+      0,   0,  52,  52,   0,   0,   0,   0,  36,   0,  38,  36,  36,  36,  36,  36,
+     60,  61,  61,  61,  61,  61,  61,  61,  61,  61,  61,  61,  61,  61,  61,  61,
+     61,  61,  61,  61,  61,  62,  36,  63,  61,  61,  61,  61,  61,  61,  61,  64,
+     12,  12,  12,  12,  12,  58,  36,  36,  60,  62,  62,  60,  62,  62,  60,  36,
+     36,  36,  61,  61,  60,  61,  61,  61,  60,  61,  60,  60,  36,  61,  60,  61,
+     61,  61,  61,  61,  61,  60,  61,  36,  61,  61,  62,  62,  61,  61,  61,  36,
+     12,  12,  12,  12,  12,  36,  61,  61,  32,  65,  29,  65,  66,  67,  68,  53,
+     53,  69,  56,  14,   0,  14,  14,  14,  14,  14,  43,  19,  19,  70,  70,   0,
+     14,  14,  14,  14,  39,  14,  14,  14,  14,  14,  14,  14,  14,  14,  38,  36,
+     42,   0,   0,   0,   0,   0,   0,   1,   0,   0,   1,   0,  14,  14,  19,   0,
+      0,   0,   0,   0,  42,   0,   0,   0,   0,   0,   0,   0,   0,   0,  52,  58,
+     14,  14,  14,  44,  14,  14,  38,  14,  65,  71,  14,  14,  72,  73,  36,  36,
+     12,  12,  12,  12,  12,  58,  14,  14,  12,  12,  12,  12,  12,  61,  61,  61,
+     14,  14,  14,  39,  36,  36,  39,  36,  74,  74,  74,  74,  74,  74,  74,  74,
+     75,  75,  75,  75,  75,  75,  75,  75,  75,  75,  75,  75,  76,  76,  76,  76,
+     76,  76,  76,  76,  76,  76,  76,  76,  14,  14,  14,  14,  38,  14,  14,  36,
+     14,  14,  14,  38,  38,  14,  14,  36,  38,  14,  14,  36,  14,  14,  14,  38,
+     38,  14,  14,  36,  14,  14,  14,  14,  14,  14,  14,  38,  14,  14,  14,  14,
+     14,  14,  14,  14,  14,  38,  42,   0,  27,  14,  14,  14,  14,  14,  14,  14,
+     14,  14,  14,  14,  14,  36,  36,  36,  14,  14,  14,  36,  14,  14,  14,  36,
+     77,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  16,  78,  36,
+     14,  14,  14,  14,  14,  27,  58,  14,  14,  14,  14,  14,  38,  36,  36,  36,
+     14,  14,  14,  14,  14,  14,  38,  14,  14,   0,  52,  36,  36,  36,  36,  36,
+     14,   0,   1,  41,  36,  36,  36,  36,  14,   0,  36,  36,  36,  36,  36,  36,
+     38,   0,  36,  36,  36,  36,  36,  36,  61,  61,  58,  79,  77,  80,  61,  36,
+     12,  12,  12,  12,  12,  36,  36,  36,  14,  53,  58,  29,  53,  19,   0,  73,
+     14,  14,  14,  14,  19,  38,  36,  36,  14,  14,  14,  36,  36,  36,  36,  36,
+      0,   0,   0,   0,   0,   0,  36,  36,  38,  36,  53,  12,  12,  12,  12,  12,
+     61,  61,  61,  61,  61,  61,  61,  36,  61,  61,  62,  36,  36,  36,  36,  36,
+     61,  61,  61,  61,  61,  61,  36,  36,  61,  61,  61,  61,  61,  36,  36,  36,
+     12,  12,  12,  12,  12,  62,  36,  61,  14,  14,  14,  19,   0,   0,  36,  14,
+     61,  61,  61,  61,  61,  61,  61,  62,  61,  61,  61,  61,  61,  61,  62,  42,
+      0,   0,   0,   0,   0,   0,   0,  52,   0,   0,  44,  14,  14,  14,  14,  14,
+     14,  14,   0,   0,   0,   0,   0,   0,   0,   0,  44,  14,  14,  14,  36,  36,
+     12,  12,  12,  12,  12,  58,  27,  58,  77,  14,  14,  14,  14,  19,   0,   0,
+      0,   0,  14,  14,  14,  14,  38,  36,   0,  44,  14,  14,  14,  14,  14,  14,
+     19,   0,   0,   0,   0,   0,   0,  14,   0,   0,  36,  36,  36,  36,  14,  14,
+      0,   0,   0,   0,  36,  81,  58,  58,  12,  12,  12,  12,  12,  36,  39,  14,
+     14,  14,  14,  14,  14,  14,  14,  58,   0,  44,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  44,  14,  19,  14,  14,   0,  44,  38,   0,  36,  36,  36,
+      0,   0,   0,  36,  36,  36,   0,   0,  14,  14,  14,  14,  39,  39,  39,  39,
+     14,  14,  14,  14,  14,  14,  14,  36,  14,  14,  38,  14,  14,  14,  14,  14,
+     14,  14,  36,  14,  14,  14,  39,  14,  36,  14,  38,  14,  14,  14,  32,  38,
+     58,  58,  58,  82,  58,  83,   0,   0,  82,  58,  84,  25,  85,  86,  85,  86,
+     28,  14,  87,  88,  89,   0,   0,  33,  50,  50,  50,  50,   7,  90,  91,  14,
+     14,  14,  92,  93,  91,  14,  14,  14,  14,  14,  14,  77,  58,  58,  27,  58,
+     94,  14,  38,   0,   0,   0,   0,   0,  14,  36,  25,  14,  14,  14,  16,  95,
+     24,  28,  25,  14,  14,  14,  16,  78,  23,  23,  23,   6,  23,  23,  23,  23,
+     23,  23,  23,  22,  23,   6,  23,  22,  23,  23,  23,  23,  23,  23,  23,  23,
+     52,  36,  36,  36,  36,  36,  36,  36,  14,  49,  24,  14,  49,  14,  14,  14,
+     14,  24,  14,  96,  14,  14,  14,  14,  24,  25,  14,  14,  14,  24,  14,  14,
+     14,  14,  28,  14,  14,  24,  14,  25,  28,  28,  28,  28,  28,  28,  14,  14,
+     28,  28,  28,  28,  28,  14,  14,  14,  14,  14,  14,  14,  24,  14,  36,  36,
+     14,  25,  25,  14,  14,  14,  14,  14,  25,  28,  14,  24,  25,  24,  14,  24,
+     24,  23,  24,  14,  14,  25,  24,  28,  25,  24,  24,  24,  28,  28,  25,  25,
+     14,  14,  28,  28,  14,  14,  28,  14,  14,  14,  14,  14,  25,  14,  25,  14,
+     14,  25,  14,  14,  14,  14,  14,  14,  28,  14,  28,  28,  14,  28,  14,  28,
+     14,  28,  14,  28,  14,  14,  14,  14,  14,  14,  24,  14,  24,  14,  14,  14,
+     14,  14,  24,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  24,
+     14,  14,  14,  14,  14,  14,  14,  97,  14,  14,  14,  14,  70,  70,  14,  14,
+     14,  25,  14,  14,  14,  98,  14,  14,  14,  14,  14,  14,  16,  99,  14,  14,
+     98,  98,  14,  14,  14,  38,  36,  36,  14,  14,  14,  38,  36,  36,  36,  36,
+     14,  14,  14,  14,  14,  38,  36,  36,  28,  28,  28,  28,  28,  28,  28,  28,
+     28,  28,  28,  28,  28,  28,  28,  25,  28,  28,  25,  14,  14,  14,  14,  14,
+     14,  28,  28,  14,  14,  14,  14,  14,  28,  24,  28,  28,  28,  14,  14,  14,
+     14,  28,  14,  28,  14,  14,  28,  14,  28,  14,  14,  28,  25,  24,  14,  28,
+     28,  14,  14,  14,  14,  14,  14,  14,  14,  28,  28,  14,  14,  14,  14,  24,
+     98,  98,  24,  25,  24,  14,  14,  28,  14,  14,  98,  28, 100,  98,  98,  98,
+     14,  14,  14,  14, 101,  98,  14,  14,  25,  25,  14,  14,  14,  14,  14,  14,
+     28,  24,  28,  24, 102,  25,  28,  24,  14,  14,  14,  14,  14,  14,  14, 101,
+     14,  14,  14,  14,  14,  14,  14,  28,  14,  14,  14,  14,  14,  14, 101,  98,
+     98,  98,  98,  98, 102,  28, 103, 101,  98, 103, 102,  28,  98,  28, 102, 103,
+     98,  24,  14,  14,  28, 102,  28,  28, 103,  98,  98, 103,  98, 102, 103,  98,
+     98,  98, 100,  14,  98,  98,  98,  14,  14,  14,  14,  24,  14,   7,  85,  85,
+      5,  53,  14,  14,  70,  70,  70,  70,  70,  70,  70,  28,  28,  28,  28,  28,
+     28,  28,  14,  14,  14,  14,  14,  14,  14,  14,  16,  99,  14,  14,  14,  14,
+     14,  14,  14,  70,  70,  70,  70,  70,  14,  16, 104, 104, 104, 104, 104, 104,
+    104, 104, 104, 104,  99,  14,  14,  14,  14,  14,  14,  14,  14,  14,  70,  14,
+     14,  14,  24,  28,  28,  14,  14,  14,  14,  14,  36,  14,  14,  14,  14,  14,
+     14,  14,  14,  36,  14,  14,  14,  14,  14,  14,  14,  14,  14,  36,  39,  14,
+     14,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  14,  14,
+     14,  14,  14,  14,  14,  14,  14,  19,   0,  14,  36,  36, 105,  58,  77, 106,
+     14,  14,  14,  14,  36,  36,  36,  39,  41,  36,  36,  36,  36,  36,  36,  42,
+     14,  14,  14,  38,  14,  14,  14,  38,  85,  85,  85,  85,  85,  85,  85,  58,
+     58,  58,  58,  27, 107,  14,  85,  14,  85,  70,  70,  70,  70,  58,  58,  56,
+     58,  27,  77,  14,  14, 108,  58,  77,  58, 109,  36,  36,  36,  36,  36,  36,
+     98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98, 110,  98,  98,
+     98,  98,  36,  36,  36,  36,  36,  36,  98,  98,  98,  36,  36,  36,  36,  36,
+     98,  98,  98,  98,  98,  98,  36,  36,  18, 111, 112,  98,  70,  70,  70,  70,
+     70,  98,  70,  70,  70,  70, 113, 114,  98,  98,  98,  98,  98,   0,   0,   0,
+     98,  98, 115,  98,  98, 112, 116,  98, 117, 118, 118, 118, 118,  98,  98,  98,
+     98, 118,  98,  98,  98,  98,  98,  98,  98, 118, 118, 118,  98,  98,  98, 119,
+     98,  98, 118, 120,  42, 121,  91, 116, 122, 118, 118, 118, 118,  98,  98,  98,
+     98,  98, 118, 119,  98, 112, 123, 116,  36,  36, 110,  98,  98,  98,  98,  98,
+     98,  98,  98,  98,  98,  98,  98,  36, 110,  98,  98,  98,  98,  98,  98,  98,
+     98,  98,  98,  98,  98,  98,  98, 124,  98,  98,  98,  98,  98, 124,  36,  36,
+    125, 125, 125, 125, 125, 125, 125, 125,  98,  98,  98,  98,  28,  28,  28,  28,
+     98,  98, 112,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98, 124,  36,
+     98,  98,  98, 124,  36,  36,  36,  36,  14,  14,  14,  14,  14,  14,  27, 106,
+     12,  12,  12,  12,  12,  14,  36,  36,   0,  44,   0,   0,   0,   0,   0,  14,
+     14,  14,  14,  14,  14,  14,  14,   0,   0,  27,  58,  58,  36,  36,  36,  36,
+     36,  36,  36,  39,  14,  14,  14,  14,  14,  44,  14,  44,  14,  19,  14,  14,
+     14,  19,   0,   0,  14,  14,  36,  36,  14,  14,  14,  14, 126,  36,  36,  36,
+     14,  14,  65,  53,  36,  36,  36,  36,   0,  14,  14,  14,  14,  14,  14,  14,
+      0,   0,  52,  36,  36,  36,  36,  58,   0,  14,  14,  14,  14,  14,  29,  36,
+     14,  14,  14,   0,   0,   0,   0,  58,  14,  14,  14,  19,   0,   0,   0,   0,
+      0,   0,  36,  36,  36,  36,  36,  39,  74,  74,  74,  74,  74,  74, 127,  36,
+     14,  19,   0,   0,   0,   0,   0,   0,  44,  14,  14,  27,  58,  14,  14,  39,
+     12,  12,  12,  12,  12,  36,  36,  14,  12,  12,  12,  12,  12,  61,  61,  62,
+     14,  14,  14,  14,  19,   0,   0,   0,   0,   0,   0,  52,  36,  36,  36,  36,
+     14,  19,  14,  14,  14,  14,   0,  36,  12,  12,  12,  12,  12,  36,  27,  58,
+     61,  62,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  36,  60,  61,  61,
+     58,  14,  19,  52,  36,  36,  36,  36,  39,  14,  14,  38,  39,  14,  14,  38,
+     39,  14,  14,  38,  36,  36,  36,  36,  14,  19,   0,   0,   0,   1,   0,  36,
+    128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 129,
+    129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 129, 129, 129,
+    129, 129, 128, 129, 129, 129, 129, 129, 129, 129,  36,  36,  36,  36,  36,  36,
+     75,  75,  75, 130,  36, 131,  76,  76,  76,  76,  76,  76,  76,  76,  36,  36,
+    132, 132, 132, 132, 132, 132, 132, 132,  36,  39,  14,  14,  36,  36, 133, 134,
+     46,  46,  46,  46,  48,  46,  46,  46,  46,  46,  46,  47,  46,  46,  47,  47,
+     46, 133,  47,  46,  46,  46,  46,  46,  36,  39,  14,  14,  14,  14,  14,  14,
+     14,  14,  14,  14,  14,  14,  14, 104,  36,  14,  14,  14,  14,  14,  14,  14,
+     14,  14,  14,  14,  14,  14, 126,  36, 135, 136,  57, 137, 138,  36,  36,  36,
+     98,  98, 139, 104, 104, 104, 104, 104, 104, 104, 111, 139, 111,  98,  98,  98,
+    111,  78,  91,  53, 139, 104, 104, 111,  98,  98,  98, 124, 140, 141,  36,  36,
+     14,  14,  14,  14,  14,  14,  38, 142, 105,  98,   6,  98,  70,  98, 111, 111,
+     98,  98,  98,  98,  98,  91,  98, 143,  98,  98,  98,  98,  98, 139, 144,  98,
+     98,  98,  98,  98,  98, 139, 144, 139, 114,  70,  93, 145, 125, 125, 125, 125,
+    146,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  91,
+     36,  14,  14,  14,  36,  14,  14,  14,  36,  14,  14,  14,  36,  14,  38,  36,
+     22,  98, 140, 147,  14,  14,  14,  38,  36,  36,  36,  36,  42,   0, 148,  36,
+     14,  14,  14,  14,  14,  14,  39,  14,  14,  14,  14,  14,  14,  38,  14,  39,
+     58,  41,  36,  39,  14,  14,  14,  14,  14,  14,  36,  39,  14,  14,  14,  14,
+     14,  14,  14,  14,  14,  14,  36,  36,  14,  14,  14,  14,  14,  14,  19,  36,
+     14,  14,  36,  36,  36,  36,  36,  36,  14,  14,  14,   0,   0,  52,  36,  36,
+     14,  14,  14,  14,  14,  14,  14,  81,  14,  14,  36,  36,  14,  14,  14,  14,
+     77,  14,  14,  36,  36,  36,  36,  36,  14,  14,  36,  36,  36,  36,  36,  39,
+     14,  14,  14,  36,  38,  14,  14,  14,  14,  14,  14,  39,  38,  36,  38,  39,
+     14,  14,  14,  81,  14,  14,  14,  14,  14,  38,  14,  36,  36,  39,  14,  14,
+     14,  14,  14,  14,  14,  14,  36,  81,  14,  14,  14,  14,  14,  36,  36,  39,
+     14,  14,  14,  14,  36,  36,  14,  14,  19,   0,  42,  52,  36,  36,   0,   0,
+     14,  14,  39,  14,  39,  14,  14,  14,  14,  14,  36,  36,   0,  52,  36,  42,
+     58,  58,  58,  58,  38,  36,  36,  36,  14,  14,  19,  52,  36,  39,  14,  14,
+     58,  58,  58, 149,  36,  36,  36,  36,  14,  14,  14,  36,  81,  58,  58,  58,
+     14,  38,  36,  36,  14,  14,  14,  14,  14,  36,  36,  36,  39,  14,  38,  36,
+     36,  36,  36,  36,  39,  14,  14,  14,  14,  38,  36,  36,  36,  36,  36,  36,
+     14,  38,  36,  36,  36,  14,  14,  14,  14,  14,  14,  14,   0,   0,   0,   0,
+      0,   0,   0,   1,  77,  14,  14,  36,  14,  14,  14,  12,  12,  12,  12,  12,
+     36,  36,  36,  36,  36,  36,  36,  42,   0,   0,   0,   0,   0,  44,  14,  58,
+     58,  36,  36,  36,  36,  36,  36,  36,   0,   0,  52,  12,  12,  12,  12,  12,
+     58,  58,  36,  36,  36,  36,  36,  36,  14,  19,  32,  38,  36,  36,  36,  36,
+     44,  14,  27,  77,  77,   0,  44,  36,  12,  12,  12,  12,  12,  32,  27,  58,
+     14,  14,  14,  14,  14,  14,   0,   0,   0,   0,   0,   0,  58,  27,  77,  36,
+     14,  14,  14,  38,  38,  14,  14,  39,  14,  14,  14,  14,  27,  36,  36,  36,
+      0,   0,   0,   0,   0,  52,  36,  36,   0,   0,  39,  14,  14,  14,  38,  39,
+     38,  36,  36,  42,  36,  36,  39,  14,  14,   0,  36,   0,   0,   0,  52,  36,
+      0,   0,  52,  36,  36,  36,  36,  36,   0,   0,  14,  14,  36,  36,  36,  36,
+      0,   0,   0,  36,   0,   0,   0,   0, 150,  58,  53,  14,  27,  58,  58,  58,
+     58,  58,  58,  58,  14,  14,   0,  36,   1,  77,  38,  36,  36,  36,  36,  36,
+      0,   0,   0,   0,  36,  36,  36,  36,  61,  61,  61,  61,  61,  36,  60,  61,
+     12,  12,  12,  12,  12,  61,  58, 151,  14,  38,  36,  36,  36,  36,  36,  39,
+     58,  58,  41,  36,  36,  36,  36,  36,  14,  14,  14,  14, 152,  70, 114,  14,
+     14,  99,  14,  70,  70,  14,  14,  14,  14,  14,  14,  14,  16, 114,  14,  14,
+     14,  14,  14,  14,  14,  14,  14,  70,  12,  12,  12,  12,  12,  36,  36,  58,
+      0,   0,   1,  36,  36,  36,  36,  36,   0,   0,   0,   1,  58,  14,  14,  14,
+     14,  14,  77,  36,  36,  36,  36,  36,  12,  12,  12,  12,  12,  39,  14,  14,
+     14,  14,  14,  14,  36,  36,  39,  14,  19,   0,   0,   0,   0,   0,   0,   0,
+     98,  36,  36,  36,  36,  36,  36,  36,  14,  14,  14,  14,  14,  36,  19,   1,
+      0,   0,  36,  36,  36,  36,  36,  36,  14,  14,  19,   0,   0,  14,  19,   0,
+      0,  44,  19,   0,   0,   0,  14,  14,  14,  14,  14,  14,  14,   0,   0,  14,
+     14,   0,  44,  36,  36,  36,  36,  36,  36,  38,  39,  38,  39,  14,  38,  14,
+     14,  14,  14,  14,  14,  39,  39,  14,  14,  14,  39,  14,  14,  14,  14,  14,
+     14,  14,  14,  39,  14,  38,  39,  14,  14,  14,  38,  14,  14,  14,  38,  14,
+     14,  14,  14,  14,  14,  39,  14,  38,  14,  14,  38,  38,  36,  14,  14,  14,
+     14,  14,  14,  14,  14,  14,  36,  12,  12,  12,  12,  12,  12,  12,  12,  12,
+      0,   0,   0,  44,  14,  19,   0,   0,   0,   0,   0,   0,   0,   0,  44,  14,
+     14,  14,  19,  14,  14,  14,  14,  14,  14,  14,  44,  27,  58,  77,  36,  36,
+     36,  36,  36,  36,  36,  42,   0,   0,  14,  14,  38,  39,  14,  14,  14,  14,
+     39,  38,  38,  39,  39,  14,  14,  14,  14,  38,  14,  14,  39,  39,  36,  36,
+     36,  38,  36,  39,  39,  39,  39,  14,  39,  38,  38,  39,  39,  39,  39,  39,
+     39,  38,  38,  39,  14,  38,  14,  14,  14,  38,  14,  14,  39,  14,  38,  38,
+     14,  14,  14,  14,  14,  39,  14,  14,  39,  14,  39,  14,  14,  39,  14,  14,
+     28,  28,  28,  28,  28,  28, 153,  36,  28,  28,  28,  28,  28,  28,  28,  38,
+     28,  28,  28,  28,  28,  14,  36,  36,  28,  28,  28,  28,  28, 153,  36,  36,
+     36,  36,  36, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+     98, 124,  36,  36,  36,  36,  36,  36,  98,  98,  98,  98, 124,  36,  36,  36,
+     98,  98,  98,  98,  98,  98,  14,  98,  98,  98, 100, 101,  98,  98, 101,  98,
+     98,  98,  98,  98,  98, 100,  14,  14, 101, 101, 101,  98,  98,  98,  98, 100,
+    100, 101,  98,  98,  98,  98,  98,  98,  14,  14,  14, 101,  98,  98,  98,  98,
+     98,  98,  98, 100,  14,  14,  14,  14,  14,  14, 101,  98,  98,  98,  98,  98,
+     98,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  98,  98,  98,
+     98,  98, 110,  98,  98,  98,  98,  98,  98,  98,  14,  14,  14,  14,  98,  98,
+     98,  98,  14,  14,  14,  98,  98,  98,  14,  14,  14,  85, 155,  91,  14,  14,
+    124,  36,  36,  36,  36,  36,  36,  36,  98,  98, 124,  36,  36,  36,  36,  36,
+     42,  36,  36,  36,  36,  36,  36,  36,
+};
+
+static RE_UINT8 re_line_break_stage_5[] = {
+    16, 16, 16, 18, 22, 20, 20, 21, 19,  6,  3, 12,  9, 10, 12,  3,
+     1, 36, 12,  9,  8, 15,  8,  7, 11, 11,  8,  8, 12, 12, 12,  6,
+    12,  1,  9, 36, 18,  2, 12, 16, 16, 29,  4,  1, 10,  9,  9,  9,
+    12, 25, 25, 12, 25,  3, 12, 18, 25, 25, 17, 12, 25,  1, 17, 25,
+    12, 17, 16,  4,  4,  4,  4, 16,  0,  0,  8, 12, 12,  0,  0, 12,
+     0,  8, 18,  0,  0, 16, 18, 16, 16, 12,  6, 16, 37, 37, 37,  0,
+    37, 12, 12, 10, 10, 10, 16,  6, 16,  0,  6,  6, 10, 11, 11, 12,
+     6, 12,  8,  6, 18, 18,  0, 10,  0, 24, 24, 24, 24,  0,  0,  9,
+    24, 12, 17, 17,  4, 17, 17, 18,  4,  6,  4, 12,  1,  2, 18, 17,
+    12,  4,  4,  0, 31, 31, 32, 32, 33, 33, 18, 12,  2,  0,  5, 24,
+    18,  9,  0, 18, 18,  4, 18, 28, 26, 25,  3,  3,  1,  3, 14, 14,
+    14, 18, 20, 20,  3, 25,  5,  5,  8,  1,  2,  5, 30, 12,  2, 25,
+     9, 12, 12, 14, 13, 13,  2, 12, 13, 12, 12, 13, 13, 25, 25, 13,
+     2,  1,  0,  6,  6, 18,  1, 18, 26, 26,  1,  0,  0, 13,  2, 13,
+    13,  5,  5,  1,  2,  2, 13, 16,  5, 13,  0, 38, 13, 38, 38, 13,
+    38,  0, 16,  5,  5, 38, 38,  5, 13,  0, 38, 38, 10, 12, 31,  0,
+    34, 35, 35, 35, 32,  0,  0, 33, 27, 27,  0, 37, 16, 37,  8,  2,
+     2,  8,  6,  1,  2, 14, 13,  1, 13,  9, 10, 13,  0, 30, 13,  6,
+    13,  2, 12, 38, 38, 12,  9,  0, 23, 25, 14,  0, 16, 17, 18, 24,
+     1,  1, 25,  0, 39, 39,  3,  5,
+};
+
+/* Line_Break: 8608 bytes. */
+
+RE_UINT32 re_get_line_break(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_line_break_stage_1[f] << 5;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_line_break_stage_2[pos + f] << 3;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_line_break_stage_3[pos + f] << 3;
+    f = code >> 1;
+    code ^= f << 1;
+    pos = (RE_UINT32)re_line_break_stage_4[pos + f] << 1;
+    value = re_line_break_stage_5[pos + code];
+
+    return value;
+}
+
+/* Numeric_Type. */
+
+static RE_UINT8 re_numeric_type_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 11, 11, 11, 12,
+    13, 14, 15, 11, 11, 11, 16, 11, 11, 11, 11, 11, 11, 17, 18, 19,
+    20, 11, 21, 22, 11, 11, 23, 11, 11, 11, 11, 11, 11, 11, 11, 24,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+};
+
+static RE_UINT8 re_numeric_type_stage_2[] = {
+     0,  1,  1,  1,  1,  1,  2,  3,  1,  4,  5,  6,  7,  8,  9, 10,
+    11,  1,  1, 12,  1,  1, 13, 14, 15, 16, 17, 18, 19,  1,  1,  1,
+    20, 21,  1,  1, 22,  1,  1, 23,  1,  1,  1,  1, 24,  1,  1,  1,
+    25, 26, 27,  1, 28,  1,  1,  1, 29,  1,  1, 30,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 31, 32,
+     1, 33,  1, 34,  1,  1, 35,  1, 36,  1,  1,  1,  1,  1, 37, 38,
+     1,  1, 39, 40,  1,  1,  1, 41,  1,  1,  1,  1,  1,  1,  1, 42,
+     1,  1,  1, 43,  1,  1, 44,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    45,  1,  1,  1, 46,  1,  1,  1,  1,  1,  1,  1, 47, 48,  1,  1,
+     1,  1,  1,  1,  1,  1, 49,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1, 50,  1, 51, 52, 53, 54,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1, 55,  1,  1,  1,  1,  1, 15,
+     1, 56, 57, 58, 59,  1,  1,  1, 60, 61, 62, 63, 64,  1, 65,  1,
+    66, 67, 54,  1, 68,  1, 69, 70, 71,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1, 72,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 73, 74,  1,  1,  1,  1,
+     1,  1,  1, 75,  1,  1,  1, 76,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1, 77,  1,  1,  1,  1,  1,  1,  1,
+     1, 78,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    79, 80,  1,  1,  1,  1,  1,  1,  1, 81, 82, 83,  1,  1,  1,  1,
+     1,  1,  1, 84,  1,  1,  1,  1,  1, 85,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 86,  1,  1,  1,  1,
+     1,  1, 87,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1, 84,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_numeric_type_stage_3[] = {
+      0,   1,   0,   0,   0,   2,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   3,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   3,   0,
+      0,   0,   0,   4,   0,   0,   0,   5,   0,   0,   0,   4,   0,   0,   0,   4,
+      0,   0,   0,   6,   0,   0,   0,   7,   0,   0,   0,   8,   0,   0,   0,   4,
+      0,   0,   0,   9,   0,   0,   0,   4,   0,   0,   1,   0,   0,   0,   1,   0,
+      0,  10,   0,   0,   0,   0,   0,   0,   0,   0,   3,   0,   1,   0,   0,   0,
+      0,   0,   0,  11,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  12,
+      0,   0,   0,   0,   0,   0,   0,  13,   1,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   4,   0,   0,   0,  14,   0,   0,   0,   0,   0,  15,   0,   0,   0,
+      0,   0,   1,   0,   0,   1,   0,   0,   0,   0,  15,   0,   0,   0,   0,   0,
+      0,   0,   0,  16,  17,   0,   0,   0,   0,   0,  18,  19,  20,   0,   0,   0,
+      0,   0,   0,  21,  22,   0,   0,  23,   0,   0,   0,  24,  25,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  26,  27,  28,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  29,   0,   0,   0,   0,  30,  31,   0,  30,  32,   0,   0,
+     33,   0,   0,   0,  34,   0,   0,   0,   0,  35,   0,   0,   0,   0,   0,   0,
+      0,   0,  36,   0,   0,   0,   0,   0,  37,   0,  26,   0,  38,  39,  40,  41,
+     36,   0,   0,  42,   0,   0,   0,   0,  43,   0,  44,  45,   0,   0,   0,   0,
+      0,   0,  46,   0,   0,   0,  47,   0,   0,   0,   0,   0,   0,   0,  48,   0,
+      0,   0,   0,   0,   0,   0,   0,  49,   0,   0,   0,  50,   0,   0,   0,  51,
+     52,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  53,
+      0,   0,  54,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  55,   0,
+     44,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  56,   0,   0,   0,
+      0,   0,   0,  53,   0,   0,   0,   0,   0,   0,   0,   0,  44,   0,   0,   0,
+      0,  54,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  57,   0,   0,
+      0,  42,   0,   0,   0,   0,   0,   0,   0,  58,  59,  60,   0,   0,   0,  56,
+      0,   3,   0,   0,   0,   0,   0,  61,   0,  62,   0,   0,   0,   0,   1,   0,
+      3,   0,   0,   0,   0,   0,   1,   1,   0,   0,   1,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,  63,   0,  55,  64,  26,
+     65,  66,  19,  67,  68,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  69,
+      0,  70,  71,   0,   0,   0,  72,   0,   0,   0,   0,   0,   0,   3,   0,   0,
+      0,   0,  73,  74,   0,  75,   0,  76,  77,   0,   0,   0,   0,  78,  79,  19,
+      0,   0,  80,  81,  82,   0,   0,  83,   0,   0,  73,  73,   0,  84,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  85,   0,   0,   0,  86,   0,   0,   0,   0,
+      0,   0,  87,  88,   0,   0,   0,   1,   0,  89,   0,   0,   0,   0,   1,  90,
+      0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   1,   0,   0,   0,   3,   0,
+      0,  91,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  92,
+     19,  19,  19,  93,   0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,   0,
+      0,   0,  94,  95,   0,   0,   0,   0,   0,   0,   0,  96,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,  97,  98,   0,   0,   0,   0,   0,   0,  75,   0,
+     99,   0,   0,   0,   0,   0,   0,   0,  58,   0,   0,  43,   0,   0,   0, 100,
+      0,  58,   0,   0,   0,   0,   0,   0,   0,  35,   0,   0, 101,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 102, 103,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  42,   0,   0,   0,   0,   0,   0,   0,  60,   0,   0,   0,
+     48,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  36,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_numeric_type_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  1,  2,  0,  0,  3,  4,  1,  2,  0,  0,
+     5,  1,  0,  0,  5,  1,  6,  7,  5,  1,  8,  0,  5,  1,  9,  0,
+     5,  1,  0, 10,  5,  1, 11,  0,  1, 12, 13,  0,  0, 14, 15, 16,
+     0, 17, 18,  0,  1,  2, 19,  7,  0,  0,  1, 20,  1,  2,  1,  2,
+     0,  0, 21, 22, 23, 22,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19,
+    24,  7,  0,  0, 23, 25, 26, 27, 19, 23, 25, 13,  0, 28, 29, 30,
+     0,  0, 31, 32, 23, 33, 34,  0,  0,  0,  0, 35, 36,  0,  0,  0,
+    37,  7,  0,  9,  0,  0, 38,  0, 19,  7,  0,  0,  0, 19, 37, 19,
+     0,  0, 37, 19, 35,  0,  0,  0, 39,  0,  0,  0,  0, 40,  0,  0,
+     0, 35,  0,  0, 41, 42,  0,  0,  0, 43, 44,  0,  0,  0,  0, 36,
+    18,  0,  0, 36,  0, 18,  0,  0,  0,  0, 18,  0, 43,  0,  0,  0,
+    45,  0,  0,  0,  0, 46,  0,  0, 47, 43,  0,  0, 48,  0,  0,  0,
+     0,  0,  0, 39,  0,  0, 42, 42,  0,  0,  0, 40,  0,  0,  0, 17,
+     0, 49, 18,  0,  0,  0,  0, 45,  0, 43,  0,  0,  0,  0, 40,  0,
+     0,  0, 45,  0,  0, 45, 39,  0, 42,  0,  0,  0, 45, 43,  0,  0,
+     0,  0,  0, 18, 17, 19,  0,  0,  0,  0, 11,  0,  0, 39, 39, 18,
+     0,  0, 50,  0, 36, 19, 19, 19, 19, 19, 13,  0, 19, 19, 19, 18,
+     0, 51,  0,  0, 37, 19, 19, 13, 13,  0,  0,  0, 42, 40,  0,  0,
+     0,  0, 52,  0,  0,  0,  0, 19,  0,  0,  0, 37, 36, 19,  0,  0,
+     0,  0,  0, 53,  0,  0, 17, 13,  0,  0,  0, 54, 19, 19,  8, 19,
+    55,  0,  0,  0,  0,  0,  0, 56,  0,  0,  0, 57,  0, 53,  0,  0,
+     0, 37,  0,  0,  0,  0,  0,  8, 23, 25, 19, 10,  0,  0, 58, 59,
+    60,  1,  0,  0,  0,  0,  5,  1, 37, 19, 16,  0,  0,  0,  1, 61,
+     1, 12,  9,  0, 19, 10,  0,  0,  0,  0,  1, 62,  7,  0,  0,  0,
+    19, 19,  7,  0,  0,  5,  1,  1,  1,  1,  1,  1, 23, 63,  0,  0,
+    40,  0,  0,  0, 39, 43,  0, 43,  0, 40,  0, 35,  0,  0,  0, 42,
+};
+
+static RE_UINT8 re_numeric_type_stage_5[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0,
+    0, 2, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 3,
+    0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+    1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0,
+    3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+    0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+    1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+    3, 3, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2,
+    2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+    1, 1, 1, 0, 0, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+    0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 1, 2, 0, 0, 0, 0, 0, 0, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1,
+    0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+    0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1,
+    0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+    0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+    0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
+    0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+    0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+    0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+    0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2, 1, 1, 1, 1,
+    0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+    0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 0, 0, 0, 0,
+    3, 3, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 0, 0, 0,
+};
+
+/* Numeric_Type: 2304 bytes. */
+
+RE_UINT32 re_get_numeric_type(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_numeric_type_stage_1[f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_numeric_type_stage_2[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_numeric_type_stage_3[pos + f] << 2;
+    f = code >> 3;
+    code ^= f << 3;
+    pos = (RE_UINT32)re_numeric_type_stage_4[pos + f] << 3;
+    value = re_numeric_type_stage_5[pos + code];
+
+    return value;
+}
+
+/* Numeric_Value. */
+
+static RE_UINT8 re_numeric_value_stage_1[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 11, 11, 11, 12,
+    13, 14, 15, 11, 11, 11, 16, 11, 11, 11, 11, 11, 11, 17, 18, 19,
+    20, 11, 21, 22, 11, 11, 23, 11, 11, 11, 11, 11, 11, 11, 11, 24,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+};
+
+static RE_UINT8 re_numeric_value_stage_2[] = {
+     0,  1,  1,  1,  1,  1,  2,  3,  1,  4,  5,  6,  7,  8,  9, 10,
+    11,  1,  1, 12,  1,  1, 13, 14, 15, 16, 17, 18, 19,  1,  1,  1,
+    20, 21,  1,  1, 22,  1,  1, 23,  1,  1,  1,  1, 24,  1,  1,  1,
+    25, 26, 27,  1, 28,  1,  1,  1, 29,  1,  1, 30,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 31, 32,
+     1, 33,  1, 34,  1,  1, 35,  1, 36,  1,  1,  1,  1,  1, 37, 38,
+     1,  1, 39, 40,  1,  1,  1, 41,  1,  1,  1,  1,  1,  1,  1, 42,
+     1,  1,  1, 43,  1,  1, 44,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    45,  1,  1,  1, 46,  1,  1,  1,  1,  1,  1,  1, 47, 48,  1,  1,
+     1,  1,  1,  1,  1,  1, 49,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1, 50,  1, 51, 52, 53, 54,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1, 55,  1,  1,  1,  1,  1, 15,
+     1, 56, 57, 58, 59,  1,  1,  1, 60, 61, 62, 63, 64,  1, 65,  1,
+    66, 67, 54,  1, 68,  1, 69, 70, 71,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1, 72,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 73, 74,  1,  1,  1,  1,
+     1,  1,  1, 75,  1,  1,  1, 76,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1, 77,  1,  1,  1,  1,  1,  1,  1,
+     1, 78,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    79, 80,  1,  1,  1,  1,  1,  1,  1, 81, 82, 83,  1,  1,  1,  1,
+     1,  1,  1, 84,  1,  1,  1,  1,  1, 85,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 86,  1,  1,  1,  1,
+     1,  1, 87,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1, 88,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_numeric_value_stage_3[] = {
+      0,   1,   0,   0,   0,   2,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   3,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   3,   0,
+      0,   0,   0,   4,   0,   0,   0,   5,   0,   0,   0,   4,   0,   0,   0,   4,
+      0,   0,   0,   6,   0,   0,   0,   7,   0,   0,   0,   8,   0,   0,   0,   4,
+      0,   0,   0,   9,   0,   0,   0,   4,   0,   0,   1,   0,   0,   0,   1,   0,
+      0,  10,   0,   0,   0,   0,   0,   0,   0,   0,   3,   0,   1,   0,   0,   0,
+      0,   0,   0,  11,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  12,
+      0,   0,   0,   0,   0,   0,   0,  13,   1,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   4,   0,   0,   0,  14,   0,   0,   0,   0,   0,  13,   0,   0,   0,
+      0,   0,   1,   0,   0,   1,   0,   0,   0,   0,  13,   0,   0,   0,   0,   0,
+      0,   0,   0,  15,   3,   0,   0,   0,   0,   0,  16,  17,  18,   0,   0,   0,
+      0,   0,   0,  19,  20,   0,   0,  21,   0,   0,   0,  22,  23,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  24,  25,  26,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  27,   0,   0,   0,   0,  28,  29,   0,  28,  30,   0,   0,
+     31,   0,   0,   0,  32,   0,   0,   0,   0,  33,   0,   0,   0,   0,   0,   0,
+      0,   0,  34,   0,   0,   0,   0,   0,  35,   0,  36,   0,  37,  38,  39,  40,
+     41,   0,   0,  42,   0,   0,   0,   0,  43,   0,  44,  45,   0,   0,   0,   0,
+      0,   0,  46,   0,   0,   0,  47,   0,   0,   0,   0,   0,   0,   0,  48,   0,
+      0,   0,   0,   0,   0,   0,   0,  49,   0,   0,   0,  50,   0,   0,   0,  51,
+     52,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  53,
+      0,   0,  54,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  55,   0,
+     56,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  57,   0,   0,   0,
+      0,   0,   0,  58,   0,   0,   0,   0,   0,   0,   0,   0,  59,   0,   0,   0,
+      0,  60,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  61,   0,   0,
+      0,  62,   0,   0,   0,   0,   0,   0,   0,  63,  64,  65,   0,   0,   0,  66,
+      0,   3,   0,   0,   0,   0,   0,  67,   0,  68,   0,   0,   0,   0,   1,   0,
+      3,   0,   0,   0,   0,   0,   1,   1,   0,   0,   1,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,  69,   0,  70,  71,  72,
+     73,  74,  75,  76,  77,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  78,
+      0,  79,  80,   0,   0,   0,  81,   0,   0,   0,   0,   0,   0,   3,   0,   0,
+      0,   0,  82,  83,   0,  84,   0,  85,  86,   0,   0,   0,   0,  87,  88,  89,
+      0,   0,  90,  91,  92,   0,   0,  93,   0,   0,  94,  94,   0,  95,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  96,   0,   0,   0,  97,   0,   0,   0,   0,
+      0,   0,  98,  99,   0,   0,   0,   1,   0, 100,   0,   0,   0,   0,   1, 101,
+      0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   1,   0,   0,   0,   3,   0,
+      0, 102,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 103,
+    104, 105, 106, 107,   0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,   0,
+      0,   0, 108, 109,   0,   0,   0,   0,   0,   0,   0, 110,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 111, 112,   0,   0,   0,   0,   0,   0, 113,   0,
+    114,   0,   0,   0,   0,   0,   0,   0, 115,   0,   0, 116,   0,   0,   0, 117,
+      0, 118,   0,   0,   0,   0,   0,   0,   0, 119,   0,   0, 120,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 121, 122,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  62,   0,   0,   0,   0,   0,   0,   0, 123,   0,   0,   0,
+    124,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 125,   0,   0,   0,   0,
+      0,   0,   0,   0, 126,   0,   0,   0,
+};
+
+static RE_UINT8 re_numeric_value_stage_4[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   3,   0,
+      0,   0,   0,   0,   4,   0,   5,   6,   1,   2,   3,   0,   0,   0,   0,   0,
+      0,   7,   8,   9,   0,   0,   0,   0,   0,   7,   8,   9,   0,  10,  11,   0,
+      0,   7,   8,   9,  12,  13,   0,   0,   0,   7,   8,   9,  14,   0,   0,   0,
+      0,   7,   8,   9,   0,   0,   1,  15,   0,   7,   8,   9,  16,  17,   0,   0,
+      1,   2,  18,  19,  20,   0,   0,   0,   0,   0,  21,   2,  22,  23,  24,  25,
+      0,   0,   0,  26,  27,   0,   0,   0,   1,   2,   3,   0,   1,   2,   3,   0,
+      0,   0,   0,   0,   1,   2,  28,   0,   0,   0,   0,   0,  29,   2,   3,   0,
+      0,   0,   0,   0,  30,  31,  32,  33,  34,  35,  36,  37,  34,  35,  36,  37,
+     38,  39,  40,   0,   0,   0,   0,   0,  34,  35,  36,  41,  42,  34,  35,  36,
+     41,  42,  34,  35,  36,  41,  42,   0,   0,   0,  43,  44,  45,  46,   2,  47,
+      0,   0,   0,   0,   0,  48,  49,  50,  34,  35,  51,  49,  50,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  52,   0,  53,   0,   0,   0,   0,   0,   0,
+     21,   2,   3,   0,   0,   0,  54,   0,   0,   0,   0,   0,  48,  55,   0,   0,
+     34,  35,  56,   0,   0,   0,   0,   0,   0,   0,  57,  58,  59,  60,  61,  62,
+      0,   0,   0,   0,  63,  64,  65,  66,   0,  67,   0,   0,   0,   0,   0,   0,
+     68,   0,   0,   0,   0,   0,   0,   0,   0,   0,  69,   0,   0,   0,   0,   0,
+      0,   0,   0,  70,   0,   0,   0,   0,  71,  72,  73,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  74,   0,   0,   0,  75,   0,  76,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  77,  78,   0,   0,   0,   0,   0,   0,  79,
+      0,   0,  80,   0,   0,   0,   0,   0,   0,   0,   0,  67,   0,   0,   0,   0,
+      0,   0,   0,   0,  81,   0,   0,   0,   0,  82,   0,   0,   0,   0,   0,   0,
+      0,  83,   0,   0,   0,   0,   0,   0,   0,   0,  84,  85,   0,   0,   0,   0,
+     86,  87,   0,  88,   0,   0,   0,   0,  89,  80,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,  90,   0,   0,   0,   0,   0,   5,   0,   5,   0,
+      0,   0,   0,   0,   0,   0,  91,   0,   0,   0,   0,   0,   0,   0,   0,  92,
+      0,   0,   0,  15,  75,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  93,
+      0,   0,   0,  94,   0,   0,   0,   0,   0,   0,   0,   0,  95,   0,   0,   0,
+      0,  95,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  96,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  97,   0,  98,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,  25,   0,   0,   0,   0,   0,   0,   0,  99,  68,   0,   0,   0,
+      0,   0,   0,   0,  75,   0,   0,   0, 100,   0,   0,   0,   0,   0,   0,   0,
+      0, 101,   0,  81,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 102,   0,
+      0,   0,   0,   0,   0, 103,   0,   0,   0,  48,  49, 104,   0,   0,   0,   0,
+      0,   0,   0,   0, 105, 106,   0,   0,   0,   0, 107,   0, 108,   0,  75,   0,
+      0,   0,   0,   0, 103,   0,   0,   0,   0,   0,   0,   0, 109,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0, 110,   0, 111,   8,   9,  57,  58, 112, 113,
+    114, 115, 116, 117, 118,   0,   0,   0, 119, 120, 121, 122, 123, 124, 125, 126,
+    127, 128, 129, 130, 122, 131, 132,   0,   0,   0, 133,   0,   0,   0,   0,   0,
+     21,   2,  22,  23,  24, 134, 135,   0, 136,   0,   0,   0,   0,   0,   0,   0,
+    137,   0, 138,   0,   0,   0,   0,   0,   0,   0,   0,   0, 139, 140,   0,   0,
+      0,   0,   0,   0,   0,   0, 141, 142,   0,   0,   0,   0,   0,   0,  21, 143,
+      0, 111, 144, 145,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 111, 145,
+      0,   0,   0,   0,   0, 146, 147,   0,   0,   0,   0,   0,   0,   0,   0, 148,
+     34,  35, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162,
+     34, 163,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 164,
+      0,   0,   0,   0,   0,   0,   0, 165,   0,   0, 111, 145,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,  34, 163,   0,   0,  21, 166,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 167, 168,  34,  35, 149, 150, 169, 152, 170, 171,
+      0,   0,   0,   0,  48,  49,  50, 172, 173, 174,   8,   9,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   7,   8,   9,  21,   2,  22,  23,  24, 175,   0,   0,
+      0,   0,   0,   0,   1,   2,  22,   0,   1,   2,  22,  23, 176,   0,   0,   0,
+      8,   9,  49, 177,  35, 178,   2, 179, 180, 181,   9, 182, 183, 182, 184, 185,
+    186, 187, 188, 189, 144, 190, 191, 192, 193, 194, 195, 196,   0,   0,   0,   0,
+      0,   0,   0,   0,   1,   2, 197, 198, 199,   0,   0,   0,   0,   0,   0,   0,
+     34,  35, 149, 150, 200,   0,   0,   0,   0,   0,   0,   7,   8,   9,   1,   2,
+    201,   8,   9,   1,   2, 201,   8,   9,   0, 111,   8,   9,   0,   0,   0,   0,
+    202,  49, 104,  29,   0,   0,   0,   0,  70,   0,   0,   0,   0,   0,   0,   0,
+      0, 203,   0,   0,   0,   0,   0,   0,  98,   0,   0,   0,   0,   0,   0,   0,
+     67,   0,   0,   0,   0,   0,   0,   0,   0,   0,  91,   0,   0,   0,   0,   0,
+    204,   0,   0,  88,   0,   0,   0,  88,   0,   0, 101,   0,   0,   0,   0,  73,
+      0,   0,   0,   0,   0,   0,  73,   0,   0,   0,   0,   0,   0,   0,  80,   0,
+      0,   0,   0,   0,   0,   0, 107,   0,   0,   0,   0, 205,   0,   0,   0,   0,
+      0,   0,   0,   0, 206,   0,   0,   0,
+};
+
+static RE_UINT8 re_numeric_value_stage_5[] = {
+      0,   0,   0,   0,   2,  27,  29,  31,  33,  35,  37,  39,  41,  43,   0,   0,
+      0,   0,  29,  31,   0,  27,   0,   0,  12,  17,  22,   0,   0,   0,   2,  27,
+     29,  31,  33,  35,  37,  39,  41,  43,   3,   7,  10,  12,  22,  50,   0,   0,
+      0,   0,  12,  17,  22,   3,   7,  10,  44,  89,  98,   0,  27,  29,  31,   0,
+     44,  89,  98,  12,  17,  22,   0,   0,  41,  43,  17,  28,  30,  32,  34,  36,
+     38,  40,  42,   1,   0,  27,  29,  31,  41,  43,  44,  54,  64,  74,  84,  85,
+     86,  87,  88,  89, 107,   0,   0,   0,   0,   0,  51,  52,  53,   0,   0,   0,
+     41,  43,  27,   0,   2,   0,   0,   0,   8,   6,   5,  13,  21,  11,  15,  19,
+     23,   9,  24,   7,  14,  20,  25,  27,  27,  29,  31,  33,  35,  37,  39,  41,
+     43,  44,  45,  46,  84,  89,  93,  98,  98, 102, 107,   0,   0,  37,  84, 111,
+    116,   2,   0,   0,  47,  48,  49,  50,  51,  52,  53,  54,   0,   0,   2,  45,
+     46,  47,  48,  49,  50,  51,  52,  53,  54,  27,  29,  31,  41,  43,  44,   2,
+      0,   0,  27,  29,  31,  33,  35,  37,  39,  41,  43,  44,  43,  44,  27,  29,
+      0,  17,   0,   0,   0,   0,   0,   2,  44,  54,  64,   0,  31,  33,   0,   0,
+     43,  44,   0,   0,  44,  54,  64,  74,  84,  85,  86,  87,   0,  55,  56,  57,
+     58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,   0,  70,  71,  72,
+     73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,   0,  35,   0,   0,
+      0,   0,   0,  29,   0,   0,  35,   0,   0,  39,   0,   0,  27,   0,   0,  39,
+      0,   0,   0, 107,   0,  31,   0,   0,   0,  43,   0,   0,  29,   0,   0,   0,
+     35,   0,  33,   0,   0,   0,   0, 128,  44,   0,   0,   0,   0,   0,   0,  98,
+     31,   0,   0,   0,  89,   0,   0,   0, 128,   0,   0,   0,   0,   0, 130,   0,
+      0,  29,   0,  41,   0,  37,   0,   0,   0,  44,   0,  98,  54,  64,   0,   0,
+     74,   0,   0,   0,   0,  31,  31,  31,   0,   0,   0,  33,   0,   0,  27,   0,
+      0,   0,  43,  54,   0,   0,  44,   0,  41,   0,   0,   0,   0,   0,  39,   0,
+      0,   0,  43,   0,   0,   0,  89,   0,   0,   0,  33,   0,   0,   0,  29,   0,
+      0,  98,   0,   0,   0,   0,  37,   0,  37,   0,   0,   0,   0,   0,   2,   0,
+     39,  41,  43,   2,  12,  17,  22,   3,   7,  10,   0,   0,   0,   0,   0,  31,
+      0,   0,   0,  44,   0,  37,   0,  37,   0,  44,   0,   0,   0,   0,   0,  27,
+     88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103,
+    104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,  12,  17,  27,  35,
+     84,  93, 102, 111,  35,  44,  84,  89,  93,  98, 102,  35,  44,  84,  89,  93,
+     98, 107, 111,  44,  27,  27,  27,  29,  29,  29,  29,  35,  44,  44,  44,  44,
+     44,  64,  84,  84,  84,  84,  89,  91,  93,  93,  93,  93,  84,  17,  17,  21,
+     22,   0,   0,   0,   0,   0,   2,  12,  90,  91,  92,  93,  94,  95,  96,  97,
+     27,  35,  44,  84,   0,  88,   0,   0,   0,   0,  97,   0,   0,  27,  29,  44,
+     54,  89,   0,   0,  27,  29,  31,  44,  54,  89,  98, 107,  33,  35,  44,  54,
+     29,  31,  33,  33,  35,  44,  54,  89,   0,   0,  27,  44,  54,  89,  29,  31,
+     26,  17,   0,   0,  43,  44,  54,  64,  74,  84,  85,  86,   0,   0,  89,  90,
+     91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106,
+    107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 122, 123, 124,
+    125, 126,   4,   9,  12,  13,  16,  17,  18,  21,  22,  24,  44,  54,  89,  98,
+      0,  27,  84,   0,   0,  27,  44,  54,  33,  44,  54,  89,   0,   0,  27,  35,
+     44,  84,  89,  98,  87,  88,  89,  90,  95,  96,  97,  17,  12,  13,  21,   0,
+     54,  64,  74,  84,  85,  86,  87,  88,  89,  98,   2,  27,  98,   0,   0,   0,
+     86,  87,  88,   0,  39,  41,  43,  33,  43,  27,  29,  31,  41,  43,  27,  29,
+     31,  33,  35,  29,  31,  31,  33,  35,  27,  29,  31,  31,  33,  35, 118, 121,
+     33,  35,  31,  31,  33,  33,  33,  33,  37,  39,  39,  39,  41,  41,  43,  43,
+     43,  43,  29,  31,  33,  35,  37,  27,  35,  35,  29,  31,  27,  29,  13,  21,
+     24,  13,  21,   7,  12,   9,  12,  12,  17,  13,  21,  74,  84,  33,  35,  37,
+     39,  41,  43,   0,  41,  43,   0,  44,  89, 107, 127, 128, 129, 130,   0,   0,
+     87,  88,   0,   0,  41,  43,   2,  27,   2,   2,  27,  29,  33,   0,   0,   0,
+      0,   0,   0,  64,   0,  33,   0,   0,  43,   0,   0,   0,
+};
+
+/* Numeric_Value: 3228 bytes. */
+
+RE_UINT32 re_get_numeric_value(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 12;
+    code = ch ^ (f << 12);
+    pos = (RE_UINT32)re_numeric_value_stage_1[f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_numeric_value_stage_2[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_numeric_value_stage_3[pos + f] << 3;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_numeric_value_stage_4[pos + f] << 2;
+    value = re_numeric_value_stage_5[pos + code];
+
+    return value;
+}
+
+/* Bidi_Mirrored. */
+
+static RE_UINT8 re_bidi_mirrored_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_bidi_mirrored_stage_2[] = {
+    0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+
+static RE_UINT8 re_bidi_mirrored_stage_3[] = {
+     0,  1,  1,  1,  1,  1,  1,  2,  1,  1,  1,  3,  1,  1,  1,  1,
+     4,  5,  1,  6,  7,  8,  1,  9, 10,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 11,
+     1,  1,  1, 12,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_bidi_mirrored_stage_4[] = {
+     0,  1,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+     3,  3,  3,  3,  4,  3,  3,  3,  3,  3,  5,  3,  3,  3,  3,  3,
+     6,  7,  8,  3,  3,  9,  3,  3, 10, 11, 12, 13, 14,  3,  3,  3,
+     3,  3,  3,  3,  3, 15,  3, 16,  3,  3,  3,  3,  3,  3, 17, 18,
+    19, 20, 21, 22,  3,  3,  3,  3, 23,  3,  3,  3,  3,  3,  3,  3,
+    24,  3,  3,  3,  3,  3,  3,  3,  3, 25,  3,  3, 26, 27,  3,  3,
+     3,  3,  3, 28, 29, 30, 31, 32,
+};
+
+static RE_UINT8 re_bidi_mirrored_stage_5[] = {
+      0,   0,   0,   0,   0,   3,   0,  80,   0,   0,   0,  40,   0,   0,   0,  40,
+      0,   0,   0,   0,   0,   8,   0,   8,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  60,   0,   0,   0,  24,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   6,  96,   0,   0,   0,   0,   0,   0,  96,
+      0,  96,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,
+     30,  63,  98, 188,  87, 248,  15, 250, 255,  31,  60, 128, 245, 207, 255, 255,
+    255, 159,   7,   1, 204, 255, 255, 193,   0,  62, 195, 255, 255,  63, 255, 255,
+      0,  15,   0,   0,   3,   6,   0,   0,   0,   0,   0,   0,   0, 255,  63,   0,
+    121,  59, 120, 112, 252, 255,   0,   0, 248, 255, 255, 249, 255, 255,   0,   1,
+     63, 194,  55,  31,  58,   3, 240,  51,   0, 252, 255, 223,  83, 122,  48, 112,
+      0,   0, 128,   1,  48, 188,  25, 254, 255, 255, 255, 255, 207, 191, 255, 255,
+    255, 255, 127,  80, 124, 112, 136,  47,  60,  54,   0,  48, 255,   3,   0,   0,
+      0, 255, 243,  15,   0,   0,   0,   0,   0,   0,   0, 126,  48,   0,   0,   0,
+      0,   3,   0,  80,   0,   0,   0,  40,   0,   0,   0, 168,  13,   0,   0,   0,
+      0,   0,   0,   8,   0,   0,   0,   0,   0,   0,  32,   0,   0,   0,   0,   0,
+      0, 128,   0,   0,   0,   0,   0,   0,   0,   2,   0,   0,   0,   0,   0,   0,
+      8,   0,   0,   0,   0,   0,   0,   0,
+};
+
+/* Bidi_Mirrored: 489 bytes. */
+
+RE_UINT32 re_get_bidi_mirrored(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_bidi_mirrored_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_bidi_mirrored_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_bidi_mirrored_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_bidi_mirrored_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_bidi_mirrored_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Indic_Positional_Category. */
+
+static RE_UINT8 re_indic_positional_category_stage_1[] = {
+    0, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_indic_positional_category_stage_2[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,
+     8,  0,  0,  0,  0,  0,  0,  9,  0, 10, 11, 12, 13,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0, 14, 15, 16, 17,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 18,  0,  0,  0,  0,  0,
+    19, 20, 21, 22, 23, 24, 25, 26,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_indic_positional_category_stage_3[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      1,   0,   0,   2,   3,   4,   5,   0,   6,   0,   0,   7,   8,   9,   5,   0,
+     10,   0,   0,   7,  11,   0,   0,  12,  10,   0,   0,   7,  13,   0,   5,   0,
+      6,   0,   0,  14,  15,  16,   5,   0,  17,   0,   0,  18,  19,   9,   0,   0,
+     20,   0,   0,  21,  22,  23,   5,   0,   6,   0,   0,  14,  24,  25,   5,   0,
+      6,   0,   0,  18,  26,   9,   5,   0,  27,   0,   0,   0,  28,  29,   0,  27,
+      0,   0,   0,  30,  31,   0,   0,   0,   0,   0,   0,  32,  33,   0,   0,   0,
+      0,  34,   0,  35,   0,   0,   0,  36,  37,  38,  39,  40,  41,   0,   0,   0,
+      0,   0,  42,  43,   0,  44,  45,  46,  47,  48,   0,   0,   0,   0,   0,   0,
+      0,  49,   0,  49,   0,  50,   0,  50,   0,   0,   0,  51,  52,  53,   0,   0,
+      0,   0,  54,  55,   0,   0,   0,   0,   0,   0,   0,  56,  57,   0,   0,   0,
+      0,  58,   0,   0,   0,  59,  60,  61,   0,   0,   0,   0,   0,   0,   0,   0,
+     62,   0,   0,  63,  64,   0,  65,  66,  67,   0,  68,   0,   0,   0,  69,  70,
+      0,   0,  71,  72,   0,   0,   0,   0,   0,   0,   0,   0,   0,  73,  74,  75,
+     76,   0,  77,   0,   0,   0,   0,   0,  78,   0,   0,  79,  80,   0,  81,  82,
+      0,   0,  83,   0,  84,  70,   0,   0,   1,   0,   0,  85,  86,   0,  87,   0,
+      0,   0,  88,  89,  90,   0,   0,  91,   0,   0,   0,  92,  93,   0,  94,  95,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  96,   0,
+     97,   0,   0,  98,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     99,   0,   0, 100, 101,   0,   0,   0,  67,   0,   0, 102,   0,   0,   0,   0,
+    103,   0, 104, 105,   0,   0,   0, 106,  67,   0,   0, 107, 108,   0,   0,   0,
+      0,   0, 109, 110,   0,   0,   0,   0,   0,   0,   0,   0,   0, 111, 112,   0,
+      6,   0,   0,  18, 113,   9, 114, 115,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 116, 117,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 118, 119, 120, 121,   0,   0,
+      0,   0,   0, 122, 123,   0,   0,   0,   0,   0, 124, 125,   0,   0,   0,   0,
+      0, 126, 127,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_indic_positional_category_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  2,  3,  4,  5,  6,  7,  1,  2,  8,  5,  9,
+    10,  7,  1,  6,  0,  0,  0,  0,  0,  6,  0,  0,  0,  0,  0,  0,
+    10,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,  4,
+     5,  6,  3, 11, 12, 13, 14,  0,  0,  0,  0, 15,  0,  0,  0,  0,
+    10,  2,  0,  0,  0,  0,  0,  0,  5,  3,  0, 10, 16, 10, 17,  0,
+     1,  0, 18,  0,  0,  0,  0,  0,  5,  6,  7, 10, 19, 15,  5,  0,
+     0,  0,  0,  0,  0,  0,  3, 20,  5,  6,  3, 11, 21, 13, 22,  0,
+     0,  0,  0, 19,  0,  0,  0,  0,  0, 16,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  8,  2, 23,  0, 24, 12, 25, 26,  0,
+     2,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,
+     2,  8, 23,  1, 27,  1,  1,  0,  0,  0, 10,  3,  0,  0,  0,  0,
+    28,  8, 23, 19, 29, 30,  1,  0,  0,  0, 15, 23,  0,  0,  0,  0,
+     8,  5,  3, 24, 12, 25, 26,  0,  0,  8,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 16,  0, 15,  8,  1,  3,  3,  4, 31, 32, 33,
+    20,  8,  1,  1,  6,  3,  0,  0, 34, 34, 35, 10,  1,  1,  1, 16,
+    20,  8,  1,  1,  6, 10,  3,  0, 34, 34, 36,  0,  1,  1,  1,  0,
+     0,  0,  0,  0,  6,  0,  0,  0,  0,  0, 18, 18, 10,  0,  0,  4,
+    18, 37,  6, 38, 38,  1,  1,  2, 37,  1,  3,  1,  0,  0, 18,  6,
+     6,  6,  6,  6, 18,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  3,  0,  0,  0,  0,  3,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 15, 20, 17, 39,  1,  1, 17, 23,  2, 18,  3,
+     0,  0,  0,  8,  6,  0,  0,  6,  3,  8, 23, 15,  8,  8,  8,  0,
+    10,  1, 16,  0,  0,  0,  0,  0,  0, 40, 41,  2,  8,  8,  5, 15,
+     0,  0,  0,  0,  0,  8, 20,  0,  0, 17,  3,  0,  0,  0,  0,  0,
+     0, 17,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,  1, 17,  6, 42,
+    43, 24, 25,  2, 20,  1,  1,  1,  1, 10,  0,  0,  0,  0, 10,  0,
+     1, 40, 44, 45,  2,  8,  0,  0,  8, 40,  8,  8,  5, 17,  0,  0,
+     8,  8, 46, 34,  8, 35,  8,  8, 23,  0,  0,  0,  8,  0,  0,  0,
+     0,  0,  0, 10, 39, 20,  0,  0,  0,  0, 11, 40,  1, 17,  6,  3,
+    15,  2, 20,  1, 17,  7, 40, 24, 24, 41,  1,  1,  1,  1, 16, 18,
+     1,  1, 23,  0,  0,  0,  0,  0,  0,  0,  2,  1,  6, 47, 48, 24,
+    25, 19, 23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,  7,  1,
+     1,  1,  0,  0,  0,  0,  0,  0,  1, 23,  0,  0,  0,  0,  0,  0,
+    15,  6, 17,  9,  1, 23,  6,  0,  0,  0,  0,  2,  1,  8, 20, 20,
+     1,  8,  0,  0,  0,  0,  0,  0,  0,  0,  8,  4, 49,  8,  7,  1,
+     1,  1, 24, 17,  0,  0,  0,  0,  1, 16, 50,  6,  6,  1,  6,  6,
+     2, 51, 51, 51, 52,  0, 18,  0,  0,  0, 16,  0,  0,  0,  0,  0,
+     0,  0,  0, 16,  0, 10,  0,  0,  0, 15,  5,  2,  0,  0,  0,  0,
+     8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  8,  8,  8,  8,  8,
+     8,  8,  3,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 18,  6,  0,
+     0,  0,  0, 18,  6, 17,  6,  7,  0, 10,  8,  1,  6, 24,  2,  8,
+    53,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 10,  1, 17, 54, 41, 40, 55,  3,  0,  0,  0,  0,
+     0, 10,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0, 15,  2,  0,
+     2,  1, 56, 57, 58, 46, 35,  1, 10,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 11,  7,  9,  0,  0, 15,  0,  0,  0,  0,  0,
+     0, 15, 20,  8, 40, 23,  5,  0, 59,  6, 10, 52,  0,  0,  6,  7,
+     0,  0,  0,  0, 17,  3,  0,  0, 20, 23,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  1,  1,  6,  6,  6,  1,  1, 16,  0,  0,  0,  0,
+     4,  5,  7,  2,  5,  3,  0,  0,  1, 16,  0,  0,  0,  0,  0,  0,
+     0,  0,  0, 10,  1,  6, 41, 38, 17,  3, 16,  0,  0,  0,  0,  0,
+     0, 18,  0,  0,  0,  0,  0,  0,  0, 15,  9,  6,  6,  6,  1, 19,
+    23,  0,  0,  0,  0, 10,  3,  0,  0,  0,  0,  0,  0,  0,  8,  5,
+     1, 30,  2,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,
+     4,  5,  7,  1, 17,  3,  0,  0,  2,  8, 23, 11, 12, 13, 33,  0,
+     0,  8,  0,  1,  1,  1, 16,  0,  1,  1, 16,  0,  0,  0,  0,  0,
+     4,  5,  6,  6, 39, 60, 33, 26,  2,  6,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0, 15,  9,  6,  6,  0, 49, 32,  1,  5,
+     3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,
+     8,  5,  6,  6,  7,  2, 20,  5, 16,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0, 10, 20,  9,  6,  1,  1,  5,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 18, 10,  8,  1,  6, 41,  7,  1,  0,  0,
+};
+
+static RE_UINT8 re_indic_positional_category_stage_5[] = {
+     0,  0,  5,  5,  5,  1,  6,  0,  1,  2,  1,  6,  6,  6,  6,  5,
+     1,  1,  2,  1,  0,  5,  0,  2,  2,  0,  0,  4,  4,  6,  0,  1,
+     5,  0,  5,  6,  0,  6,  5,  8,  1,  5,  9,  0, 10,  6,  1,  0,
+     2,  2,  4,  4,  4,  5,  7,  0,  8,  1,  8,  0,  8,  8,  9,  2,
+     4, 10,  4,  1,  3,  3,  3,  1,  3,  0,  5,  7,  7,  7,  6,  2,
+     6,  1,  2,  5,  9, 10,  4,  2,  1,  8,  8,  5,  1,  3,  6, 11,
+     7, 12,  2,  9, 13,  6, 13, 13, 13,  0, 11,  0,  5,  2,  2,  6,
+     6,  3,  3,  5,  5,  3,  0, 13,  5,  9,
+};
+
+/* Indic_Positional_Category: 1842 bytes. */
+
+RE_UINT32 re_get_indic_positional_category(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 13;
+    code = ch ^ (f << 13);
+    pos = (RE_UINT32)re_indic_positional_category_stage_1[f] << 5;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_indic_positional_category_stage_2[pos + f] << 4;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_indic_positional_category_stage_3[pos + f] << 3;
+    f = code >> 1;
+    code ^= f << 1;
+    pos = (RE_UINT32)re_indic_positional_category_stage_4[pos + f] << 1;
+    value = re_indic_positional_category_stage_5[pos + code];
+
+    return value;
+}
+
+/* Indic_Syllabic_Category. */
+
+static RE_UINT8 re_indic_syllabic_category_stage_1[] = {
+    0, 1, 2, 2, 2, 3, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_indic_syllabic_category_stage_2[] = {
+     0,  1,  1,  1,  1,  1,  1,  1,  1,  2,  3,  4,  5,  6,  7,  8,
+     9,  1,  1,  1,  1,  1,  1, 10,  1, 11, 12, 13, 14,  1,  1,  1,
+    15,  1,  1,  1,  1, 16,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1, 17, 18, 19, 20,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 21,  1,  1,  1,  1,  1,
+    22, 23, 24, 25, 26, 27, 28, 29,  1,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_indic_syllabic_category_stage_3[] = {
+      0,   0,   1,   2,   0,   0,   0,   0,   0,   0,   3,   4,   0,   5,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  12,  20,
+     21,  15,  16,  22,  23,  24,  25,  26,  27,  28,  16,  29,  30,   0,  12,  31,
+     14,  15,  16,  29,  32,  33,  12,  34,  35,  36,  37,  38,  39,  40,  25,   0,
+     41,  42,  16,  43,  44,  45,  12,   0,  46,  42,  16,  47,  44,  48,  12,  49,
+     46,  42,   8,  50,  51,  52,  12,  53,  54,  55,   8,  56,  57,  58,  25,  59,
+     60,   8,  61,  62,  63,   2,   0,   0,  64,  65,  66,  67,  68,  69,   0,   0,
+      0,   0,  70,  71,  72,   8,  73,  74,  75,  76,  77,  78,  79,   0,   0,   0,
+      8,   8,  80,  81,  82,  83,  84,  85,  86,  87,   0,   0,   0,   0,   0,   0,
+     88,  89,  90,  89,  90,  91,  88,  92,   8,   8,  93,  94,  95,  96,   2,   0,
+     97,  61,  98,  99,  25,   8, 100, 101,   8,   8, 102, 103, 104,   2,   0,   0,
+      8, 105,   8,   8, 106, 107, 108, 109,   2,   2,   0,   0,   0,   0,   0,   0,
+    110,  90,   8, 111, 112,   2,   0,   0, 113,   8, 114, 115,   8,   8, 116, 117,
+      8,   8, 118, 119, 120,   0,   0,   0,   0,   0,   0,   0,   0, 121, 122, 123,
+    124, 125,   0,   0,   0,   0,   0, 126, 127,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 128,   0,   0,   0,
+    129,   8, 130,   0,   8, 131, 132, 133, 134, 135,   8, 136, 137,   2, 138, 122,
+    139,   8, 140,   8, 141, 142,   0,   0, 143,   8,   8, 144, 145,   2, 146, 147,
+    148,   8, 149, 150, 151,   2,   8, 152,   8,   8,   8, 153, 154,   0, 155, 156,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 157, 158, 159,   2,
+    160, 161,   8, 162, 163,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    164,  90,   8, 165, 166, 167, 168, 169, 170,   8,   8, 171,   0,   0,   0,   0,
+    172,   8, 173, 174,   0, 175,   8, 176, 177, 178,   8, 179, 180,   2, 181, 182,
+    183, 184, 185, 186,   0,   0,   0,   0, 187, 188, 189, 190,   8, 191, 192,   2,
+    193,  15,  16,  29,  32,  40, 194, 195,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0, 196,   8,   8, 197, 198,   2,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0, 199,   8, 200, 201, 202, 203,   0,   0,
+    199,   8,   8, 204, 205,   2,   0,   0, 190,   8, 206, 207,   2,   0,   0,   0,
+      8, 208, 209, 210,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_indic_syllabic_category_stage_4[] = {
+      0,   0,   0,   0,   0,   0,   0,   1,   2,   2,   3,   0,   4,   0,   0,   0,
+      5,   0,   0,   0,   0,   6,   0,   0,   7,   8,   8,   8,   8,   9,  10,  10,
+     10,  10,  10,  10,  10,  10,  11,  12,  13,  13,  13,  14,  15,  16,  10,  10,
+     17,  18,   2,   2,  19,   8,  10,  10,  20,  21,   8,  22,  22,   9,  10,  10,
+     10,  10,  23,  10,  24,  25,  26,  12,  13,  27,  27,  28,   0,  29,   0,  30,
+     26,   0,   0,   0,  20,  21,  31,  32,  23,  33,  26,  34,  35,  29,  27,  36,
+      0,   0,  37,  24,   0,  18,   2,   2,  38,  39,   0,   0,  20,  21,   8,  40,
+     40,   9,  10,  10,  23,  37,  26,  12,  13,  41,  41,  36,   0,   0,  42,   0,
+     13,  27,  27,  36,   0,  43,   0,  30,  42,   0,   0,   0,  44,  21,  31,  19,
+     45,  46,  33,  23,  47,  48,  49,  25,  10,  10,  26,  43,  35,  43,  50,  36,
+      0,  29,   0,   0,   7,  21,   8,  45,  45,   9,  10,  10,  10,  10,  26,  51,
+     13,  50,  50,  36,   0,  52,  49,   0,  20,  21,   8,  45,  10,  37,  26,  12,
+      0,  52,   0,  53,  54,   0,   0,   0,  10,  10,  49,  51,  13,  50,  50,  55,
+      0,  29,   0,  32,   0,   0,  56,  57,  58,  21,   8,   8,   8,  31,  25,  10,
+     30,  10,  10,  42,  10,  49,  59,  29,  13,  60,  13,  13,  43,   0,   0,   0,
+     37,  10,  10,  10,  10,  10,  10,  49,  13,  13,  61,   0,  13,  41,  62,  63,
+     33,  64,  24,  42,   0,  10,  37,  10,  37,  65,  25,  33,  13,  13,  41,  66,
+     13,  67,  62,  68,   2,   2,   3,  10,   2,   2,   2,   2,   2,  69,  70,   0,
+     10,  10,  37,  10,  10,  10,  10,  48,  16,  13,  13,  71,  72,  73,  74,  75,
+     76,  76,  77,  76,  76,  76,  76,  76,  76,  76,  76,  78,   0,  79,   0,   0,
+     80,   8,  81,  13,  13,  82,  83,  84,   2,   2,   3,  85,  86,  17,  87,  88,
+     89,  90,  91,  92,  93,  94,  10,  10,  95,  96,  62,  97,   2,   2,  98,  99,
+    100,  10,  10,  23,  11, 101,   0,   0, 100,  10,  10,  10,  11,   0,   0,   0,
+    102,   0,   0,   0, 103,   8,   8,   8,   8,  43,  13,  13,  13,  71, 104, 105,
+    106,   0,   0, 107, 108,  10,  10,  10,  13,  13, 109,   0, 110, 111, 112,   0,
+    113, 114, 114, 115, 116, 117,   0,   0,  10,  10,  10,   0,  13,  13,  13,  13,
+    118, 111, 119,   0,  10, 120,  13,   0,  10,  10,  10,  80, 100, 121, 111, 122,
+    123,  13,  13,  13,  13,  91, 124, 125, 126, 127,   8,   8,  10, 128,  13,  13,
+     13, 129,  10,   0, 130,   8, 131,  10, 132,  13, 133, 134,   2,   2, 135, 136,
+     10, 137,  13,  13, 138,   0,   0,   0,  10, 139,  13, 118, 111, 140,   0,   0,
+      2,   2,   3,  37, 141, 142, 142, 142, 143,   0,   0,   0, 144, 145, 143,   0,
+      0,   0,   0, 146, 147,   4,   0,   0,   0, 148,   0,   0,   5, 148,   0,   0,
+      0,   0,   0,   4,  40, 149, 150,  10, 120,  13,   0,   0,  10,  10,  10, 151,
+    152, 153, 154,  10, 155,   0,   0,   0, 156,   8,   8,   8, 131,  10,  10,  10,
+     10, 157,  13,  13,  13, 158,   0,   0, 142, 142, 142, 142,   2,   2, 159,  10,
+    151, 114, 160, 119,  10, 120,  13, 161, 162,   0,   0,   0, 163,   8,   9, 100,
+    164,  13,  13, 165, 158,   0,   0,   0,  10, 166,  10,  10,   2,   2, 159,  49,
+      8, 131,  10,  10,  10,  10,  93,  13, 167, 168,   0,   0, 111, 111, 111, 169,
+     37,   0, 170,  92,  13,  13,  13,  96, 171,   0,   0,   0, 131,  10, 120,  13,
+      0, 172,   0,   0,  10,  10,  10,  86, 173,  10, 174, 111, 175,  13,  35, 176,
+     93,  52,   0,  71,  10,  37,  37,  10,  10,   0, 177, 178,   2,   2,   0,   0,
+    179, 180,   8,   8,  10,  10,  13,  13,  13, 181,   0,   0, 182, 183, 183, 183,
+    183, 184,   2,   2,   0,   0,   0, 185, 186,   8,   8,   9,  13,  13, 187,   0,
+    186, 100,  10,  10,  10, 120,  13,  13, 188, 189,   2,   2, 114, 190,  10,  10,
+    164,   0,   0,   0, 186,   8,   8,   8,   9,  10,  10,  10, 120,  13,  13,  13,
+    191,   0, 192,  67, 193,   2,   2,   2,   2, 194,   0,   0,   8,   8,  10,  10,
+     30,  10,  10,  10,  10,  10,  10,  13,  13, 195,   0,   0,   8,  49,  23,  30,
+     10,  10,  10,  30,  10,  10,  48,   0,   8,   8, 131,  10,  10,  10,  10, 150,
+     13,  13, 196,   0,   7,  21,   8,  22,  17, 197, 142, 145, 142, 145,   0,   0,
+     21,   8,   8, 100,  13,  13,  13, 198, 199, 107,   0,   0,   8,   8,   8, 131,
+     10,  10,  10, 120,  13,  99,  13, 200, 201,   0,   0,   0,   0,   0,   8,  99,
+     13,  13,  13, 202,  67,   0,   0,   0,  10,  10, 150, 203,  13, 204,   0,   0,
+     10,  10,  26, 205,  13,  13, 206,   0,   2,   2,   2,   0,
+};
+
+static RE_UINT8 re_indic_syllabic_category_stage_5[] = {
+     0,  0,  0,  0,  0, 11,  0,  0, 33, 33, 33, 33, 33, 33,  0,  0,
+    11,  0,  0,  0,  0,  0, 28, 28,  0,  0,  0, 11,  1,  1,  1,  2,
+     8,  8,  8,  8,  8, 12, 12, 12, 12, 12, 12, 12, 12, 12,  9,  9,
+     4,  3,  9,  9,  9,  9,  9,  9,  9,  5,  9,  9,  0, 26, 26,  0,
+     0,  9,  9,  9,  8,  8,  9,  9,  0,  0, 33, 33,  0,  0,  8,  8,
+     0,  1,  1,  2,  0,  8,  8,  8,  8,  0,  0,  8, 12,  0, 12, 12,
+    12,  0, 12,  0,  0,  0, 12, 12, 12, 12,  0,  0,  9,  0,  0,  9,
+     9,  5, 13,  0,  0,  0,  0,  9, 12, 12,  0, 12,  8,  8,  8,  0,
+     0,  0,  0,  8,  0, 12, 12,  0,  4,  0,  9,  9,  9,  9,  9,  0,
+     9,  5,  0,  0,  0, 12, 12, 12,  1, 25, 11, 11,  0, 19,  0,  0,
+     8,  8,  0,  8,  9,  9,  0,  9,  0, 12,  0,  0,  0,  0,  9,  9,
+     0,  0,  1, 22,  8,  0,  8,  8,  8, 12,  0,  0,  0,  0,  0, 12,
+    12,  0,  0,  0, 12, 12, 12,  0,  9,  0,  9,  9,  0,  3,  9,  9,
+     0,  9,  9,  0,  0,  0, 12,  0,  0, 14, 14,  0,  9,  5, 16,  0,
+     0,  0, 13, 13, 13, 13, 13, 13,  0,  0,  1,  2,  0,  0,  5,  0,
+     9,  0,  9,  0,  9,  9,  6,  0, 24, 24, 24, 24, 29,  1,  6,  0,
+    12,  0,  0, 12,  0, 12,  0, 12, 19, 19,  0,  0,  9,  0,  0,  0,
+     0,  1,  0,  0,  0, 28,  0, 28,  0,  4,  0,  0,  9,  9,  1,  2,
+     9,  9,  1,  1,  6,  3,  0,  0, 21, 21, 21, 21, 21, 18, 18, 18,
+    18, 18, 18, 18,  0, 18, 18, 18, 18,  0,  0,  0,  0,  0, 28,  0,
+    12,  8,  8,  8,  8,  8,  8,  9,  9,  9,  1, 24,  2,  7,  6, 19,
+    19, 19, 19, 12,  0,  0, 11,  0, 12, 12,  8,  8,  9,  9, 12, 12,
+    12, 12, 19, 19, 19, 12,  9, 24, 24, 12, 12,  9,  9, 24, 24, 24,
+    24, 24, 12, 12, 12,  9,  9,  9,  9, 12, 12, 12, 12, 12, 19,  9,
+     9,  9,  9, 24, 24, 24, 12, 24, 33, 33, 24, 24,  9,  9,  0,  0,
+     8,  8,  8, 12,  6,  0,  0,  0, 12,  0,  9,  9, 12, 12, 12,  8,
+     9, 27, 27, 28, 17, 29, 28, 28, 28,  6,  7, 28,  3,  0,  0,  0,
+    11, 12, 12, 12,  9, 18, 18, 18, 20, 20,  1, 20, 20, 20, 20, 20,
+    20, 20,  9, 28, 12, 12, 12, 10, 10, 10, 10, 10, 10, 10,  0,  0,
+    23, 23, 23, 23, 23,  0,  0,  0,  9, 20, 20, 20, 24, 24,  0,  0,
+    12, 12, 12,  9, 12, 19, 19, 20, 20, 20, 20,  0,  7,  9,  9,  9,
+    24, 24, 28, 28, 28,  0,  0, 28,  1,  1,  1, 17,  2,  8,  8,  8,
+     4,  9,  9,  9,  5, 12, 12, 12,  1, 17,  2,  8,  8,  8, 12, 12,
+    12, 18, 18, 18,  9,  9,  6,  7, 18, 18, 12, 12, 33, 33,  3, 12,
+    12, 12, 20, 20,  8,  8,  4,  9, 20, 20,  6,  6, 18, 18,  9,  9,
+     1,  1, 28,  4, 26, 26, 26,  0, 26, 26, 26, 26, 26, 26,  0,  0,
+     0,  0,  2,  2, 26,  0,  0,  0, 30, 31,  0,  0, 11, 11, 11, 11,
+    28,  0,  0,  0,  8,  8,  6, 12, 12, 12, 12,  1, 12, 12, 10, 10,
+    10, 10, 12, 12, 12, 12, 10, 18, 18, 12, 12, 12, 12, 18, 12,  1,
+     1,  2,  8,  8, 20,  9,  9,  9,  5,  0,  0,  0, 33, 33, 12, 12,
+    10, 10, 10, 24,  9,  9,  9, 20, 20, 20, 20,  6,  1,  1, 17,  2,
+    12, 12, 12,  4,  9, 18, 19, 19, 12,  9,  0, 12,  9,  9,  9, 19,
+    19, 19, 19,  0, 20, 20,  0,  0,  0,  0, 12, 24, 23, 24, 23,  0,
+     0,  2,  7,  0, 12,  8, 12, 12, 12, 12, 12, 20, 20, 20, 20,  9,
+    24,  6,  0,  0,  4,  4,  4,  0,  0,  0,  0,  7,  1,  1,  2, 14,
+    14,  8,  8,  8,  9,  9,  5,  0,  0,  0, 34, 34, 34, 34, 34, 34,
+    34, 34, 33, 33,  0,  0,  0, 32,  1,  1,  2,  8,  9,  5,  4,  0,
+     9,  9,  9,  7,  6,  0, 33, 33, 10, 12, 12, 12,  5,  3, 15, 15,
+     0,  0,  4,  9,  0, 33, 33, 33, 33,  0,  0,  0,  1,  5,  4, 25,
+     9,  4,  6,  0,  0,  0, 26, 26,  9,  9,  9,  1,  1,  2,  5,  4,
+     1,  1,  2,  5,  4,  0,  0,  0,  9,  1,  2,  5,  2,  9,  9,  9,
+     9,  9,  5,  4,  0, 19, 19, 19,  9,  9,  9,  6,
+};
+
+/* Indic_Syllabic_Category: 2448 bytes. */
+
+RE_UINT32 re_get_indic_syllabic_category(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 13;
+    code = ch ^ (f << 13);
+    pos = (RE_UINT32)re_indic_syllabic_category_stage_1[f] << 5;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_indic_syllabic_category_stage_2[pos + f] << 4;
+    f = code >> 4;
+    code ^= f << 4;
+    pos = (RE_UINT32)re_indic_syllabic_category_stage_3[pos + f] << 2;
+    f = code >> 2;
+    code ^= f << 2;
+    pos = (RE_UINT32)re_indic_syllabic_category_stage_4[pos + f] << 2;
+    value = re_indic_syllabic_category_stage_5[pos + code];
+
+    return value;
+}
+
+/* Alphanumeric. */
+
+static RE_UINT8 re_alphanumeric_stage_1[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3,
+};
+
+static RE_UINT8 re_alphanumeric_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 13, 13, 13, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 13, 13, 26, 27, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 28,  7, 29, 30,  7, 31, 13, 13, 13, 13, 13, 32,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_alphanumeric_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1, 17, 18, 19,  1, 20, 21, 22, 23, 24, 25, 26, 27,  1, 28,
+    29, 30, 31, 31, 32, 31, 31, 31, 31, 31, 31, 31, 33, 34, 35, 31,
+    36, 37, 31, 31,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 38,  1,  1,  1,  1,  1,  1,  1,  1,  1, 39,
+     1,  1,  1,  1, 40,  1, 41, 42, 43, 44, 45, 46,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1, 47, 31, 31, 31, 31, 31, 31, 31, 31,
+    31,  1, 48, 49,  1, 50, 51, 52, 53, 54, 55, 56, 57, 58,  1, 59,
+    60, 61, 62, 63, 64, 31, 31, 31, 65, 66, 67, 68, 69, 70, 71, 72,
+    73, 31, 74, 31, 31, 31, 31, 31,  1,  1,  1, 75, 76, 77, 31, 31,
+     1,  1,  1,  1, 78, 31, 31, 31, 31, 31, 31, 31,  1,  1, 79, 31,
+     1,  1, 80, 81, 31, 31, 31, 82, 83, 31, 31, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 84, 31, 31, 31, 31, 31, 31, 31, 85, 86, 87, 88,
+    89, 31, 31, 31, 31, 31, 90, 31, 31, 91, 31, 31, 31, 31, 31, 31,
+     1,  1,  1,  1,  1,  1, 92,  1,  1,  1,  1,  1,  1,  1,  1, 93,
+    94,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 95, 31,
+     1,  1, 96, 31, 31, 31, 31, 31,
+};
+
+static RE_UINT8 re_alphanumeric_stage_4[] = {
+      0,   1,   2,   2,   0,   3,   4,   4,   5,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,   5,   5,   5,   6,   7,   0,   0,   8,   9,  10,  11,   5,  12,
+      5,   5,   5,   5,  13,   5,   5,   5,   5,  14,  15,  16,  17,  18,  19,  20,
+     21,   5,  22,  23,   5,   5,  24,  25,  26,   5,  27,   5,   5,  28,   5,  29,
+     30,  31,  32,   0,   0,  33,   0,  34,   5,  35,  36,  37,  38,  39,  40,  41,
+     42,  43,  44,  45,  46,  47,  48,  49,  50,  47,  51,  52,  53,  54,  55,  56,
+     57,  58,  59,  60,  61,  62,  63,  64,  61,  65,  66,  67,  68,  69,  70,  71,
+     16,  72,  73,   0,  74,  75,  76,   0,  77,  78,  79,  80,  81,  82,   0,   0,
+      5,  83,  84,  85,  86,   5,  87,  88,   5,   5,  89,   5,  90,  91,  92,   5,
+     93,   5,  94,   0,  95,   5,   5,  96,  16,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,  97,   2,   5,   5,  98,  99, 100, 100, 101,   5, 102, 103,  78,
+      1,   5,   5, 104,   5, 105,   5, 106, 107, 108, 109, 110,   5, 111, 112,   0,
+    113,   5, 107, 114, 112, 115,   0,   0,   5, 116, 117,   0,   5, 118,   5, 119,
+      5, 106, 120, 121,   0,   0,   0, 122,   5,   5,   5,   5,   5,   5,   0, 123,
+     96,   5, 124, 121,   5, 125, 126, 127,   0,   0,   0, 128, 129,   0,   0,   0,
+    130, 131, 132,   5, 133,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 134,   5,  78,   5, 135, 107,   5,   5,   5,   5, 136,
+      5,  87,   5, 137, 138, 139, 139,   5,   0, 140,   0,   0,   0,   0,   0,   0,
+    141, 142,  16,   5, 143,  16,   5,  88, 144, 145,   5,   5, 146,  72,   0,  26,
+      5,   5,   5,   5,   5, 106,   0,   0,   5,   5,   5,   5,   5,   5, 106,   0,
+      5,   5,   5,   5,  31,   0,  26, 121, 147, 148,   5, 149,   5,   5,   5,  95,
+    150, 151,   5,   5, 152, 153,   0, 150, 154,  17,   5, 100,   5,   5, 155, 156,
+      5, 105, 157,  82,   5, 158, 159, 160,   5, 138, 161, 162,   5, 107, 163, 164,
+    165, 166,  88, 167,   5,   5,   5, 168,   5,   5,   5,   5,   5, 169, 170, 113,
+      5,   5,   5, 171,   5,   5, 172,   0, 173, 174, 175,   5,   5,  28, 176,   5,
+      5, 121,  26,   5, 177,   5,  17, 178,   0,   0,   0, 179,   5,   5,   5,  82,
+      1,   2,   2, 109,   5, 107, 180,   0, 181, 182, 183,   0,   5,   5,   5,  72,
+      0,   0,   5,  33,   0,   0,   0,   0,   0,   0,   0,   0,  82,   5, 184,   0,
+      5,  26, 105,  72, 121,   5, 185,   0,   5,   5,   5,   5, 121,  78,   0,   0,
+      5, 186,   5, 187,   0,   0,   0,   0,   5, 138, 106,  17,   0,   0,   0,   0,
+    188, 189, 106, 138, 107,   0,   0, 190, 106, 172,   0,   0,   5, 191,   0,   0,
+    192, 100,   0,  82,  82,   0,  79, 193,   5, 106, 106, 157,  28,   0,   0,   0,
+      5,   5, 133,   0,   5, 157,   5, 157,   5,   5, 194,  56, 151,  32,  26, 195,
+      5, 196,  26, 197,   5,   5, 198,   0, 199, 200,   0,   0, 201, 202,   5, 195,
+     38,  47, 203, 187,   0,   0,   0,   0,   0,   0,   0,   0,   5,   5, 204,   0,
+      0,   0,   0,   0,   5, 205, 206,   0,   5, 107, 207,   0,   5, 106,  78,   0,
+    208, 168,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   5,   5, 209,
+      0,   0,   0,   0,   0,   0,   5,  32,   5,   5,   5,   5, 172,   0,   0,   0,
+      5,   5,   5, 146,   5,   5,   5,   5,   5,   5, 187,   0,   0,   0,   0,   0,
+      5, 146,   0,   0,   0,   0,   0,   0,   5,   5, 210,   0,   0,   0,   0,   0,
+      5,  32, 107,  78,   0,   0,  26, 211,   5, 138, 155, 212,  95,   0,   0,   0,
+      5,   5, 213, 107, 176,   0,   0,   0, 214,   0,   0,   0,   0,   0,   0,   0,
+      5,   5,   5, 215, 216,   0,   0,   0,   5,   5, 217,   5, 218, 219, 220,   5,
+    221, 222, 223,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5, 224, 225,  88,
+    217, 217, 135, 135, 226, 226, 227,   5,   5,   5,   5,   5,   5,   5, 193,   0,
+    220, 228, 229, 230, 231, 232,   0,   0,   0,  26,  84,  84,  78,   0,   0,   0,
+      5,   5,   5,   5,   5,   5, 138,   0,   5,  33,   5,   5,   5,   5,   5,   5,
+    121,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5, 214,   0,   0,
+    121,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_alphanumeric_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 254, 255, 255,   7,   0,   4,  32,   4,
+    255, 255, 127, 255, 255, 255, 255, 255, 195, 255,   3,   0,  31,  80,   0,   0,
+     32,   0,   0,   0,   0,   0, 223, 188,  64, 215, 255, 255, 251, 255, 255, 255,
+    255, 255, 191, 255,   3, 252, 255, 255, 255, 255, 254, 255, 255, 255, 127,   2,
+    254, 255, 255, 255, 255,   0,   0,   0,   0,   0, 255, 191, 182,   0, 255, 255,
+    255,   7,   7,   0,   0,   0, 255,   7, 255, 255, 255, 254, 255, 195, 255, 255,
+    255, 255, 239,  31, 254, 225, 255, 159,   0,   0, 255, 255,   0, 224, 255, 255,
+    255, 255,   3,   0, 255,   7,  48,   4, 255, 255, 255, 252, 255,  31,   0,   0,
+    255, 255, 255,   1, 255, 255,  31,   0, 248,   3, 255, 255, 255, 255, 255, 239,
+    255, 223, 225, 255, 207, 255, 254, 255, 239, 159, 249, 255, 255, 253, 197, 227,
+    159,  89, 128, 176, 207, 255,   3,   0, 238, 135, 249, 255, 255, 253, 109, 195,
+    135,  25,   2,  94, 192, 255,  63,   0, 238, 191, 251, 255, 255, 253, 237, 227,
+    191,  27,   1,   0, 207, 255,   0,   2, 238, 159, 249, 255, 159,  25, 192, 176,
+    207, 255,   2,   0, 236, 199,  61, 214,  24, 199, 255, 195, 199,  29, 129,   0,
+    192, 255,   0,   0, 239, 223, 253, 255, 255, 253, 255, 227, 223,  29,  96,   7,
+    207, 255,   0,   0, 238, 223, 253, 255, 255, 253, 239, 227, 223,  29,  96,  64,
+    207, 255,   6,   0, 255, 255, 255, 231, 223,  93, 128, 128, 207, 255,   0, 252,
+    236, 255, 127, 252, 255, 255, 251,  47, 127, 128,  95, 255, 192, 255,  12,   0,
+    255, 255, 255,   7, 127,  32, 255,   3, 150,  37, 240, 254, 174, 236, 255,  59,
+     95,  32, 255, 243,   1,   0,   0,   0, 255,   3,   0,   0, 255, 254, 255, 255,
+    255,  31, 254, 255,   3, 255, 255, 254, 255, 255, 255,  31, 255, 255, 127, 249,
+    255,   3, 255, 255, 231, 193, 255, 255, 127,  64, 255,  51, 191,  32, 255, 255,
+    255, 255, 255, 247, 255,  61, 127,  61, 255,  61, 255, 255, 255, 255,  61, 127,
+     61, 255, 127, 255, 255, 255,  61, 255, 255, 255, 255, 135, 255, 255,   0,   0,
+    255, 255,  63,  63, 255, 159, 255, 255, 255, 199, 255,   1, 255, 223,  15,   0,
+    255, 255,  15,   0, 255, 223,  13,   0, 255, 255, 207, 255, 255,   1, 128,  16,
+    255, 255, 255,   0, 255,   7, 255, 255, 255, 255,  63,   0, 255, 255, 255, 127,
+    255,  15, 255,   1, 192, 255, 255, 255, 255,  63,  31,   0, 255,  15, 255, 255,
+    255,   3, 255,   3, 255, 255, 255,  15, 254, 255,  31,   0, 128,   0,   0,   0,
+    255, 255, 239, 255, 239,  15, 255,   3, 255, 243, 255, 255, 191, 255,   3,   0,
+    255, 227, 255, 255, 255, 255, 255,  63,   0, 222, 111,   0, 128, 255,  31,   0,
+     63,  63, 255, 170, 255, 255, 223,  95, 220,  31, 207,  15, 255,  31, 220,  31,
+      0,   0,   2, 128,   0,   0, 255,  31, 132, 252,  47,  62,  80, 189, 255, 243,
+    224,  67,   0,   0, 255,   1,   0,   0,   0,   0, 192, 255, 255, 127, 255, 255,
+     31, 120,  12,   0, 255, 128,   0,   0, 255, 255, 127,   0, 127, 127, 127, 127,
+      0, 128,   0,   0, 224,   0,   0,   0, 254,   3,  62,  31, 255, 255, 127, 224,
+    224, 255, 255, 255, 255,  63, 254, 255, 255, 127,   0,   0, 255,  31, 255, 255,
+    255,  15,   0,   0, 255, 127, 240, 143,   0,   0, 128, 255, 252, 255, 255, 255,
+    255, 249, 255, 255, 255,  63, 255,   0, 187, 247, 255, 255,  15,   0, 255,   3,
+      0,   0, 252,  40, 255, 255,   7,   0, 255, 255, 247, 255,   0, 128, 255,   3,
+    223, 255, 255, 127, 255,  63, 255,   3, 255, 255, 127, 196,   5,   0,   0,  56,
+    255, 255,  60,   0, 126, 126, 126,   0, 127, 127, 255, 255,  63,   0, 255, 255,
+    255,   7, 255,   3,  15,   0, 255, 255, 127, 248, 255, 255, 255,  63, 255, 255,
+    255, 255, 255,   3, 127,   0, 248, 224, 255, 253, 127,  95, 219, 255, 255, 255,
+      0,   0, 248, 255, 255, 255, 252, 255,   0,   0, 255,  15,   0,   0, 223, 255,
+    252, 252, 252,  28, 255, 239, 255, 255, 127, 255, 255, 183, 255,  63, 255,  63,
+    255, 255,   1,   0,  15, 255,  62,   0, 255,   0, 255, 255,  15,   0,   0,   0,
+     63, 253, 255, 255, 255, 255, 191, 145, 255, 255,  55,   0, 255, 255, 255, 192,
+    111, 240, 239, 254,  31,   0,   0,   0,  63,   0,   0,   0, 255,   1, 255,   3,
+    255, 255, 199, 255, 255, 255,  71,   0,  30,   0, 255,  23, 255, 255, 251, 255,
+    255, 255, 159,   0, 127, 189, 255, 191, 255,   1, 255, 255, 159,  25, 129, 224,
+    179,   0, 255,   3, 255, 255,  63, 127,   0,   0,   0,  63,  17,   0, 255,   3,
+    255, 255, 255, 227, 255,   3,   0, 128, 127,   0,   0,   0, 255,  63,   0,   0,
+    248, 255, 255, 224,  31,   0, 255, 255,   3,   0,   0,   0, 255,   7, 255,  31,
+    255,   1, 255,  67, 255, 255, 223, 255, 255, 255, 255, 223, 100, 222, 255, 235,
+    239, 255, 255, 255, 191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,
+     63, 255, 255, 255, 253, 255, 255, 247, 255, 253, 255, 255, 247, 207, 255, 255,
+    150, 254, 247,  10, 132, 234, 150, 170, 150, 247, 247,  94, 255, 251, 255,  15,
+    238, 251, 255,  15,
+};
+
+/* Alphanumeric: 2117 bytes. */
+
+RE_UINT32 re_get_alphanumeric(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_alphanumeric_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_alphanumeric_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_alphanumeric_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_alphanumeric_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_alphanumeric_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Any. */
+
+RE_UINT32 re_get_any(RE_UINT32 ch) {
+    return 1;
+}
+
+/* Blank. */
+
+static RE_UINT8 re_blank_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_blank_stage_2[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_blank_stage_3[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
+    3, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_blank_stage_4[] = {
+    0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 3, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 1, 1, 1,
+    3, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_blank_stage_5[] = {
+      0,   2,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   1,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,
+    255,   7,   0,   0,   0, 128,   0,   0,   0,   0,   0, 128,   0,   0,   0,   0,
+};
+
+/* Blank: 169 bytes. */
+
+RE_UINT32 re_get_blank(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_blank_stage_1[f] << 3;
+    f = code >> 13;
+    code ^= f << 13;
+    pos = (RE_UINT32)re_blank_stage_2[pos + f] << 4;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_blank_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_blank_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_blank_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Graph. */
+
+static RE_UINT8 re_graph_stage_1[] = {
+    0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 4, 8,
+    4, 8,
+};
+
+static RE_UINT8 re_graph_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13,  7,  7,  7, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 26, 13, 27, 28, 29,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 30,  7, 31, 32,  7, 33, 13, 13, 13, 13, 13, 34,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    35, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 36,
+};
+
+static RE_UINT8 re_graph_stage_3[] = {
+      0,   1,   1,   2,   1,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
+     14,   1,  15,  16,   1,   1,  17,  18,  19,  20,  21,  22,  23,  24,   1,  25,
+     26,  27,   1,  28,  29,   1,   1,   1,   1,   1,   1,  30,  31,  32,  33,  34,
+     35,  36,  37,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,  38,   1,   1,   1,   1,   1,   1,   1,   1,   1,  39,
+      1,   1,   1,   1,  40,   1,  41,  42,  43,  44,  45,  46,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,  47,  48,  48,  48,  48,  48,  48,  48,  48,
+      1,   1,  49,  50,   1,  51,  52,  53,  54,  55,  56,  57,  58,  59,   1,  60,
+     61,  62,  63,  64,  65,  48,  66,  48,  67,  68,  69,  70,  71,  72,  73,  74,
+     75,  48,  76,  48,  48,  48,  48,  48,   1,   1,   1,  77,  78,  79,  48,  48,
+      1,   1,   1,   1,  80,  48,  48,  48,  48,  48,  48,  48,   1,   1,  81,  48,
+      1,   1,  82,  83,  48,  48,  48,  84,  85,  48,  48,  48,  48,  48,  48,  48,
+     48,  48,  48,  48,  86,  48,  48,  48,  87,  88,  89,  90,  91,  92,  93,  94,
+      1,   1,  95,  48,  48,  48,  48,  48,  96,  48,  48,  48,  48,  48,  97,  48,
+     98,  99, 100,   1,   1, 101, 102, 103, 104, 105,  48,  48,  48,  48,  48,  48,
+      1,   1,   1,   1,   1,   1, 106,   1,   1,   1,   1,   1,   1,   1,   1, 107,
+    108,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1, 109,  48,
+      1,   1, 110,  48,  48,  48,  48,  48, 111, 112,  48,  48,  48,  48,  48,  48,
+      1,   1,   1,   1,   1,   1,   1, 113,
+};
+
+static RE_UINT8 re_graph_stage_4[] = {
+      0,   1,   2,   3,   0,   1,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   4,   5,   6,   2,   2,   2,   7,   8,   1,   9,   2,  10,  11,
+     12,   2,   2,   2,   2,   2,   2,   2,  13,   2,  14,   2,   2,  15,   2,  16,
+      2,  17,  18,   0,   0,  19,   0,  20,   2,   2,   2,   2,  21,  22,  23,  24,
+     25,  26,  27,  28,  29,  30,  31,  32,  33,  30,  34,  35,  36,  37,  38,  39,
+     40,  41,  42,  43,  44,  45,  46,  47,  44,  48,  49,  50,  51,  52,  53,  54,
+      1,  55,  56,   0,  57,  58,  59,   0,   2,   2,  60,  61,  62,  12,  63,   0,
+      2,   2,   2,   2,   2,   2,  64,   2,   2,   2,  65,   2,  66,  67,  68,   2,
+     69,   2,  48,  70,  71,   2,   2,  72,   2,   2,   2,   2,  73,   2,   2,  74,
+     75,  76,  77,  78,   2,   2,  79,  80,  81,   2,   2,  82,   2,  83,   2,  84,
+      3,  85,  86,  87,   2,  88,  89,   2,  90,   2,   3,  91,  80,  17,   0,   0,
+      2,   2,  88,  70,   2,   2,   2,  92,   2,  93,  94,   2,   0,   0,  10,  95,
+      2,   2,   2,   2,   2,   2,   2,  96,  72,   2,  97,  79,   2,  98,  99, 100,
+    101, 102,   3, 103, 104,   3, 105, 106,   2,   2,   2,   2,  88,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,  16,   2, 107, 108,   2,   2,   2,   2,   2,
+      2,   2,   2, 109, 110, 111, 112, 113,   2, 114,   3,   2,   2,   2,   2, 115,
+      2,  64,   2, 116,  76, 117, 117,   2,   2,   2, 118,   0, 119,   2,   2,  77,
+      2,   2,   2,   2,   2,   2,  84, 120,   1,   2,   1,   2,   8,   2,   2,   2,
+    121, 122,   2,   2, 114,  16,   2, 123,   3,   2,   2,   2,   2,   2,   2,   3,
+      2,   2,   2,   2,   2,  84,   2,   2,   2,   2,   2,   2,   2,   2,  84,   0,
+      2,   2,   2,   2, 124,   2, 125,   2,   2, 126,   2,   2,   2,   2,   2,  82,
+      2,   2,   2,   2,   2, 127,   0, 128,   2, 129,   2,  82,   2,   2, 130,  79,
+      2,   2, 131,  70,   2,   2, 132,   3,   2,  76, 133,   2,   2,   2, 134,  76,
+    135, 136,   2, 137,   2,   2,   2, 138,   2,   2,   2,   2,   2, 123, 139,  56,
+      0,   0,   0,   0,   0,   0,   0,   0,   2,   2,   2, 140,   2,   2,  71,   0,
+    141, 142, 143,   2,   2,   2, 144,   2,   2,   2, 105,   2, 145,   2, 146, 147,
+     71,   2, 148, 149,   2,   2,   2,  91,   1,   2,   2,   2,   2,   3, 150, 151,
+    152, 153, 154,   0,   2,   2,   2,  16, 155, 156,   2,   2, 157, 158, 105,  79,
+      0,   0,   0,   0,  70,   2, 106,  56,   2, 123,  83,  16, 159,   2, 160,   0,
+      2,   2,   2,   2,  79, 161,   0,   0,   2,  10,   2, 162,   0,   0,   0,   0,
+      2,  76,  84, 146,   0,   0,   0,   0, 163, 164, 165,   2,   3, 166,   0, 167,
+    168, 169,   0,   0,   2, 170, 145,   2, 171, 172, 173,   2,   2,   0,   2, 174,
+      2, 175, 110, 176, 177, 178,   0,   0,   2,   2, 179,   0,   2, 180,   2, 181,
+      0,   0,   0,   3,   0,   0,   0,   0,   2,   2, 182, 183,   2,   2, 184, 185,
+      2,  98, 123,  76,   2,   2, 140, 186, 187,  79,   0,   0, 188, 189,   2, 190,
+     21,  30, 191, 192,   0,   0,   0,   0,   0,   0,   0,   0,   2,   2, 193,   0,
+      0,   0,   0,   0,   2, 110,  79,   0,   2,   2, 194,   0,   2,  82, 161,   0,
+    111,  88,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   2,   2, 195,
+      0,   0,   0,   0,   0,   0,   2,  74,   2,   2,   2,   2,  71,   0,   0,   0,
+      2,   2,   2, 196,   2,   2,   2,   2,   2,   2, 197,   0,   0,   0,   0,   0,
+      2, 198,   0,   0,   0,   0,   0,   0,   2,   2, 107,   0,   0,   0,   0,   0,
+      2,  74,   3, 199,   0,   0, 105, 200,   2,   2, 201, 202, 203,   0,   0,   0,
+      2,   2, 204,   3, 205,   0,   0,   0, 206,   0,   0,   0,   0,   0,   0,   0,
+      2,   2,   2, 207, 208, 197,   0,   0,   2,   2,   2,   2,   2,   2,   2,  84,
+      2, 209,   2,   2,   2,   2,   2, 179,   2,   2, 210,   0,   0,   0,   0,   0,
+      2,   2,  76,  15,   0,   0,   0,   0,   2,   2,  98,   2,  12, 211, 212,   2,
+    213, 214, 215,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 216,   2,   2,
+      2,   2,   2,   2,   2,   2, 217,   2,   2,   2,   2,   2, 218, 219,   0,   0,
+      2,   2,   2,   2,   2,   2, 220,   0, 212, 221, 222, 223, 224, 225,   0, 226,
+      2,  88,   2,   2,  77, 227, 228,  84, 124, 114,   2,  88,  16,   0,   0, 229,
+    230,  16, 231,   0,   0,   0,   0,   0,   2,   2,   2, 119,   2, 212,   2,   2,
+      2,   2,   2,   2,   2,   2, 106, 232,   2,   2,   2,  77,   2,   2,  19,   0,
+     88,   2, 193,   2,  10, 233,   0,   0, 234,   0,   0,   0, 235,   0, 158,   0,
+      2,   2,   2,   2,   2,   2,  76,   0,   2,  19,   2,   2,   2,   2,   2,   2,
+     79,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2, 206,   0,   0,
+     79,   0,   0,   0,   0,   0,   0,   0, 236,   2,   2,   2,   0,   0,   0,   0,
+      2,   2,   2,   2,   2,   2,   2, 203,   2,   2,   2,   2,   2,   2,   2,  79,
+};
+
+static RE_UINT8 re_graph_stage_5[] = {
+      0,   0,   0,   0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127,
+    255, 255, 255, 252, 240, 215, 255, 255, 251, 255, 255, 255, 255, 255, 254, 255,
+    255, 255, 127, 254, 255, 230, 254, 255, 255,   0, 255, 255, 255,   7,  31,   0,
+    255, 255, 255, 223, 255, 191, 255, 255, 255, 231, 255, 255, 255, 255,   3,   0,
+    255, 255, 255,   7, 255,  63, 255, 127, 255, 255, 255,  79, 255, 255,  31,   0,
+    248, 255, 255, 255, 239, 159, 249, 255, 255, 253, 197, 243, 159, 121, 128, 176,
+    207, 255, 255,  15, 238, 135, 249, 255, 255, 253, 109, 211, 135,  57,   2,  94,
+    192, 255,  63,   0, 238, 191, 251, 255, 255, 253, 237, 243, 191,  59,   1,   0,
+    207, 255,   3,   2, 238, 159, 249, 255, 159,  57, 192, 176, 207, 255, 255,   0,
+    236, 199,  61, 214,  24, 199, 255, 195, 199,  61, 129,   0, 192, 255, 255,   7,
+    239, 223, 253, 255, 255, 253, 255, 227, 223,  61,  96,   7, 207, 255,   0, 255,
+    238, 223, 253, 255, 255, 253, 239, 243, 223,  61,  96,  64, 207, 255,   6,   0,
+    255, 255, 255, 231, 223, 125, 128, 128, 207, 255,  63, 254, 236, 255, 127, 252,
+    255, 255, 251,  47, 127, 132,  95, 255, 192, 255,  28,   0, 255, 255, 255, 135,
+    255, 255, 255,  15, 150,  37, 240, 254, 174, 236, 255,  59,  95,  63, 255, 243,
+    255, 254, 255, 255, 255,  31, 254, 255, 255, 255, 255, 254, 255, 223, 255,   7,
+    191,  32, 255, 255, 255,  61, 127,  61, 255,  61, 255, 255, 255, 255,  61, 127,
+     61, 255, 127, 255, 255, 255,  61, 255, 255, 255, 255,  31, 255, 255, 255,   3,
+    255, 255,  63,  63, 254, 255, 255,  31, 255, 255, 255,   1, 255, 223,  31,   0,
+    255, 255, 127,   0, 255, 255,  15,   0, 255, 223,  13,   0, 255, 255, 255,  63,
+    255,   3, 255,   3, 255, 127, 255,   3, 255, 255, 255,   0, 255,   7, 255, 255,
+    255, 255,  63,   0, 255,  15, 255,  15, 241, 255, 255, 255, 255,  63,  31,   0,
+    255,  15, 255, 255, 255,   3, 255, 199, 255, 255, 255, 207, 255, 255, 255, 159,
+    255, 255,  15, 240, 255, 255, 255, 248, 255, 227, 255, 255, 255, 255, 127,   3,
+    255, 255,  63, 240,  63,  63, 255, 170, 255, 255, 223, 255, 223, 255, 207, 239,
+    255, 255, 220, 127,   0, 248, 255, 255, 255, 124, 255, 255, 223, 255, 243, 255,
+    255, 127, 255,  31,   0,   0, 255, 255, 255, 255,   1,   0, 127,   0,   0,   0,
+    255,   7,   0,   0, 255, 255, 207, 255, 255, 255,  63, 255, 255, 255, 255, 227,
+    255, 253,   3,   0,   0, 240,   0,   0, 255, 127, 255, 255, 255, 255,  15, 254,
+    255, 128,   1, 128, 127, 127, 127, 127,   7,   0,   0,   0, 255, 255, 255, 251,
+      0,   0, 255,  15, 224, 255, 255, 255, 255,  63, 254, 255,  15,   0, 255, 255,
+    255,  31, 255, 255, 127,   0, 255, 255, 255,  15,   0,   0, 255,  63, 255,   0,
+      0,   0, 128, 255, 255,  15, 255,   3,  31, 192, 255,   3, 255, 255,  15, 128,
+    255, 191, 255, 195, 255,  63, 255, 243,   7,   0,   0, 248, 126, 126, 126,   0,
+    127, 127, 255, 255,  63,   0, 255, 255, 255,  63, 255,   3, 127, 248, 255, 255,
+    255,  63, 255, 255, 127,   0, 248, 224, 255, 255, 127,  95, 219, 255, 255, 255,
+      3,   0, 248, 255, 255, 255, 252, 255, 255,   0,   0,   0,   0,   0, 255,  63,
+    255, 255, 247, 255, 127,  15, 223, 255, 252, 252, 252,  28, 127, 127,   0,  62,
+    255, 239, 255, 255, 127, 255, 255, 183, 255,  63, 255,  63, 135, 255, 255, 255,
+    255, 255, 143, 255, 255,  31, 255,  15,   1,   0,   0,   0, 255, 255, 255, 191,
+     15, 255,  63,   0, 255,   3,   0,   0,  15, 128,   0,   0,  63, 253, 255, 255,
+    255, 255, 191, 145, 255, 255, 191, 255, 128, 255,   0,   0, 255, 255,  55, 248,
+    255, 255, 255, 143, 255, 255, 255, 131, 255, 255, 255, 240, 111, 240, 239, 254,
+    255, 255,  15, 135, 255,   0, 255,   1, 127, 248, 127,   0, 255, 255,  63, 254,
+    255, 255,   7, 255, 255, 255,   3,  30,   0, 254,   0,   0, 255,   1,   0,   0,
+    255, 255,   7,   0, 255, 255,   7, 252, 255,  63, 252, 255, 255, 255,   0, 128,
+      3,   0, 255, 255, 255,   1, 255,   3, 254, 255,  31,   0, 255, 255, 251, 255,
+    127, 189, 255, 191, 255,   3, 255, 255, 255,   7, 255,   3, 159,  57, 129, 224,
+    207,  31,  31,   0, 255,   0, 255,   3,  31,   0, 255,   3, 255, 255,   7, 128,
+    255, 127,  31,   0,  15,   0,   0,   0, 255, 127,   0,   0, 255, 195,   0,   0,
+    255,  63,  63,   0,  63,   0, 255, 251, 251, 255, 255, 224, 255, 255,   0,   0,
+     31,   0, 255, 255,   0, 128, 255, 255,   3,   0,   0,   0, 255,   7, 255,  31,
+    255,   1, 255, 243, 127, 254, 255, 255,  63,   0,   0,   0, 100, 222, 255, 235,
+    239, 255, 255, 255, 191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,
+     63, 255, 255, 255, 255, 207, 255, 255, 255,  15,   0, 248, 254, 255,   0,   0,
+    159, 255, 127,   0, 150, 254, 247,  10, 132, 234, 150, 170, 150, 247, 247,  94,
+    255, 251, 255,  15, 238, 251, 255,  15,   0,   0,   3,   0, 255, 127, 254, 255,
+    254, 255, 254, 255, 192, 255, 255, 255,   7,   0, 255, 255, 255,   1,   3,   0,
+    255,  31,  15,   0, 255,  63,   0,   0,   0,   0, 255,   1,  31,   0,   0,   0,
+      2,   0,   0,   0,
+};
+
+/* Graph: 2334 bytes. */
+
+RE_UINT32 re_get_graph(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_graph_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_graph_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_graph_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_graph_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_graph_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Print. */
+
+static RE_UINT8 re_print_stage_1[] = {
+    0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 4, 8,
+    4, 8,
+};
+
+static RE_UINT8 re_print_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13,  7,  7,  7, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 26, 13, 27, 28, 29,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 30,  7, 31, 32,  7, 33, 13, 13, 13, 13, 13, 34,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    35, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 36,
+};
+
+static RE_UINT8 re_print_stage_3[] = {
+      0,   1,   1,   2,   1,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
+     14,   1,  15,  16,   1,   1,  17,  18,  19,  20,  21,  22,  23,  24,   1,  25,
+     26,  27,   1,  28,  29,   1,   1,   1,   1,   1,   1,  30,  31,  32,  33,  34,
+     35,  36,  37,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,  38,   1,   1,   1,   1,   1,   1,   1,   1,   1,  39,
+      1,   1,   1,   1,  40,   1,  41,  42,  43,  44,  45,  46,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,  47,  48,  48,  48,  48,  48,  48,  48,  48,
+      1,   1,  49,  50,   1,  51,  52,  53,  54,  55,  56,  57,  58,  59,   1,  60,
+     61,  62,  63,  64,  65,  48,  66,  48,  67,  68,  69,  70,  71,  72,  73,  74,
+     75,  48,  76,  48,  48,  48,  48,  48,   1,   1,   1,  77,  78,  79,  48,  48,
+      1,   1,   1,   1,  80,  48,  48,  48,  48,  48,  48,  48,   1,   1,  81,  48,
+      1,   1,  82,  83,  48,  48,  48,  84,  85,  48,  48,  48,  48,  48,  48,  48,
+     48,  48,  48,  48,  86,  48,  48,  48,  87,  88,  89,  90,  91,  92,  93,  94,
+      1,   1,  95,  48,  48,  48,  48,  48,  96,  48,  48,  48,  48,  48,  97,  48,
+     98,  99, 100,   1,   1, 101, 102, 103, 104, 105,  48,  48,  48,  48,  48,  48,
+      1,   1,   1,   1,   1,   1, 106,   1,   1,   1,   1,   1,   1,   1,   1, 107,
+    108,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1, 109,  48,
+      1,   1, 110,  48,  48,  48,  48,  48, 111, 112,  48,  48,  48,  48,  48,  48,
+      1,   1,   1,   1,   1,   1,   1, 113,
+};
+
+static RE_UINT8 re_print_stage_4[] = {
+      0,   1,   1,   2,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   3,   4,   5,   1,   1,   1,   6,   7,   8,   9,   1,  10,  11,
+     12,   1,   1,   1,   1,   1,   1,   1,  13,   1,  14,   1,   1,  15,   1,  16,
+      1,  17,  18,   0,   0,  19,   0,  20,   1,   1,   1,   1,  21,  22,  23,  24,
+     25,  26,  27,  28,  29,  30,  31,  32,  33,  30,  34,  35,  36,  37,  38,  39,
+     40,  41,  42,  43,  44,  45,  46,  47,  44,  48,  49,  50,  51,  52,  53,  54,
+      8,  55,  56,   0,  57,  58,  59,   0,   1,   1,  60,  61,  62,  12,  63,   0,
+      1,   1,   1,   1,   1,   1,  64,   1,   1,   1,  65,   1,  66,  67,  68,   1,
+     69,   1,  48,  70,  71,   1,   1,  72,   1,   1,   1,   1,  70,   1,   1,  73,
+     74,  75,  76,  77,   1,   1,  78,  79,  80,   1,   1,  81,   1,  82,   1,  83,
+      2,  84,  85,  86,   1,  87,  88,   1,  89,   1,   2,  90,  79,  17,   0,   0,
+      1,   1,  87,  70,   1,   1,   1,  91,   1,  92,  93,   1,   0,   0,  10,  94,
+      1,   1,   1,   1,   1,   1,   1,  95,  72,   1,  96,  78,   1,  97,  98,  99,
+      1, 100,   1, 101, 102,   2, 103, 104,   1,   1,   1,   1,  87,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,  16,   1, 105, 106,   1,   1,   1,   1,   1,
+      1,   1,   1, 107, 108, 109, 110, 111,   1, 112,   2,   1,   1,   1,   1, 113,
+      1,  64,   1, 114,  75, 115, 115,   1,   1,   1, 116,   0, 117,   1,   1,  76,
+      1,   1,   1,   1,   1,   1,  83, 118,   1,   1,   8,   1,   7,   1,   1,   1,
+    119, 120,   1,   1, 112,  16,   1, 121,   2,   1,   1,   1,   1,   1,   1,   2,
+      1,   1,   1,   1,   1,  83,   1,   1,   1,   1,   1,   1,   1,   1,  83,   0,
+      1,   1,   1,   1, 122,   1, 123,   1,   1, 124,   1,   1,   1,   1,   1,  81,
+      1,   1,   1,   1,   1, 125,   0, 126,   1, 127,   1,  81,   1,   1, 128,  78,
+      1,   1, 129,  70,   1,   1, 130,   2,   1,  75, 131,   1,   1,   1, 132,  75,
+    133, 134,   1, 135,   1,   1,   1, 136,   1,   1,   1,   1,   1, 121, 137,  56,
+      0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1, 138,   1,   1,  71,   0,
+    139, 140, 141,   1,   1,   1, 142,   1,   1,   1, 103,   1, 143,   1, 144, 145,
+     71,   1, 146, 147,   1,   1,   1,  90,   8,   1,   1,   1,   1,   2, 148, 149,
+    150, 151, 152,   0,   1,   1,   1,  16, 153, 154,   1,   1, 155, 156, 103,  78,
+      0,   0,   0,   0,  70,   1, 104,  56,   1, 121,  82,  16, 157,   1, 158,   0,
+      1,   1,   1,   1,  78, 159,   0,   0,   1,  10,   1, 160,   0,   0,   0,   0,
+      1,  75,  83, 144,   0,   0,   0,   0, 161, 162, 163,   1,   2, 164,   0, 165,
+    166, 167,   0,   0,   1, 168, 143,   1, 169, 170, 171,   1,   1,   0,   1, 172,
+      1, 173, 108, 174, 175, 176,   0,   0,   1,   1, 177,   0,   1, 178,   1, 179,
+      0,   0,   0,   2,   0,   0,   0,   0,   1,   1, 180, 181,   1,   1, 182, 183,
+      1,  97, 121,  75,   1,   1, 138, 184, 185,  78,   0,   0, 186, 187,   1, 188,
+     21,  30, 189, 190,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1, 191,   0,
+      0,   0,   0,   0,   1, 108,  78,   0,   1,   1, 192,   0,   1,  81, 159,   0,
+    109,  87,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1, 193,
+      0,   0,   0,   0,   0,   0,   1,  73,   1,   1,   1,   1,  71,   0,   0,   0,
+      1,   1,   1, 194,   1,   1,   1,   1,   1,   1, 195,   0,   0,   0,   0,   0,
+      1, 196,   0,   0,   0,   0,   0,   0,   1,   1, 105,   0,   0,   0,   0,   0,
+      1,  73,   2, 197,   0,   0, 103, 198,   1,   1, 199, 200, 201,   0,   0,   0,
+      1,   1, 202,   2, 203,   0,   0,   0, 204,   0,   0,   0,   0,   0,   0,   0,
+      1,   1,   1, 205, 206, 195,   0,   0,   1,   1,   1,   1,   1,   1,   1,  83,
+      1, 207,   1,   1,   1,   1,   1, 177,   1,   1, 208,   0,   0,   0,   0,   0,
+      1,   1,  75,  15,   0,   0,   0,   0,   1,   1,  97,   1,  12, 209, 210,   1,
+    211, 212, 213,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1, 214,   1,   1,
+      1,   1,   1,   1,   1,   1, 215,   1,   1,   1,   1,   1, 216, 217,   0,   0,
+      1,   1,   1,   1,   1,   1, 218,   0, 210, 219, 220, 221, 222, 223,   0, 224,
+      1,  87,   1,   1,  76, 225, 226,  83, 122, 112,   1,  87,  16,   0,   0, 227,
+    228,  16, 229,   0,   0,   0,   0,   0,   1,   1,   1, 117,   1, 210,   1,   1,
+      1,   1,   1,   1,   1,   1, 104, 230,   1,   1,   1,  76,   1,   1,  19,   0,
+     87,   1, 191,   1,  10, 231,   0,   0, 232,   0,   0,   0, 233,   0, 156,   0,
+      1,   1,   1,   1,   1,   1,  75,   0,   1,  19,   1,   1,   1,   1,   1,   1,
+     78,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1, 204,   0,   0,
+     78,   0,   0,   0,   0,   0,   0,   0, 234,   1,   1,   1,   0,   0,   0,   0,
+      1,   1,   1,   1,   1,   1,   1, 201,   1,   1,   1,   1,   1,   1,   1,  78,
+};
+
+static RE_UINT8 re_print_stage_5[] = {
+      0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 127, 255, 255, 255, 252,
+    240, 215, 255, 255, 251, 255, 255, 255, 255, 255, 254, 255, 255, 255, 127, 254,
+    254, 255, 255, 255, 255, 230, 254, 255, 255,   0, 255, 255, 255,   7,  31,   0,
+    255, 255, 255, 223, 255, 191, 255, 255, 255, 231, 255, 255, 255, 255,   3,   0,
+    255, 255, 255,   7, 255,  63, 255, 127, 255, 255, 255,  79, 255, 255,  31,   0,
+    248, 255, 255, 255, 239, 159, 249, 255, 255, 253, 197, 243, 159, 121, 128, 176,
+    207, 255, 255,  15, 238, 135, 249, 255, 255, 253, 109, 211, 135,  57,   2,  94,
+    192, 255,  63,   0, 238, 191, 251, 255, 255, 253, 237, 243, 191,  59,   1,   0,
+    207, 255,   3,   2, 238, 159, 249, 255, 159,  57, 192, 176, 207, 255, 255,   0,
+    236, 199,  61, 214,  24, 199, 255, 195, 199,  61, 129,   0, 192, 255, 255,   7,
+    239, 223, 253, 255, 255, 253, 255, 227, 223,  61,  96,   7, 207, 255,   0, 255,
+    238, 223, 253, 255, 255, 253, 239, 243, 223,  61,  96,  64, 207, 255,   6,   0,
+    255, 255, 255, 231, 223, 125, 128, 128, 207, 255,  63, 254, 236, 255, 127, 252,
+    255, 255, 251,  47, 127, 132,  95, 255, 192, 255,  28,   0, 255, 255, 255, 135,
+    255, 255, 255,  15, 150,  37, 240, 254, 174, 236, 255,  59,  95,  63, 255, 243,
+    255, 254, 255, 255, 255,  31, 254, 255, 255, 255, 255, 254, 255, 223, 255,   7,
+    191,  32, 255, 255, 255,  61, 127,  61, 255,  61, 255, 255, 255, 255,  61, 127,
+     61, 255, 127, 255, 255, 255,  61, 255, 255, 255, 255,  31, 255, 255, 255,   3,
+    255, 255,  63,  63, 255, 255, 255,   1, 255, 223,  31,   0, 255, 255, 127,   0,
+    255, 255,  15,   0, 255, 223,  13,   0, 255, 255, 255,  63, 255,   3, 255,   3,
+    255, 127, 255,   3, 255, 255, 255,   0, 255,   7, 255, 255, 255, 255,  63,   0,
+    255,  15, 255,  15, 241, 255, 255, 255, 255,  63,  31,   0, 255,  15, 255, 255,
+    255,   3, 255, 199, 255, 255, 255, 207, 255, 255, 255, 159, 255, 255,  15, 240,
+    255, 255, 255, 248, 255, 227, 255, 255, 255, 255, 127,   3, 255, 255,  63, 240,
+     63,  63, 255, 170, 255, 255, 223, 255, 223, 255, 207, 239, 255, 255, 220, 127,
+    255, 252, 255, 255, 223, 255, 243, 255, 255, 127, 255,  31,   0,   0, 255, 255,
+    255, 255,   1,   0, 127,   0,   0,   0, 255,   7,   0,   0, 255, 255, 207, 255,
+    255, 255,  63, 255, 255, 255, 255, 227, 255, 253,   3,   0,   0, 240,   0,   0,
+    255, 127, 255, 255, 255, 255,  15, 254, 255, 128,   1, 128, 127, 127, 127, 127,
+      7,   0,   0,   0, 255, 255, 255, 251,   0,   0, 255,  15, 224, 255, 255, 255,
+    255,  63, 254, 255,  15,   0, 255, 255, 255,  31, 255, 255, 127,   0, 255, 255,
+    255,  15,   0,   0, 255,  63, 255,   0,   0,   0, 128, 255, 255,  15, 255,   3,
+     31, 192, 255,   3, 255, 255,  15, 128, 255, 191, 255, 195, 255,  63, 255, 243,
+      7,   0,   0, 248, 126, 126, 126,   0, 127, 127, 255, 255,  63,   0, 255, 255,
+    255,  63, 255,   3, 127, 248, 255, 255, 255,  63, 255, 255, 127,   0, 248, 224,
+    255, 255, 127,  95, 219, 255, 255, 255,   3,   0, 248, 255, 255, 255, 252, 255,
+    255,   0,   0,   0,   0,   0, 255,  63, 255, 255, 247, 255, 127,  15, 223, 255,
+    252, 252, 252,  28, 127, 127,   0,  62, 255, 239, 255, 255, 127, 255, 255, 183,
+    255,  63, 255,  63, 135, 255, 255, 255, 255, 255, 143, 255, 255,  31, 255,  15,
+      1,   0,   0,   0, 255, 255, 255, 191,  15, 255,  63,   0, 255,   3,   0,   0,
+     15, 128,   0,   0,  63, 253, 255, 255, 255, 255, 191, 145, 255, 255, 191, 255,
+    128, 255,   0,   0, 255, 255,  55, 248, 255, 255, 255, 143, 255, 255, 255, 131,
+    255, 255, 255, 240, 111, 240, 239, 254, 255, 255,  15, 135, 255,   0, 255,   1,
+    127, 248, 127,   0, 255, 255,  63, 254, 255, 255,   7, 255, 255, 255,   3,  30,
+      0, 254,   0,   0, 255,   1,   0,   0, 255, 255,   7,   0, 255, 255,   7, 252,
+    255,  63, 252, 255, 255, 255,   0, 128,   3,   0, 255, 255, 255,   1, 255,   3,
+    254, 255,  31,   0, 255, 255, 251, 255, 127, 189, 255, 191, 255,   3, 255, 255,
+    255,   7, 255,   3, 159,  57, 129, 224, 207,  31,  31,   0, 255,   0, 255,   3,
+     31,   0, 255,   3, 255, 255,   7, 128, 255, 127,  31,   0,  15,   0,   0,   0,
+    255, 127,   0,   0, 255, 195,   0,   0, 255,  63,  63,   0,  63,   0, 255, 251,
+    251, 255, 255, 224, 255, 255,   0,   0,  31,   0, 255, 255,   0, 128, 255, 255,
+      3,   0,   0,   0, 255,   7, 255,  31, 255,   1, 255, 243, 127, 254, 255, 255,
+     63,   0,   0,   0, 100, 222, 255, 235, 239, 255, 255, 255, 191, 231, 223, 223,
+    255, 255, 255, 123,  95, 252, 253, 255,  63, 255, 255, 255, 255, 207, 255, 255,
+    255,  15,   0, 248, 254, 255,   0,   0, 159, 255, 127,   0, 150, 254, 247,  10,
+    132, 234, 150, 170, 150, 247, 247,  94, 255, 251, 255,  15, 238, 251, 255,  15,
+      0,   0,   3,   0, 255, 127, 254, 255, 254, 255, 254, 255, 192, 255, 255, 255,
+      7,   0, 255, 255, 255,   1,   3,   0, 255,  31,  15,   0, 255,  63,   0,   0,
+      0,   0, 255,   1,  31,   0,   0,   0,   2,   0,   0,   0,
+};
+
+/* Print: 2326 bytes. */
+
+RE_UINT32 re_get_print(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_print_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_print_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_print_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_print_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_print_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Word. */
+
+static RE_UINT8 re_word_stage_1[] = {
+    0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6,
+    6, 6,
+};
+
+static RE_UINT8 re_word_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 13, 13, 13, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 26, 13, 27, 28, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 29,  7, 30, 31,  7, 32, 13, 13, 13, 13, 13, 33,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    34, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_word_stage_3[] = {
+      0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
+     16,   1,  17,  18,  19,   1,  20,  21,  22,  23,  24,  25,  26,  27,   1,  28,
+     29,  30,  31,  31,  32,  31,  31,  31,  31,  31,  31,  31,  33,  34,  35,  31,
+     36,  37,  31,  31,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,  38,   1,   1,   1,   1,   1,   1,   1,   1,   1,  39,
+      1,   1,   1,   1,  40,   1,  41,  42,  43,  44,  45,  46,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,  47,  31,  31,  31,  31,  31,  31,  31,  31,
+     31,   1,  48,  49,   1,  50,  51,  52,  53,  54,  55,  56,  57,  58,   1,  59,
+     60,  61,  62,  63,  64,  31,  31,  31,  65,  66,  67,  68,  69,  70,  71,  72,
+     73,  31,  74,  31,  31,  31,  31,  31,   1,   1,   1,  75,  76,  77,  31,  31,
+      1,   1,   1,   1,  78,  31,  31,  31,  31,  31,  31,  31,   1,   1,  79,  31,
+      1,   1,  80,  81,  31,  31,  31,  82,  83,  31,  31,  31,  31,  31,  31,  31,
+     31,  31,  31,  31,  84,  31,  31,  31,  31,  85,  86,  31,  87,  88,  89,  90,
+     31,  31,  91,  31,  31,  31,  31,  31,  92,  31,  31,  31,  31,  31,  93,  31,
+     31,  94,  31,  31,  31,  31,  31,  31,   1,   1,   1,   1,   1,   1,  95,   1,
+      1,   1,   1,   1,   1,   1,   1,  96,  97,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,  98,  31,   1,   1,  99,  31,  31,  31,  31,  31,
+     31, 100,  31,  31,  31,  31,  31,  31,
+};
+
+static RE_UINT8 re_word_stage_4[] = {
+      0,   1,   2,   3,   0,   4,   5,   5,   6,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6,   6,   7,   8,   6,   6,   6,   9,  10,  11,   6,  12,
+      6,   6,   6,   6,  11,   6,   6,   6,   6,  13,  14,  15,  16,  17,  18,  19,
+     20,   6,   6,  21,   6,   6,  22,  23,  24,   6,  25,   6,   6,  26,   6,  27,
+      6,  28,  29,   0,   0,  30,   0,  31,   6,   6,   6,  32,  33,  34,  35,  36,
+     37,  38,  39,  40,  41,  42,  43,  44,  45,  42,  46,  47,  48,  49,  50,  51,
+     52,  53,  54,  55,  56,  57,  58,  59,  56,  60,  61,  62,  63,  64,  65,  66,
+     15,  67,  68,   0,  69,  70,  71,   0,  72,  73,  74,  75,  76,  77,  78,   0,
+      6,   6,  79,   6,  80,   6,  81,  82,   6,   6,  83,   6,  84,  85,  86,   6,
+     87,   6,  60,   0,  88,   6,   6,  89,  15,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,  90,   3,   6,   6,  91,  92,  30,  93,  94,   6,   6,  95,  96,
+     97,   6,   6,  98,   6,  99,   6, 100, 101, 102, 103, 104,   6, 105, 106,   0,
+     29,   6, 101, 107, 106, 108,   0,   0,   6,   6, 109, 110,   6,   6,   6,  93,
+      6,  98, 111,  80,   0,   0, 112, 113,   6,   6,   6,   6,   6,   6,   6, 114,
+     89,   6, 115,  80,   6, 116, 117, 118, 119, 120, 121, 122, 123,   0,  24, 124,
+    125, 126, 127,   6, 128,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 129,   6,  96,   6, 130, 101,   6,   6,   6,   6, 131,
+      6,  81,   6, 132, 133, 134, 134,   6,   0, 135,   0,   0,   0,   0,   0,   0,
+    136, 137,  15,   6, 138,  15,   6,  82, 139, 140,   6,   6, 141,  67,   0,  24,
+      6,   6,   6,   6,   6, 100,   0,   0,   6,   6,   6,   6,   6,   6, 100,   0,
+      6,   6,   6,   6, 142,   0,  24,  80, 143, 144,   6, 145,   6,   6,   6,  26,
+    146, 147,   6,   6, 148, 149,   0, 146,   6, 150,   6,  93,   6,   6, 151, 152,
+      6, 153,  93,  77,   6,   6, 154, 101,   6, 133, 155, 156,   6,   6, 157, 158,
+    159, 160,  82, 161,   6,   6,   6, 162,   6,   6,   6,   6,   6, 163, 164,  29,
+      6,   6,   6, 153,   6,   6, 165,   0, 166, 167, 168,   6,   6,  26, 169,   6,
+      6,  80,  24,   6, 170,   6, 150, 171,  88, 172, 173, 174,   6,   6,   6,  77,
+      1,   2,   3, 103,   6, 101, 175,   0, 176, 177, 178,   0,   6,   6,   6,  67,
+      0,   0,   6,  30,   0,   0,   0, 179,   0,   0,   0,   0,  77,   6, 124, 180,
+      6,  24,  99,  67,  80,   6, 181,   0,   6,   6,   6,   6,  80,  96,   0,   0,
+      6, 182,   6, 183,   0,   0,   0,   0,   6, 133, 100, 150,   0,   0,   0,   0,
+    184, 185, 100, 133, 101,   0,   0, 186, 100, 165,   0,   0,   6, 187,   0,   0,
+    188, 189,   0,  77,  77,   0,  74, 190,   6, 100, 100, 191,  26,   0,   0,   0,
+      6,   6, 128,   0,   6, 191,   6, 191,   6,   6, 190, 192,   6,  67,  24, 193,
+      6, 194,  24, 195,   6,   6, 196,   0, 197,  98,   0,   0, 198, 199,   6, 200,
+     33,  42, 201, 202,   0,   0,   0,   0,   0,   0,   0,   0,   6,   6, 203,   0,
+      0,   0,   0,   0,   6, 204, 205,   0,   6,   6, 206,   0,   6,  98,  96,   0,
+    207, 109,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   6,   6, 208,
+      0,   0,   0,   0,   0,   0,   6, 209,   6,   6,   6,   6, 165,   0,   0,   0,
+      6,   6,   6, 141,   6,   6,   6,   6,   6,   6, 183,   0,   0,   0,   0,   0,
+      6, 141,   0,   0,   0,   0,   0,   0,   6,   6, 190,   0,   0,   0,   0,   0,
+      6, 209, 101,  96,   0,   0,  24, 104,   6, 133, 210, 211,  88,   0,   0,   0,
+      6,   6, 212, 101, 213,   0,   0,   0, 214,   0,   0,   0,   0,   0,   0,   0,
+      6,   6,   6, 215, 216,   0,   0,   0,   0,   0,   0, 217, 218, 219,   0,   0,
+      0,   0, 220,   0,   0,   0,   0,   0,   6,   6, 194,   6, 221, 222, 223,   6,
+    224, 225, 226,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6, 227, 228,  82,
+    194, 194, 130, 130, 229, 229, 230,   6,   6, 231,   6, 232, 233, 234,   0,   0,
+      6,   6,   6,   6,   6,   6, 235,   0, 223, 236, 237, 238, 239, 240,   0,   0,
+      0,  24,  79,  79,  96,   0,   0,   0,   6,   6,   6,   6,   6,   6, 133,   0,
+      6,  30,   6,   6,   6,   6,   6,   6,  80,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6, 214,   0,   0,  80,   0,   0,   0,   0,   0,   0,   0,
+      6,   6,   6,   6,   6,   6,   6,  88,
+};
+
+static RE_UINT8 re_word_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 254, 255, 255, 135, 254, 255, 255,   7,
+      0,   4,  32,   4, 255, 255, 127, 255, 255, 255, 255, 255, 195, 255,   3,   0,
+     31,  80,   0,   0, 255, 255, 223, 188,  64, 215, 255, 255, 251, 255, 255, 255,
+    255, 255, 191, 255, 255, 255, 254, 255, 255, 255, 127,   2, 254, 255, 255, 255,
+    255,   0, 254, 255, 255, 255, 255, 191, 182,   0, 255, 255, 255,   7,   7,   0,
+      0,   0, 255,   7, 255, 195, 255, 255, 255, 255, 239, 159, 255, 253, 255, 159,
+      0,   0, 255, 255, 255, 231, 255, 255, 255, 255,   3,   0, 255, 255,  63,   4,
+    255,  63,   0,   0, 255, 255, 255,  15, 255, 255,  31,   0, 248, 255, 255, 255,
+    207, 255, 254, 255, 239, 159, 249, 255, 255, 253, 197, 243, 159, 121, 128, 176,
+    207, 255,   3,   0, 238, 135, 249, 255, 255, 253, 109, 211, 135,  57,   2,  94,
+    192, 255,  63,   0, 238, 191, 251, 255, 255, 253, 237, 243, 191,  59,   1,   0,
+    207, 255,   0,   2, 238, 159, 249, 255, 159,  57, 192, 176, 207, 255,   2,   0,
+    236, 199,  61, 214,  24, 199, 255, 195, 199,  61, 129,   0, 192, 255,   0,   0,
+    239, 223, 253, 255, 255, 253, 255, 227, 223,  61,  96,   7, 207, 255,   0,   0,
+    238, 223, 253, 255, 255, 253, 239, 243, 223,  61,  96,  64, 207, 255,   6,   0,
+    255, 255, 255, 231, 223, 125, 128, 128, 207, 255,   0, 252, 236, 255, 127, 252,
+    255, 255, 251,  47, 127, 132,  95, 255, 192, 255,  12,   0, 255, 255, 255,   7,
+    255, 127, 255,   3, 150,  37, 240, 254, 174, 236, 255,  59,  95,  63, 255, 243,
+      1,   0,   0,   3, 255,   3, 160, 194, 255, 254, 255, 255, 255,  31, 254, 255,
+    223, 255, 255, 254, 255, 255, 255,  31,  64,   0,   0,   0, 255,   3, 255, 255,
+    255, 255, 255,  63, 191,  32, 255, 255, 255, 255, 255, 247, 255,  61, 127,  61,
+    255,  61, 255, 255, 255, 255,  61, 127,  61, 255, 127, 255, 255, 255,  61, 255,
+    255, 255,   0,   0, 255, 255,  63,  63, 255, 159, 255, 255, 255, 199, 255,   1,
+    255, 223,  31,   0, 255, 255,  15,   0, 255, 223,  13,   0, 255, 255, 143,  48,
+    255,   3,   0,   0,   0,  56, 255,   3, 255, 255, 255,   0, 255,   7, 255, 255,
+    255, 255,  63,   0, 255, 255, 255, 127, 255,  15, 255,  15, 192, 255, 255, 255,
+    255,  63,  31,   0, 255,  15, 255, 255, 255,   3, 255,   3, 255, 255, 255, 159,
+    128,   0, 255, 127, 255,  15, 255,   3,   0, 248,  15,   0, 255, 227, 255, 255,
+      0,   0, 247, 255, 255, 255, 127,   3, 255, 255,  63, 240,  63,  63, 255, 170,
+    255, 255, 223,  95, 220,  31, 207,  15, 255,  31, 220,  31,   0,  48,   0,   0,
+      0,   0,   0, 128,   1,   0,  16,   0,   0,   0,   2, 128,   0,   0, 255,  31,
+    255, 255,   1,   0, 132, 252,  47,  62,  80, 189, 255, 243, 224,  67,   0,   0,
+    255,   1,   0,   0,   0,   0, 192, 255, 255, 127, 255, 255,  31, 248,  15,   0,
+    255, 128,   0, 128, 255, 255, 127,   0, 127, 127, 127, 127,   0, 128,   0,   0,
+    224,   0,   0,   0, 254, 255,  62,  31, 255, 255, 127, 230, 224, 255, 255, 255,
+    255,  63, 254, 255, 255, 127,   0,   0, 255,  31,   0,   0, 255,  31, 255, 255,
+    255,  15,   0,   0, 255, 255, 247, 191,   0,   0, 128, 255, 252, 255, 255, 255,
+    255, 249, 255, 255, 255,  63, 255,   0, 255,   0,   0,   0,  31,   0, 255,   3,
+    255, 255, 255,  40, 255,  63, 255, 255,   1, 128, 255,   3, 255,  63, 255,   3,
+    255, 255, 127, 252,   7,   0,   0,  56, 255, 255, 124,   0, 126, 126, 126,   0,
+    127, 127, 255, 255,  63,   0, 255, 255, 255,  55, 255,   3,  15,   0, 255, 255,
+    127, 248, 255, 255, 255, 255, 255,   3, 127,   0, 248, 224, 255, 253, 127,  95,
+    219, 255, 255, 255,   0,   0, 248, 255, 255, 255, 252, 255,   0,   0, 255,  15,
+    255, 255,  24,   0,   0, 224,   0,   0,   0,   0, 223, 255, 252, 252, 252,  28,
+    255, 239, 255, 255, 127, 255, 255, 183, 255,  63, 255,  63,   0,   0,   0,  32,
+      1,   0,   0,   0,  15, 255,  62,   0, 255,   0, 255, 255,  15,   0,   0,   0,
+     63, 253, 255, 255, 255, 255, 191, 145, 255, 255,  55,   0, 255, 255, 255, 192,
+    111, 240, 239, 254, 255, 255,  15, 135, 127,   0,   0,   0, 255, 255,   7,   0,
+    192, 255,   0, 128, 255,   1, 255,   3, 255, 255, 223, 255, 255, 255,  79,   0,
+     31,  28, 255,  23, 255, 255, 251, 255, 127, 189, 255, 191, 255,   1, 255, 255,
+    255,   7, 255,   3, 159,  57, 129, 224, 207,  31,  31,   0, 191,   0, 255,   3,
+    255, 255,  63, 255,   1,   0,   0,  63,  17,   0, 255,   3, 255, 255, 255, 227,
+    255,   3,   0, 128, 255, 255, 255,   1,  15,   0, 255,   3, 248, 255, 255, 224,
+     31,   0, 255, 255,   0, 128, 255, 255,   3,   0,   0,   0, 255,   7, 255,  31,
+    255,   1, 255,  99, 224, 227,   7, 248, 231,  15,   0,   0,   0,  60,   0,   0,
+     28,   0,   0,   0, 255, 255, 255, 223, 100, 222, 255, 235, 239, 255, 255, 255,
+    191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,  63, 255, 255, 255,
+    253, 255, 255, 247, 255, 253, 255, 255, 247, 207, 255, 255, 255, 255, 127, 248,
+    255,  31,  32,   0,  16,   0,   0, 248, 254, 255,   0,   0,  31,   0, 127,   0,
+    150, 254, 247,  10, 132, 234, 150, 170, 150, 247, 247,  94, 255, 251, 255,  15,
+    238, 251, 255,  15,
+};
+
+/* Word: 2214 bytes. */
+
+RE_UINT32 re_get_word(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 15;
+    code = ch ^ (f << 15);
+    pos = (RE_UINT32)re_word_stage_1[f] << 4;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_word_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_word_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_word_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_word_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* XDigit. */
+
+static RE_UINT8 re_xdigit_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_xdigit_stage_2[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4,
+    5, 6, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 8, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_xdigit_stage_3[] = {
+     0,  1,  1,  1,  1,  1,  2,  3,  1,  4,  4,  4,  4,  4,  5,  6,
+     7,  1,  1,  1,  1,  1,  1,  8,  9, 10, 11, 12, 13,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  6,  1, 14, 15, 16, 17,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 18,
+     1,  1,  1,  1, 19,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    20, 21, 17,  1, 14,  1, 22, 23,  8,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 24, 16,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1, 25,  1,  1,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_xdigit_stage_4[] = {
+     0,  1,  2,  2,  2,  2,  2,  2,  2,  3,  2,  0,  2,  2,  2,  4,
+     2,  5,  2,  5,  2,  6,  2,  6,  3,  2,  2,  2,  2,  4,  6,  2,
+     2,  2,  2,  3,  6,  2,  2,  2,  2,  7,  2,  6,  2,  2,  8,  2,
+     2,  6,  0,  2,  2,  8,  2,  2,  2,  2,  2,  6,  4,  2,  2,  9,
+     2,  6,  2,  2,  2,  2,  2,  0, 10, 11,  2,  2,  2,  2,  3,  2,
+     2,  5,  2,  0, 12,  2,  2,  6,  2,  6,  2,  4,  0,  2,  2,  2,
+     2,  3,  2,  2,  2,  2,  2, 13,
+};
+
+static RE_UINT8 re_xdigit_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 126,   0,   0,   0, 126,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255,   3,   0,   0,
+    255,   3,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 192, 255,   0,   0,
+      0,   0, 255,   3,   0,   0,   0,   0, 192, 255,   0,   0,   0,   0,   0,   0,
+    255,   3, 255,   3,   0,   0,   0,   0,   0,   0, 255,   3,   0,   0, 255,   3,
+      0,   0, 255,   3, 126,   0,   0,   0, 126,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 192, 255,   0, 192, 255, 255, 255, 255, 255, 255,
+};
+
+/* XDigit: 425 bytes. */
+
+RE_UINT32 re_get_xdigit(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_xdigit_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_xdigit_stage_2[pos + f] << 4;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_xdigit_stage_3[pos + f] << 2;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_xdigit_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_xdigit_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Posix_Digit. */
+
+static RE_UINT8 re_posix_digit_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_posix_digit_stage_2[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_posix_digit_stage_3[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_posix_digit_stage_4[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_posix_digit_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+
+/* Posix_Digit: 97 bytes. */
+
+RE_UINT32 re_get_posix_digit(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_posix_digit_stage_1[f] << 4;
+    f = code >> 12;
+    code ^= f << 12;
+    pos = (RE_UINT32)re_posix_digit_stage_2[pos + f] << 3;
+    f = code >> 9;
+    code ^= f << 9;
+    pos = (RE_UINT32)re_posix_digit_stage_3[pos + f] << 3;
+    f = code >> 6;
+    code ^= f << 6;
+    pos = (RE_UINT32)re_posix_digit_stage_4[pos + f] << 6;
+    pos += code;
+    value = (re_posix_digit_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Posix_AlNum. */
+
+static RE_UINT8 re_posix_alnum_stage_1[] = {
+    0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3,
+};
+
+static RE_UINT8 re_posix_alnum_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 13, 13, 13, 14,
+    15, 16, 17, 18, 19, 13, 20, 13, 21, 13, 13, 13, 13, 22, 13, 13,
+    13, 13, 13, 13, 13, 13, 23, 24, 13, 13, 25, 13, 13, 26, 27, 13,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7, 28,  7, 29, 30,  7, 31, 13, 13, 13, 13, 13, 32,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+};
+
+static RE_UINT8 re_posix_alnum_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1, 17, 18, 19,  1, 20, 21, 22, 23, 24, 25, 26, 27,  1, 28,
+    29, 30, 31, 31, 32, 31, 31, 31, 31, 31, 31, 31, 33, 34, 35, 31,
+    36, 37, 31, 31,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 38,  1,  1,  1,  1,  1,  1,  1,  1,  1, 39,
+     1,  1,  1,  1, 40,  1, 41, 42, 43, 44, 45, 46,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1, 47, 31, 31, 31, 31, 31, 31, 31, 31,
+    31,  1, 48, 49,  1, 50, 51, 52, 53, 54, 55, 56, 57, 58,  1, 59,
+    60, 61, 62, 63, 64, 31, 31, 31, 65, 66, 67, 68, 69, 70, 71, 72,
+    73, 31, 74, 31, 31, 31, 31, 31,  1,  1,  1, 75, 76, 77, 31, 31,
+     1,  1,  1,  1, 78, 31, 31, 31, 31, 31, 31, 31,  1,  1, 79, 31,
+     1,  1, 80, 81, 31, 31, 31, 82, 83, 31, 31, 31, 31, 31, 31, 31,
+    31, 31, 31, 31, 84, 31, 31, 31, 31, 31, 31, 31, 85, 86, 87, 88,
+    89, 31, 31, 31, 31, 31, 90, 31, 31, 91, 31, 31, 31, 31, 31, 31,
+     1,  1,  1,  1,  1,  1, 92,  1,  1,  1,  1,  1,  1,  1,  1, 93,
+    94,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 95, 31,
+     1,  1, 96, 31, 31, 31, 31, 31,
+};
+
+static RE_UINT8 re_posix_alnum_stage_4[] = {
+      0,   1,   2,   2,   0,   3,   4,   4,   5,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,   5,   5,   5,   6,   7,   0,   0,   8,   9,  10,  11,   5,  12,
+      5,   5,   5,   5,  13,   5,   5,   5,   5,  14,  15,  16,  17,  18,  19,  20,
+     21,   5,  22,  23,   5,   5,  24,  25,  26,   5,  27,   5,   5,  28,  29,  30,
+     31,  32,  33,   0,   0,  34,   0,  35,   5,  36,  37,  38,  39,  40,  41,  42,
+     43,  44,  45,  46,  47,  48,  49,  50,  51,  48,  52,  53,  54,  55,  56,   0,
+     57,  58,  59,  60,  61,  62,  63,  64,  61,  65,  66,  67,  68,  69,  70,  71,
+     16,  72,  73,   0,  74,  75,  76,   0,  77,   0,  78,  79,  80,  81,   0,   0,
+      5,  82,  26,  83,  84,   5,  85,  86,   5,   5,  87,   5,  88,  89,  90,   5,
+     91,   5,  92,   0,  93,   5,   5,  94,  16,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,  95,   2,   5,   5,  96,  97,  98,  98,  99,   5, 100, 101,   0,
+      0,   5,   5, 102,   5, 103,   5, 104, 105, 106,  26, 107,   5, 108, 109,   0,
+    110,   5, 105, 111,   0, 112,   0,   0,   5, 113, 114,   0,   5, 115,   5, 116,
+      5, 104, 117, 118,   0,   0,   0, 119,   5,   5,   5,   5,   5,   5,   0, 120,
+     94,   5, 121, 118,   5, 122, 123, 124,   0,   0,   0, 125, 126,   0,   0,   0,
+    127, 128, 129,   5, 130,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0, 131,   5, 109,   5, 132, 105,   5,   5,   5,   5, 133,
+      5,  85,   5, 134, 135, 136, 136,   5,   0, 137,   0,   0,   0,   0,   0,   0,
+    138, 139,  16,   5, 140,  16,   5,  86, 141, 142,   5,   5, 143,  72,   0,  26,
+      5,   5,   5,   5,   5, 104,   0,   0,   5,   5,   5,   5,   5,   5, 104,   0,
+      5,   5,   5,   5,  32,   0,  26, 118, 144, 145,   5, 146,   5,   5,   5,  93,
+    147, 148,   5,   5, 149, 150,   0, 147, 151,  17,   5,  98,   5,   5,  60, 152,
+     29, 103, 153,  81,   5, 154, 137, 155,   5, 135, 156, 157,   5, 105, 158, 159,
+    160, 161,  86, 162,   5,   5,   5, 163,   5,   5,   5,   5,   5, 164, 165, 110,
+      5,   5,   5, 166,   5,   5, 167,   0, 168, 169, 170,   5,   5,  28, 171,   5,
+      5, 118,  26,   5, 172,   5,  17, 173,   0,   0,   0, 174,   5,   5,   5,  81,
+      0,   2,   2, 175,   5, 105, 176,   0, 177, 178, 179,   0,   5,   5,   5,  72,
+      0,   0,   5,  34,   0,   0,   0,   0,   0,   0,   0,   0,  81,   5, 180,   0,
+      5,  26, 103,  72, 118,   5, 181,   0,   5,   5,   5,   5, 118,   0,   0,   0,
+      5, 182,   5,  60,   0,   0,   0,   0,   5, 135, 104,  17,   0,   0,   0,   0,
+    183, 184, 104, 135, 105,   0,   0, 185, 104, 167,   0,   0,   5, 186,   0,   0,
+    187,  98,   0,  81,  81,   0,  78, 188,   5, 104, 104, 153,  28,   0,   0,   0,
+      5,   5, 130,   0,   5, 153,   5, 153,   5,   5, 189,   0, 148,  33,  26, 130,
+      5, 153,  26, 190,   5,   5, 191,   0, 192, 193,   0,   0, 194, 195,   5, 130,
+     39,  48, 196,  60,   0,   0,   0,   0,   0,   0,   0,   0,   5,   5, 197,   0,
+      0,   0,   0,   0,   5, 198, 199,   0,   5, 105, 200,   0,   5, 104,   0,   0,
+    201, 163,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   5,   5, 202,
+      0,   0,   0,   0,   0,   0,   5,  33,   5,   5,   5,   5, 167,   0,   0,   0,
+      5,   5,   5, 143,   5,   5,   5,   5,   5,   5,  60,   0,   0,   0,   0,   0,
+      5, 143,   0,   0,   0,   0,   0,   0,   5,   5, 203,   0,   0,   0,   0,   0,
+      5,  33, 105,   0,   0,   0,  26, 156,   5, 135,  60, 204,  93,   0,   0,   0,
+      5,   5, 205, 105, 171,   0,   0,   0, 206,   0,   0,   0,   0,   0,   0,   0,
+      5,   5,   5, 207, 208,   0,   0,   0,   5,   5, 209,   5, 210, 211, 212,   5,
+    213, 214, 215,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5, 216, 217,  86,
+    209, 209, 132, 132, 218, 218, 219,   0,   5,   5,   5,   5,   5,   5, 188,   0,
+    212, 220, 221, 222, 223, 224,   0,   0,   0,  26, 225, 225, 109,   0,   0,   0,
+      5,   5,   5,   5,   5,   5, 135,   0,   5,  34,   5,   5,   5,   5,   5,   5,
+    118,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5, 206,   0,   0,
+    118,   0,   0,   0,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_posix_alnum_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 254, 255, 255,   7,   0,   4,  32,   4,
+    255, 255, 127, 255, 255, 255, 255, 255, 195, 255,   3,   0,  31,  80,   0,   0,
+     32,   0,   0,   0,   0,   0, 223, 188,  64, 215, 255, 255, 251, 255, 255, 255,
+    255, 255, 191, 255,   3, 252, 255, 255, 255, 255, 254, 255, 255, 255, 127,   2,
+    254, 255, 255, 255, 255,   0,   0,   0,   0,   0, 255, 191, 182,   0, 255, 255,
+    255,   7,   7,   0,   0,   0, 255,   7, 255, 255, 255, 254,   0, 192, 255, 255,
+    255, 255, 239,  31, 254, 225,   0, 156,   0,   0, 255, 255,   0, 224, 255, 255,
+    255, 255,   3,   0,   0, 252, 255, 255, 255,   7,  48,   4, 255, 255, 255, 252,
+    255,  31,   0,   0, 255, 255, 255,   1, 255, 255,  31,   0, 248,   3, 255, 255,
+    255, 255, 255, 239, 255, 223, 225, 255,  15,   0, 254, 255, 239, 159, 249, 255,
+    255, 253, 197, 227, 159,  89, 128, 176,  15,   0,   3,   0, 238, 135, 249, 255,
+    255, 253, 109, 195, 135,  25,   2,  94,   0,   0,  63,   0, 238, 191, 251, 255,
+    255, 253, 237, 227, 191,  27,   1,   0,  15,   0,   0,   2, 238, 159, 249, 255,
+    159,  25, 192, 176,  15,   0,   2,   0, 236, 199,  61, 214,  24, 199, 255, 195,
+    199,  29, 129,   0, 239, 223, 253, 255, 255, 253, 255, 227, 223,  29,  96,   7,
+     15,   0,   0,   0, 238, 223, 253, 255, 255, 253, 239, 227, 223,  29,  96,  64,
+     15,   0,   6,   0, 255, 255, 255, 231, 223,  93, 128, 128,  15,   0,   0, 252,
+    236, 255, 127, 252, 255, 255, 251,  47, 127, 128,  95, 255,   0,   0,  12,   0,
+    255, 255, 255,   7, 127,  32,   0,   0, 150,  37, 240, 254, 174, 236, 255,  59,
+     95,  32,   0, 240,   1,   0,   0,   0, 255, 254, 255, 255, 255,  31, 254, 255,
+      3, 255, 255, 254, 255, 255, 255,  31, 255, 255, 127, 249, 231, 193, 255, 255,
+    127,  64,   0,  48, 191,  32, 255, 255, 255, 255, 255, 247, 255,  61, 127,  61,
+    255,  61, 255, 255, 255, 255,  61, 127,  61, 255, 127, 255, 255, 255,  61, 255,
+    255, 255, 255, 135, 255, 255,   0,   0, 255, 255,  63,  63, 255, 159, 255, 255,
+    255, 199, 255,   1, 255, 223,  15,   0, 255, 255,  15,   0, 255, 223,  13,   0,
+    255, 255, 207, 255, 255,   1, 128,  16, 255, 255, 255,   0, 255,   7, 255, 255,
+    255, 255,  63,   0, 255, 255, 255, 127, 255,  15, 255,   1, 255,  63,  31,   0,
+    255,  15, 255, 255, 255,   3,   0,   0, 255, 255, 255,  15, 254, 255,  31,   0,
+    128,   0,   0,   0, 255, 255, 239, 255, 239,  15,   0,   0, 255, 243,   0, 252,
+    191, 255,   3,   0,   0, 224,   0, 252, 255, 255, 255,  63,   0, 222, 111,   0,
+    128, 255,  31,   0,  63,  63, 255, 170, 255, 255, 223,  95, 220,  31, 207,  15,
+    255,  31, 220,  31,   0,   0,   2, 128,   0,   0, 255,  31, 132, 252,  47,  62,
+     80, 189, 255, 243, 224,  67,   0,   0, 255,   1,   0,   0,   0,   0, 192, 255,
+    255, 127, 255, 255,  31, 120,  12,   0, 255, 128,   0,   0, 255, 255, 127,   0,
+    127, 127, 127, 127,   0, 128,   0,   0, 224,   0,   0,   0, 254,   3,  62,  31,
+    255, 255, 127, 224, 224, 255, 255, 255, 255,  63, 254, 255, 255, 127,   0,   0,
+    255,  31, 255, 255,   0,  12,   0,   0, 255, 127, 240, 143,   0,   0, 128, 255,
+    252, 255, 255, 255, 255, 249, 255, 255, 255,  63, 255,   0, 187, 247, 255, 255,
+      0,   0, 252,  40, 255, 255,   7,   0, 255, 255, 247, 255, 223, 255,   0, 124,
+    255,  63,   0,   0, 255, 255, 127, 196,   5,   0,   0,  56, 255, 255,  60,   0,
+    126, 126, 126,   0, 127, 127, 255, 255,  63,   0, 255, 255, 255,   7,   0,   0,
+     15,   0, 255, 255, 127, 248, 255, 255, 255,  63, 255, 255, 255, 255, 255,   3,
+    127,   0, 248, 224, 255, 253, 127,  95, 219, 255, 255, 255,   0,   0, 248, 255,
+    255, 255, 252, 255,   0,   0, 255,  15,   0,   0, 223, 255, 192, 255, 255, 255,
+    252, 252, 252,  28, 255, 239, 255, 255, 127, 255, 255, 183, 255,  63, 255,  63,
+    255, 255,   1,   0,  15, 255,  62,   0, 255,   0, 255, 255,  63, 253, 255, 255,
+    255, 255, 191, 145, 255, 255,  55,   0, 255, 255, 255, 192, 111, 240, 239, 254,
+     31,   0,   0,   0,  63,   0,   0,   0, 255, 255,  71,   0,  30,   0,   0,  20,
+    255, 255, 251, 255, 255, 255, 159,   0, 127, 189, 255, 191, 255,   1, 255, 255,
+    159,  25, 129, 224, 179,   0,   0,   0, 255, 255,  63, 127,   0,   0,   0,  63,
+     17,   0,   0,   0, 255, 255, 255, 227,   0,   0,   0, 128, 127,   0,   0,   0,
+    248, 255, 255, 224,  31,   0, 255, 255,   3,   0,   0,   0, 255,   7, 255,  31,
+    255,   1, 255,  67, 255, 255, 223, 255, 255, 255, 255, 223, 100, 222, 255, 235,
+    239, 255, 255, 255, 191, 231, 223, 223, 255, 255, 255, 123,  95, 252, 253, 255,
+     63, 255, 255, 255, 253, 255, 255, 247, 255, 253, 255, 255, 247,  15,   0,   0,
+    150, 254, 247,  10, 132, 234, 150, 170, 150, 247, 247,  94, 255, 251, 255,  15,
+    238, 251, 255,  15, 255,   3, 255, 255,
+};
+
+/* Posix_AlNum: 2089 bytes. */
+
+RE_UINT32 re_get_posix_alnum(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_posix_alnum_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_posix_alnum_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_posix_alnum_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_posix_alnum_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_posix_alnum_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Posix_Punct. */
+
+static RE_UINT8 re_posix_punct_stage_1[] = {
+    0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2,
+};
+
+static RE_UINT8 re_posix_punct_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  9, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7, 11,
+    12, 13, 14,  7, 15,  7,  7,  7,  7,  7,  7,  7,  7, 16,  7,  7,
+     7,  7,  7,  7,  7,  7,  7, 17,  7,  7, 18, 19,  7, 20, 21, 22,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+};
+
+static RE_UINT8 re_posix_punct_stage_3[] = {
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16,  1,  1, 17, 18,  1, 19, 20, 21, 22, 23, 24, 25,  1,  1, 26,
+    27, 28, 29, 30, 31, 29, 29, 32, 29, 29, 29, 33, 34, 35, 36, 37,
+    38, 39, 40, 29,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1, 41,  1,  1,  1,  1,  1,  1, 42,  1, 43, 44,
+    45, 46, 47, 48,  1,  1,  1,  1,  1,  1,  1, 49,  1, 50, 51, 52,
+     1, 53,  1, 54,  1, 55,  1,  1, 56, 57, 58, 59,  1,  1,  1,  1,
+    60, 61, 62,  1, 63, 64, 65, 66,  1,  1,  1,  1, 67,  1,  1,  1,
+     1,  1, 68, 69,  1,  1,  1,  1,  1,  1,  1,  1, 70,  1,  1,  1,
+    71, 72, 73, 74,  1,  1, 75, 76, 29, 29, 77,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1, 10,  1, 78, 79, 80, 29, 29, 81, 82, 83,
+    84, 85,  1,  1,  1,  1,  1,  1,
+};
+
+static RE_UINT8 re_posix_punct_stage_4[] = {
+      0,   1,   2,   3,   0,   4,   5,   5,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   6,   7,   0,   0,   0,   8,   9,   0,   0,  10,
+      0,   0,   0,   0,  11,   0,   0,   0,   0,   0,  12,   0,  13,  14,  15,  16,
+     17,   0,   0,  18,   0,   0,  19,  20,  21,   0,   0,   0,   0,   0,   0,  22,
+      0,  23,  14,   0,   0,   0,   0,   0,   0,   0,   0,  24,   0,   0,   0,  25,
+      0,   0,   0,   0,   0,   0,   0,  26,   0,   0,   0,  27,   0,   0,   0,  28,
+      0,   0,   0,  29,   0,   0,   0,   0,   0,   0,   0,  30,   0,   0,   0,  31,
+      0,  29,  32,   0,   0,   0,   0,   0,  33,  34,   0,   0,  35,  36,  37,   0,
+      0,   0,  38,   0,  36,   0,   0,  39,   0,   0,   0,  40,  41,   0,   0,   0,
+     42,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  43,  44,   0,   0,  45,
+      0,  46,   0,   0,   0,   0,  47,   0,  48,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,  49,   0,   0,   0,  36,  50,  36,   0,   0,   0,   0,  51,   0,   0,
+      0,   0,  12,  52,   0,   0,   0,  53,   0,  54,   0,  36,   0,   0,  55,   0,
+      0,   0,   0,   0,   0,  56,  57,  58,  59,  60,  61,  62,  63,  61,   0,   0,
+     64,  65,  66,   0,  67,  50,  50,  50,  50,  50,  50,  50,  50,  50,  50,  50,
+     50,  50,  50,  50,  50,  50,  50,  68,  50,  69,  48,   0,  53,  70,   0,   0,
+     50,  50,  50,  70,  71,  50,  50,  50,  50,  50,  50,  72,  73,  74,  75,  76,
+      0,   0,   0,   0,   0,   0,   0,  77,   0,   0,   0,  27,   0,   0,   0,   0,
+     50,  78,  79,   0,  80,  50,  50,  81,  50,  50,  50,  50,  50,  50,  70,  82,
+     83,  84,   0,   0,  44,  42,   0,  39,   0,   0,   0,   0,  85,   0,  50,  86,
+     61,  87,  88,  50,  87,  89,  50,  61,   0,   0,   0,   0,   0,   0,  50,  50,
+      0,   0,   0,   0,  59,  50,  69,  36,  90,   0,   0,  91,   0,   0,   0,  92,
+     93,  94,   0,   0,  95,   0,   0,   0,   0,  96,   0,  97,   0,   0,  98,  99,
+      0,  98,  29,   0,   0,   0, 100,   0,   0,   0,  53, 101,   0,   0,  36,  26,
+      0,   0,  39,   0,   0,   0,   0, 102,   0, 103,   0,   0,   0, 104,  94,   0,
+      0,  36,   0,   0,   0,   0,   0, 105,  41,  59, 106, 107,   0,   0,   0,   0,
+      1,   2,   2, 108,   0,   0,   0, 109,  79, 110,   0, 111, 112,  42,  59, 113,
+      0,   0,   0,   0,  29,   0,  27,   0,   0,   0,   0, 114,   0,   0,   0,   0,
+      0,   0,   5, 115,   0,   0,   0,   0,  29,  29,   0,   0,   0,   0,   0,   0,
+      0,   0, 116,  29,   0,   0, 117, 118,   0, 111,   0,   0, 119,   0,   0,   0,
+      0,   0, 120,   0,   0, 121,  94,   0,   0,   0,  86, 122,   0,   0, 123,   0,
+      0, 124,   0,   0,   0, 103,   0,   0,   0,   0,   0,   0,   0,   0, 125,   0,
+      0,   0,   0,   0,   0,   0, 126,   0,   0,   0, 127,   0,   0,   0,   0,   0,
+      0,  53,   0,   0,   0,   0,   0,   0,   0,   0,   0, 128,   0,   0,   0,   0,
+      0,   0,   0,  98,   0,   0,   0, 129,   0, 110, 130,   0,   0,   0,   0,   0,
+      0,   0,   0,   0, 131,   0,   0,   0,  50,  50,  50,  50,  50,  50,  50,  70,
+     50, 132,  50, 133, 134, 135,  50,  40,  50,  50, 136,   0,   0,   0,   0,   0,
+     50,  50,  93,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 137,  39,
+    129, 129, 114, 114, 103, 103, 138,   0,   0, 139,   0, 140, 141,   0,   0,   0,
+     50, 142,  50,  50,  81, 143, 144,  70,  59, 145,  38, 146, 147,   0,   0, 148,
+    149,  68, 150,   0,   0,   0,   0,   0,  50,  50,  50,  80,  50, 151,  50,  50,
+     50,  50,  50,  50,  50,  50,  89, 152,  50,  50,  50,  81,  50,  50, 153,   0,
+    142,  50, 154,  50,  60,  21,   0,   0, 116,   0,   0,   0, 155,   0,  42,   0,
+};
+
+static RE_UINT8 re_posix_punct_stage_5[] = {
+      0,   0,   0,   0, 254, 255,   0, 252,   1,   0,   0, 248,   1,   0,   0, 120,
+    254, 219, 211, 137,   0,   0, 128,   0,  60,   0, 252, 255, 224, 175, 255, 255,
+      0,   0,  32,  64, 176,   0,   0,   0,   0,   0,  64,   0,   4,   0,   0,   0,
+      0,   0,   0, 252,   0, 230,   0,   0,   0,   0,   0,  64,  73,   0,   0,   0,
+      0,   0,  24,   0, 192, 255,   0, 200,   0,  60,   0,   0,   0,   0,  16,  64,
+      0,   2,   0,  96, 255,  63,   0,   0,   0,   0, 192,   3,   0,   0, 255, 127,
+     48,   0,   1,   0,   0,   0,  12,  12,   0,   0,   3,   0,   0,   0,   1,   0,
+      0,   0, 248,   7,   0,   0,   0, 128,   0,   0,   0,   2,   0,   0,  16,   0,
+      0, 128,   0,  12, 254, 255, 255, 252,   0,   0,  80,  61,  32,   0,   0,   0,
+      0,   0,   0, 192, 191, 223, 255,   7,   0, 252,   0,   0,   0,   0,   0,   8,
+    255,   1,   0,   0,   0,   0, 255,   3,   1,   0,   0,   0,   0,  96,   0,   0,
+      0,   0,   0,  24,   0,  56,   0,   0,   0,   0,  96,   0,   0,   0, 112,  15,
+    255,   7,   0,   0,  49,   0,   0,   0, 255, 255, 255, 255, 127,  63,   0,   0,
+    255,   7, 240,  31,   0,   0,   0, 240,   0,   0,   0, 248, 255,   0,   8,   0,
+      0,   0,   0, 160,   3, 224,   0, 224,   0, 224,   0,  96,   0,   0, 255, 255,
+    255,   0, 255, 255, 255, 255, 255, 127,   0,   0,   0, 124,   0, 124,   0,   0,
+    123,   3, 208, 193, 175,  66,   0,  12,  31, 188,   0,   0,   0,  12, 255, 255,
+    255, 255, 255,   7, 127,   0,   0,   0, 255, 255,  63,   0,   0,   0, 240, 255,
+    255, 255, 207, 255, 255, 255,  63, 255, 255, 255, 255, 227, 255, 253,   3,   0,
+      0, 240,   0,   0, 224,   7,   0, 222, 255, 127, 255, 255,   7,   0,   0,   0,
+    255, 255, 255, 251, 255, 255,  15,   0,   0,   0, 255,  15,  30, 255, 255, 255,
+      1,   0, 193, 224,   0,   0, 195, 255,  15,   0,   0,   0,   0, 252, 255, 255,
+    255,   0,   1,   0, 255, 255,   1,   0,   0, 224,   0,   0,   0,   0,   8,  64,
+      0,   0, 252,   0, 255, 255, 127,   0,   3,   0,   0,   0,   0,   6,   0,   0,
+      0,  15, 192,   3,   0,   0, 240,   0,   0, 192,   0,   0,   0,   0,   0,  23,
+    254,  63,   0, 192,   0,   0, 128,   3,   0,   8,   0,   0,   0,   2,   0,   0,
+      0,   0, 252, 255,   0,   0,   0,  48, 255, 255, 247, 255, 127,  15,   0,   0,
+     63,   0,   0,   0, 127, 127,   0,  48,   0,   0, 128, 255,   0,   0,   0, 254,
+    255,  19, 255,  15, 255, 255, 255,  31,   0, 128,   0,   0,   0,   0, 128,   1,
+      0,   0, 255,   1,   0,   1,   0,   0,   0,   0, 127,   0,   0,   0,   0,  30,
+    128,  63,   0,   0,   0,   0,   0, 216,   0,   0,  48,   0, 224,  35,   0, 232,
+      0,   0,   0,  63,  64,   0,   0,   0, 254, 255, 255,   0,  14,   0,   0,   0,
+      0,   0,  31,   0,   0,   0,  32,   0,  48,   0,   0,   0,   0,   0,   0, 144,
+    127, 254, 255, 255,  31,  28,   0,   0,  24, 240, 255, 255, 255, 195, 255, 255,
+     35,   0,   0,   0,   2,   0,   0,   8,   8,   0,   0,   0,   0,   0, 128,   7,
+      0, 224, 223, 255, 239,  15,   0,   0, 255,  15, 255, 255, 255, 127, 254, 255,
+    254, 255, 254, 255, 255, 127,   0,   0,   0,  12,   0,   0,   0, 252, 255,   7,
+    192, 255, 255, 255,   7,   0, 255, 255, 255,   1,   3,   0, 239, 255, 255, 255,
+    255,  31,  15,   0, 255, 255,  31,   0, 255,   0, 255,   3,  31,   0,   0,   0,
+};
+
+/* Posix_Punct: 1609 bytes. */
+
+RE_UINT32 re_get_posix_punct(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_posix_punct_stage_1[f] << 5;
+    f = code >> 11;
+    code ^= f << 11;
+    pos = (RE_UINT32)re_posix_punct_stage_2[pos + f] << 3;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_posix_punct_stage_3[pos + f] << 3;
+    f = code >> 5;
+    code ^= f << 5;
+    pos = (RE_UINT32)re_posix_punct_stage_4[pos + f] << 5;
+    pos += code;
+    value = (re_posix_punct_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* Posix_XDigit. */
+
+static RE_UINT8 re_posix_xdigit_stage_1[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1,
+};
+
+static RE_UINT8 re_posix_xdigit_stage_2[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_posix_xdigit_stage_3[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_posix_xdigit_stage_4[] = {
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static RE_UINT8 re_posix_xdigit_stage_5[] = {
+      0,   0,   0,   0,   0,   0, 255,   3, 126,   0,   0,   0, 126,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+
+/* Posix_XDigit: 97 bytes. */
+
+RE_UINT32 re_get_posix_xdigit(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+
+    f = ch >> 16;
+    code = ch ^ (f << 16);
+    pos = (RE_UINT32)re_posix_xdigit_stage_1[f] << 3;
+    f = code >> 13;
+    code ^= f << 13;
+    pos = (RE_UINT32)re_posix_xdigit_stage_2[pos + f] << 3;
+    f = code >> 10;
+    code ^= f << 10;
+    pos = (RE_UINT32)re_posix_xdigit_stage_3[pos + f] << 3;
+    f = code >> 7;
+    code ^= f << 7;
+    pos = (RE_UINT32)re_posix_xdigit_stage_4[pos + f] << 7;
+    pos += code;
+    value = (re_posix_xdigit_stage_5[pos >> 3] >> (pos & 0x7)) & 0x1;
+
+    return value;
+}
+
+/* All_Cases. */
+
+static RE_UINT8 re_all_cases_stage_1[] = {
+    0, 1, 2, 2, 2, 3, 2, 4, 5, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_all_cases_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     7,  6,  6,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9, 10, 11,
+     6, 12,  6,  6, 13,  6,  6,  6,  6,  6,  6,  6, 14, 15,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 16, 17,  6,  6,  6, 18,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 19,  6,  6,  6, 20,
+     6,  6,  6,  6, 21,  6,  6,  6,  6,  6,  6,  6, 22,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6, 23,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_all_cases_stage_3[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   3,   4,   5,   6,   7,   8,
+      0,   0,   0,   0,   0,   0,   9,   0,  10,  11,  12,  13,  14,  15,  16,  17,
+     18,  18,  18,  18,  18,  18,  19,  20,  21,  22,  18,  18,  18,  18,  18,  23,
+     24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  21,  34,  18,  18,  35,  18,
+     18,  18,  18,  18,  36,  18,  37,  38,  39,  18,  40,  41,  42,  43,  44,  45,
+     46,  47,  48,  49,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,  50,   0,   0,   0,   0,   0,  51,  52,
+     53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  18,  18,  18,  64,  65,
+     66,  66,  11,  11,  11,  11,  15,  15,  15,  15,  67,  67,  18,  18,  18,  18,
+     68,  69,  18,  18,  18,  18,  18,  18,  70,  71,  18,  18,  18,  18,  18,  18,
+     18,  18,  18,  18,  18,  18,  72,  73,  73,  73,  74,   0,  75,  76,  76,  76,
+     77,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  78,  78,  78,  78,  79,  80,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  82,  83,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  84,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  85,  18,  18,  18,
+     18,  18,  86,  87,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,
+     88,  89,  82,  83,  88,  89,  88,  89,  82,  83,  90,  91,  88,  89,  92,  93,
+     88,  89,  88,  89,  88,  89,  94,  95,  96,  97,  98,  99, 100, 101,  96, 102,
+      0,   0,   0,   0, 103, 104, 105,   0,   0, 106,   0,   0, 107, 107, 108, 108,
+    109,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 110, 111, 111, 111, 112, 112, 112, 113,   0,   0,
+     73,  73,  73,  73,  73,  74,  76,  76,  76,  76,  76,  77, 114, 115, 116, 117,
+     18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  37, 118, 119,   0,
+    120, 120, 120, 120, 121, 122,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,  18,  18,  18,  18,  18,  86,   0,   0,
+     18,  18,  18,  37,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  69,  18,  69,  18,  18,  18,  18,  18,  18,  18,   0, 123,
+     18, 124,  51,  18,  18, 125, 126,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 127,   0,   0,   0, 128, 128,
+    128, 128, 128, 128, 128, 128, 128, 128,   0,   0,   0,   0,   0,   0,   0,   0,
+    129,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   1,  11,  11,   4,   5,  15,  15,   8,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    130, 130, 130, 130, 130, 131, 131, 131, 131, 131,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    132, 132, 132, 132, 132, 132, 133,   0, 134, 134, 134, 134, 134, 134, 135,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,  11,  11,  11,  11,  15,  15,  15,  15,   0,   0,   0,   0,
+};
+
+static RE_UINT8 re_all_cases_stage_4[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,   1,
+      1,   2,   1,   3,   1,   1,   1,   1,   1,   1,   1,   4,   1,   1,   1,   1,
+      1,   1,   1,   0,   0,   0,   0,   0,   0,   5,   5,   5,   5,   5,   5,   5,
+      5,   6,   5,   7,   5,   5,   5,   5,   5,   5,   5,   8,   5,   5,   5,   5,
+      5,   5,   5,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   9,   0,   0,
+      1,   1,   1,   1,   1,  10,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   0,   1,   1,   1,   1,   1,   1,   1,  11,
+      5,   5,   5,   5,   5,  12,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,   5,   5,   5,   5,   0,   5,   5,   5,   5,   5,   5,   5,  13,
+     14,  15,  14,  15,  14,  15,  14,  15,  16,  17,  14,  15,  14,  15,  14,  15,
+      0,  14,  15,  14,  15,  14,  15,  14,  15,  14,  15,  14,  15,  14,  15,  14,
+     15,   0,  14,  15,  14,  15,  14,  15,  18,  14,  15,  14,  15,  14,  15,  19,
+     20,  21,  14,  15,  14,  15,  22,  14,  15,  23,  23,  14,  15,   0,  24,  25,
+     26,  14,  15,  23,  27,  28,  29,  30,  14,  15,  31,   0,  29,  32,  33,  34,
+     14,  15,  14,  15,  14,  15,  35,  14,  15,  35,   0,   0,  14,  15,  35,  14,
+     15,  36,  36,  14,  15,  14,  15,  37,  14,  15,   0,   0,  14,  15,   0,  38,
+      0,   0,   0,   0,  39,  40,  41,  39,  40,  41,  39,  40,  41,  14,  15,  14,
+     15,  14,  15,  14,  15,  42,  14,  15,   0,  39,  40,  41,  14,  15,  43,  44,
+     45,   0,  14,  15,  14,  15,  14,  15,  14,  15,  14,  15,   0,   0,   0,   0,
+      0,   0,  46,  14,  15,  47,  48,  49,  49,  14,  15,  50,  51,  52,  14,  15,
+     53,  54,  55,  56,  57,   0,  58,  58,   0,  59,   0,  60,  61,   0,   0,   0,
+     58,  62,   0,  63,   0,  64,  65,   0,  66,  67,   0,  68,  69,   0,   0,  67,
+      0,  70,  71,   0,   0,  72,   0,   0,   0,   0,   0,   0,   0,  73,   0,   0,
+     74,   0,   0,  74,   0,   0,   0,  75,  74,  76,  77,  77,  78,   0,   0,   0,
+      0,   0,  79,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  80,  81,   0,
+      0,   0,   0,   0,   0,  82,   0,   0,  14,  15,  14,  15,   0,   0,  14,  15,
+      0,   0,   0,  33,  33,  33,   0,  83,   0,   0,   0,   0,   0,   0,  84,   0,
+     85,  85,  85,   0,  86,   0,  87,  87,  88,   1,  89,   1,   1,  90,   1,   1,
+     91,  92,  93,   1,  94,   1,   1,   1,  95,  96,   0,  97,   1,   1,  98,   1,
+      1,  99,   1,   1, 100, 101, 101, 101, 102,   5, 103,   5,   5, 104,   5,   5,
+    105, 106, 107,   5, 108,   5,   5,   5, 109, 110, 111, 112,   5,   5, 113,   5,
+      5, 114,   5,   5, 115, 116, 116, 117, 118, 119,   0,   0,   0, 120, 121, 122,
+    123, 124, 125, 126, 127, 128,   0,  14,  15, 129,  14,  15,   0,  45,  45,  45,
+    130, 130, 130, 130, 130, 130, 130, 130, 131, 131, 131, 131, 131, 131, 131, 131,
+     14,  15,   0,   0,   0,   0,   0,   0,   0,   0,  14,  15,  14,  15,  14,  15,
+    132,  14,  15,  14,  15,  14,  15,  14,  15,  14,  15,  14,  15,  14,  15, 133,
+      0, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
+    134, 134, 134, 134, 134, 134, 134,   0,   0, 135, 135, 135, 135, 135, 135, 135,
+    135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135,   0,
+    136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,   0, 136,
+      0,   0,   0,   0,   0, 136,   0,   0, 137, 137, 137, 137, 137, 137, 137, 137,
+    117, 117, 117, 117, 117, 117,   0,   0, 122, 122, 122, 122, 122, 122,   0,   0,
+      0, 138,   0,   0,   0, 139,   0,   0, 140, 141,  14,  15,  14,  15,  14,  15,
+     14,  15,  14,  15,  14,  15,   0,   0,   0,   0,   0, 142,   0,   0, 143,   0,
+    117, 117, 117, 117, 117, 117, 117, 117, 122, 122, 122, 122, 122, 122, 122, 122,
+      0, 117,   0, 117,   0, 117,   0, 117,   0, 122,   0, 122,   0, 122,   0, 122,
+    144, 144, 145, 145, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149,   0,   0,
+    117, 117,   0, 150,   0,   0,   0,   0, 122, 122, 151, 151, 152,   0, 153,   0,
+      0,   0,   0, 150,   0,   0,   0,   0, 154, 154, 154, 154, 152,   0,   0,   0,
+    117, 117,   0, 155,   0,   0,   0,   0, 122, 122, 156, 156,   0,   0,   0,   0,
+    117, 117,   0, 157,   0, 125,   0,   0, 122, 122, 158, 158, 129,   0,   0,   0,
+    159, 159, 160, 160, 152,   0,   0,   0,   0,   0,   0,   0,   0,   0, 161,   0,
+      0,   0, 162, 163,   0,   0,   0,   0,   0,   0, 164,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 165,   0, 166, 166, 166, 166, 166, 166, 166, 166,
+    167, 167, 167, 167, 167, 167, 167, 167,   0,   0,   0,  14,  15,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
+    169, 169, 169, 169, 169, 169, 169, 169, 169, 169,   0,   0,   0,   0,   0,   0,
+     14,  15, 170, 171, 172, 173, 174,  14,  15,  14,  15,  14,  15, 175, 176, 177,
+    178,   0,  14,  15,   0,  14,  15,   0,   0,   0,   0,   0,   0,   0, 179, 179,
+      0,   0,   0,  14,  15,  14,  15,   0,   0,   0,  14,  15,   0,   0,   0,   0,
+    180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180,   0, 180,
+      0,   0,   0,   0,   0, 180,   0,   0,   0,  14,  15,  14,  15, 181,  14,  15,
+      0,   0,   0,  14,  15, 182,   0,   0,  14,  15, 183, 184, 185, 186,   0,   0,
+    187, 188, 189, 190,  14,  15,  14,  15,   0,   0,   0, 191,   0,   0,   0,   0,
+    192, 192, 192, 192, 192, 192, 192, 192,   0,   0,   0,   0,   0,  14,  15,   0,
+    193, 193, 193, 193, 193, 193, 193, 193, 194, 194, 194, 194, 194, 194, 194, 194,
+     86,  86,  86,  86,  86,  86,  86,  86,  86,  86,  86,   0,   0,   0,   0,   0,
+    115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115,   0,   0,   0,   0,   0,
+};
+
+/* All_Cases: 2184 bytes. */
+
+static RE_AllCases re_all_cases_table[] = {
+    {{     0,     0,     0}},
+    {{    32,     0,     0}},
+    {{    32,   232,     0}},
+    {{    32,  8415,     0}},
+    {{    32,   300,     0}},
+    {{   -32,     0,     0}},
+    {{   -32,   199,     0}},
+    {{   -32,  8383,     0}},
+    {{   -32,   268,     0}},
+    {{   743,   775,     0}},
+    {{    32,  8294,     0}},
+    {{  7615,     0,     0}},
+    {{   -32,  8262,     0}},
+    {{   121,     0,     0}},
+    {{     1,     0,     0}},
+    {{    -1,     0,     0}},
+    {{  -199,     0,     0}},
+    {{  -232,     0,     0}},
+    {{  -121,     0,     0}},
+    {{  -300,  -268,     0}},
+    {{   195,     0,     0}},
+    {{   210,     0,     0}},
+    {{   206,     0,     0}},
+    {{   205,     0,     0}},
+    {{    79,     0,     0}},
+    {{   202,     0,     0}},
+    {{   203,     0,     0}},
+    {{   207,     0,     0}},
+    {{    97,     0,     0}},
+    {{   211,     0,     0}},
+    {{   209,     0,     0}},
+    {{   163,     0,     0}},
+    {{   213,     0,     0}},
+    {{   130,     0,     0}},
+    {{   214,     0,     0}},
+    {{   218,     0,     0}},
+    {{   217,     0,     0}},
+    {{   219,     0,     0}},
+    {{    56,     0,     0}},
+    {{     1,     2,     0}},
+    {{    -1,     1,     0}},
+    {{    -2,    -1,     0}},
+    {{   -79,     0,     0}},
+    {{   -97,     0,     0}},
+    {{   -56,     0,     0}},
+    {{  -130,     0,     0}},
+    {{ 10795,     0,     0}},
+    {{  -163,     0,     0}},
+    {{ 10792,     0,     0}},
+    {{ 10815,     0,     0}},
+    {{  -195,     0,     0}},
+    {{    69,     0,     0}},
+    {{    71,     0,     0}},
+    {{ 10783,     0,     0}},
+    {{ 10780,     0,     0}},
+    {{ 10782,     0,     0}},
+    {{  -210,     0,     0}},
+    {{  -206,     0,     0}},
+    {{  -205,     0,     0}},
+    {{  -202,     0,     0}},
+    {{  -203,     0,     0}},
+    {{ 42319,     0,     0}},
+    {{ 42315,     0,     0}},
+    {{  -207,     0,     0}},
+    {{ 42280,     0,     0}},
+    {{ 42308,     0,     0}},
+    {{  -209,     0,     0}},
+    {{  -211,     0,     0}},
+    {{ 10743,     0,     0}},
+    {{ 42305,     0,     0}},
+    {{ 10749,     0,     0}},
+    {{  -213,     0,     0}},
+    {{  -214,     0,     0}},
+    {{ 10727,     0,     0}},
+    {{  -218,     0,     0}},
+    {{ 42282,     0,     0}},
+    {{   -69,     0,     0}},
+    {{  -217,     0,     0}},
+    {{   -71,     0,     0}},
+    {{  -219,     0,     0}},
+    {{ 42261,     0,     0}},
+    {{ 42258,     0,     0}},
+    {{    84,   116,  7289}},
+    {{   116,     0,     0}},
+    {{    38,     0,     0}},
+    {{    37,     0,     0}},
+    {{    64,     0,     0}},
+    {{    63,     0,     0}},
+    {{  7235,     0,     0}},
+    {{    32,    62,     0}},
+    {{    32,    96,     0}},
+    {{    32,    57,    92}},
+    {{   -84,    32,  7205}},
+    {{    32,    86,     0}},
+    {{  -743,    32,     0}},
+    {{    32,    54,     0}},
+    {{    32,    80,     0}},
+    {{    31,    32,     0}},
+    {{    32,    47,     0}},
+    {{    32,  7549,     0}},
+    {{   -38,     0,     0}},
+    {{   -37,     0,     0}},
+    {{  7219,     0,     0}},
+    {{   -32,    30,     0}},
+    {{   -32,    64,     0}},
+    {{   -32,    25,    60}},
+    {{  -116,   -32,  7173}},
+    {{   -32,    54,     0}},
+    {{  -775,   -32,     0}},
+    {{   -32,    22,     0}},
+    {{   -32,    48,     0}},
+    {{   -31,     1,     0}},
+    {{   -32,    -1,     0}},
+    {{   -32,    15,     0}},
+    {{   -32,  7517,     0}},
+    {{   -64,     0,     0}},
+    {{   -63,     0,     0}},
+    {{     8,     0,     0}},
+    {{   -62,   -30,     0}},
+    {{   -57,   -25,    35}},
+    {{   -47,   -15,     0}},
+    {{   -54,   -22,     0}},
+    {{    -8,     0,     0}},
+    {{   -86,   -54,     0}},
+    {{   -80,   -48,     0}},
+    {{     7,     0,     0}},
+    {{  -116,     0,     0}},
+    {{   -92,   -60,   -35}},
+    {{   -96,   -64,     0}},
+    {{    -7,     0,     0}},
+    {{    80,     0,     0}},
+    {{   -80,     0,     0}},
+    {{    15,     0,     0}},
+    {{   -15,     0,     0}},
+    {{    48,     0,     0}},
+    {{   -48,     0,     0}},
+    {{  7264,     0,     0}},
+    {{ 38864,     0,     0}},
+    {{ 35332,     0,     0}},
+    {{  3814,     0,     0}},
+    {{     1,    59,     0}},
+    {{    -1,    58,     0}},
+    {{   -59,   -58,     0}},
+    {{ -7615,     0,     0}},
+    {{    74,     0,     0}},
+    {{    86,     0,     0}},
+    {{   100,     0,     0}},
+    {{   128,     0,     0}},
+    {{   112,     0,     0}},
+    {{   126,     0,     0}},
+    {{     9,     0,     0}},
+    {{   -74,     0,     0}},
+    {{    -9,     0,     0}},
+    {{ -7289, -7205, -7173}},
+    {{   -86,     0,     0}},
+    {{ -7235,     0,     0}},
+    {{  -100,     0,     0}},
+    {{ -7219,     0,     0}},
+    {{  -112,     0,     0}},
+    {{  -128,     0,     0}},
+    {{  -126,     0,     0}},
+    {{ -7549, -7517,     0}},
+    {{ -8415, -8383,     0}},
+    {{ -8294, -8262,     0}},
+    {{    28,     0,     0}},
+    {{   -28,     0,     0}},
+    {{    16,     0,     0}},
+    {{   -16,     0,     0}},
+    {{    26,     0,     0}},
+    {{   -26,     0,     0}},
+    {{-10743,     0,     0}},
+    {{ -3814,     0,     0}},
+    {{-10727,     0,     0}},
+    {{-10795,     0,     0}},
+    {{-10792,     0,     0}},
+    {{-10780,     0,     0}},
+    {{-10749,     0,     0}},
+    {{-10783,     0,     0}},
+    {{-10782,     0,     0}},
+    {{-10815,     0,     0}},
+    {{ -7264,     0,     0}},
+    {{-35332,     0,     0}},
+    {{-42280,     0,     0}},
+    {{-42308,     0,     0}},
+    {{-42319,     0,     0}},
+    {{-42315,     0,     0}},
+    {{-42305,     0,     0}},
+    {{-42258,     0,     0}},
+    {{-42282,     0,     0}},
+    {{-42261,     0,     0}},
+    {{   928,     0,     0}},
+    {{  -928,     0,     0}},
+    {{-38864,     0,     0}},
+    {{    40,     0,     0}},
+    {{   -40,     0,     0}},
+};
+
+/* All_Cases: 2340 bytes. */
+
+int re_get_all_cases(RE_UINT32 ch, RE_UINT32* codepoints) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+    RE_AllCases* all_cases;
+    int count;
+
+    f = ch >> 13;
+    code = ch ^ (f << 13);
+    pos = (RE_UINT32)re_all_cases_stage_1[f] << 5;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_all_cases_stage_2[pos + f] << 5;
+    f = code >> 3;
+    code ^= f << 3;
+    pos = (RE_UINT32)re_all_cases_stage_3[pos + f] << 3;
+    value = re_all_cases_stage_4[pos + code];
+
+    all_cases = &re_all_cases_table[value];
+
+    codepoints[0] = ch;
+    count = 1;
+
+    while (count < RE_MAX_CASES && all_cases->diffs[count - 1] != 0) {
+        codepoints[count] = (RE_UINT32)((RE_INT32)ch + all_cases->diffs[count -
+          1]);
+        ++count;
+    }
+
+    return count;
+}
+
+/* Simple_Case_Folding. */
+
+static RE_UINT8 re_simple_case_folding_stage_1[] = {
+    0, 1, 2, 2, 2, 3, 2, 4, 5, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_simple_case_folding_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     7,  6,  6,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9, 10,
+     6, 11,  6,  6, 12,  6,  6,  6,  6,  6,  6,  6, 13,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 14, 15,  6,  6,  6, 16,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 17,
+     6,  6,  6,  6, 18,  6,  6,  6,  6,  6,  6,  6, 19,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6, 20,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_simple_case_folding_stage_3[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  2,  3,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  4,  0,  2,  2,  5,  5,  0,  0,  0,  0,
+     6,  6,  6,  6,  6,  6,  7,  8,  8,  7,  6,  6,  6,  6,  6,  9,
+    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  8, 20,  6,  6, 21,  6,
+     6,  6,  6,  6, 22,  6, 23, 24, 25,  6,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0, 26,  0,  0,  0,  0,  0, 27, 28,
+    29, 30,  1,  2, 31, 32,  0,  0, 33, 34, 35,  6,  6,  6, 36, 37,
+    38, 38,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  6,  6,  6,  6,
+    39,  7,  6,  6,  6,  6,  6,  6, 40, 41,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 42, 43, 43, 43, 44,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 45, 45, 45, 45, 46, 47,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6, 49, 50,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     0, 51,  0, 48,  0, 51,  0, 51,  0, 48,  0, 52,  0, 51,  0,  0,
+     0, 51,  0, 51,  0, 51,  0, 53,  0, 54,  0, 55,  0, 56,  0, 57,
+     0,  0,  0,  0, 58, 59, 60,  0,  0,  0,  0,  0, 61, 61,  0,  0,
+    62,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 63, 64, 64, 64,  0,  0,  0,  0,  0,  0,
+    43, 43, 43, 43, 43, 44,  0,  0,  0,  0,  0,  0, 65, 66, 67, 68,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 23, 69, 33,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  6,  6,  6,  6,  6, 49,  0,  0,
+     6,  6,  6, 23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  7,  6,  7,  6,  6,  6,  6,  6,  6,  6,  0, 70,
+     6, 71, 27,  6,  6, 72, 73,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 74, 74,
+    74, 74, 74, 74, 74, 74, 74, 74,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  1,  2,  2,  3,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    75, 75, 75, 75, 75,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    76, 76, 76, 76, 76, 76, 77,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_simple_case_folding_stage_4[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  2,  0,  0,  1,  1,  1,  1,  1,  1,  1,  0,
+     3,  0,  3,  0,  3,  0,  3,  0,  0,  0,  3,  0,  3,  0,  3,  0,
+     0,  3,  0,  3,  0,  3,  0,  3,  4,  3,  0,  3,  0,  3,  0,  5,
+     0,  6,  3,  0,  3,  0,  7,  3,  0,  8,  8,  3,  0,  0,  9, 10,
+    11,  3,  0,  8, 12,  0, 13, 14,  3,  0,  0,  0, 13, 15,  0, 16,
+     3,  0,  3,  0,  3,  0, 17,  3,  0, 17,  0,  0,  3,  0, 17,  3,
+     0, 18, 18,  3,  0,  3,  0, 19,  3,  0,  0,  0,  3,  0,  0,  0,
+     0,  0,  0,  0, 20,  3,  0, 20,  3,  0, 20,  3,  0,  3,  0,  3,
+     0,  3,  0,  3,  0,  0,  3,  0,  0, 20,  3,  0,  3,  0, 21, 22,
+    23,  0,  3,  0,  3,  0,  3,  0,  3,  0,  3,  0,  0,  0,  0,  0,
+     0,  0, 24,  3,  0, 25, 26,  0,  0,  3,  0, 27, 28, 29,  3,  0,
+     0,  0,  0,  0,  0, 30,  0,  0,  3,  0,  3,  0,  0,  0,  3,  0,
+     0,  0,  0,  0,  0,  0,  0, 30,  0,  0,  0,  0,  0,  0, 31,  0,
+    32, 32, 32,  0, 33,  0, 34, 34,  1,  1,  0,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  3,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0, 35, 36, 37,  0,  0,  0, 38, 39,  0,
+    40, 41,  0,  0, 42, 43,  0,  3,  0, 44,  3,  0,  0, 23, 23, 23,
+    45, 45, 45, 45, 45, 45, 45, 45,  3,  0,  0,  0,  0,  0,  0,  0,
+    46,  3,  0,  3,  0,  3,  0,  3,  0,  3,  0,  3,  0,  3,  0,  0,
+     0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+    47, 47, 47, 47, 47, 47, 47,  0, 48, 48, 48, 48, 48, 48, 48, 48,
+    48, 48, 48, 48, 48, 48,  0, 48,  0,  0,  0,  0,  0, 48,  0,  0,
+    49, 49, 49, 49, 49, 49,  0,  0,  3,  0,  3,  0,  3,  0,  0,  0,
+     0,  0,  0, 50,  0,  0, 51,  0, 49, 49, 49, 49, 49, 49, 49, 49,
+     0, 49,  0, 49,  0, 49,  0, 49, 49, 49, 52, 52, 53,  0, 54,  0,
+    55, 55, 55, 55, 53,  0,  0,  0, 49, 49, 56, 56,  0,  0,  0,  0,
+    49, 49, 57, 57, 44,  0,  0,  0, 58, 58, 59, 59, 53,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 60,  0,  0,  0, 61, 62,  0,  0,  0,  0,
+     0,  0, 63,  0,  0,  0,  0,  0, 64, 64, 64, 64, 64, 64, 64, 64,
+     0,  0,  0,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 65, 65,
+    65, 65, 65, 65, 65, 65, 65, 65,  3,  0, 66, 67, 68,  0,  0,  3,
+     0,  3,  0,  3,  0, 69, 70, 71, 72,  0,  3,  0,  0,  3,  0,  0,
+     0,  0,  0,  0,  0,  0, 73, 73,  0,  0,  0,  3,  0,  3,  0,  0,
+     0,  3,  0,  3,  0, 74,  3,  0,  0,  0,  0,  3,  0, 75,  0,  0,
+     3,  0, 76, 77, 78, 79,  0,  0, 80, 81, 82, 83,  3,  0,  3,  0,
+    84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 85,
+    33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,  0,  0,  0,  0,  0,
+};
+
+/* Simple_Case_Folding: 1624 bytes. */
+
+static RE_INT32 re_simple_case_folding_table[] = {
+         0,
+        32,
+       775,
+         1,
+      -121,
+      -268,
+       210,
+       206,
+       205,
+        79,
+       202,
+       203,
+       207,
+       211,
+       209,
+       213,
+       214,
+       218,
+       217,
+       219,
+         2,
+       -97,
+       -56,
+      -130,
+     10795,
+      -163,
+     10792,
+      -195,
+        69,
+        71,
+       116,
+        38,
+        37,
+        64,
+        63,
+         8,
+       -30,
+       -25,
+       -15,
+       -22,
+       -54,
+       -48,
+       -60,
+       -64,
+        -7,
+        80,
+        15,
+        48,
+      7264,
+        -8,
+       -58,
+     -7615,
+       -74,
+        -9,
+     -7173,
+       -86,
+      -100,
+      -112,
+      -128,
+      -126,
+     -7517,
+     -8383,
+     -8262,
+        28,
+        16,
+        26,
+    -10743,
+     -3814,
+    -10727,
+    -10780,
+    -10749,
+    -10783,
+    -10782,
+    -10815,
+    -35332,
+    -42280,
+    -42308,
+    -42319,
+    -42315,
+    -42305,
+    -42258,
+    -42282,
+    -42261,
+       928,
+    -38864,
+        40,
+};
+
+/* Simple_Case_Folding: 344 bytes. */
+
+RE_UINT32 re_get_simple_case_folding(RE_UINT32 ch) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+    RE_INT32 diff;
+
+    f = ch >> 13;
+    code = ch ^ (f << 13);
+    pos = (RE_UINT32)re_simple_case_folding_stage_1[f] << 5;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_simple_case_folding_stage_2[pos + f] << 5;
+    f = code >> 3;
+    code ^= f << 3;
+    pos = (RE_UINT32)re_simple_case_folding_stage_3[pos + f] << 3;
+    value = re_simple_case_folding_stage_4[pos + code];
+
+    diff = re_simple_case_folding_table[value];
+
+    return (RE_UINT32)((RE_INT32)ch + diff);
+}
+
+/* Full_Case_Folding. */
+
+static RE_UINT8 re_full_case_folding_stage_1[] = {
+    0, 1, 2, 2, 2, 3, 2, 4, 5, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static RE_UINT8 re_full_case_folding_stage_2[] = {
+     0,  1,  2,  3,  4,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     7,  6,  6,  8,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  9, 10,
+     6, 11,  6,  6, 12,  6,  6,  6,  6,  6,  6,  6, 13,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6, 14, 15,  6,  6,  6, 16,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6, 17,  6,  6,  6, 18,
+     6,  6,  6,  6, 19,  6,  6,  6,  6,  6,  6,  6, 20,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6, 21,  6,  6,  6,  6,  6,  6,  6,
+};
+
+static RE_UINT8 re_full_case_folding_stage_3[] = {
+     0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  2,  3,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  4,  0,  2,  2,  5,  6,  0,  0,  0,  0,
+     7,  7,  7,  7,  7,  7,  8,  9,  9, 10,  7,  7,  7,  7,  7, 11,
+    12, 13, 14, 15, 16, 17, 18, 19, 20, 21,  9, 22,  7,  7, 23,  7,
+     7,  7,  7,  7, 24,  7, 25, 26, 27,  7,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0, 28,  0,  0,  0,  0,  0, 29, 30,
+    31, 32, 33,  2, 34, 35, 36,  0, 37, 38, 39,  7,  7,  7, 40, 41,
+    42, 42,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  7,  7,  7,  7,
+    43, 44,  7,  7,  7,  7,  7,  7, 45, 46,  7,  7,  7,  7,  7,  7,
+     7,  7,  7,  7,  7,  7, 47, 48, 48, 48, 49,  0,  0,  0,  0,  0,
+    50,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 51, 51, 51, 51, 52, 53,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 54,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     7,  7, 55, 56,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+     0, 57,  0, 54,  0, 57,  0, 57,  0, 54, 58, 59,  0, 57,  0,  0,
+    60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+     0,  0,  0,  0, 76, 77, 78,  0,  0,  0,  0,  0, 79, 79,  0,  0,
+    80,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0, 81, 82, 82, 82,  0,  0,  0,  0,  0,  0,
+    48, 48, 48, 48, 48, 49,  0,  0,  0,  0,  0,  0, 83, 84, 85, 86,
+     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 25, 87, 37,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  7,  7,  7,  7,  7, 88,  0,  0,
+     7,  7,  7, 25,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0, 44,  7, 44,  7,  7,  7,  7,  7,  7,  7,  0, 89,
+     7, 90, 29,  7,  7, 91, 92,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 93, 93,
+    93, 93, 93, 93, 93, 93, 93, 93,  0,  0,  0,  0,  0,  0,  0,  0,
+    94,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  1,  2,  2,  3,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    96, 96, 96, 96, 96,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    97, 97, 97, 97, 97, 97, 98,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static RE_UINT8 re_full_case_folding_stage_4[] = {
+      0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   2,   0,   0,   1,   1,   1,   1,   1,   1,   1,   0,
+      1,   1,   1,   1,   1,   1,   1,   3,   4,   0,   4,   0,   4,   0,   4,   0,
+      5,   0,   4,   0,   4,   0,   4,   0,   0,   4,   0,   4,   0,   4,   0,   4,
+      0,   6,   4,   0,   4,   0,   4,   0,   7,   4,   0,   4,   0,   4,   0,   8,
+      0,   9,   4,   0,   4,   0,  10,   4,   0,  11,  11,   4,   0,   0,  12,  13,
+     14,   4,   0,  11,  15,   0,  16,  17,   4,   0,   0,   0,  16,  18,   0,  19,
+      4,   0,   4,   0,   4,   0,  20,   4,   0,  20,   0,   0,   4,   0,  20,   4,
+      0,  21,  21,   4,   0,   4,   0,  22,   4,   0,   0,   0,   4,   0,   0,   0,
+      0,   0,   0,   0,  23,   4,   0,  23,   4,   0,  23,   4,   0,   4,   0,   4,
+      0,   4,   0,   4,   0,   0,   4,   0,  24,  23,   4,   0,   4,   0,  25,  26,
+     27,   0,   4,   0,   4,   0,   4,   0,   4,   0,   4,   0,   0,   0,   0,   0,
+      0,   0,  28,   4,   0,  29,  30,   0,   0,   4,   0,  31,  32,  33,   4,   0,
+      0,   0,   0,   0,   0,  34,   0,   0,   4,   0,   4,   0,   0,   0,   4,   0,
+      0,   0,   0,   0,   0,   0,   0,  34,   0,   0,   0,   0,   0,   0,  35,   0,
+     36,  36,  36,   0,  37,   0,  38,  38,  39,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1,   0,   0,   0,   0,
+     40,   0,   0,   0,   0,   0,   0,   0,   0,   0,   4,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,  41,  42,  43,   0,   0,   0,  44,  45,   0,
+     46,  47,   0,   0,  48,  49,   0,   4,   0,  50,   4,   0,   0,  27,  27,  27,
+     51,  51,  51,  51,  51,  51,  51,  51,   4,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   4,   0,   4,   0,   4,   0,  52,   4,   0,   4,   0,   4,   0,   4,
+      0,   4,   0,   4,   0,   4,   0,   0,   0,  53,  53,  53,  53,  53,  53,  53,
+     53,  53,  53,  53,  53,  53,  53,  53,  53,  53,  53,  53,  53,  53,  53,   0,
+      0,   0,   0,   0,   0,   0,   0,  54,  55,  55,  55,  55,  55,  55,  55,  55,
+     55,  55,  55,  55,  55,  55,   0,  55,   0,   0,   0,   0,   0,  55,   0,   0,
+     56,  56,  56,  56,  56,  56,   0,   0,   4,   0,   4,   0,   4,   0,  57,  58,
+     59,  60,  61,  62,   0,   0,  63,   0,  56,  56,  56,  56,  56,  56,  56,  56,
+     64,   0,  65,   0,  66,   0,  67,   0,   0,  56,   0,  56,   0,  56,   0,  56,
+     68,  68,  68,  68,  68,  68,  68,  68,  69,  69,  69,  69,  69,  69,  69,  69,
+     70,  70,  70,  70,  70,  70,  70,  70,  71,  71,  71,  71,  71,  71,  71,  71,
+     72,  72,  72,  72,  72,  72,  72,  72,  73,  73,  73,  73,  73,  73,  73,  73,
+      0,   0,  74,  75,  76,   0,  77,  78,  56,  56,  79,  79,  80,   0,  81,   0,
+      0,   0,  82,  83,  84,   0,  85,  86,  87,  87,  87,  87,  88,   0,   0,   0,
+      0,   0,  89,  90,   0,   0,  91,  92,  56,  56,  93,  93,   0,   0,   0,   0,
+      0,   0,  94,  95,  96,   0,  97,  98,  56,  56,  99,  99,  50,   0,   0,   0,
+      0,   0, 100, 101, 102,   0, 103, 104, 105, 105, 106, 106, 107,   0,   0,   0,
+      0,   0,   0,   0,   0,   0, 108,   0,   0,   0, 109, 110,   0,   0,   0,   0,
+      0,   0, 111,   0,   0,   0,   0,   0, 112, 112, 112, 112, 112, 112, 112, 112,
+      0,   0,   0,   4,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 113, 113,
+    113, 113, 113, 113, 113, 113, 113, 113,   4,   0, 114, 115, 116,   0,   0,   4,
+      0,   4,   0,   4,   0, 117, 118, 119, 120,   0,   4,   0,   0,   4,   0,   0,
+      0,   0,   0,   0,   0,   0, 121, 121,   0,   0,   0,   4,   0,   4,   0,   0,
+      4,   0,   4,   0,   4,   0,   0,   0,   0,   4,   0,   4,   0, 122,   4,   0,
+      0,   0,   0,   4,   0, 123,   0,   0,   4,   0, 124, 125, 126, 127,   0,   0,
+    128, 129, 130, 131,   4,   0,   4,   0, 132, 132, 132, 132, 132, 132, 132, 132,
+    133, 134, 135, 136, 137, 138, 139,   0,   0,   0,   0, 140, 141, 142, 143, 144,
+    145, 145, 145, 145, 145, 145, 145, 145,  37,  37,  37,  37,  37,  37,  37,  37,
+     37,  37,  37,   0,   0,   0,   0,   0,
+};
+
+/* Full_Case_Folding: 1824 bytes. */
+
+static RE_FullCaseFolding re_full_case_folding_table[] = {
+    {     0, {   0,   0}},
+    {    32, {   0,   0}},
+    {   775, {   0,   0}},
+    {  -108, { 115,   0}},
+    {     1, {   0,   0}},
+    {  -199, { 775,   0}},
+    {   371, { 110,   0}},
+    {  -121, {   0,   0}},
+    {  -268, {   0,   0}},
+    {   210, {   0,   0}},
+    {   206, {   0,   0}},
+    {   205, {   0,   0}},
+    {    79, {   0,   0}},
+    {   202, {   0,   0}},
+    {   203, {   0,   0}},
+    {   207, {   0,   0}},
+    {   211, {   0,   0}},
+    {   209, {   0,   0}},
+    {   213, {   0,   0}},
+    {   214, {   0,   0}},
+    {   218, {   0,   0}},
+    {   217, {   0,   0}},
+    {   219, {   0,   0}},
+    {     2, {   0,   0}},
+    {  -390, { 780,   0}},
+    {   -97, {   0,   0}},
+    {   -56, {   0,   0}},
+    {  -130, {   0,   0}},
+    { 10795, {   0,   0}},
+    {  -163, {   0,   0}},
+    { 10792, {   0,   0}},
+    {  -195, {   0,   0}},
+    {    69, {   0,   0}},
+    {    71, {   0,   0}},
+    {   116, {   0,   0}},
+    {    38, {   0,   0}},
+    {    37, {   0,   0}},
+    {    64, {   0,   0}},
+    {    63, {   0,   0}},
+    {    41, { 776, 769}},
+    {    21, { 776, 769}},
+    {     8, {   0,   0}},
+    {   -30, {   0,   0}},
+    {   -25, {   0,   0}},
+    {   -15, {   0,   0}},
+    {   -22, {   0,   0}},
+    {   -54, {   0,   0}},
+    {   -48, {   0,   0}},
+    {   -60, {   0,   0}},
+    {   -64, {   0,   0}},
+    {    -7, {   0,   0}},
+    {    80, {   0,   0}},
+    {    15, {   0,   0}},
+    {    48, {   0,   0}},
+    {   -34, {1410,   0}},
+    {  7264, {   0,   0}},
+    {    -8, {   0,   0}},
+    { -7726, { 817,   0}},
+    { -7715, { 776,   0}},
+    { -7713, { 778,   0}},
+    { -7712, { 778,   0}},
+    { -7737, { 702,   0}},
+    {   -58, {   0,   0}},
+    { -7723, { 115,   0}},
+    { -7051, { 787,   0}},
+    { -7053, { 787, 768}},
+    { -7055, { 787, 769}},
+    { -7057, { 787, 834}},
+    {  -128, { 953,   0}},
+    {  -136, { 953,   0}},
+    {  -112, { 953,   0}},
+    {  -120, { 953,   0}},
+    {   -64, { 953,   0}},
+    {   -72, { 953,   0}},
+    {   -66, { 953,   0}},
+    { -7170, { 953,   0}},
+    { -7176, { 953,   0}},
+    { -7173, { 834,   0}},
+    { -7174, { 834, 953}},
+    {   -74, {   0,   0}},
+    { -7179, { 953,   0}},
+    { -7173, {   0,   0}},
+    {   -78, { 953,   0}},
+    { -7180, { 953,   0}},
+    { -7190, { 953,   0}},
+    { -7183, { 834,   0}},
+    { -7184, { 834, 953}},
+    {   -86, {   0,   0}},
+    { -7189, { 953,   0}},
+    { -7193, { 776, 768}},
+    { -7194, { 776, 769}},
+    { -7197, { 834,   0}},
+    { -7198, { 776, 834}},
+    {  -100, {   0,   0}},
+    { -7197, { 776, 768}},
+    { -7198, { 776, 769}},
+    { -7203, { 787,   0}},
+    { -7201, { 834,   0}},
+    { -7202, { 776, 834}},
+    {  -112, {   0,   0}},
+    {  -118, { 953,   0}},
+    { -7210, { 953,   0}},
+    { -7206, { 953,   0}},
+    { -7213, { 834,   0}},
+    { -7214, { 834, 953}},
+    {  -128, {   0,   0}},
+    {  -126, {   0,   0}},
+    { -7219, { 953,   0}},
+    { -7517, {   0,   0}},
+    { -8383, {   0,   0}},
+    { -8262, {   0,   0}},
+    {    28, {   0,   0}},
+    {    16, {   0,   0}},
+    {    26, {   0,   0}},
+    {-10743, {   0,   0}},
+    { -3814, {   0,   0}},
+    {-10727, {   0,   0}},
+    {-10780, {   0,   0}},
+    {-10749, {   0,   0}},
+    {-10783, {   0,   0}},
+    {-10782, {   0,   0}},
+    {-10815, {   0,   0}},
+    {-35332, {   0,   0}},
+    {-42280, {   0,   0}},
+    {-42308, {   0,   0}},
+    {-42319, {   0,   0}},
+    {-42315, {   0,   0}},
+    {-42305, {   0,   0}},
+    {-42258, {   0,   0}},
+    {-42282, {   0,   0}},
+    {-42261, {   0,   0}},
+    {   928, {   0,   0}},
+    {-38864, {   0,   0}},
+    {-64154, { 102,   0}},
+    {-64155, { 105,   0}},
+    {-64156, { 108,   0}},
+    {-64157, { 102, 105}},
+    {-64158, { 102, 108}},
+    {-64146, { 116,   0}},
+    {-64147, { 116,   0}},
+    {-62879, {1398,   0}},
+    {-62880, {1381,   0}},
+    {-62881, {1387,   0}},
+    {-62872, {1398,   0}},
+    {-62883, {1389,   0}},
+    {    40, {   0,   0}},
+};
+
+/* Full_Case_Folding: 1168 bytes. */
+
+int re_get_full_case_folding(RE_UINT32 ch, RE_UINT32* codepoints) {
+    RE_UINT32 code;
+    RE_UINT32 f;
+    RE_UINT32 pos;
+    RE_UINT32 value;
+    RE_FullCaseFolding* case_folding;
+    int count;
+
+    f = ch >> 13;
+    code = ch ^ (f << 13);
+    pos = (RE_UINT32)re_full_case_folding_stage_1[f] << 5;
+    f = code >> 8;
+    code ^= f << 8;
+    pos = (RE_UINT32)re_full_case_folding_stage_2[pos + f] << 5;
+    f = code >> 3;
+    code ^= f << 3;
+    pos = (RE_UINT32)re_full_case_folding_stage_3[pos + f] << 3;
+    value = re_full_case_folding_stage_4[pos + code];
+
+    case_folding = &re_full_case_folding_table[value];
+
+    codepoints[0] = (RE_UINT32)((RE_INT32)ch + case_folding->diff);
+    count = 1;
+
+    while (count < RE_MAX_FOLDED && case_folding->codepoints[count - 1] != 0) {
+        codepoints[count] = case_folding->codepoints[count - 1];
+        ++count;
+    }
+
+    return count;
+}
+
+/* Property function table. */
+
+RE_GetPropertyFunc re_get_property[] = {
+    re_get_general_category,
+    re_get_block,
+    re_get_script,
+    re_get_word_break,
+    re_get_grapheme_cluster_break,
+    re_get_sentence_break,
+    re_get_math,
+    re_get_alphabetic,
+    re_get_lowercase,
+    re_get_uppercase,
+    re_get_cased,
+    re_get_case_ignorable,
+    re_get_changes_when_lowercased,
+    re_get_changes_when_uppercased,
+    re_get_changes_when_titlecased,
+    re_get_changes_when_casefolded,
+    re_get_changes_when_casemapped,
+    re_get_id_start,
+    re_get_id_continue,
+    re_get_xid_start,
+    re_get_xid_continue,
+    re_get_default_ignorable_code_point,
+    re_get_grapheme_extend,
+    re_get_grapheme_base,
+    re_get_grapheme_link,
+    re_get_white_space,
+    re_get_bidi_control,
+    re_get_join_control,
+    re_get_dash,
+    re_get_hyphen,
+    re_get_quotation_mark,
+    re_get_terminal_punctuation,
+    re_get_other_math,
+    re_get_hex_digit,
+    re_get_ascii_hex_digit,
+    re_get_other_alphabetic,
+    re_get_ideographic,
+    re_get_diacritic,
+    re_get_extender,
+    re_get_other_lowercase,
+    re_get_other_uppercase,
+    re_get_noncharacter_code_point,
+    re_get_other_grapheme_extend,
+    re_get_ids_binary_operator,
+    re_get_ids_trinary_operator,
+    re_get_radical,
+    re_get_unified_ideograph,
+    re_get_other_default_ignorable_code_point,
+    re_get_deprecated,
+    re_get_soft_dotted,
+    re_get_logical_order_exception,
+    re_get_other_id_start,
+    re_get_other_id_continue,
+    re_get_sterm,
+    re_get_variation_selector,
+    re_get_pattern_white_space,
+    re_get_pattern_syntax,
+    re_get_hangul_syllable_type,
+    re_get_bidi_class,
+    re_get_canonical_combining_class,
+    re_get_decomposition_type,
+    re_get_east_asian_width,
+    re_get_joining_group,
+    re_get_joining_type,
+    re_get_line_break,
+    re_get_numeric_type,
+    re_get_numeric_value,
+    re_get_bidi_mirrored,
+    re_get_indic_positional_category,
+    re_get_indic_syllabic_category,
+    re_get_alphanumeric,
+    re_get_any,
+    re_get_blank,
+    re_get_graph,
+    re_get_print,
+    re_get_word,
+    re_get_xdigit,
+    re_get_posix_digit,
+    re_get_posix_alnum,
+    re_get_posix_punct,
+    re_get_posix_xdigit,
+};
diff --git a/lib/regex/_regex_unicode.h b/lib/regex/_regex_unicode.h
new file mode 100644
index 000000000..0d2fd62db
--- /dev/null
+++ b/lib/regex/_regex_unicode.h
@@ -0,0 +1,226 @@
+typedef unsigned char RE_UINT8;
+typedef signed char RE_INT8;
+typedef unsigned short RE_UINT16;
+typedef signed short RE_INT16;
+typedef unsigned int RE_UINT32;
+typedef signed int RE_INT32;
+
+typedef unsigned char BOOL;
+enum {FALSE, TRUE};
+
+#define RE_ASCII_MAX 0x7F
+#define RE_LOCALE_MAX 0xFF
+#define RE_UNICODE_MAX 0x10FFFF
+
+#define RE_MAX_CASES 4
+#define RE_MAX_FOLDED 3
+
+typedef struct RE_Property {
+    RE_UINT16 name;
+    RE_UINT8 id;
+    RE_UINT8 value_set;
+} RE_Property;
+
+typedef struct RE_PropertyValue {
+    RE_UINT16 name;
+    RE_UINT8 value_set;
+    RE_UINT16 id;
+} RE_PropertyValue;
+
+typedef RE_UINT32 (*RE_GetPropertyFunc)(RE_UINT32 ch);
+
+#define RE_PROP_GC 0x0
+#define RE_PROP_CASED 0xA
+#define RE_PROP_UPPERCASE 0x9
+#define RE_PROP_LOWERCASE 0x8
+
+#define RE_PROP_C 30
+#define RE_PROP_L 31
+#define RE_PROP_M 32
+#define RE_PROP_N 33
+#define RE_PROP_P 34
+#define RE_PROP_S 35
+#define RE_PROP_Z 36
+#define RE_PROP_ASSIGNED 38
+#define RE_PROP_CASEDLETTER 37
+
+#define RE_PROP_CN 0
+#define RE_PROP_LU 1
+#define RE_PROP_LL 2
+#define RE_PROP_LT 3
+#define RE_PROP_LM 4
+#define RE_PROP_LO 5
+#define RE_PROP_MN 6
+#define RE_PROP_ME 7
+#define RE_PROP_MC 8
+#define RE_PROP_ND 9
+#define RE_PROP_NL 10
+#define RE_PROP_NO 11
+#define RE_PROP_ZS 12
+#define RE_PROP_ZL 13
+#define RE_PROP_ZP 14
+#define RE_PROP_CC 15
+#define RE_PROP_CF 16
+#define RE_PROP_CO 17
+#define RE_PROP_CS 18
+#define RE_PROP_PD 19
+#define RE_PROP_PS 20
+#define RE_PROP_PE 21
+#define RE_PROP_PC 22
+#define RE_PROP_PO 23
+#define RE_PROP_SM 24
+#define RE_PROP_SC 25
+#define RE_PROP_SK 26
+#define RE_PROP_SO 27
+#define RE_PROP_PI 28
+#define RE_PROP_PF 29
+
+#define RE_PROP_C_MASK 0x00078001
+#define RE_PROP_L_MASK 0x0000003E
+#define RE_PROP_M_MASK 0x000001C0
+#define RE_PROP_N_MASK 0x00000E00
+#define RE_PROP_P_MASK 0x30F80000
+#define RE_PROP_S_MASK 0x0F000000
+#define RE_PROP_Z_MASK 0x00007000
+
+#define RE_PROP_ALNUM 0x460001
+#define RE_PROP_ALPHA 0x070001
+#define RE_PROP_ANY 0x470001
+#define RE_PROP_ASCII 0x010001
+#define RE_PROP_BLANK 0x480001
+#define RE_PROP_CNTRL 0x00000F
+#define RE_PROP_DIGIT 0x000009
+#define RE_PROP_GRAPH 0x490001
+#define RE_PROP_LOWER 0x080001
+#define RE_PROP_PRINT 0x4A0001
+#define RE_PROP_SPACE 0x190001
+#define RE_PROP_UPPER 0x090001
+#define RE_PROP_WORD 0x4B0001
+#define RE_PROP_XDIGIT 0x4C0001
+#define RE_PROP_POSIX_ALNUM 0x4E0001
+#define RE_PROP_POSIX_DIGIT 0x4D0001
+#define RE_PROP_POSIX_PUNCT 0x4F0001
+#define RE_PROP_POSIX_XDIGIT 0x500001
+
+#define RE_BREAK_OTHER 0
+#define RE_BREAK_DOUBLEQUOTE 1
+#define RE_BREAK_SINGLEQUOTE 2
+#define RE_BREAK_HEBREWLETTER 3
+#define RE_BREAK_CR 4
+#define RE_BREAK_LF 5
+#define RE_BREAK_NEWLINE 6
+#define RE_BREAK_EXTEND 7
+#define RE_BREAK_REGIONALINDICATOR 8
+#define RE_BREAK_FORMAT 9
+#define RE_BREAK_KATAKANA 10
+#define RE_BREAK_ALETTER 11
+#define RE_BREAK_MIDLETTER 12
+#define RE_BREAK_MIDNUM 13
+#define RE_BREAK_MIDNUMLET 14
+#define RE_BREAK_NUMERIC 15
+#define RE_BREAK_EXTENDNUMLET 16
+
+#define RE_GBREAK_OTHER 0
+#define RE_GBREAK_CR 1
+#define RE_GBREAK_LF 2
+#define RE_GBREAK_CONTROL 3
+#define RE_GBREAK_EXTEND 4
+#define RE_GBREAK_REGIONALINDICATOR 5
+#define RE_GBREAK_SPACINGMARK 6
+#define RE_GBREAK_L 7
+#define RE_GBREAK_V 8
+#define RE_GBREAK_T 9
+#define RE_GBREAK_LV 10
+#define RE_GBREAK_LVT 11
+#define RE_GBREAK_PREPEND 12
+
+extern char* re_strings[1296];
+extern RE_Property re_properties[147];
+extern RE_PropertyValue re_property_values[1412];
+extern RE_UINT16 re_expand_on_folding[104];
+extern RE_GetPropertyFunc re_get_property[81];
+
+RE_UINT32 re_get_general_category(RE_UINT32 ch);
+RE_UINT32 re_get_block(RE_UINT32 ch);
+RE_UINT32 re_get_script(RE_UINT32 ch);
+RE_UINT32 re_get_word_break(RE_UINT32 ch);
+RE_UINT32 re_get_grapheme_cluster_break(RE_UINT32 ch);
+RE_UINT32 re_get_sentence_break(RE_UINT32 ch);
+RE_UINT32 re_get_math(RE_UINT32 ch);
+RE_UINT32 re_get_alphabetic(RE_UINT32 ch);
+RE_UINT32 re_get_lowercase(RE_UINT32 ch);
+RE_UINT32 re_get_uppercase(RE_UINT32 ch);
+RE_UINT32 re_get_cased(RE_UINT32 ch);
+RE_UINT32 re_get_case_ignorable(RE_UINT32 ch);
+RE_UINT32 re_get_changes_when_lowercased(RE_UINT32 ch);
+RE_UINT32 re_get_changes_when_uppercased(RE_UINT32 ch);
+RE_UINT32 re_get_changes_when_titlecased(RE_UINT32 ch);
+RE_UINT32 re_get_changes_when_casefolded(RE_UINT32 ch);
+RE_UINT32 re_get_changes_when_casemapped(RE_UINT32 ch);
+RE_UINT32 re_get_id_start(RE_UINT32 ch);
+RE_UINT32 re_get_id_continue(RE_UINT32 ch);
+RE_UINT32 re_get_xid_start(RE_UINT32 ch);
+RE_UINT32 re_get_xid_continue(RE_UINT32 ch);
+RE_UINT32 re_get_default_ignorable_code_point(RE_UINT32 ch);
+RE_UINT32 re_get_grapheme_extend(RE_UINT32 ch);
+RE_UINT32 re_get_grapheme_base(RE_UINT32 ch);
+RE_UINT32 re_get_grapheme_link(RE_UINT32 ch);
+RE_UINT32 re_get_white_space(RE_UINT32 ch);
+RE_UINT32 re_get_bidi_control(RE_UINT32 ch);
+RE_UINT32 re_get_join_control(RE_UINT32 ch);
+RE_UINT32 re_get_dash(RE_UINT32 ch);
+RE_UINT32 re_get_hyphen(RE_UINT32 ch);
+RE_UINT32 re_get_quotation_mark(RE_UINT32 ch);
+RE_UINT32 re_get_terminal_punctuation(RE_UINT32 ch);
+RE_UINT32 re_get_other_math(RE_UINT32 ch);
+RE_UINT32 re_get_hex_digit(RE_UINT32 ch);
+RE_UINT32 re_get_ascii_hex_digit(RE_UINT32 ch);
+RE_UINT32 re_get_other_alphabetic(RE_UINT32 ch);
+RE_UINT32 re_get_ideographic(RE_UINT32 ch);
+RE_UINT32 re_get_diacritic(RE_UINT32 ch);
+RE_UINT32 re_get_extender(RE_UINT32 ch);
+RE_UINT32 re_get_other_lowercase(RE_UINT32 ch);
+RE_UINT32 re_get_other_uppercase(RE_UINT32 ch);
+RE_UINT32 re_get_noncharacter_code_point(RE_UINT32 ch);
+RE_UINT32 re_get_other_grapheme_extend(RE_UINT32 ch);
+RE_UINT32 re_get_ids_binary_operator(RE_UINT32 ch);
+RE_UINT32 re_get_ids_trinary_operator(RE_UINT32 ch);
+RE_UINT32 re_get_radical(RE_UINT32 ch);
+RE_UINT32 re_get_unified_ideograph(RE_UINT32 ch);
+RE_UINT32 re_get_other_default_ignorable_code_point(RE_UINT32 ch);
+RE_UINT32 re_get_deprecated(RE_UINT32 ch);
+RE_UINT32 re_get_soft_dotted(RE_UINT32 ch);
+RE_UINT32 re_get_logical_order_exception(RE_UINT32 ch);
+RE_UINT32 re_get_other_id_start(RE_UINT32 ch);
+RE_UINT32 re_get_other_id_continue(RE_UINT32 ch);
+RE_UINT32 re_get_sterm(RE_UINT32 ch);
+RE_UINT32 re_get_variation_selector(RE_UINT32 ch);
+RE_UINT32 re_get_pattern_white_space(RE_UINT32 ch);
+RE_UINT32 re_get_pattern_syntax(RE_UINT32 ch);
+RE_UINT32 re_get_hangul_syllable_type(RE_UINT32 ch);
+RE_UINT32 re_get_bidi_class(RE_UINT32 ch);
+RE_UINT32 re_get_canonical_combining_class(RE_UINT32 ch);
+RE_UINT32 re_get_decomposition_type(RE_UINT32 ch);
+RE_UINT32 re_get_east_asian_width(RE_UINT32 ch);
+RE_UINT32 re_get_joining_group(RE_UINT32 ch);
+RE_UINT32 re_get_joining_type(RE_UINT32 ch);
+RE_UINT32 re_get_line_break(RE_UINT32 ch);
+RE_UINT32 re_get_numeric_type(RE_UINT32 ch);
+RE_UINT32 re_get_numeric_value(RE_UINT32 ch);
+RE_UINT32 re_get_bidi_mirrored(RE_UINT32 ch);
+RE_UINT32 re_get_indic_positional_category(RE_UINT32 ch);
+RE_UINT32 re_get_indic_syllabic_category(RE_UINT32 ch);
+RE_UINT32 re_get_alphanumeric(RE_UINT32 ch);
+RE_UINT32 re_get_any(RE_UINT32 ch);
+RE_UINT32 re_get_blank(RE_UINT32 ch);
+RE_UINT32 re_get_graph(RE_UINT32 ch);
+RE_UINT32 re_get_print(RE_UINT32 ch);
+RE_UINT32 re_get_word(RE_UINT32 ch);
+RE_UINT32 re_get_xdigit(RE_UINT32 ch);
+RE_UINT32 re_get_posix_digit(RE_UINT32 ch);
+RE_UINT32 re_get_posix_alnum(RE_UINT32 ch);
+RE_UINT32 re_get_posix_punct(RE_UINT32 ch);
+RE_UINT32 re_get_posix_xdigit(RE_UINT32 ch);
+int re_get_all_cases(RE_UINT32 ch, RE_UINT32* codepoints);
+RE_UINT32 re_get_simple_case_folding(RE_UINT32 ch);
+int re_get_full_case_folding(RE_UINT32 ch, RE_UINT32* codepoints);
diff --git a/lib/regex/test_regex.py b/lib/regex/test_regex.py
new file mode 100644
index 000000000..050c3c004
--- /dev/null
+++ b/lib/regex/test_regex.py
@@ -0,0 +1,3585 @@
+from __future__ import with_statement
+import regex
+import string
+from weakref import proxy
+import unittest
+import copy
+from test.test_support import run_unittest
+import re
+
+# _AssertRaisesContext is defined here because the class doesn't exist before
+# Python 2.7.
+class _AssertRaisesContext(object):
+    """A context manager used to implement TestCase.assertRaises* methods."""
+
+    def __init__(self, expected, test_case, expected_regexp=None):
+        self.expected = expected
+        self.failureException = test_case.failureException
+        self.expected_regexp = expected_regexp
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exc_type, exc_value, tb):
+        if exc_type is None:
+            try:
+                exc_name = self.expected.__name__
+            except AttributeError:
+                exc_name = str(self.expected)
+            raise self.failureException(
+                "%s not raised" % exc_name)
+        if not issubclass(exc_type, self.expected):
+            # let unexpected exceptions pass through
+            return False
+        self.exception = exc_value # store for later retrieval
+        if self.expected_regexp is None:
+            return True
+
+        expected_regexp = self.expected_regexp
+        if isinstance(expected_regexp, basestring):
+            expected_regexp = re.compile(expected_regexp)
+        if not expected_regexp.search(str(exc_value)):
+            raise self.failureException('"%s" does not match "%s"' %
+                     (expected_regexp.pattern, str(exc_value)))
+        return True
+
+class RegexTests(unittest.TestCase):
+    PATTERN_CLASS = "<type '_regex.Pattern'>"
+    FLAGS_WITH_COMPILED_PAT = "cannot process flags argument with a compiled pattern"
+    INVALID_GROUP_REF = "invalid group reference"
+    MISSING_GT = "missing >"
+    BAD_GROUP_NAME = "bad character in group name"
+    MISSING_GROUP_NAME = "missing group name"
+    MISSING_LT = "missing <"
+    UNKNOWN_GROUP_I = "unknown group"
+    UNKNOWN_GROUP = "unknown group"
+    BAD_ESCAPE = r"bad escape \(end of pattern\)"
+    BAD_OCTAL_ESCAPE = r"bad escape \\"
+    BAD_SET = "unterminated character set"
+    STR_PAT_ON_BYTES = "cannot use a string pattern on a bytes-like object"
+    BYTES_PAT_ON_STR = "cannot use a bytes pattern on a string-like object"
+    STR_PAT_BYTES_TEMPL = "expected str instance, bytes found"
+    BYTES_PAT_STR_TEMPL = "expected a bytes-like object, str found"
+    BYTES_PAT_UNI_FLAG = "cannot use UNICODE flag with a bytes pattern"
+    MIXED_FLAGS = "ASCII, LOCALE and UNICODE flags are mutually incompatible"
+    MISSING_RPAREN = "missing \\)"
+    TRAILING_CHARS = "unbalanced parenthesis"
+    BAD_CHAR_RANGE = "bad character range"
+    NOTHING_TO_REPEAT = "nothing to repeat"
+    MULTIPLE_REPEAT = "multiple repeat"
+    OPEN_GROUP = "cannot refer to an open group"
+    DUPLICATE_GROUP = "duplicate group"
+    CANT_TURN_OFF = "bad inline flags: cannot turn flags off"
+    UNDEF_CHAR_NAME = "undefined character name"
+
+    # assertRaisesRegex is defined here because the method isn't in the
+    # superclass before Python 2.7.
+    def assertRaisesRegex(self, expected_exception, expected_regexp,
+                           callable_obj=None, *args, **kwargs):
+        """Asserts that the message in a raised exception matches a regexp.
+
+        Args:
+            expected_exception: Exception class expected to be raised.
+            expected_regexp: Regexp (re pattern object or string) expected
+                    to be found in error message.
+            callable_obj: Function to be called.
+            args: Extra args.
+            kwargs: Extra kwargs.
+        """
+        context = _AssertRaisesContext(expected_exception, self, expected_regexp)
+        if callable_obj is None:
+            return context
+        with context:
+            callable_obj(*args, **kwargs)
+
+    def assertTypedEqual(self, actual, expect, msg=None):
+        self.assertEqual(actual, expect, msg)
+
+        def recurse(actual, expect):
+            if isinstance(expect, (tuple, list)):
+                for x, y in zip(actual, expect):
+                    recurse(x, y)
+            else:
+                self.assertIs(type(actual), type(expect), msg)
+
+        recurse(actual, expect)
+
+    def test_weakref(self):
+        s = 'QabbbcR'
+        x = regex.compile('ab+c')
+        y = proxy(x)
+        if x.findall('QabbbcR') != y.findall('QabbbcR'):
+            self.fail()
+
+    def test_search_star_plus(self):
+        self.assertEqual(regex.search('a*', 'xxx').span(0), (0, 0))
+        self.assertEqual(regex.search('x*', 'axx').span(), (0, 0))
+        self.assertEqual(regex.search('x+', 'axx').span(0), (1, 3))
+        self.assertEqual(regex.search('x+', 'axx').span(), (1, 3))
+        self.assertEqual(regex.search('x', 'aaa'), None)
+        self.assertEqual(regex.match('a*', 'xxx').span(0), (0, 0))
+        self.assertEqual(regex.match('a*', 'xxx').span(), (0, 0))
+        self.assertEqual(regex.match('x*', 'xxxa').span(0), (0, 3))
+        self.assertEqual(regex.match('x*', 'xxxa').span(), (0, 3))
+        self.assertEqual(regex.match('a+', 'xxx'), None)
+
+    def bump_num(self, matchobj):
+        int_value = int(matchobj[0])
+        return str(int_value + 1)
+
+    def test_basic_regex_sub(self):
+        self.assertEqual(regex.sub("(?i)b+", "x", "bbbb BBBB"), 'x x')
+        self.assertEqual(regex.sub(r'\d+', self.bump_num, '08.2 -2 23x99y'),
+          '9.3 -3 24x100y')
+        self.assertEqual(regex.sub(r'\d+', self.bump_num, '08.2 -2 23x99y', 3),
+          '9.3 -3 23x99y')
+
+        self.assertEqual(regex.sub('.', lambda m: r"\n", 'x'), "\\n")
+        self.assertEqual(regex.sub('.', r"\n", 'x'), "\n")
+
+        self.assertEqual(regex.sub('(?P<a>x)', r'\g<a>\g<a>', 'xx'), 'xxxx')
+        self.assertEqual(regex.sub('(?P<a>x)', r'\g<a>\g<1>', 'xx'), 'xxxx')
+        self.assertEqual(regex.sub('(?P<unk>x)', r'\g<unk>\g<unk>', 'xx'),
+          'xxxx')
+        self.assertEqual(regex.sub('(?P<unk>x)', r'\g<1>\g<1>', 'xx'), 'xxxx')
+
+        self.assertEqual(regex.sub('a', r'\t\n\v\r\f\a\b\B\Z\a\A\w\W\s\S\d\D',
+          'a'), "\t\n\v\r\f\a\b\\B\\Z\a\\A\\w\\W\\s\\S\\d\\D")
+        self.assertEqual(regex.sub('a', '\t\n\v\r\f\a', 'a'), "\t\n\v\r\f\a")
+        self.assertEqual(regex.sub('a', '\t\n\v\r\f\a', 'a'), chr(9) + chr(10)
+          + chr(11) + chr(13) + chr(12) + chr(7))
+
+        self.assertEqual(regex.sub(r'^\s*', 'X', 'test'), 'Xtest')
+
+        self.assertEqual(regex.sub(ur"x", ur"\x0A", u"x"), u"\n")
+        self.assertEqual(regex.sub(ur"x", ur"\u000A", u"x"), u"\n")
+        self.assertEqual(regex.sub(ur"x", ur"\U0000000A", u"x"), u"\n")
+        self.assertEqual(regex.sub(ur"x", ur"\N{LATIN CAPITAL LETTER A}",
+          u"x"), u"A")
+
+        self.assertEqual(regex.sub(r"x", r"\x0A", "x"), "\n")
+        self.assertEqual(regex.sub(r"x", r"\u000A", "x"), "\\u000A")
+        self.assertEqual(regex.sub(r"x", r"\U0000000A", "x"),
+          "\\U0000000A")
+        self.assertEqual(regex.sub(r"x", r"\N{LATIN CAPITAL LETTER A}",
+          "x"), "\\N{LATIN CAPITAL LETTER A}")
+
+    def test_bug_449964(self):
+        # Fails for group followed by other escape.
+        self.assertEqual(regex.sub(r'(?P<unk>x)', r'\g<1>\g<1>\b', 'xx'),
+          "xx\bxx\b")
+
+    def test_bug_449000(self):
+        # Test for sub() on escaped characters.
+        self.assertEqual(regex.sub(r'\r\n', r'\n', 'abc\r\ndef\r\n'),
+          "abc\ndef\n")
+        self.assertEqual(regex.sub('\r\n', r'\n', 'abc\r\ndef\r\n'),
+          "abc\ndef\n")
+        self.assertEqual(regex.sub(r'\r\n', '\n', 'abc\r\ndef\r\n'),
+          "abc\ndef\n")
+        self.assertEqual(regex.sub('\r\n', '\n', 'abc\r\ndef\r\n'),
+          "abc\ndef\n")
+
+    def test_bug_1140(self):
+        # regex.sub(x, y, u'') should return u'', not '', and
+        # regex.sub(x, y, '') should return '', not u''.
+        # Also:
+        # regex.sub(x, y, unicode(x)) should return unicode(y), and
+        # regex.sub(x, y, str(x)) should return
+        #     str(y) if isinstance(y, str) else unicode(y).
+        for x in 'x', u'x':
+            for y in 'y', u'y':
+                z = regex.sub(x, y, u'')
+                self.assertEqual((type(z), z), (unicode, u''))
+                z = regex.sub(x, y, '')
+                self.assertEqual((type(z), z), (str, ''))
+                z = regex.sub(x, y, unicode(x))
+                self.assertEqual((type(z), z), (unicode, unicode(y)))
+                z = regex.sub(x, y, str(x))
+                self.assertEqual((type(z), z), (type(y), y))
+
+    def test_bug_1661(self):
+        # Verify that flags do not get silently ignored with compiled patterns
+        pattern = regex.compile('.')
+        self.assertRaisesRegex(ValueError, self.FLAGS_WITH_COMPILED_PAT,
+          lambda: regex.match(pattern, 'A', regex.I))
+        self.assertRaisesRegex(ValueError, self.FLAGS_WITH_COMPILED_PAT,
+          lambda: regex.search(pattern, 'A', regex.I))
+        self.assertRaisesRegex(ValueError, self.FLAGS_WITH_COMPILED_PAT,
+          lambda: regex.findall(pattern, 'A', regex.I))
+        self.assertRaisesRegex(ValueError, self.FLAGS_WITH_COMPILED_PAT,
+          lambda: regex.compile(pattern, regex.I))
+
+    def test_bug_3629(self):
+        # A regex that triggered a bug in the sre-code validator
+        self.assertEqual(repr(type(regex.compile("(?P<quote>)(?(quote))"))),
+          self.PATTERN_CLASS)
+
+    def test_sub_template_numeric_escape(self):
+        # Bug 776311 and friends.
+        self.assertEqual(regex.sub('x', r'\0', 'x'), "\0")
+        self.assertEqual(regex.sub('x', r'\000', 'x'), "\000")
+        self.assertEqual(regex.sub('x', r'\001', 'x'), "\001")
+        self.assertEqual(regex.sub('x', r'\008', 'x'), "\0" + "8")
+        self.assertEqual(regex.sub('x', r'\009', 'x'), "\0" + "9")
+        self.assertEqual(regex.sub('x', r'\111', 'x'), "\111")
+        self.assertEqual(regex.sub('x', r'\117', 'x'), "\117")
+
+        self.assertEqual(regex.sub('x', r'\1111', 'x'), "\1111")
+        self.assertEqual(regex.sub('x', r'\1111', 'x'), "\111" + "1")
+
+        self.assertEqual(regex.sub('x', r'\00', 'x'), '\x00')
+        self.assertEqual(regex.sub('x', r'\07', 'x'), '\x07')
+        self.assertEqual(regex.sub('x', r'\08', 'x'), "\0" + "8")
+        self.assertEqual(regex.sub('x', r'\09', 'x'), "\0" + "9")
+        self.assertEqual(regex.sub('x', r'\0a', 'x'), "\0" + "a")
+
+        self.assertEqual(regex.sub(u'x', ur'\400', u'x'), u"\u0100")
+        self.assertEqual(regex.sub(u'x', ur'\777', u'x'), u"\u01FF")
+        self.assertEqual(regex.sub('x', r'\400', 'x'), "\x00")
+        self.assertEqual(regex.sub('x', r'\777', 'x'), "\xFF")
+
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\1', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\8', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\9', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\11', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\18', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\1a', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\90', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\99', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\118', 'x')) # r'\11' + '8'
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\11a', 'x'))
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\181', 'x')) # r'\18' + '1'
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.sub('x', r'\800', 'x')) # r'\80' + '0'
+
+        # In Python 2.3 (etc), these loop endlessly in sre_parser.py.
+        self.assertEqual(regex.sub('(((((((((((x)))))))))))', r'\11', 'x'),
+          'x')
+        self.assertEqual(regex.sub('((((((((((y))))))))))(.)', r'\118', 'xyz'),
+          'xz8')
+        self.assertEqual(regex.sub('((((((((((y))))))))))(.)', r'\11a', 'xyz'),
+          'xza')
+
+    def test_qualified_re_sub(self):
+        self.assertEqual(regex.sub('a', 'b', 'aaaaa'), 'bbbbb')
+        self.assertEqual(regex.sub('a', 'b', 'aaaaa', 1), 'baaaa')
+
+    def test_bug_114660(self):
+        self.assertEqual(regex.sub(r'(\S)\s+(\S)', r'\1 \2', 'hello  there'),
+          'hello there')
+
+    def test_bug_462270(self):
+        # Test for empty sub() behaviour, see SF bug #462270
+        self.assertEqual(regex.sub('(?V0)x*', '-', 'abxd'), '-a-b-d-')
+        self.assertEqual(regex.sub('(?V1)x*', '-', 'abxd'), '-a-b--d-')
+        self.assertEqual(regex.sub('x+', '-', 'abxd'), 'ab-d')
+
+    def test_bug_14462(self):
+        # chr(255) is not a valid identifier in Python 2.
+        group_name = u'\xFF'
+        self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda:
+          regex.search(ur'(?P<' + group_name + '>a)', u'a'))
+
+    def test_symbolic_refs(self):
+        self.assertRaisesRegex(regex.error, self.MISSING_GT, lambda:
+          regex.sub('(?P<a>x)', r'\g<a', 'xx'))
+        self.assertRaisesRegex(regex.error, self.MISSING_GROUP_NAME, lambda:
+          regex.sub('(?P<a>x)', r'\g<', 'xx'))
+        self.assertRaisesRegex(regex.error, self.MISSING_LT, lambda:
+          regex.sub('(?P<a>x)', r'\g', 'xx'))
+        self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda:
+          regex.sub('(?P<a>x)', r'\g<a a>', 'xx'))
+        self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda:
+          regex.sub('(?P<a>x)', r'\g<1a1>', 'xx'))
+        self.assertRaisesRegex(IndexError, self.UNKNOWN_GROUP_I, lambda:
+          regex.sub('(?P<a>x)', r'\g<ab>', 'xx'))
+
+        # The new behaviour of unmatched but valid groups is to treat them like
+        # empty matches in the replacement template, like in Perl.
+        self.assertEqual(regex.sub('(?P<a>x)|(?P<b>y)', r'\g<b>', 'xx'), '')
+        self.assertEqual(regex.sub('(?P<a>x)|(?P<b>y)', r'\2', 'xx'), '')
+
+        # The old behaviour was to raise it as an IndexError.
+        self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda:
+          regex.sub('(?P<a>x)', r'\g<-1>', 'xx'))
+
+    def test_re_subn(self):
+        self.assertEqual(regex.subn("(?i)b+", "x", "bbbb BBBB"), ('x x', 2))
+        self.assertEqual(regex.subn("b+", "x", "bbbb BBBB"), ('x BBBB', 1))
+        self.assertEqual(regex.subn("b+", "x", "xyz"), ('xyz', 0))
+        self.assertEqual(regex.subn("b*", "x", "xyz"), ('xxxyxzx', 4))
+        self.assertEqual(regex.subn("b*", "x", "xyz", 2), ('xxxyz', 2))
+
+    def test_re_split(self):
+        self.assertEqual(regex.split(":", ":a:b::c"), ['', 'a', 'b', '', 'c'])
+        self.assertEqual(regex.split(":*", ":a:b::c"), ['', 'a', 'b', 'c'])
+        self.assertEqual(regex.split("(:*)", ":a:b::c"), ['', ':', 'a', ':',
+          'b', '::', 'c'])
+        self.assertEqual(regex.split("(?::*)", ":a:b::c"), ['', 'a', 'b', 'c'])
+        self.assertEqual(regex.split("(:)*", ":a:b::c"), ['', ':', 'a', ':',
+          'b', ':', 'c'])
+        self.assertEqual(regex.split("([b:]+)", ":a:b::c"), ['', ':', 'a',
+          ':b::', 'c'])
+        self.assertEqual(regex.split("(b)|(:+)", ":a:b::c"), ['', None, ':',
+          'a', None, ':', '', 'b', None, '', None, '::', 'c'])
+        self.assertEqual(regex.split("(?:b)|(?::+)", ":a:b::c"), ['', 'a', '',
+          '', 'c'])
+
+        self.assertEqual(regex.split("x", "xaxbxc"), ['', 'a', 'b', 'c'])
+        self.assertEqual([m for m in regex.splititer("x", "xaxbxc")], ['', 'a',
+          'b', 'c'])
+
+        self.assertEqual(regex.split("(?r)x", "xaxbxc"), ['c', 'b', 'a', ''])
+        self.assertEqual([m for m in regex.splititer("(?r)x", "xaxbxc")], ['c',
+          'b', 'a', ''])
+
+        self.assertEqual(regex.split("(x)|(y)", "xaxbxc"), ['', 'x', None, 'a',
+          'x', None, 'b', 'x', None, 'c'])
+        self.assertEqual([m for m in regex.splititer("(x)|(y)", "xaxbxc")],
+          ['', 'x', None, 'a', 'x', None, 'b', 'x', None, 'c'])
+
+        self.assertEqual(regex.split("(?r)(x)|(y)", "xaxbxc"), ['c', 'x', None,
+          'b', 'x', None, 'a', 'x', None, ''])
+        self.assertEqual([m for m in regex.splititer("(?r)(x)|(y)", "xaxbxc")],
+          ['c', 'x', None, 'b', 'x', None, 'a', 'x', None, ''])
+
+        self.assertEqual(regex.split(r"(?V1)\b", "a b c"), ['', 'a', ' ', 'b',
+          ' ', 'c', ''])
+        self.assertEqual(regex.split(r"(?V1)\m", "a b c"), ['', 'a ', 'b ',
+          'c'])
+        self.assertEqual(regex.split(r"(?V1)\M", "a b c"), ['a', ' b', ' c',
+          ''])
+
+    def test_qualified_re_split(self):
+        self.assertEqual(regex.split(":", ":a:b::c", 2), ['', 'a', 'b::c'])
+        self.assertEqual(regex.split(':', 'a:b:c:d', 2), ['a', 'b', 'c:d'])
+        self.assertEqual(regex.split("(:)", ":a:b::c", 2), ['', ':', 'a', ':',
+          'b::c'])
+        self.assertEqual(regex.split("(:*)", ":a:b::c", 2), ['', ':', 'a', ':',
+          'b::c'])
+
+    def test_re_findall(self):
+        self.assertEqual(regex.findall(":+", "abc"), [])
+        self.assertEqual(regex.findall(":+", "a:b::c:::d"), [':', '::', ':::'])
+        self.assertEqual(regex.findall("(:+)", "a:b::c:::d"), [':', '::',
+          ':::'])
+        self.assertEqual(regex.findall("(:)(:*)", "a:b::c:::d"), [(':', ''),
+          (':', ':'), (':', '::')])
+
+        self.assertEqual(regex.findall(r"\((?P<test>.{0,5}?TEST)\)",
+          "(MY TEST)"), ["MY TEST"])
+        self.assertEqual(regex.findall(r"\((?P<test>.{0,3}?TEST)\)",
+          "(MY TEST)"), ["MY TEST"])
+        self.assertEqual(regex.findall(r"\((?P<test>.{0,3}?T)\)", "(MY T)"),
+          ["MY T"])
+
+        self.assertEqual(regex.findall(r"[^a]{2}[A-Z]", "\n  S"), ['  S'])
+        self.assertEqual(regex.findall(r"[^a]{2,3}[A-Z]", "\n  S"), ['\n  S'])
+        self.assertEqual(regex.findall(r"[^a]{2,3}[A-Z]", "\n   S"), ['   S'])
+
+        self.assertEqual(regex.findall(r"X(Y[^Y]+?){1,2}( |Q)+DEF",
+          "XYABCYPPQ\nQ DEF"), [('YPPQ\n', ' ')])
+
+        self.assertEqual(regex.findall(r"(\nTest(\n+.+?){0,2}?)?\n+End",
+          "\nTest\nxyz\nxyz\nEnd"), [('\nTest\nxyz\nxyz', '\nxyz')])
+
+    def test_bug_117612(self):
+        self.assertEqual(regex.findall(r"(a|(b))", "aba"), [('a', ''), ('b',
+          'b'), ('a', '')])
+
+    def test_re_match(self):
+        self.assertEqual(regex.match('a', 'a')[:], ('a',))
+        self.assertEqual(regex.match('(a)', 'a')[:], ('a', 'a'))
+        self.assertEqual(regex.match(r'(a)', 'a')[0], 'a')
+        self.assertEqual(regex.match(r'(a)', 'a')[1], 'a')
+        self.assertEqual(regex.match(r'(a)', 'a').group(1, 1), ('a', 'a'))
+
+        pat = regex.compile('((a)|(b))(c)?')
+        self.assertEqual(pat.match('a')[:], ('a', 'a', 'a', None, None))
+        self.assertEqual(pat.match('b')[:], ('b', 'b', None, 'b', None))
+        self.assertEqual(pat.match('ac')[:], ('ac', 'a', 'a', None, 'c'))
+        self.assertEqual(pat.match('bc')[:], ('bc', 'b', None, 'b', 'c'))
+        self.assertEqual(pat.match('bc')[:], ('bc', 'b', None, 'b', 'c'))
+
+        # A single group.
+        m = regex.match('(a)', 'a')
+        self.assertEqual(m.group(), 'a')
+        self.assertEqual(m.group(0), 'a')
+        self.assertEqual(m.group(1), 'a')
+        self.assertEqual(m.group(1, 1), ('a', 'a'))
+
+        pat = regex.compile('(?:(?P<a1>a)|(?P<b2>b))(?P<c3>c)?')
+        self.assertEqual(pat.match('a').group(1, 2, 3), ('a', None, None))
+        self.assertEqual(pat.match('b').group('a1', 'b2', 'c3'), (None, 'b',
+          None))
+        self.assertEqual(pat.match('ac').group(1, 'b2', 3), ('a', None, 'c'))
+
+    def test_re_groupref_exists(self):
+        self.assertEqual(regex.match(r'^(\()?([^()]+)(?(1)\))$', '(a)')[:],
+          ('(a)', '(', 'a'))
+        self.assertEqual(regex.match(r'^(\()?([^()]+)(?(1)\))$', 'a')[:], ('a',
+          None, 'a'))
+        self.assertEqual(regex.match(r'^(\()?([^()]+)(?(1)\))$', 'a)'), None)
+        self.assertEqual(regex.match(r'^(\()?([^()]+)(?(1)\))$', '(a'), None)
+        self.assertEqual(regex.match('^(?:(a)|c)((?(1)b|d))$', 'ab')[:], ('ab',
+          'a', 'b'))
+        self.assertEqual(regex.match('^(?:(a)|c)((?(1)b|d))$', 'cd')[:], ('cd',
+          None, 'd'))
+        self.assertEqual(regex.match('^(?:(a)|c)((?(1)|d))$', 'cd')[:], ('cd',
+          None, 'd'))
+        self.assertEqual(regex.match('^(?:(a)|c)((?(1)|d))$', 'a')[:], ('a',
+          'a', ''))
+
+        # Tests for bug #1177831: exercise groups other than the first group.
+        p = regex.compile('(?P<g1>a)(?P<g2>b)?((?(g2)c|d))')
+        self.assertEqual(p.match('abc')[:], ('abc', 'a', 'b', 'c'))
+        self.assertEqual(p.match('ad')[:], ('ad', 'a', None, 'd'))
+        self.assertEqual(p.match('abd'), None)
+        self.assertEqual(p.match('ac'), None)
+
+    def test_re_groupref(self):
+        self.assertEqual(regex.match(r'^(\|)?([^()]+)\1$', '|a|')[:], ('|a|',
+          '|', 'a'))
+        self.assertEqual(regex.match(r'^(\|)?([^()]+)\1?$', 'a')[:], ('a',
+          None, 'a'))
+        self.assertEqual(regex.match(r'^(\|)?([^()]+)\1$', 'a|'), None)
+        self.assertEqual(regex.match(r'^(\|)?([^()]+)\1$', '|a'), None)
+        self.assertEqual(regex.match(r'^(?:(a)|c)(\1)$', 'aa')[:], ('aa', 'a',
+          'a'))
+        self.assertEqual(regex.match(r'^(?:(a)|c)(\1)?$', 'c')[:], ('c', None,
+          None))
+
+        self.assertEqual(regex.findall("(?i)(.{1,40}?),(.{1,40}?)(?:;)+(.{1,80}).{1,40}?\\3(\ |;)+(.{1,80}?)\\1",
+          "TEST, BEST; LEST ; Lest 123 Test, Best"), [('TEST', ' BEST',
+          ' LEST', ' ', '123 ')])
+
+    def test_groupdict(self):
+        self.assertEqual(regex.match('(?P<first>first) (?P<second>second)',
+          'first second').groupdict(), {'first': 'first', 'second': 'second'})
+
+    def test_expand(self):
+        self.assertEqual(regex.match("(?P<first>first) (?P<second>second)",
+          "first second").expand(r"\2 \1 \g<second> \g<first>"),
+          'second first second first')
+
+    def test_repeat_minmax(self):
+        self.assertEqual(regex.match(r"^(\w){1}$", "abc"), None)
+        self.assertEqual(regex.match(r"^(\w){1}?$", "abc"), None)
+        self.assertEqual(regex.match(r"^(\w){1,2}$", "abc"), None)
+        self.assertEqual(regex.match(r"^(\w){1,2}?$", "abc"), None)
+
+        self.assertEqual(regex.match(r"^(\w){3}$", "abc")[1], 'c')
+        self.assertEqual(regex.match(r"^(\w){1,3}$", "abc")[1], 'c')
+        self.assertEqual(regex.match(r"^(\w){1,4}$", "abc")[1], 'c')
+        self.assertEqual(regex.match(r"^(\w){3,4}?$", "abc")[1], 'c')
+        self.assertEqual(regex.match(r"^(\w){3}?$", "abc")[1], 'c')
+        self.assertEqual(regex.match(r"^(\w){1,3}?$", "abc")[1], 'c')
+        self.assertEqual(regex.match(r"^(\w){1,4}?$", "abc")[1], 'c')
+        self.assertEqual(regex.match(r"^(\w){3,4}?$", "abc")[1], 'c')
+
+        self.assertEqual(regex.match("^x{1}$", "xxx"), None)
+        self.assertEqual(regex.match("^x{1}?$", "xxx"), None)
+        self.assertEqual(regex.match("^x{1,2}$", "xxx"), None)
+        self.assertEqual(regex.match("^x{1,2}?$", "xxx"), None)
+
+        self.assertEqual(regex.match("^x{1}", "xxx")[0], 'x')
+        self.assertEqual(regex.match("^x{1}?", "xxx")[0], 'x')
+        self.assertEqual(regex.match("^x{0,1}", "xxx")[0], 'x')
+        self.assertEqual(regex.match("^x{0,1}?", "xxx")[0], '')
+
+        self.assertEqual(bool(regex.match("^x{3}$", "xxx")), True)
+        self.assertEqual(bool(regex.match("^x{1,3}$", "xxx")), True)
+        self.assertEqual(bool(regex.match("^x{1,4}$", "xxx")), True)
+        self.assertEqual(bool(regex.match("^x{3,4}?$", "xxx")), True)
+        self.assertEqual(bool(regex.match("^x{3}?$", "xxx")), True)
+        self.assertEqual(bool(regex.match("^x{1,3}?$", "xxx")), True)
+        self.assertEqual(bool(regex.match("^x{1,4}?$", "xxx")), True)
+        self.assertEqual(bool(regex.match("^x{3,4}?$", "xxx")), True)
+
+        self.assertEqual(regex.match("^x{}$", "xxx"), None)
+        self.assertEqual(bool(regex.match("^x{}$", "x{}")), True)
+
+    def test_getattr(self):
+        self.assertEqual(regex.compile("(?i)(a)(b)").pattern, '(?i)(a)(b)')
+        self.assertEqual(regex.compile("(?i)(a)(b)").flags, regex.A | regex.I |
+          regex.DEFAULT_VERSION)
+        self.assertEqual(regex.compile(u"(?i)(a)(b)").flags, regex.I | regex.U
+          | regex.DEFAULT_VERSION)
+        self.assertEqual(regex.compile("(?i)(a)(b)").groups, 2)
+        self.assertEqual(regex.compile("(?i)(a)(b)").groupindex, {})
+
+        self.assertEqual(regex.compile("(?i)(?P<first>a)(?P<other>b)").groupindex,
+          {'first': 1, 'other': 2})
+
+        self.assertEqual(regex.match("(a)", "a").pos, 0)
+        self.assertEqual(regex.match("(a)", "a").endpos, 1)
+
+        self.assertEqual(regex.search("b(c)", "abcdef").pos, 0)
+        self.assertEqual(regex.search("b(c)", "abcdef").endpos, 6)
+        self.assertEqual(regex.search("b(c)", "abcdef").span(), (1, 3))
+        self.assertEqual(regex.search("b(c)", "abcdef").span(1), (2, 3))
+
+        self.assertEqual(regex.match("(a)", "a").string, 'a')
+        self.assertEqual(regex.match("(a)", "a").regs, ((0, 1), (0, 1)))
+        self.assertEqual(repr(type(regex.match("(a)", "a").re)),
+          self.PATTERN_CLASS)
+
+        # Issue 14260.
+        p = regex.compile(r'abc(?P<n>def)')
+        p.groupindex["n"] = 0
+        self.assertEqual(p.groupindex["n"], 1)
+
+    def test_special_escapes(self):
+        self.assertEqual(regex.search(r"\b(b.)\b", "abcd abc bcd bx")[1], 'bx')
+        self.assertEqual(regex.search(r"\B(b.)\B", "abc bcd bc abxd")[1], 'bx')
+        self.assertEqual(regex.search(r"\b(b.)\b", "abcd abc bcd bx",
+          regex.LOCALE)[1], 'bx')
+        self.assertEqual(regex.search(r"\B(b.)\B", "abc bcd bc abxd",
+          regex.LOCALE)[1], 'bx')
+        self.assertEqual(regex.search(ur"\b(b.)\b", u"abcd abc bcd bx",
+          regex.UNICODE)[1], u'bx')
+        self.assertEqual(regex.search(ur"\B(b.)\B", u"abc bcd bc abxd",
+          regex.UNICODE)[1], u'bx')
+
+        self.assertEqual(regex.search(r"^abc$", "\nabc\n", regex.M)[0], 'abc')
+        self.assertEqual(regex.search(r"^\Aabc\Z$", "abc", regex.M)[0], 'abc')
+        self.assertEqual(regex.search(r"^\Aabc\Z$", "\nabc\n", regex.M), None)
+
+        self.assertEqual(regex.search(ur"\b(b.)\b", u"abcd abc bcd bx")[1],
+          u'bx')
+        self.assertEqual(regex.search(ur"\B(b.)\B", u"abc bcd bc abxd")[1],
+          u'bx')
+        self.assertEqual(regex.search(ur"^abc$", u"\nabc\n", regex.M)[0],
+          u'abc')
+        self.assertEqual(regex.search(ur"^\Aabc\Z$", u"abc", regex.M)[0],
+          u'abc')
+        self.assertEqual(regex.search(ur"^\Aabc\Z$", u"\nabc\n", regex.M),
+          None)
+
+        self.assertEqual(regex.search(r"\d\D\w\W\s\S", "1aa! a")[0], '1aa! a')
+        self.assertEqual(regex.search(r"\d\D\w\W\s\S", "1aa! a",
+          regex.LOCALE)[0], '1aa! a')
+        self.assertEqual(regex.search(ur"\d\D\w\W\s\S", u"1aa! a",
+          regex.UNICODE)[0], u'1aa! a')
+
+    def test_bigcharset(self):
+        self.assertEqual(regex.match(ur"(?u)([\u2222\u2223])", u"\u2222")[1],
+          u'\u2222')
+        self.assertEqual(regex.match(ur"(?u)([\u2222\u2223])", u"\u2222",
+          regex.UNICODE)[1], u'\u2222')
+        self.assertEqual(u"".join(regex.findall(u".",
+          u"e\xe8\xe9\xea\xeb\u0113\u011b\u0117", flags=regex.UNICODE)),
+          u'e\xe8\xe9\xea\xeb\u0113\u011b\u0117')
+        self.assertEqual(u"".join(regex.findall(ur"[e\xe8\xe9\xea\xeb\u0113\u011b\u0117]",
+          u"e\xe8\xe9\xea\xeb\u0113\u011b\u0117", flags=regex.UNICODE)),
+          u'e\xe8\xe9\xea\xeb\u0113\u011b\u0117')
+        self.assertEqual(u"".join(regex.findall(ur"e|\xe8|\xe9|\xea|\xeb|\u0113|\u011b|\u0117",
+          u"e\xe8\xe9\xea\xeb\u0113\u011b\u0117", flags=regex.UNICODE)),
+          u'e\xe8\xe9\xea\xeb\u0113\u011b\u0117')
+
+    def test_anyall(self):
+        self.assertEqual(regex.match("a.b", "a\nb", regex.DOTALL)[0], "a\nb")
+        self.assertEqual(regex.match("a.*b", "a\n\nb", regex.DOTALL)[0],
+          "a\n\nb")
+
+    def test_non_consuming(self):
+        self.assertEqual(regex.match(r"(a(?=\s[^a]))", "a b")[1], 'a')
+        self.assertEqual(regex.match(r"(a(?=\s[^a]*))", "a b")[1], 'a')
+        self.assertEqual(regex.match(r"(a(?=\s[abc]))", "a b")[1], 'a')
+        self.assertEqual(regex.match(r"(a(?=\s[abc]*))", "a bc")[1], 'a')
+        self.assertEqual(regex.match(r"(a)(?=\s\1)", "a a")[1], 'a')
+        self.assertEqual(regex.match(r"(a)(?=\s\1*)", "a aa")[1], 'a')
+        self.assertEqual(regex.match(r"(a)(?=\s(abc|a))", "a a")[1], 'a')
+
+        self.assertEqual(regex.match(r"(a(?!\s[^a]))", "a a")[1], 'a')
+        self.assertEqual(regex.match(r"(a(?!\s[abc]))", "a d")[1], 'a')
+        self.assertEqual(regex.match(r"(a)(?!\s\1)", "a b")[1], 'a')
+        self.assertEqual(regex.match(r"(a)(?!\s(abc|a))", "a b")[1], 'a')
+
+    def test_ignore_case(self):
+        self.assertEqual(regex.match("abc", "ABC", regex.I)[0], 'ABC')
+        self.assertEqual(regex.match(u"abc", u"ABC", regex.I)[0], u'ABC')
+
+        self.assertEqual(regex.match(r"(a\s[^a]*)", "a bb", regex.I)[1],
+          'a bb')
+        self.assertEqual(regex.match(r"(a\s[abc])", "a b", regex.I)[1], 'a b')
+        self.assertEqual(regex.match(r"(a\s[abc]*)", "a bb", regex.I)[1],
+          'a bb')
+        self.assertEqual(regex.match(r"((a)\s\2)", "a a", regex.I)[1], 'a a')
+        self.assertEqual(regex.match(r"((a)\s\2*)", "a aa", regex.I)[1],
+          'a aa')
+        self.assertEqual(regex.match(r"((a)\s(abc|a))", "a a", regex.I)[1],
+          'a a')
+        self.assertEqual(regex.match(r"((a)\s(abc|a)*)", "a aa", regex.I)[1],
+          'a aa')
+
+        # Issue 3511.
+        self.assertEqual(regex.match(r"[Z-a]", "_").span(), (0, 1))
+        self.assertEqual(regex.match(r"(?i)[Z-a]", "_").span(), (0, 1))
+
+        self.assertEqual(bool(regex.match(ur"(?iu)nao", u"nAo")), True)
+        self.assertEqual(bool(regex.match(ur"(?iu)n\xE3o", u"n\xC3o")), True)
+        self.assertEqual(bool(regex.match(ur"(?iu)n\xE3o", u"N\xC3O")), True)
+        self.assertEqual(bool(regex.match(ur"(?iu)s", u"\u017F")), True)
+
+    def test_case_folding(self):
+        self.assertEqual(regex.search(ur"(?fiu)ss", u"SS").span(), (0, 2))
+        self.assertEqual(regex.search(ur"(?fiu)SS", u"ss").span(), (0, 2))
+        self.assertEqual(regex.search(ur"(?fiu)SS",
+          u"\N{LATIN SMALL LETTER SHARP S}").span(), (0, 1))
+        self.assertEqual(regex.search(ur"(?fi)\N{LATIN SMALL LETTER SHARP S}",
+          u"SS").span(), (0, 2))
+
+        self.assertEqual(regex.search(ur"(?fiu)\N{LATIN SMALL LIGATURE ST}",
+          u"ST").span(), (0, 2))
+        self.assertEqual(regex.search(ur"(?fiu)ST",
+          u"\N{LATIN SMALL LIGATURE ST}").span(), (0, 1))
+        self.assertEqual(regex.search(ur"(?fiu)ST",
+          u"\N{LATIN SMALL LIGATURE LONG S T}").span(), (0, 1))
+
+        self.assertEqual(regex.search(ur"(?fiu)SST",
+          u"\N{LATIN SMALL LETTER SHARP S}t").span(), (0, 2))
+        self.assertEqual(regex.search(ur"(?fiu)SST",
+          u"s\N{LATIN SMALL LIGATURE LONG S T}").span(), (0, 2))
+        self.assertEqual(regex.search(ur"(?fiu)SST",
+          u"s\N{LATIN SMALL LIGATURE ST}").span(), (0, 2))
+        self.assertEqual(regex.search(ur"(?fiu)\N{LATIN SMALL LIGATURE ST}",
+          u"SST").span(), (1, 3))
+        self.assertEqual(regex.search(ur"(?fiu)SST",
+          u"s\N{LATIN SMALL LIGATURE ST}").span(), (0, 2))
+
+        self.assertEqual(regex.search(ur"(?fiu)FFI",
+          u"\N{LATIN SMALL LIGATURE FFI}").span(), (0, 1))
+        self.assertEqual(regex.search(ur"(?fiu)FFI",
+          u"\N{LATIN SMALL LIGATURE FF}i").span(), (0, 2))
+        self.assertEqual(regex.search(ur"(?fiu)FFI",
+          u"f\N{LATIN SMALL LIGATURE FI}").span(), (0, 2))
+        self.assertEqual(regex.search(ur"(?fiu)\N{LATIN SMALL LIGATURE FFI}",
+          u"FFI").span(), (0, 3))
+        self.assertEqual(regex.search(ur"(?fiu)\N{LATIN SMALL LIGATURE FF}i",
+          u"FFI").span(), (0, 3))
+        self.assertEqual(regex.search(ur"(?fiu)f\N{LATIN SMALL LIGATURE FI}",
+          u"FFI").span(), (0, 3))
+
+        sigma = u"\u03A3\u03C3\u03C2"
+        for ch1 in sigma:
+            for ch2 in sigma:
+                if not regex.match(ur"(?fiu)" + ch1, ch2):
+                    self.fail()
+
+        self.assertEqual(bool(regex.search(ur"(?iuV1)ff", u"\uFB00\uFB01")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)ff", u"\uFB01\uFB00")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)fi", u"\uFB00\uFB01")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)fi", u"\uFB01\uFB00")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)fffi", u"\uFB00\uFB01")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)f\uFB03",
+          u"\uFB00\uFB01")), True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)ff", u"\uFB00\uFB01")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)fi", u"\uFB00\uFB01")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)fffi", u"\uFB00\uFB01")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)f\uFB03",
+          u"\uFB00\uFB01")), True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)f\uFB01", u"\uFB00i")),
+          True)
+        self.assertEqual(bool(regex.search(ur"(?iuV1)f\uFB01", u"\uFB00i")),
+          True)
+
+        self.assertEqual(regex.findall(ur"(?iuV0)\m(?:word){e<=3}\M(?<!\m(?:word){e<=1}\M)",
+          u"word word2 word word3 word word234 word23 word"), [u"word234",
+          u"word23"])
+        self.assertEqual(regex.findall(ur"(?iuV1)\m(?:word){e<=3}\M(?<!\m(?:word){e<=1}\M)",
+          u"word word2 word word3 word word234 word23 word"), [u"word234",
+          u"word23"])
+
+        self.assertEqual(regex.search(ur"(?fi)a\N{LATIN SMALL LIGATURE FFI}ne",
+          u"  affine  ").span(), (2, 8))
+        self.assertEqual(regex.search(ur"(?fi)a(?:\N{LATIN SMALL LIGATURE FFI}|x)ne",
+           u"  affine  ").span(), (2, 8))
+        self.assertEqual(regex.search(ur"(?fi)a(?:\N{LATIN SMALL LIGATURE FFI}|xy)ne",
+           u"  affine  ").span(), (2, 8))
+        self.assertEqual(regex.search(ur"(?fi)a\L<options>ne", u"affine",
+          options=[u"\N{LATIN SMALL LIGATURE FFI}"]).span(), (0, 6))
+        self.assertEqual(regex.search(ur"(?fi)a\L<options>ne",
+          u"a\N{LATIN SMALL LIGATURE FFI}ne", options=[u"ffi"]).span(), (0, 4))
+
+    def test_category(self):
+        self.assertEqual(regex.match(r"(\s)", " ")[1], ' ')
+
+    def test_not_literal(self):
+        self.assertEqual(regex.search(r"\s([^a])", " b")[1], 'b')
+        self.assertEqual(regex.search(r"\s([^a]*)", " bb")[1], 'bb')
+
+    def test_search_coverage(self):
+        self.assertEqual(regex.search(r"\s(b)", " b")[1], 'b')
+        self.assertEqual(regex.search(r"a\s", "a ")[0], 'a ')
+
+    def test_re_escape(self):
+        p = ""
+        self.assertEqual(regex.escape(p), p)
+        for i in range(0, 256):
+            p += chr(i)
+            self.assertEqual(bool(regex.match(regex.escape(chr(i)), chr(i))),
+              True)
+            self.assertEqual(regex.match(regex.escape(chr(i)), chr(i)).span(),
+              (0, 1))
+
+        pat = regex.compile(regex.escape(p))
+        self.assertEqual(pat.match(p).span(), (0, 256))
+
+    def test_constants(self):
+        if regex.I != regex.IGNORECASE:
+            self.fail()
+        if regex.L != regex.LOCALE:
+            self.fail()
+        if regex.M != regex.MULTILINE:
+            self.fail()
+        if regex.S != regex.DOTALL:
+            self.fail()
+        if regex.X != regex.VERBOSE:
+            self.fail()
+
+    def test_flags(self):
+        for flag in [regex.I, regex.M, regex.X, regex.S, regex.L]:
+            self.assertEqual(repr(type(regex.compile('^pattern$', flag))),
+              self.PATTERN_CLASS)
+
+    def test_sre_character_literals(self):
+        for i in [0, 8, 16, 32, 64, 127, 128, 255]:
+            self.assertEqual(bool(regex.match(r"\%03o" % i, chr(i))), True)
+            self.assertEqual(bool(regex.match(r"\%03o0" % i, chr(i) + "0")),
+              True)
+            self.assertEqual(bool(regex.match(r"\%03o8" % i, chr(i) + "8")),
+              True)
+            self.assertEqual(bool(regex.match(r"\x%02x" % i, chr(i))), True)
+            self.assertEqual(bool(regex.match(r"\x%02x0" % i, chr(i) + "0")),
+              True)
+            self.assertEqual(bool(regex.match(r"\x%02xz" % i, chr(i) + "z")),
+              True)
+
+        self.assertRaisesRegex(regex.error, self.INVALID_GROUP_REF, lambda:
+          regex.match(r"\911", ""))
+
+    def test_sre_character_class_literals(self):
+        for i in [0, 8, 16, 32, 64, 127, 128, 255]:
+            self.assertEqual(bool(regex.match(r"[\%03o]" % i, chr(i))), True)
+            self.assertEqual(bool(regex.match(r"[\%03o0]" % i, chr(i))), True)
+            self.assertEqual(bool(regex.match(r"[\%03o8]" % i, chr(i))), True)
+            self.assertEqual(bool(regex.match(r"[\x%02x]" % i, chr(i))), True)
+            self.assertEqual(bool(regex.match(r"[\x%02x0]" % i, chr(i))), True)
+            self.assertEqual(bool(regex.match(r"[\x%02xz]" % i, chr(i))), True)
+
+        self.assertRaisesRegex(regex.error, self.BAD_OCTAL_ESCAPE, lambda:
+          regex.match(r"[\911]", ""))
+
+    def test_bug_113254(self):
+        self.assertEqual(regex.match(r'(a)|(b)', 'b').start(1), -1)
+        self.assertEqual(regex.match(r'(a)|(b)', 'b').end(1), -1)
+        self.assertEqual(regex.match(r'(a)|(b)', 'b').span(1), (-1, -1))
+
+    def test_bug_527371(self):
+        # Bug described in patches 527371/672491.
+        self.assertEqual(regex.match(r'(a)?a','a').lastindex, None)
+        self.assertEqual(regex.match(r'(a)(b)?b','ab').lastindex, 1)
+        self.assertEqual(regex.match(r'(?P<a>a)(?P<b>b)?b','ab').lastgroup,
+          'a')
+        self.assertEqual(regex.match("(?P<a>a(b))", "ab").lastgroup, 'a')
+        self.assertEqual(regex.match("((a))", "a").lastindex, 1)
+
+    def test_bug_545855(self):
+        # Bug 545855 -- This pattern failed to cause a compile error as it
+        # should, instead provoking a TypeError.
+        self.assertRaisesRegex(regex.error, self.BAD_SET, lambda:
+          regex.compile('foo[a-'))
+
+    def test_bug_418626(self):
+        # Bugs 418626 at al. -- Testing Greg Chapman's addition of op code
+        # SRE_OP_MIN_REPEAT_ONE for eliminating recursion on simple uses of
+        # pattern '*?' on a long string.
+        self.assertEqual(regex.match('.*?c', 10000 * 'ab' + 'cd').end(0),
+          20001)
+        self.assertEqual(regex.match('.*?cd', 5000 * 'ab' + 'c' + 5000 * 'ab' +
+          'cde').end(0), 20003)
+        self.assertEqual(regex.match('.*?cd', 20000 * 'abc' + 'de').end(0),
+          60001)
+        # Non-simple '*?' still used to hit the recursion limit, before the
+        # non-recursive scheme was implemented.
+        self.assertEqual(regex.search('(a|b)*?c', 10000 * 'ab' + 'cd').end(0),
+          20001)
+
+    def test_bug_612074(self):
+        pat = u"[" + regex.escape(u"\u2039") + u"]"
+        self.assertEqual(regex.compile(pat) and 1, 1)
+
+    def test_stack_overflow(self):
+        # Nasty cases that used to overflow the straightforward recursive
+        # implementation of repeated groups.
+        self.assertEqual(regex.match('(x)*', 50000 * 'x')[1], 'x')
+        self.assertEqual(regex.match('(x)*y', 50000 * 'x' + 'y')[1], 'x')
+        self.assertEqual(regex.match('(x)*?y', 50000 * 'x' + 'y')[1], 'x')
+
+    def test_scanner(self):
+        def s_ident(scanner, token): return token
+        def s_operator(scanner, token): return "op%s" % token
+        def s_float(scanner, token): return float(token)
+        def s_int(scanner, token): return int(token)
+
+        scanner = regex.Scanner([(r"[a-zA-Z_]\w*", s_ident), (r"\d+\.\d*",
+          s_float), (r"\d+", s_int), (r"=|\+|-|\*|/", s_operator), (r"\s+",
+            None), ])
+
+        self.assertEqual(repr(type(scanner.scanner.scanner("").pattern)),
+          self.PATTERN_CLASS)
+
+        self.assertEqual(scanner.scan("sum = 3*foo + 312.50 + bar"), (['sum',
+          'op=', 3, 'op*', 'foo', 'op+', 312.5, 'op+', 'bar'], ''))
+
+    def test_bug_448951(self):
+        # Bug 448951 (similar to 429357, but with single char match).
+        # (Also test greedy matches.)
+        for op in '', '?', '*':
+            self.assertEqual(regex.match(r'((.%s):)?z' % op, 'z')[:], ('z',
+              None, None))
+            self.assertEqual(regex.match(r'((.%s):)?z' % op, 'a:z')[:], ('a:z',
+              'a:', 'a'))
+
+    def test_bug_725106(self):
+        # Capturing groups in alternatives in repeats.
+        self.assertEqual(regex.match('^((a)|b)*', 'abc')[:], ('ab', 'b', 'a'))
+        self.assertEqual(regex.match('^(([ab])|c)*', 'abc')[:], ('abc', 'c',
+          'b'))
+        self.assertEqual(regex.match('^((d)|[ab])*', 'abc')[:], ('ab', 'b',
+          None))
+        self.assertEqual(regex.match('^((a)c|[ab])*', 'abc')[:], ('ab', 'b',
+          None))
+        self.assertEqual(regex.match('^((a)|b)*?c', 'abc')[:], ('abc', 'b',
+          'a'))
+        self.assertEqual(regex.match('^(([ab])|c)*?d', 'abcd')[:], ('abcd',
+          'c', 'b'))
+        self.assertEqual(regex.match('^((d)|[ab])*?c', 'abc')[:], ('abc', 'b',
+          None))
+        self.assertEqual(regex.match('^((a)c|[ab])*?c', 'abc')[:], ('abc', 'b',
+          None))
+
+    def test_bug_725149(self):
+        # Mark_stack_base restoring before restoring marks.
+        self.assertEqual(regex.match('(a)(?:(?=(b)*)c)*', 'abb')[:], ('a', 'a',
+          None))
+        self.assertEqual(regex.match('(a)((?!(b)*))*', 'abb')[:], ('a', 'a',
+          None, None))
+
+    def test_bug_764548(self):
+        # Bug 764548, regex.compile() barfs on str/unicode subclasses.
+        class my_unicode(str): pass
+        pat = regex.compile(my_unicode("abc"))
+        self.assertEqual(pat.match("xyz"), None)
+
+    def test_finditer(self):
+        it = regex.finditer(r":+", "a:b::c:::d")
+        self.assertEqual([item[0] for item in it], [':', '::', ':::'])
+
+    def test_bug_926075(self):
+        if regex.compile('bug_926075') is regex.compile(u'bug_926075'):
+            self.fail()
+
+    def test_bug_931848(self):
+        pattern = u"[\u002E\u3002\uFF0E\uFF61]"
+        self.assertEqual(regex.compile(pattern).split("a.b.c"), ['a', 'b',
+          'c'])
+
+    def test_bug_581080(self):
+        it = regex.finditer(r"\s", "a b")
+        self.assertEqual(it.next().span(), (1, 2))
+        self.assertRaises(StopIteration, lambda: it.next())
+
+        scanner = regex.compile(r"\s").scanner("a b")
+        self.assertEqual(scanner.search().span(), (1, 2))
+        self.assertEqual(scanner.search(), None)
+
+    def test_bug_817234(self):
+        it = regex.finditer(r".*", "asdf")
+        self.assertEqual(it.next().span(), (0, 4))
+        self.assertEqual(it.next().span(), (4, 4))
+        self.assertRaises(StopIteration, lambda: it.next())
+
+    def test_empty_array(self):
+        # SF buf 1647541.
+        import array
+        for typecode in 'cbBuhHiIlLfd':
+            a = array.array(typecode)
+            self.assertEqual(regex.compile("bla").match(a), None)
+            self.assertEqual(regex.compile("").match(a)[1 : ], ())
+
+    def test_inline_flags(self):
+        # Bug #1700.
+        upper_char = unichr(0x1ea0) # Latin Capital Letter A with Dot Below
+        lower_char = unichr(0x1ea1) # Latin Small Letter A with Dot Below
+
+        p = regex.compile(upper_char, regex.I | regex.U)
+        self.assertEqual(bool(p.match(lower_char)), True)
+
+        p = regex.compile(lower_char, regex.I | regex.U)
+        self.assertEqual(bool(p.match(upper_char)), True)
+
+        p = regex.compile('(?i)' + upper_char, regex.U)
+        self.assertEqual(bool(p.match(lower_char)), True)
+
+        p = regex.compile('(?i)' + lower_char, regex.U)
+        self.assertEqual(bool(p.match(upper_char)), True)
+
+        p = regex.compile('(?iu)' + upper_char)
+        self.assertEqual(bool(p.match(lower_char)), True)
+
+        p = regex.compile('(?iu)' + lower_char)
+        self.assertEqual(bool(p.match(upper_char)), True)
+
+        self.assertEqual(bool(regex.match(r"(?i)a", "A")), True)
+        self.assertEqual(bool(regex.match(r"a(?i)", "A")), True)
+        self.assertEqual(bool(regex.match(r"(?iV1)a", "A")), True)
+        self.assertEqual(regex.match(r"a(?iV1)", "A"), None)
+
+    def test_dollar_matches_twice(self):
+        # $ matches the end of string, and just before the terminating \n.
+        pattern = regex.compile('$')
+        self.assertEqual(pattern.sub('#', 'a\nb\n'), 'a\nb#\n#')
+        self.assertEqual(pattern.sub('#', 'a\nb\nc'), 'a\nb\nc#')
+        self.assertEqual(pattern.sub('#', '\n'), '#\n#')
+
+        pattern = regex.compile('$', regex.MULTILINE)
+        self.assertEqual(pattern.sub('#', 'a\nb\n' ), 'a#\nb#\n#')
+        self.assertEqual(pattern.sub('#', 'a\nb\nc'), 'a#\nb#\nc#')
+        self.assertEqual(pattern.sub('#', '\n'), '#\n#')
+
+    def test_ascii_and_unicode_flag(self):
+        # Unicode patterns.
+        for flags in (0, regex.UNICODE):
+            pat = regex.compile(u'\xc0', flags | regex.IGNORECASE)
+            self.assertEqual(bool(pat.match(u'\xe0')), True)
+            pat = regex.compile(u'\w', flags)
+            self.assertEqual(bool(pat.match(u'\xe0')), True)
+
+        pat = regex.compile(u'\xc0', regex.ASCII | regex.IGNORECASE)
+        self.assertEqual(pat.match(u'\xe0'), None)
+        pat = regex.compile(u'(?a)\xc0', regex.IGNORECASE)
+        self.assertEqual(pat.match(u'\xe0'), None)
+        pat = regex.compile(u'\w', regex.ASCII)
+        self.assertEqual(pat.match(u'\xe0'), None)
+        pat = regex.compile(u'(?a)\w')
+        self.assertEqual(pat.match(u'\xe0'), None)
+
+        # String patterns.
+        for flags in (0, regex.ASCII):
+            pat = regex.compile('\xc0', flags | regex.IGNORECASE)
+            self.assertEqual(pat.match('\xe0'), None)
+            pat = regex.compile('\w')
+            self.assertEqual(pat.match('\xe0'), None)
+
+        self.assertRaisesRegex(ValueError, self.MIXED_FLAGS, lambda:
+          regex.compile('(?au)\w'))
+
+    def test_subscripting_match(self):
+        m = regex.match(r'(?<a>\w)', 'xy')
+        if not m:
+            self.fail("Failed: expected match but returned None")
+        elif not m or m[0] != m.group(0) or m[1] != m.group(1):
+            self.fail("Failed")
+        if not m:
+            self.fail("Failed: expected match but returned None")
+        elif m[:] != ('x', 'x'):
+            self.fail("Failed: expected \"('x', 'x')\" but got %s instead" %
+              repr(m[:]))
+
+    def test_new_named_groups(self):
+        m0 = regex.match(r'(?P<a>\w)', 'x')
+        m1 = regex.match(r'(?<a>\w)', 'x')
+        if not (m0 and m1 and m0[:] == m1[:]):
+            self.fail("Failed")
+
+    def test_properties(self):
+        self.assertEqual(regex.match('(?i)\xC0', '\xE0'), None)
+        self.assertEqual(regex.match(r'(?i)\xC0', '\xE0'), None)
+        self.assertEqual(regex.match(r'\w', '\xE0'), None)
+        self.assertEqual(bool(regex.match(ur'(?u)\w', u'\xE0')), True)
+
+        # Dropped the following test. It's not possible to determine what the
+        # correct result should be in the general case.
+#        self.assertEqual(bool(regex.match(r'(?L)\w', '\xE0')),
+#          '\xE0'.isalnum())
+
+        self.assertEqual(bool(regex.match(r'(?L)\d', '0')), True)
+        self.assertEqual(bool(regex.match(r'(?L)\s', ' ')), True)
+        self.assertEqual(bool(regex.match(r'(?L)\w', 'a')), True)
+        self.assertEqual(regex.match(r'(?L)\d', '?'), None)
+        self.assertEqual(regex.match(r'(?L)\s', '?'), None)
+        self.assertEqual(regex.match(r'(?L)\w', '?'), None)
+
+        self.assertEqual(regex.match(r'(?L)\D', '0'), None)
+        self.assertEqual(regex.match(r'(?L)\S', ' '), None)
+        self.assertEqual(regex.match(r'(?L)\W', 'a'), None)
+        self.assertEqual(bool(regex.match(r'(?L)\D', '?')), True)
+        self.assertEqual(bool(regex.match(r'(?L)\S', '?')), True)
+        self.assertEqual(bool(regex.match(r'(?L)\W', '?')), True)
+
+        self.assertEqual(bool(regex.match(ur'(?u)\p{Cyrillic}',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)(?iu)\p{Cyrillic}',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{IsCyrillic}',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{Script=Cyrillic}',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{InCyrillic}',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{Block=Cyrillic}',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:Cyrillic:]]',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:IsCyrillic:]]',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:Script=Cyrillic:]]',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:InCyrillic:]]',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:Block=Cyrillic:]]',
+          u'\N{CYRILLIC CAPITAL LETTER A}')), True)
+
+        self.assertEqual(bool(regex.match(ur'(?u)\P{Cyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\P{IsCyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\P{Script=Cyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\P{InCyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\P{Block=Cyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{^Cyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{^IsCyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{^Script=Cyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{^InCyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{^Block=Cyrillic}',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:^Cyrillic:]]',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:^IsCyrillic:]]',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:^Script=Cyrillic:]]',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:^InCyrillic:]]',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)[[:^Block=Cyrillic:]]',
+          u'\N{LATIN CAPITAL LETTER A}')), True)
+
+        self.assertEqual(bool(regex.match(ur'(?u)\d', u'0')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\s', u' ')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\w', u'A')), True)
+        self.assertEqual(regex.match(ur"(?u)\d", u"?"), None)
+        self.assertEqual(regex.match(ur"(?u)\s", u"?"), None)
+        self.assertEqual(regex.match(ur"(?u)\w", u"?"), None)
+        self.assertEqual(regex.match(ur"(?u)\D", u"0"), None)
+        self.assertEqual(regex.match(ur"(?u)\S", u" "), None)
+        self.assertEqual(regex.match(ur"(?u)\W", u"A"), None)
+        self.assertEqual(bool(regex.match(ur'(?u)\D', u'?')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\S', u'?')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\W', u'?')), True)
+
+        self.assertEqual(bool(regex.match(ur'(?u)\p{L}', u'A')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{L}', u'a')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{Lu}', u'A')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\p{Ll}', u'a')), True)
+
+        self.assertEqual(bool(regex.match(ur'(?u)(?i)a', u'a')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)(?i)a', u'A')), True)
+
+        self.assertEqual(bool(regex.match(ur'(?u)\w', u'0')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\w', u'a')), True)
+        self.assertEqual(bool(regex.match(ur'(?u)\w', u'_')), True)
+
+        self.assertEqual(regex.match(ur"(?u)\X", u"\xE0").span(), (0, 1))
+        self.assertEqual(regex.match(ur"(?u)\X", u"a\u0300").span(), (0, 2))
+        self.assertEqual(regex.findall(ur"(?u)\X",
+          u"a\xE0a\u0300e\xE9e\u0301"), [u'a', u'\xe0', u'a\u0300', u'e',
+          u'\xe9', u'e\u0301'])
+        self.assertEqual(regex.findall(ur"(?u)\X{3}",
+          u"a\xE0a\u0300e\xE9e\u0301"), [u'a\xe0a\u0300', u'e\xe9e\u0301'])
+        self.assertEqual(regex.findall(ur"(?u)\X", u"\r\r\n\u0301A\u0301"),
+          [u'\r', u'\r\n', u'\u0301', u'A\u0301'])
+
+        self.assertEqual(bool(regex.match(ur'(?u)\p{Ll}', u'a')), True)
+
+        chars_u = u"-09AZaz_\u0393\u03b3"
+        chars_b = "-09AZaz_"
+        word_set = set("Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc".split())
+
+        tests = [
+            (ur"(?u)\w", chars_u, u"09AZaz_\u0393\u03b3"),
+            (ur"(?u)[[:word:]]", chars_u, u"09AZaz_\u0393\u03b3"),
+            (ur"(?u)\W", chars_u, u"-"),
+            (ur"(?u)[[:^word:]]", chars_u, u"-"),
+            (ur"(?u)\d", chars_u, u"09"),
+            (ur"(?u)[[:digit:]]", chars_u, u"09"),
+            (ur"(?u)\D", chars_u, u"-AZaz_\u0393\u03b3"),
+            (ur"(?u)[[:^digit:]]", chars_u, u"-AZaz_\u0393\u03b3"),
+            (ur"(?u)[[:alpha:]]", chars_u, u"AZaz\u0393\u03b3"),
+            (ur"(?u)[[:^alpha:]]", chars_u, u"-09_"),
+            (ur"(?u)[[:alnum:]]", chars_u, u"09AZaz\u0393\u03b3"),
+            (ur"(?u)[[:^alnum:]]", chars_u, u"-_"),
+            (ur"(?u)[[:xdigit:]]", chars_u, u"09Aa"),
+            (ur"(?u)[[:^xdigit:]]", chars_u, u"-Zz_\u0393\u03b3"),
+            (ur"(?u)\p{InBasicLatin}", u"a\xE1", u"a"),
+            (ur"(?u)\P{InBasicLatin}", u"a\xE1", u"\xE1"),
+            (ur"(?iu)\p{InBasicLatin}", u"a\xE1", u"a"),
+            (ur"(?iu)\P{InBasicLatin}", u"a\xE1", u"\xE1"),
+
+            (r"(?L)\w", chars_b, "09AZaz_"),
+            (r"(?L)[[:word:]]", chars_b, "09AZaz_"),
+            (r"(?L)\W", chars_b, "-"),
+            (r"(?L)[[:^word:]]", chars_b, "-"),
+            (r"(?L)\d", chars_b, "09"),
+            (r"(?L)[[:digit:]]", chars_b, "09"),
+            (r"(?L)\D", chars_b, "-AZaz_"),
+            (r"(?L)[[:^digit:]]", chars_b, "-AZaz_"),
+            (r"(?L)[[:alpha:]]", chars_b, "AZaz"),
+            (r"(?L)[[:^alpha:]]", chars_b, "-09_"),
+            (r"(?L)[[:alnum:]]", chars_b, "09AZaz"),
+            (r"(?L)[[:^alnum:]]", chars_b, "-_"),
+            (r"(?L)[[:xdigit:]]", chars_b, "09Aa"),
+            (r"(?L)[[:^xdigit:]]", chars_b, "-Zz_"),
+
+            (r"\w", chars_b, "09AZaz_"),
+            (r"[[:word:]]", chars_b, "09AZaz_"),
+            (r"\W", chars_b, "-"),
+            (r"[[:^word:]]", chars_b, "-"),
+            (r"\d", chars_b, "09"),
+            (r"[[:digit:]]", chars_b, "09"),
+            (r"\D", chars_b, "-AZaz_"),
+            (r"[[:^digit:]]", chars_b, "-AZaz_"),
+            (r"[[:alpha:]]", chars_b, "AZaz"),
+            (r"[[:^alpha:]]", chars_b, "-09_"),
+            (r"[[:alnum:]]", chars_b, "09AZaz"),
+            (r"[[:^alnum:]]", chars_b, "-_"),
+            (r"[[:xdigit:]]", chars_b, "09Aa"),
+            (r"[[:^xdigit:]]", chars_b, "-Zz_"),
+        ]
+        for pattern, chars, expected in tests:
+            try:
+                if chars[ : 0].join(regex.findall(pattern, chars)) != expected:
+                    self.fail("Failed: %s" % pattern)
+            except Exception, e:
+                self.fail("Failed: %s raised %s" % (pattern, repr(e)))
+
+        self.assertEqual(bool(regex.match(ur"(?u)\p{NumericValue=0}", u"0")),
+          True)
+        self.assertEqual(bool(regex.match(ur"(?u)\p{NumericValue=1/2}",
+          u"\N{VULGAR FRACTION ONE HALF}")), True)
+        self.assertEqual(bool(regex.match(ur"(?u)\p{NumericValue=0.5}",
+          u"\N{VULGAR FRACTION ONE HALF}")), True)
+
+    def test_word_class(self):
+        self.assertEqual(regex.findall(ur"(?u)\w+",
+          u" \u0939\u093f\u0928\u094d\u0926\u0940,"),
+          [u'\u0939\u093f\u0928\u094d\u0926\u0940'])
+        self.assertEqual(regex.findall(ur"(?u)\W+",
+          u" \u0939\u093f\u0928\u094d\u0926\u0940,"), [u' ', u','])
+        self.assertEqual(regex.split(ur"(?uV1)\b",
+          u" \u0939\u093f\u0928\u094d\u0926\u0940,"), [u' ',
+          u'\u0939\u093f\u0928\u094d\u0926\u0940', u','])
+        self.assertEqual(regex.split(ur"(?uV1)\B",
+          u" \u0939\u093f\u0928\u094d\u0926\u0940,"), [u'', u' \u0939',
+          u'\u093f', u'\u0928', u'\u094d', u'\u0926', u'\u0940,', u''])
+
+    def test_search_anchor(self):
+        self.assertEqual(regex.findall(r"\G\w{2}", "abcd ef"), ['ab', 'cd'])
+
+    def test_search_reverse(self):
+        self.assertEqual(regex.findall(r"(?r).", "abc"), ['c', 'b', 'a'])
+        self.assertEqual(regex.findall(r"(?r).", "abc", overlapped=True), ['c',
+          'b', 'a'])
+        self.assertEqual(regex.findall(r"(?r)..", "abcde"), ['de', 'bc'])
+        self.assertEqual(regex.findall(r"(?r)..", "abcde", overlapped=True),
+          ['de', 'cd', 'bc', 'ab'])
+        self.assertEqual(regex.findall(r"(?r)(.)(-)(.)", "a-b-c",
+          overlapped=True), [("b", "-", "c"), ("a", "-", "b")])
+
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r).", "abc")], ['c',
+          'b', 'a'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r)..", "abcde",
+          overlapped=True)], ['de', 'cd', 'bc', 'ab'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r).", "abc")], ['c',
+          'b', 'a'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r)..", "abcde",
+          overlapped=True)], ['de', 'cd', 'bc', 'ab'])
+
+        self.assertEqual(regex.findall(r"^|\w+", "foo bar"), ['', 'foo',
+          'bar'])
+        self.assertEqual(regex.findall(r"(?V1)^|\w+", "foo bar"), ['', 'foo',
+          'bar'])
+        self.assertEqual(regex.findall(r"(?r)^|\w+", "foo bar"), ['bar', 'foo',
+          ''])
+        self.assertEqual(regex.findall(r"(?rV1)^|\w+", "foo bar"), ['bar',
+          'foo', ''])
+
+        self.assertEqual([m[0] for m in regex.finditer(r"^|\w+", "foo bar")],
+          ['', 'foo', 'bar'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?V1)^|\w+",
+          "foo bar")], ['', 'foo', 'bar'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r)^|\w+",
+          "foo bar")], ['bar', 'foo', ''])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?rV1)^|\w+",
+          "foo bar")], ['bar', 'foo', ''])
+
+        self.assertEqual(regex.findall(r"\G\w{2}", "abcd ef"), ['ab', 'cd'])
+        self.assertEqual(regex.findall(r".{2}(?<=\G.*)", "abcd"), ['ab', 'cd'])
+        self.assertEqual(regex.findall(r"(?r)\G\w{2}", "abcd ef"), [])
+        self.assertEqual(regex.findall(r"(?r)\w{2}\G", "abcd ef"), ['ef'])
+
+        self.assertEqual(regex.findall(r"q*", "qqwe"), ['qq', '', '', ''])
+        self.assertEqual(regex.findall(r"(?V1)q*", "qqwe"), ['qq', '', '', ''])
+        self.assertEqual(regex.findall(r"(?r)q*", "qqwe"), ['', '', 'qq', ''])
+        self.assertEqual(regex.findall(r"(?rV1)q*", "qqwe"), ['', '', 'qq',
+          ''])
+
+        self.assertEqual(regex.findall(".", "abcd", pos=1, endpos=3), ['b',
+          'c'])
+        self.assertEqual(regex.findall(".", "abcd", pos=1, endpos=-1), ['b',
+          'c'])
+        self.assertEqual([m[0] for m in regex.finditer(".", "abcd", pos=1,
+          endpos=3)], ['b', 'c'])
+        self.assertEqual([m[0] for m in regex.finditer(".", "abcd", pos=1,
+          endpos=-1)], ['b', 'c'])
+
+        self.assertEqual([m[0] for m in regex.finditer("(?r).", "abcd", pos=1,
+          endpos=3)], ['c', 'b'])
+        self.assertEqual([m[0] for m in regex.finditer("(?r).", "abcd", pos=1,
+          endpos=-1)], ['c', 'b'])
+        self.assertEqual(regex.findall("(?r).", "abcd", pos=1, endpos=3), ['c',
+          'b'])
+        self.assertEqual(regex.findall("(?r).", "abcd", pos=1, endpos=-1),
+          ['c', 'b'])
+
+        self.assertEqual(regex.findall(r"[ab]", "aB", regex.I), ['a', 'B'])
+        self.assertEqual(regex.findall(r"(?r)[ab]", "aB", regex.I), ['B', 'a'])
+
+        self.assertEqual(regex.findall(r"(?r).{2}", "abc"), ['bc'])
+        self.assertEqual(regex.findall(r"(?r).{2}", "abc", overlapped=True),
+          ['bc', 'ab'])
+        self.assertEqual(regex.findall(r"(\w+) (\w+)",
+          "first second third fourth fifth"), [('first', 'second'), ('third',
+          'fourth')])
+        self.assertEqual(regex.findall(r"(?r)(\w+) (\w+)",
+          "first second third fourth fifth"), [('fourth', 'fifth'), ('second',
+          'third')])
+
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r).{2}", "abc")],
+          ['bc'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r).{2}", "abc",
+          overlapped=True)], ['bc', 'ab'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(\w+) (\w+)",
+          "first second third fourth fifth")], ['first second',
+          'third fourth'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r)(\w+) (\w+)",
+          "first second third fourth fifth")], ['fourth fifth',
+          'second third'])
+
+        self.assertEqual(regex.search("abcdef", "abcdef").span(), (0, 6))
+        self.assertEqual(regex.search("(?r)abcdef", "abcdef").span(), (0, 6))
+        self.assertEqual(regex.search("(?i)abcdef", "ABCDEF").span(), (0, 6))
+        self.assertEqual(regex.search("(?ir)abcdef", "ABCDEF").span(), (0, 6))
+
+        self.assertEqual(regex.sub(r"(.)", r"\1", "abc"), 'abc')
+        self.assertEqual(regex.sub(r"(?r)(.)", r"\1", "abc"), 'abc')
+
+    def test_atomic(self):
+        # Issue 433030.
+        self.assertEqual(regex.search(r"(?>a*)a", "aa"), None)
+
+    def test_possessive(self):
+        # Single-character non-possessive.
+        self.assertEqual(regex.search(r"a?a", "a").span(), (0, 1))
+        self.assertEqual(regex.search(r"a*a", "aaa").span(), (0, 3))
+        self.assertEqual(regex.search(r"a+a", "aaa").span(), (0, 3))
+        self.assertEqual(regex.search(r"a{1,3}a", "aaa").span(), (0, 3))
+
+        # Multiple-character non-possessive.
+        self.assertEqual(regex.search(r"(?:ab)?ab", "ab").span(), (0, 2))
+        self.assertEqual(regex.search(r"(?:ab)*ab", "ababab").span(), (0, 6))
+        self.assertEqual(regex.search(r"(?:ab)+ab", "ababab").span(), (0, 6))
+        self.assertEqual(regex.search(r"(?:ab){1,3}ab", "ababab").span(), (0,
+          6))
+
+        # Single-character possessive.
+        self.assertEqual(regex.search(r"a?+a", "a"), None)
+        self.assertEqual(regex.search(r"a*+a", "aaa"), None)
+        self.assertEqual(regex.search(r"a++a", "aaa"), None)
+        self.assertEqual(regex.search(r"a{1,3}+a", "aaa"), None)
+
+        # Multiple-character possessive.
+        self.assertEqual(regex.search(r"(?:ab)?+ab", "ab"), None)
+        self.assertEqual(regex.search(r"(?:ab)*+ab", "ababab"), None)
+        self.assertEqual(regex.search(r"(?:ab)++ab", "ababab"), None)
+        self.assertEqual(regex.search(r"(?:ab){1,3}+ab", "ababab"), None)
+
+    def test_zerowidth(self):
+        # Issue 3262.
+        self.assertEqual(regex.split(r"\b", "a b"), ['a b'])
+        self.assertEqual(regex.split(r"(?V1)\b", "a b"), ['', 'a', ' ', 'b',
+          ''])
+
+        # Issue 1647489.
+        self.assertEqual(regex.findall(r"^|\w+", "foo bar"), ['', 'foo',
+          'bar'])
+        self.assertEqual([m[0] for m in regex.finditer(r"^|\w+", "foo bar")],
+          ['', 'foo', 'bar'])
+        self.assertEqual(regex.findall(r"(?r)^|\w+", "foo bar"), ['bar', 'foo',
+          ''])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r)^|\w+",
+          "foo bar")], ['bar', 'foo', ''])
+        self.assertEqual(regex.findall(r"(?V1)^|\w+", "foo bar"), ['', 'foo',
+          'bar'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?V1)^|\w+",
+          "foo bar")], ['', 'foo', 'bar'])
+        self.assertEqual(regex.findall(r"(?rV1)^|\w+", "foo bar"), ['bar',
+          'foo', ''])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?rV1)^|\w+",
+          "foo bar")], ['bar', 'foo', ''])
+
+        self.assertEqual(regex.split("", "xaxbxc"), ['xaxbxc'])
+        self.assertEqual([m for m in regex.splititer("", "xaxbxc")],
+          ['xaxbxc'])
+
+        self.assertEqual(regex.split("(?r)", "xaxbxc"), ['xaxbxc'])
+        self.assertEqual([m for m in regex.splititer("(?r)", "xaxbxc")],
+          ['xaxbxc'])
+
+        self.assertEqual(regex.split("(?V1)", "xaxbxc"), ['', 'x', 'a', 'x',
+          'b', 'x', 'c', ''])
+        self.assertEqual([m for m in regex.splititer("(?V1)", "xaxbxc")], ['',
+          'x', 'a', 'x', 'b', 'x', 'c', ''])
+
+        self.assertEqual(regex.split("(?rV1)", "xaxbxc"), ['', 'c', 'x', 'b',
+          'x', 'a', 'x', ''])
+        self.assertEqual([m for m in regex.splititer("(?rV1)", "xaxbxc")], ['',
+          'c', 'x', 'b', 'x', 'a', 'x', ''])
+
+    def test_scoped_and_inline_flags(self):
+        # Issues 433028, 433024, 433027.
+        self.assertEqual(regex.search(r"(?i)Ab", "ab").span(), (0, 2))
+        self.assertEqual(regex.search(r"(?i:A)b", "ab").span(), (0, 2))
+        self.assertEqual(regex.search(r"A(?i)b", "ab").span(), (0, 2))
+        self.assertEqual(regex.search(r"A(?iV1)b", "ab"), None)
+
+        self.assertRaisesRegex(regex.error, self.CANT_TURN_OFF, lambda:
+          regex.search(r"(?V0-i)Ab", "ab", flags=regex.I))
+
+        self.assertEqual(regex.search(r"(?V0)Ab", "ab"), None)
+        self.assertEqual(regex.search(r"(?V1)Ab", "ab"), None)
+        self.assertEqual(regex.search(r"(?V1-i)Ab", "ab", flags=regex.I), None)
+        self.assertEqual(regex.search(r"(?-i:A)b", "ab", flags=regex.I), None)
+        self.assertEqual(regex.search(r"A(?V1-i)b", "ab",
+          flags=regex.I).span(), (0, 2))
+
+    def test_repeated_repeats(self):
+        # Issue 2537.
+        self.assertEqual(regex.search(r"(?:a+)+", "aaa").span(), (0, 3))
+        self.assertEqual(regex.search(r"(?:(?:ab)+c)+", "abcabc").span(), (0,
+          6))
+
+    def test_lookbehind(self):
+        self.assertEqual(regex.search(r"123(?<=a\d+)", "a123").span(), (1, 4))
+        self.assertEqual(regex.search(r"123(?<=a\d+)", "b123"), None)
+        self.assertEqual(regex.search(r"123(?<!a\d+)", "a123"), None)
+        self.assertEqual(regex.search(r"123(?<!a\d+)", "b123").span(), (1, 4))
+
+        self.assertEqual(bool(regex.match("(a)b(?<=b)(c)", "abc")), True)
+        self.assertEqual(regex.match("(a)b(?<=c)(c)", "abc"), None)
+        self.assertEqual(bool(regex.match("(a)b(?=c)(c)", "abc")), True)
+        self.assertEqual(regex.match("(a)b(?=b)(c)", "abc"), None)
+
+        self.assertEqual(regex.match("(?:(a)|(x))b(?<=(?(2)x|c))c", "abc"),
+          None)
+        self.assertEqual(regex.match("(?:(a)|(x))b(?<=(?(2)b|x))c", "abc"),
+          None)
+        self.assertEqual(bool(regex.match("(?:(a)|(x))b(?<=(?(2)x|b))c",
+          "abc")), True)
+        self.assertEqual(regex.match("(?:(a)|(x))b(?<=(?(1)c|x))c", "abc"),
+          None)
+        self.assertEqual(bool(regex.match("(?:(a)|(x))b(?<=(?(1)b|x))c",
+          "abc")), True)
+
+        self.assertEqual(bool(regex.match("(?:(a)|(x))b(?=(?(2)x|c))c",
+          "abc")), True)
+        self.assertEqual(regex.match("(?:(a)|(x))b(?=(?(2)c|x))c", "abc"),
+          None)
+        self.assertEqual(bool(regex.match("(?:(a)|(x))b(?=(?(2)x|c))c",
+          "abc")), True)
+        self.assertEqual(regex.match("(?:(a)|(x))b(?=(?(1)b|x))c", "abc"),
+          None)
+        self.assertEqual(bool(regex.match("(?:(a)|(x))b(?=(?(1)c|x))c",
+          "abc")), True)
+
+        self.assertEqual(regex.match("(a)b(?<=(?(2)x|c))(c)", "abc"), None)
+        self.assertEqual(regex.match("(a)b(?<=(?(2)b|x))(c)", "abc"), None)
+        self.assertEqual(regex.match("(a)b(?<=(?(1)c|x))(c)", "abc"), None)
+        self.assertEqual(bool(regex.match("(a)b(?<=(?(1)b|x))(c)", "abc")),
+          True)
+
+        self.assertEqual(bool(regex.match("(a)b(?=(?(2)x|c))(c)", "abc")),
+          True)
+        self.assertEqual(regex.match("(a)b(?=(?(2)b|x))(c)", "abc"), None)
+        self.assertEqual(bool(regex.match("(a)b(?=(?(1)c|x))(c)", "abc")),
+          True)
+
+        self.assertEqual(repr(type(regex.compile(r"(a)\2(b)"))),
+          self.PATTERN_CLASS)
+
+    def test_unmatched_in_sub(self):
+        # Issue 1519638.
+        self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "xy"), 'y-x')
+        self.assertEqual(regex.sub(r"(?V1)(x)?(y)?", r"\2-\1", "xy"), 'y-x-')
+        self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "x"), '-x')
+        self.assertEqual(regex.sub(r"(?V1)(x)?(y)?", r"\2-\1", "x"), '-x-')
+        self.assertEqual(regex.sub(r"(?V0)(x)?(y)?", r"\2-\1", "y"), 'y-')
+        self.assertEqual(regex.sub(r"(?V1)(x)?(y)?", r"\2-\1", "y"), 'y--')
+
+    def test_bug_10328 (self):
+        # Issue 10328.
+        pat = regex.compile(r'(?mV0)(?P<trailing_ws>[ \t]+\r*$)|(?P<no_final_newline>(?<=[^\n])\Z)')
+        self.assertEqual(pat.subn(lambda m: '<' + m.lastgroup + '>',
+          'foobar '), ('foobar<trailing_ws>', 1))
+        self.assertEqual([m.group() for m in pat.finditer('foobar ')], [' ',
+          ''])
+        pat = regex.compile(r'(?mV1)(?P<trailing_ws>[ \t]+\r*$)|(?P<no_final_newline>(?<=[^\n])\Z)')
+        self.assertEqual(pat.subn(lambda m: '<' + m.lastgroup + '>',
+          'foobar '), ('foobar<trailing_ws><no_final_newline>', 2))
+        self.assertEqual([m.group() for m in pat.finditer('foobar ')], [' ',
+          ''])
+
+    def test_overlapped(self):
+        self.assertEqual(regex.findall(r"..", "abcde"), ['ab', 'cd'])
+        self.assertEqual(regex.findall(r"..", "abcde", overlapped=True), ['ab',
+          'bc', 'cd', 'de'])
+        self.assertEqual(regex.findall(r"(?r)..", "abcde"), ['de', 'bc'])
+        self.assertEqual(regex.findall(r"(?r)..", "abcde", overlapped=True),
+          ['de', 'cd', 'bc', 'ab'])
+        self.assertEqual(regex.findall(r"(.)(-)(.)", "a-b-c", overlapped=True),
+          [("a", "-", "b"), ("b", "-", "c")])
+
+        self.assertEqual([m[0] for m in regex.finditer(r"..", "abcde")], ['ab',
+          'cd'])
+        self.assertEqual([m[0] for m in regex.finditer(r"..", "abcde",
+          overlapped=True)], ['ab', 'bc', 'cd', 'de'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r)..", "abcde")],
+          ['de', 'bc'])
+        self.assertEqual([m[0] for m in regex.finditer(r"(?r)..", "abcde",
+          overlapped=True)], ['de', 'cd', 'bc', 'ab'])
+
+        self.assertEqual([m.groups() for m in regex.finditer(r"(.)(-)(.)",
+          "a-b-c", overlapped=True)], [("a", "-", "b"), ("b", "-", "c")])
+        self.assertEqual([m.groups() for m in regex.finditer(r"(?r)(.)(-)(.)",
+          "a-b-c", overlapped=True)], [("b", "-", "c"), ("a", "-", "b")])
+
+    def test_splititer(self):
+        self.assertEqual(regex.split(r",", "a,b,,c,"), ['a', 'b', '', 'c', ''])
+        self.assertEqual([m for m in regex.splititer(r",", "a,b,,c,")], ['a',
+          'b', '', 'c', ''])
+
+    def test_grapheme(self):
+        self.assertEqual(regex.match(ur"(?u)\X", u"\xE0").span(), (0, 1))
+        self.assertEqual(regex.match(ur"(?u)\X", u"a\u0300").span(), (0, 2))
+
+        self.assertEqual(regex.findall(ur"(?u)\X",
+          u"a\xE0a\u0300e\xE9e\u0301"), [u'a', u'\xe0', u'a\u0300', u'e',
+          u'\xe9', u'e\u0301'])
+        self.assertEqual(regex.findall(ur"(?u)\X{3}",
+          u"a\xE0a\u0300e\xE9e\u0301"), [u'a\xe0a\u0300', u'e\xe9e\u0301'])
+        self.assertEqual(regex.findall(ur"(?u)\X", u"\r\r\n\u0301A\u0301"),
+          [u'\r', u'\r\n', u'\u0301', u'A\u0301'])
+
+    def test_word_boundary(self):
+        text = u'The quick ("brown") fox can\'t jump 32.3 feet, right?'
+        self.assertEqual(regex.split(ur'(?V1)\b', text), [u'', u'The', u' ',
+          u'quick', u' ("', u'brown', u'") ', u'fox', u' ', u'can', u"'", u't',
+          u' ', u'jump', u' ', u'32', u'.', u'3', u' ', u'feet', u', ',
+          u'right', u'?'])
+        self.assertEqual(regex.split(ur'(?V1w)\b', text), [u'', u'The', u' ',
+          u'quick', u' ', u'(', u'"', u'brown', u'"', u')', u' ', u'fox', u' ',
+          u"can't", u' ', u'jump', u' ', u'32.3', u' ', u'feet', u',', u' ',
+          u'right', u'?', u''])
+
+        text = u"The  fox"
+        self.assertEqual(regex.split(ur'(?V1)\b', text), [u'', u'The', u'  ',
+          u'fox', u''])
+        self.assertEqual(regex.split(ur'(?V1w)\b', text), [u'', u'The', u' ',
+          u' ', u'fox', u''])
+
+        text = u"can't aujourd'hui l'objectif"
+        self.assertEqual(regex.split(ur'(?V1)\b', text), [u'', u'can', u"'",
+          u't', u' ', u'aujourd', u"'", u'hui', u' ', u'l', u"'", u'objectif',
+          u''])
+        self.assertEqual(regex.split(ur'(?V1w)\b', text), [u'', u"can't", u' ',
+          u"aujourd'hui", u' ', u"l'", u'objectif', u''])
+
+    def test_line_boundary(self):
+        self.assertEqual(regex.findall(r".+", "Line 1\nLine 2\n"), ["Line 1",
+          "Line 2"])
+        self.assertEqual(regex.findall(r".+", "Line 1\rLine 2\r"),
+          ["Line 1\rLine 2\r"])
+        self.assertEqual(regex.findall(r".+", "Line 1\r\nLine 2\r\n"),
+          ["Line 1\r", "Line 2\r"])
+        self.assertEqual(regex.findall(r"(?w).+", "Line 1\nLine 2\n"),
+          ["Line 1", "Line 2"])
+        self.assertEqual(regex.findall(r"(?w).+", "Line 1\rLine 2\r"),
+          ["Line 1", "Line 2"])
+        self.assertEqual(regex.findall(r"(?w).+", "Line 1\r\nLine 2\r\n"),
+          ["Line 1", "Line 2"])
+
+        self.assertEqual(regex.search(r"^abc", "abc").start(), 0)
+        self.assertEqual(regex.search(r"^abc", "\nabc"), None)
+        self.assertEqual(regex.search(r"^abc", "\rabc"), None)
+        self.assertEqual(regex.search(r"(?w)^abc", "abc").start(), 0)
+        self.assertEqual(regex.search(r"(?w)^abc", "\nabc"), None)
+        self.assertEqual(regex.search(r"(?w)^abc", "\rabc"), None)
+
+        self.assertEqual(regex.search(r"abc$", "abc").start(), 0)
+        self.assertEqual(regex.search(r"abc$", "abc\n").start(), 0)
+        self.assertEqual(regex.search(r"abc$", "abc\r"), None)
+        self.assertEqual(regex.search(r"(?w)abc$", "abc").start(), 0)
+        self.assertEqual(regex.search(r"(?w)abc$", "abc\n").start(), 0)
+        self.assertEqual(regex.search(r"(?w)abc$", "abc\r").start(), 0)
+
+        self.assertEqual(regex.search(r"(?m)^abc", "abc").start(), 0)
+        self.assertEqual(regex.search(r"(?m)^abc", "\nabc").start(), 1)
+        self.assertEqual(regex.search(r"(?m)^abc", "\rabc"), None)
+        self.assertEqual(regex.search(r"(?mw)^abc", "abc").start(), 0)
+        self.assertEqual(regex.search(r"(?mw)^abc", "\nabc").start(), 1)
+        self.assertEqual(regex.search(r"(?mw)^abc", "\rabc").start(), 1)
+
+        self.assertEqual(regex.search(r"(?m)abc$", "abc").start(), 0)
+        self.assertEqual(regex.search(r"(?m)abc$", "abc\n").start(), 0)
+        self.assertEqual(regex.search(r"(?m)abc$", "abc\r"), None)
+        self.assertEqual(regex.search(r"(?mw)abc$", "abc").start(), 0)
+        self.assertEqual(regex.search(r"(?mw)abc$", "abc\n").start(), 0)
+        self.assertEqual(regex.search(r"(?mw)abc$", "abc\r").start(), 0)
+
+    def test_branch_reset(self):
+        self.assertEqual(regex.match(r"(?:(a)|(b))(c)", "ac").groups(), ('a',
+          None, 'c'))
+        self.assertEqual(regex.match(r"(?:(a)|(b))(c)", "bc").groups(), (None,
+          'b', 'c'))
+        self.assertEqual(regex.match(r"(?:(?<a>a)|(?<b>b))(?<c>c)",
+          "ac").groups(), ('a', None, 'c'))
+        self.assertEqual(regex.match(r"(?:(?<a>a)|(?<b>b))(?<c>c)",
+          "bc").groups(), (None, 'b', 'c'))
+
+        self.assertEqual(regex.match(r"(?<a>a)(?:(?<b>b)|(?<c>c))(?<d>d)",
+          "abd").groups(), ('a', 'b', None, 'd'))
+        self.assertEqual(regex.match(r"(?<a>a)(?:(?<b>b)|(?<c>c))(?<d>d)",
+          "acd").groups(), ('a', None, 'c', 'd'))
+        self.assertEqual(regex.match(r"(a)(?:(b)|(c))(d)", "abd").groups(),
+          ('a', 'b', None, 'd'))
+
+        self.assertEqual(regex.match(r"(a)(?:(b)|(c))(d)", "acd").groups(),
+          ('a', None, 'c', 'd'))
+        self.assertEqual(regex.match(r"(a)(?|(b)|(b))(d)", "abd").groups(),
+          ('a', 'b', 'd'))
+        self.assertEqual(regex.match(r"(?|(?<a>a)|(?<b>b))(c)", "ac").groups(),
+          ('a', None, 'c'))
+        self.assertEqual(regex.match(r"(?|(?<a>a)|(?<b>b))(c)", "bc").groups(),
+          (None, 'b', 'c'))
+        self.assertEqual(regex.match(r"(?|(?<a>a)|(?<a>b))(c)", "ac").groups(),
+          ('a', 'c'))
+
+        self.assertEqual(regex.match(r"(?|(?<a>a)|(?<a>b))(c)", "bc").groups(),
+          ('b', 'c'))
+
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(?<b>c)(?<a>d))(e)",
+          "abe").groups(), ('a', 'b', 'e'))
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(?<b>c)(?<a>d))(e)",
+          "cde").groups(), ('d', 'c', 'e'))
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(?<b>c)(d))(e)",
+          "abe").groups(), ('a', 'b', 'e'))
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(?<b>c)(d))(e)",
+          "cde").groups(), ('d', 'c', 'e'))
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(c)(d))(e)",
+          "abe").groups(), ('a', 'b', 'e'))
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(c)(d))(e)",
+          "cde").groups(), ('c', 'd', 'e'))
+
+        # Hg issue 87.
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(c)(?<a>d))(e)",
+          "abe").groups(), ("a", "b", "e"))
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(c)(?<a>d))(e)",
+          "abe").capturesdict(), {"a": ["a"], "b": ["b"]})
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(c)(?<a>d))(e)",
+          "cde").groups(), ("d", None, "e"))
+        self.assertEqual(regex.match(r"(?|(?<a>a)(?<b>b)|(c)(?<a>d))(e)",
+          "cde").capturesdict(), {"a": ["c", "d"], "b": []})
+
+    def test_set(self):
+        self.assertEqual(regex.match(r"[a]", "a").span(), (0, 1))
+        self.assertEqual(regex.match(r"(?i)[a]", "A").span(), (0, 1))
+        self.assertEqual(regex.match(r"[a-b]", r"a").span(), (0, 1))
+        self.assertEqual(regex.match(r"(?i)[a-b]", r"A").span(), (0, 1))
+
+        self.assertEqual(regex.sub(r"(?V0)([][])", r"-", "a[b]c"), "a-b-c")
+
+        self.assertEqual(regex.findall(ur"[\p{Alpha}]", u"a0"), [u"a"])
+        self.assertEqual(regex.findall(ur"(?i)[\p{Alpha}]", u"A0"), [u"A"])
+
+        self.assertEqual(regex.findall(ur"[a\p{Alpha}]", u"ab0"), [u"a", u"b"])
+        self.assertEqual(regex.findall(ur"[a\P{Alpha}]", u"ab0"), [u"a", u"0"])
+        self.assertEqual(regex.findall(ur"(?i)[a\p{Alpha}]", u"ab0"), [u"a",
+          u"b"])
+        self.assertEqual(regex.findall(ur"(?i)[a\P{Alpha}]", u"ab0"), [u"a",
+          u"0"])
+
+        self.assertEqual(regex.findall(ur"[a-b\p{Alpha}]", u"abC0"), [u"a",
+          u"b", u"C"])
+        self.assertEqual(regex.findall(ur"(?i)[a-b\p{Alpha}]", u"AbC0"), [u"A",
+          u"b", u"C"])
+
+        self.assertEqual(regex.findall(ur"[\p{Alpha}]", u"a0"), [u"a"])
+        self.assertEqual(regex.findall(ur"[\P{Alpha}]", u"a0"), [u"0"])
+        self.assertEqual(regex.findall(ur"[^\p{Alpha}]", u"a0"), [u"0"])
+        self.assertEqual(regex.findall(ur"[^\P{Alpha}]", u"a0"), [u"a"])
+
+        self.assertEqual("".join(regex.findall(r"[^\d-h]", "a^b12c-h")),
+          'a^bc')
+        self.assertEqual("".join(regex.findall(r"[^\dh]", "a^b12c-h")),
+          'a^bc-')
+        self.assertEqual("".join(regex.findall(r"[^h\s\db]", "a^b 12c-h")),
+          'a^c-')
+        self.assertEqual("".join(regex.findall(r"[^b\w]", "a b")), ' ')
+        self.assertEqual("".join(regex.findall(r"[^b\S]", "a b")), ' ')
+        self.assertEqual("".join(regex.findall(r"[^8\d]", "a 1b2")), 'a b')
+
+        all_chars = u"".join(unichr(c) for c in range(0x100))
+        self.assertEqual(len(regex.findall(ur"(?u)\p{ASCII}", all_chars)), 128)
+        self.assertEqual(len(regex.findall(ur"(?u)\p{Letter}", all_chars)),
+          117)
+        self.assertEqual(len(regex.findall(ur"(?u)\p{Digit}", all_chars)), 10)
+
+        # Set operators
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{ASCII}&&\p{Letter}]",
+          all_chars)), 52)
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{ASCII}&&\p{Alnum}&&\p{Letter}]",
+          all_chars)), 52)
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{ASCII}&&\p{Alnum}&&\p{Digit}]",
+          all_chars)), 10)
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{ASCII}&&\p{Cc}]",
+          all_chars)), 33)
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{ASCII}&&\p{Graph}]",
+          all_chars)), 94)
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{ASCII}--\p{Cc}]",
+          all_chars)), 95)
+        self.assertEqual(len(regex.findall(ur"(?u)[\p{Letter}\p{Digit}]",
+          all_chars)), 127)
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{Letter}||\p{Digit}]",
+          all_chars)), 127)
+        self.assertEqual(len(regex.findall(ur"(?u)\p{HexDigit}", all_chars)),
+          22)
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{HexDigit}~~\p{Digit}]",
+          all_chars)), 12)
+        self.assertEqual(len(regex.findall(ur"(?uV1)[\p{Digit}~~\p{HexDigit}]",
+          all_chars)), 12)
+
+        self.assertEqual(repr(type(regex.compile(r"(?V0)([][-])"))),
+          self.PATTERN_CLASS)
+        self.assertEqual(regex.findall(r"(?V1)[[a-z]--[aei]]", "abc"), ["b",
+          "c"])
+        self.assertEqual(regex.findall(r"(?iV1)[[a-z]--[aei]]", "abc"), ["b",
+          "c"])
+        self.assertEqual(regex.findall("(?V1)[\w--a]","abc"), ["b", "c"])
+        self.assertEqual(regex.findall("(?iV1)[\w--a]","abc"), ["b", "c"])
+
+    def test_various(self):
+        tests = [
+            # Test ?P< and ?P= extensions.
+            ('(?P<foo_123', '', '', regex.error, self.MISSING_GT),      # Unterminated group identifier.
+            ('(?P<1>a)', '', '', regex.error, self.BAD_GROUP_NAME),     # Begins with a digit.
+            ('(?P<!>a)', '', '', regex.error, self.BAD_GROUP_NAME),     # Begins with an illegal char.
+            ('(?P<foo!>a)', '', '', regex.error, self.BAD_GROUP_NAME),  # Begins with an illegal char.
+
+            # Same tests, for the ?P= form.
+            ('(?P<foo_123>a)(?P=foo_123', 'aa', '', regex.error,
+              self.MISSING_RPAREN),
+            ('(?P<foo_123>a)(?P=1)', 'aa', '1', repr('a')),
+            ('(?P<foo_123>a)(?P=0)', 'aa', '', regex.error,
+              self.BAD_GROUP_NAME),
+            ('(?P<foo_123>a)(?P=-1)', 'aa', '', regex.error,
+              self.BAD_GROUP_NAME),
+            ('(?P<foo_123>a)(?P=!)', 'aa', '', regex.error,
+              self.BAD_GROUP_NAME),
+            ('(?P<foo_123>a)(?P=foo_124)', 'aa', '', regex.error,
+              self.UNKNOWN_GROUP),  # Backref to undefined group.
+
+            ('(?P<foo_123>a)', 'a', '1', repr('a')),
+            ('(?P<foo_123>a)(?P=foo_123)', 'aa', '1', repr('a')),
+
+            # Mal-formed \g in pattern treated as literal for compatibility.
+            (r'(?<foo_123>a)\g<foo_123', 'aa', '', repr(None)),
+            (r'(?<foo_123>a)\g<1>', 'aa', '1', repr('a')),
+            (r'(?<foo_123>a)\g<!>', 'aa', '', repr(None)),
+            (r'(?<foo_123>a)\g<foo_124>', 'aa', '', regex.error,
+              self.UNKNOWN_GROUP),  # Backref to undefined group.
+
+            ('(?<foo_123>a)', 'a', '1', repr('a')),
+            (r'(?<foo_123>a)\g<foo_123>', 'aa', '1', repr('a')),
+
+            # Test octal escapes.
+            ('\\1', 'a', '', regex.error, self.INVALID_GROUP_REF),    # Backreference.
+            ('[\\1]', '\1', '0', "'\\x01'"),  # Character.
+            ('\\09', chr(0) + '9', '0', repr(chr(0) + '9')),
+            ('\\141', 'a', '0', repr('a')),
+            ('(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\119', 'abcdefghijklk9',
+              '0,11', repr(('abcdefghijklk9', 'k'))),
+
+            # Test \0 is handled everywhere.
+            (r'\0', '\0', '0', repr('\0')),
+            (r'[\0a]', '\0', '0', repr('\0')),
+            (r'[a\0]', '\0', '0', repr('\0')),
+            (r'[^a\0]', '\0', '', repr(None)),
+
+            # Test various letter escapes.
+            (r'\a[\b]\f\n\r\t\v', '\a\b\f\n\r\t\v', '0',
+              repr('\a\b\f\n\r\t\v')),
+            (r'[\a][\b][\f][\n][\r][\t][\v]', '\a\b\f\n\r\t\v', '0',
+              repr('\a\b\f\n\r\t\v')),
+            (r'\c\e\g\h\i\j\k\o\p\q\y\z', 'ceghijkopqyz', '0',
+              repr('ceghijkopqyz')),
+            (r'\xff', '\377', '0', repr(chr(255))),
+
+            # New \x semantics.
+            (r'\x00ffffffffffffff', '\377', '', repr(None)),
+            (r'\x00f', '\017', '', repr(None)),
+            (r'\x00fe', '\376', '', repr(None)),
+
+            (r'\x00ff', '\377', '', repr(None)),
+            (r'\t\n\v\r\f\a\g', '\t\n\v\r\f\ag', '0', repr('\t\n\v\r\f\ag')),
+            ('\t\n\v\r\f\a\g', '\t\n\v\r\f\ag', '0', repr('\t\n\v\r\f\ag')),
+            (r'\t\n\v\r\f\a', '\t\n\v\r\f\a', '0', repr(chr(9) + chr(10) +
+              chr(11) + chr(13) + chr(12) + chr(7))),
+            (r'[\t][\n][\v][\r][\f][\b]', '\t\n\v\r\f\b', '0',
+              repr('\t\n\v\r\f\b')),
+
+            (r"^\w+=(\\[\000-\277]|[^\n\\])*",
+              "SRC=eval.c g.c blah blah blah \\\\\n\tapes.c", '0',
+              repr("SRC=eval.c g.c blah blah blah \\\\")),
+
+            # Test that . only matches \n in DOTALL mode.
+            ('a.b', 'acb', '0', repr('acb')),
+            ('a.b', 'a\nb', '', repr(None)),
+            ('a.*b', 'acc\nccb', '', repr(None)),
+            ('a.{4,5}b', 'acc\nccb', '', repr(None)),
+            ('a.b', 'a\rb', '0', repr('a\rb')),
+            # The new behaviour is that the inline flag affects only what follows.
+            ('a.b(?s)', 'a\nb', '0', repr('a\nb')),
+            ('a.b(?sV1)', 'a\nb', '', repr(None)),
+            ('(?s)a.b', 'a\nb', '0', repr('a\nb')),
+            ('a.*(?s)b', 'acc\nccb', '0', repr('acc\nccb')),
+            ('a.*(?sV1)b', 'acc\nccb', '', repr(None)),
+            ('(?s)a.*b', 'acc\nccb', '0', repr('acc\nccb')),
+            ('(?s)a.{4,5}b', 'acc\nccb', '0', repr('acc\nccb')),
+
+            (')', '', '', regex.error, self.TRAILING_CHARS),           # Unmatched right bracket.
+            ('', '', '0', "''"),    # Empty pattern.
+            ('abc', 'abc', '0', repr('abc')),
+            ('abc', 'xbc', '', repr(None)),
+            ('abc', 'axc', '', repr(None)),
+            ('abc', 'abx', '', repr(None)),
+            ('abc', 'xabcy', '0', repr('abc')),
+            ('abc', 'ababc', '0', repr('abc')),
+            ('ab*c', 'abc', '0', repr('abc')),
+            ('ab*bc', 'abc', '0', repr('abc')),
+
+            ('ab*bc', 'abbc', '0', repr('abbc')),
+            ('ab*bc', 'abbbbc', '0', repr('abbbbc')),
+            ('ab+bc', 'abbc', '0', repr('abbc')),
+            ('ab+bc', 'abc', '', repr(None)),
+            ('ab+bc', 'abq', '', repr(None)),
+            ('ab+bc', 'abbbbc', '0', repr('abbbbc')),
+            ('ab?bc', 'abbc', '0', repr('abbc')),
+            ('ab?bc', 'abc', '0', repr('abc')),
+            ('ab?bc', 'abbbbc', '', repr(None)),
+            ('ab?c', 'abc', '0', repr('abc')),
+
+            ('^abc$', 'abc', '0', repr('abc')),
+            ('^abc$', 'abcc', '', repr(None)),
+            ('^abc', 'abcc', '0', repr('abc')),
+            ('^abc$', 'aabc', '', repr(None)),
+            ('abc$', 'aabc', '0', repr('abc')),
+            ('^', 'abc', '0', repr('')),
+            ('$', 'abc', '0', repr('')),
+            ('a.c', 'abc', '0', repr('abc')),
+            ('a.c', 'axc', '0', repr('axc')),
+            ('a.*c', 'axyzc', '0', repr('axyzc')),
+
+            ('a.*c', 'axyzd', '', repr(None)),
+            ('a[bc]d', 'abc', '', repr(None)),
+            ('a[bc]d', 'abd', '0', repr('abd')),
+            ('a[b-d]e', 'abd', '', repr(None)),
+            ('a[b-d]e', 'ace', '0', repr('ace')),
+            ('a[b-d]', 'aac', '0', repr('ac')),
+            ('a[-b]', 'a-', '0', repr('a-')),
+            ('a[\\-b]', 'a-', '0', repr('a-')),
+            ('a[b-]', 'a-', '0', repr('a-')),
+            ('a[]b', '-', '', regex.error, self.BAD_SET),
+
+            ('a[', '-', '', regex.error, self.BAD_SET),
+            ('a\\', '-', '', regex.error, self.BAD_ESCAPE),
+            ('abc)', '-', '', regex.error, self.TRAILING_CHARS),
+            ('(abc', '-', '', regex.error, self.MISSING_RPAREN),
+            ('a]', 'a]', '0', repr('a]')),
+            ('a[]]b', 'a]b', '0', repr('a]b')),
+            ('a[]]b', 'a]b', '0', repr('a]b')),
+            ('a[^bc]d', 'aed', '0', repr('aed')),
+            ('a[^bc]d', 'abd', '', repr(None)),
+            ('a[^-b]c', 'adc', '0', repr('adc')),
+
+            ('a[^-b]c', 'a-c', '', repr(None)),
+            ('a[^]b]c', 'a]c', '', repr(None)),
+            ('a[^]b]c', 'adc', '0', repr('adc')),
+            ('\\ba\\b', 'a-', '0', repr('a')),
+            ('\\ba\\b', '-a', '0', repr('a')),
+            ('\\ba\\b', '-a-', '0', repr('a')),
+            ('\\by\\b', 'xy', '', repr(None)),
+            ('\\by\\b', 'yz', '', repr(None)),
+            ('\\by\\b', 'xyz', '', repr(None)),
+            ('x\\b', 'xyz', '', repr(None)),
+
+            ('x\\B', 'xyz', '0', repr('x')),
+            ('\\Bz', 'xyz', '0', repr('z')),
+            ('z\\B', 'xyz', '', repr(None)),
+            ('\\Bx', 'xyz', '', repr(None)),
+            ('\\Ba\\B', 'a-', '', repr(None)),
+            ('\\Ba\\B', '-a', '', repr(None)),
+            ('\\Ba\\B', '-a-', '', repr(None)),
+            ('\\By\\B', 'xy', '', repr(None)),
+            ('\\By\\B', 'yz', '', repr(None)),
+            ('\\By\\b', 'xy', '0', repr('y')),
+
+            ('\\by\\B', 'yz', '0', repr('y')),
+            ('\\By\\B', 'xyz', '0', repr('y')),
+            ('ab|cd', 'abc', '0', repr('ab')),
+            ('ab|cd', 'abcd', '0', repr('ab')),
+            ('()ef', 'def', '0,1', repr(('ef', ''))),
+            ('$b', 'b', '', repr(None)),
+            ('a\\(b', 'a(b', '', repr(('a(b',))),
+            ('a\\(*b', 'ab', '0', repr('ab')),
+            ('a\\(*b', 'a((b', '0', repr('a((b')),
+            ('a\\\\b', 'a\\b', '0', repr('a\\b')),
+
+            ('((a))', 'abc', '0,1,2', repr(('a', 'a', 'a'))),
+            ('(a)b(c)', 'abc', '0,1,2', repr(('abc', 'a', 'c'))),
+            ('a+b+c', 'aabbabc', '0', repr('abc')),
+            ('(a+|b)*', 'ab', '0,1', repr(('ab', 'b'))),
+            ('(a+|b)+', 'ab', '0,1', repr(('ab', 'b'))),
+            ('(a+|b)?', 'ab', '0,1', repr(('a', 'a'))),
+            (')(', '-', '', regex.error, self.TRAILING_CHARS),
+            ('[^ab]*', 'cde', '0', repr('cde')),
+            ('abc', '', '', repr(None)),
+            ('a*', '', '0', repr('')),
+
+            ('a|b|c|d|e', 'e', '0', repr('e')),
+            ('(a|b|c|d|e)f', 'ef', '0,1', repr(('ef', 'e'))),
+            ('abcd*efg', 'abcdefg', '0', repr('abcdefg')),
+            ('ab*', 'xabyabbbz', '0', repr('ab')),
+            ('ab*', 'xayabbbz', '0', repr('a')),
+            ('(ab|cd)e', 'abcde', '0,1', repr(('cde', 'cd'))),
+            ('[abhgefdc]ij', 'hij', '0', repr('hij')),
+            ('^(ab|cd)e', 'abcde', '', repr(None)),
+            ('(abc|)ef', 'abcdef', '0,1', repr(('ef', ''))),
+            ('(a|b)c*d', 'abcd', '0,1', repr(('bcd', 'b'))),
+
+            ('(ab|ab*)bc', 'abc', '0,1', repr(('abc', 'a'))),
+            ('a([bc]*)c*', 'abc', '0,1', repr(('abc', 'bc'))),
+            ('a([bc]*)(c*d)', 'abcd', '0,1,2', repr(('abcd', 'bc', 'd'))),
+            ('a([bc]+)(c*d)', 'abcd', '0,1,2', repr(('abcd', 'bc', 'd'))),
+            ('a([bc]*)(c+d)', 'abcd', '0,1,2', repr(('abcd', 'b', 'cd'))),
+            ('a[bcd]*dcdcde', 'adcdcde', '0', repr('adcdcde')),
+            ('a[bcd]+dcdcde', 'adcdcde', '', repr(None)),
+            ('(ab|a)b*c', 'abc', '0,1', repr(('abc', 'ab'))),
+            ('((a)(b)c)(d)', 'abcd', '1,2,3,4', repr(('abc', 'a', 'b', 'd'))),
+            ('[a-zA-Z_][a-zA-Z0-9_]*', 'alpha', '0', repr('alpha')),
+
+            ('^a(bc+|b[eh])g|.h$', 'abh', '0,1', repr(('bh', None))),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'effgz', '0,1,2', repr(('effgz',
+              'effgz', None))),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'ij', '0,1,2', repr(('ij', 'ij',
+              'j'))),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'effg', '', repr(None)),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'bcdd', '', repr(None)),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'reffgz', '0,1,2', repr(('effgz',
+              'effgz', None))),
+            ('(((((((((a)))))))))', 'a', '0', repr('a')),
+            ('multiple words of text', 'uh-uh', '', repr(None)),
+            ('multiple words', 'multiple words, yeah', '0',
+              repr('multiple words')),
+            ('(.*)c(.*)', 'abcde', '0,1,2', repr(('abcde', 'ab', 'de'))),
+
+            ('\\((.*), (.*)\\)', '(a, b)', '2,1', repr(('b', 'a'))),
+            ('[k]', 'ab', '', repr(None)),
+            ('a[-]?c', 'ac', '0', repr('ac')),
+            ('(abc)\\1', 'abcabc', '1', repr('abc')),
+            ('([a-c]*)\\1', 'abcabc', '1', repr('abc')),
+            ('^(.+)?B', 'AB', '1', repr('A')),
+            ('(a+).\\1$', 'aaaaa', '0,1', repr(('aaaaa', 'aa'))),
+            ('^(a+).\\1$', 'aaaa', '', repr(None)),
+            ('(abc)\\1', 'abcabc', '0,1', repr(('abcabc', 'abc'))),
+            ('([a-c]+)\\1', 'abcabc', '0,1', repr(('abcabc', 'abc'))),
+
+            ('(a)\\1', 'aa', '0,1', repr(('aa', 'a'))),
+            ('(a+)\\1', 'aa', '0,1', repr(('aa', 'a'))),
+            ('(a+)+\\1', 'aa', '0,1', repr(('aa', 'a'))),
+            ('(a).+\\1', 'aba', '0,1', repr(('aba', 'a'))),
+            ('(a)ba*\\1', 'aba', '0,1', repr(('aba', 'a'))),
+            ('(aa|a)a\\1$', 'aaa', '0,1', repr(('aaa', 'a'))),
+            ('(a|aa)a\\1$', 'aaa', '0,1', repr(('aaa', 'a'))),
+            ('(a+)a\\1$', 'aaa', '0,1', repr(('aaa', 'a'))),
+            ('([abc]*)\\1', 'abcabc', '0,1', repr(('abcabc', 'abc'))),
+            ('(a)(b)c|ab', 'ab', '0,1,2', repr(('ab', None, None))),
+
+            ('(a)+x', 'aaax', '0,1', repr(('aaax', 'a'))),
+            ('([ac])+x', 'aacx', '0,1', repr(('aacx', 'c'))),
+            ('([^/]*/)*sub1/', 'd:msgs/tdir/sub1/trial/away.cpp', '0,1',
+              repr(('d:msgs/tdir/sub1/', 'tdir/'))),
+            ('([^.]*)\\.([^:]*):[T ]+(.*)', 'track1.title:TBlah blah blah',
+              '0,1,2,3', repr(('track1.title:TBlah blah blah', 'track1',
+              'title', 'Blah blah blah'))),
+            ('([^N]*N)+', 'abNNxyzN', '0,1', repr(('abNNxyzN', 'xyzN'))),
+            ('([^N]*N)+', 'abNNxyz', '0,1', repr(('abNN', 'N'))),
+            ('([abc]*)x', 'abcx', '0,1', repr(('abcx', 'abc'))),
+            ('([abc]*)x', 'abc', '', repr(None)),
+            ('([xyz]*)x', 'abcx', '0,1', repr(('x', ''))),
+            ('(a)+b|aac', 'aac', '0,1', repr(('aac', None))),
+
+            # Test symbolic groups.
+            ('(?P<i d>aaa)a', 'aaaa', '', regex.error, self.BAD_GROUP_NAME),
+            ('(?P<id>aaa)a', 'aaaa', '0,id', repr(('aaaa', 'aaa'))),
+            ('(?P<id>aa)(?P=id)', 'aaaa', '0,id', repr(('aaaa', 'aa'))),
+            ('(?P<id>aa)(?P=xd)', 'aaaa', '', regex.error, self.UNKNOWN_GROUP),
+
+            # Character properties.
+            (ur"\g", u"g", '0', repr(u'g')),
+            (ur"\g<1>", u"g", '', regex.error, self.INVALID_GROUP_REF),
+            (ur"(.)\g<1>", u"gg", '0', repr(u'gg')),
+            (ur"(.)\g<1>", u"gg", '', repr((u'gg', u'g'))),
+            (ur"\N", u"N", '0', repr(u'N')),
+            (ur"\N{LATIN SMALL LETTER A}", u"a", '0', repr(u'a')),
+            (ur"\p", u"p", '0', repr(u'p')),
+            (ur"\p{Ll}", u"a", '0', repr(u'a')),
+            (ur"\P", u"P", '0', repr(u'P')),
+            (ur"\P{Lu}", u"p", '0', repr(u'p')),
+
+            # All tests from Perl.
+            ('abc', 'abc', '0', repr('abc')),
+            ('abc', 'xbc', '', repr(None)),
+            ('abc', 'axc', '', repr(None)),
+            ('abc', 'abx', '', repr(None)),
+            ('abc', 'xabcy', '0', repr('abc')),
+            ('abc', 'ababc', '0', repr('abc')),
+
+            ('ab*c', 'abc', '0', repr('abc')),
+            ('ab*bc', 'abc', '0', repr('abc')),
+            ('ab*bc', 'abbc', '0', repr('abbc')),
+            ('ab*bc', 'abbbbc', '0', repr('abbbbc')),
+            ('ab{0,}bc', 'abbbbc', '0', repr('abbbbc')),
+            ('ab+bc', 'abbc', '0', repr('abbc')),
+            ('ab+bc', 'abc', '', repr(None)),
+            ('ab+bc', 'abq', '', repr(None)),
+            ('ab{1,}bc', 'abq', '', repr(None)),
+            ('ab+bc', 'abbbbc', '0', repr('abbbbc')),
+
+            ('ab{1,}bc', 'abbbbc', '0', repr('abbbbc')),
+            ('ab{1,3}bc', 'abbbbc', '0', repr('abbbbc')),
+            ('ab{3,4}bc', 'abbbbc', '0', repr('abbbbc')),
+            ('ab{4,5}bc', 'abbbbc', '', repr(None)),
+            ('ab?bc', 'abbc', '0', repr('abbc')),
+            ('ab?bc', 'abc', '0', repr('abc')),
+            ('ab{0,1}bc', 'abc', '0', repr('abc')),
+            ('ab?bc', 'abbbbc', '', repr(None)),
+            ('ab?c', 'abc', '0', repr('abc')),
+            ('ab{0,1}c', 'abc', '0', repr('abc')),
+
+            ('^abc$', 'abc', '0', repr('abc')),
+            ('^abc$', 'abcc', '', repr(None)),
+            ('^abc', 'abcc', '0', repr('abc')),
+            ('^abc$', 'aabc', '', repr(None)),
+            ('abc$', 'aabc', '0', repr('abc')),
+            ('^', 'abc', '0', repr('')),
+            ('$', 'abc', '0', repr('')),
+            ('a.c', 'abc', '0', repr('abc')),
+            ('a.c', 'axc', '0', repr('axc')),
+            ('a.*c', 'axyzc', '0', repr('axyzc')),
+
+            ('a.*c', 'axyzd', '', repr(None)),
+            ('a[bc]d', 'abc', '', repr(None)),
+            ('a[bc]d', 'abd', '0', repr('abd')),
+            ('a[b-d]e', 'abd', '', repr(None)),
+            ('a[b-d]e', 'ace', '0', repr('ace')),
+            ('a[b-d]', 'aac', '0', repr('ac')),
+            ('a[-b]', 'a-', '0', repr('a-')),
+            ('a[b-]', 'a-', '0', repr('a-')),
+            ('a[b-a]', '-', '', regex.error, self.BAD_CHAR_RANGE),
+            ('a[]b', '-', '', regex.error, self.BAD_SET),
+
+            ('a[', '-', '', regex.error, self.BAD_SET),
+            ('a]', 'a]', '0', repr('a]')),
+            ('a[]]b', 'a]b', '0', repr('a]b')),
+            ('a[^bc]d', 'aed', '0', repr('aed')),
+            ('a[^bc]d', 'abd', '', repr(None)),
+            ('a[^-b]c', 'adc', '0', repr('adc')),
+            ('a[^-b]c', 'a-c', '', repr(None)),
+            ('a[^]b]c', 'a]c', '', repr(None)),
+            ('a[^]b]c', 'adc', '0', repr('adc')),
+            ('ab|cd', 'abc', '0', repr('ab')),
+
+            ('ab|cd', 'abcd', '0', repr('ab')),
+            ('()ef', 'def', '0,1', repr(('ef', ''))),
+            ('*a', '-', '', regex.error, self.NOTHING_TO_REPEAT),
+            ('(*)b', '-', '', regex.error, self.NOTHING_TO_REPEAT),
+            ('$b', 'b', '', repr(None)),
+            ('a\\', '-', '', regex.error, self.BAD_ESCAPE),
+            ('a\\(b', 'a(b', '', repr(('a(b',))),
+            ('a\\(*b', 'ab', '0', repr('ab')),
+            ('a\\(*b', 'a((b', '0', repr('a((b')),
+            ('a\\\\b', 'a\\b', '0', repr('a\\b')),
+
+            ('abc)', '-', '', regex.error, self.TRAILING_CHARS),
+            ('(abc', '-', '', regex.error, self.MISSING_RPAREN),
+            ('((a))', 'abc', '0,1,2', repr(('a', 'a', 'a'))),
+            ('(a)b(c)', 'abc', '0,1,2', repr(('abc', 'a', 'c'))),
+            ('a+b+c', 'aabbabc', '0', repr('abc')),
+            ('a{1,}b{1,}c', 'aabbabc', '0', repr('abc')),
+            ('a**', '-', '', regex.error, self.MULTIPLE_REPEAT),
+            ('a.+?c', 'abcabc', '0', repr('abc')),
+            ('(a+|b)*', 'ab', '0,1', repr(('ab', 'b'))),
+            ('(a+|b){0,}', 'ab', '0,1', repr(('ab', 'b'))),
+
+            ('(a+|b)+', 'ab', '0,1', repr(('ab', 'b'))),
+            ('(a+|b){1,}', 'ab', '0,1', repr(('ab', 'b'))),
+            ('(a+|b)?', 'ab', '0,1', repr(('a', 'a'))),
+            ('(a+|b){0,1}', 'ab', '0,1', repr(('a', 'a'))),
+            (')(', '-', '', regex.error, self.TRAILING_CHARS),
+            ('[^ab]*', 'cde', '0', repr('cde')),
+            ('abc', '', '', repr(None)),
+            ('a*', '', '0', repr('')),
+            ('([abc])*d', 'abbbcd', '0,1', repr(('abbbcd', 'c'))),
+            ('([abc])*bcd', 'abcd', '0,1', repr(('abcd', 'a'))),
+
+            ('a|b|c|d|e', 'e', '0', repr('e')),
+            ('(a|b|c|d|e)f', 'ef', '0,1', repr(('ef', 'e'))),
+            ('abcd*efg', 'abcdefg', '0', repr('abcdefg')),
+            ('ab*', 'xabyabbbz', '0', repr('ab')),
+            ('ab*', 'xayabbbz', '0', repr('a')),
+            ('(ab|cd)e', 'abcde', '0,1', repr(('cde', 'cd'))),
+            ('[abhgefdc]ij', 'hij', '0', repr('hij')),
+            ('^(ab|cd)e', 'abcde', '', repr(None)),
+            ('(abc|)ef', 'abcdef', '0,1', repr(('ef', ''))),
+            ('(a|b)c*d', 'abcd', '0,1', repr(('bcd', 'b'))),
+
+            ('(ab|ab*)bc', 'abc', '0,1', repr(('abc', 'a'))),
+            ('a([bc]*)c*', 'abc', '0,1', repr(('abc', 'bc'))),
+            ('a([bc]*)(c*d)', 'abcd', '0,1,2', repr(('abcd', 'bc', 'd'))),
+            ('a([bc]+)(c*d)', 'abcd', '0,1,2', repr(('abcd', 'bc', 'd'))),
+            ('a([bc]*)(c+d)', 'abcd', '0,1,2', repr(('abcd', 'b', 'cd'))),
+            ('a[bcd]*dcdcde', 'adcdcde', '0', repr('adcdcde')),
+            ('a[bcd]+dcdcde', 'adcdcde', '', repr(None)),
+            ('(ab|a)b*c', 'abc', '0,1', repr(('abc', 'ab'))),
+            ('((a)(b)c)(d)', 'abcd', '1,2,3,4', repr(('abc', 'a', 'b', 'd'))),
+            ('[a-zA-Z_][a-zA-Z0-9_]*', 'alpha', '0', repr('alpha')),
+
+            ('^a(bc+|b[eh])g|.h$', 'abh', '0,1', repr(('bh', None))),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'effgz', '0,1,2', repr(('effgz',
+              'effgz', None))),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'ij', '0,1,2', repr(('ij', 'ij',
+              'j'))),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'effg', '', repr(None)),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'bcdd', '', repr(None)),
+            ('(bc+d$|ef*g.|h?i(j|k))', 'reffgz', '0,1,2', repr(('effgz',
+              'effgz', None))),
+            ('((((((((((a))))))))))', 'a', '10', repr('a')),
+            ('((((((((((a))))))))))\\10', 'aa', '0', repr('aa')),
+
+            # Python does not have the same rules for \\41 so this is a syntax error
+            #    ('((((((((((a))))))))))\\41', 'aa', '', repr(None)),
+            #    ('((((((((((a))))))))))\\41', 'a!', '0', repr('a!')),
+            ('((((((((((a))))))))))\\41', '', '', regex.error,
+              self.INVALID_GROUP_REF),
+            ('(?i)((((((((((a))))))))))\\41', '', '', regex.error,
+              self.INVALID_GROUP_REF),
+
+            ('(((((((((a)))))))))', 'a', '0', repr('a')),
+            ('multiple words of text', 'uh-uh', '', repr(None)),
+            ('multiple words', 'multiple words, yeah', '0',
+              repr('multiple words')),
+            ('(.*)c(.*)', 'abcde', '0,1,2', repr(('abcde', 'ab', 'de'))),
+            ('\\((.*), (.*)\\)', '(a, b)', '2,1', repr(('b', 'a'))),
+            ('[k]', 'ab', '', repr(None)),
+            ('a[-]?c', 'ac', '0', repr('ac')),
+            ('(abc)\\1', 'abcabc', '1', repr('abc')),
+            ('([a-c]*)\\1', 'abcabc', '1', repr('abc')),
+            ('(?i)abc', 'ABC', '0', repr('ABC')),
+
+            ('(?i)abc', 'XBC', '', repr(None)),
+            ('(?i)abc', 'AXC', '', repr(None)),
+            ('(?i)abc', 'ABX', '', repr(None)),
+            ('(?i)abc', 'XABCY', '0', repr('ABC')),
+            ('(?i)abc', 'ABABC', '0', repr('ABC')),
+            ('(?i)ab*c', 'ABC', '0', repr('ABC')),
+            ('(?i)ab*bc', 'ABC', '0', repr('ABC')),
+            ('(?i)ab*bc', 'ABBC', '0', repr('ABBC')),
+            ('(?i)ab*?bc', 'ABBBBC', '0', repr('ABBBBC')),
+            ('(?i)ab{0,}?bc', 'ABBBBC', '0', repr('ABBBBC')),
+
+            ('(?i)ab+?bc', 'ABBC', '0', repr('ABBC')),
+            ('(?i)ab+bc', 'ABC', '', repr(None)),
+            ('(?i)ab+bc', 'ABQ', '', repr(None)),
+            ('(?i)ab{1,}bc', 'ABQ', '', repr(None)),
+            ('(?i)ab+bc', 'ABBBBC', '0', repr('ABBBBC')),
+            ('(?i)ab{1,}?bc', 'ABBBBC', '0', repr('ABBBBC')),
+            ('(?i)ab{1,3}?bc', 'ABBBBC', '0', repr('ABBBBC')),
+            ('(?i)ab{3,4}?bc', 'ABBBBC', '0', repr('ABBBBC')),
+            ('(?i)ab{4,5}?bc', 'ABBBBC', '', repr(None)),
+            ('(?i)ab??bc', 'ABBC', '0', repr('ABBC')),
+
+            ('(?i)ab??bc', 'ABC', '0', repr('ABC')),
+            ('(?i)ab{0,1}?bc', 'ABC', '0', repr('ABC')),
+            ('(?i)ab??bc', 'ABBBBC', '', repr(None)),
+            ('(?i)ab??c', 'ABC', '0', repr('ABC')),
+            ('(?i)ab{0,1}?c', 'ABC', '0', repr('ABC')),
+            ('(?i)^abc$', 'ABC', '0', repr('ABC')),
+            ('(?i)^abc$', 'ABCC', '', repr(None)),
+            ('(?i)^abc', 'ABCC', '0', repr('ABC')),
+            ('(?i)^abc$', 'AABC', '', repr(None)),
+            ('(?i)abc$', 'AABC', '0', repr('ABC')),
+
+            ('(?i)^', 'ABC', '0', repr('')),
+            ('(?i)$', 'ABC', '0', repr('')),
+            ('(?i)a.c', 'ABC', '0', repr('ABC')),
+            ('(?i)a.c', 'AXC', '0', repr('AXC')),
+            ('(?i)a.*?c', 'AXYZC', '0', repr('AXYZC')),
+            ('(?i)a.*c', 'AXYZD', '', repr(None)),
+            ('(?i)a[bc]d', 'ABC', '', repr(None)),
+            ('(?i)a[bc]d', 'ABD', '0', repr('ABD')),
+            ('(?i)a[b-d]e', 'ABD', '', repr(None)),
+            ('(?i)a[b-d]e', 'ACE', '0', repr('ACE')),
+
+            ('(?i)a[b-d]', 'AAC', '0', repr('AC')),
+            ('(?i)a[-b]', 'A-', '0', repr('A-')),
+            ('(?i)a[b-]', 'A-', '0', repr('A-')),
+            ('(?i)a[b-a]', '-', '', regex.error, self.BAD_CHAR_RANGE),
+            ('(?i)a[]b', '-', '', regex.error, self.BAD_SET),
+            ('(?i)a[', '-', '', regex.error, self.BAD_SET),
+            ('(?i)a]', 'A]', '0', repr('A]')),
+            ('(?i)a[]]b', 'A]B', '0', repr('A]B')),
+            ('(?i)a[^bc]d', 'AED', '0', repr('AED')),
+            ('(?i)a[^bc]d', 'ABD', '', repr(None)),
+
+            ('(?i)a[^-b]c', 'ADC', '0', repr('ADC')),
+            ('(?i)a[^-b]c', 'A-C', '', repr(None)),
+            ('(?i)a[^]b]c', 'A]C', '', repr(None)),
+            ('(?i)a[^]b]c', 'ADC', '0', repr('ADC')),
+            ('(?i)ab|cd', 'ABC', '0', repr('AB')),
+            ('(?i)ab|cd', 'ABCD', '0', repr('AB')),
+            ('(?i)()ef', 'DEF', '0,1', repr(('EF', ''))),
+            ('(?i)*a', '-', '', regex.error, self.NOTHING_TO_REPEAT),
+            ('(?i)(*)b', '-', '', regex.error, self.NOTHING_TO_REPEAT),
+            ('(?i)$b', 'B', '', repr(None)),
+
+            ('(?i)a\\', '-', '', regex.error, self.BAD_ESCAPE),
+            ('(?i)a\\(b', 'A(B', '', repr(('A(B',))),
+            ('(?i)a\\(*b', 'AB', '0', repr('AB')),
+            ('(?i)a\\(*b', 'A((B', '0', repr('A((B')),
+            ('(?i)a\\\\b', 'A\\B', '0', repr('A\\B')),
+            ('(?i)abc)', '-', '', regex.error, self.TRAILING_CHARS),
+            ('(?i)(abc', '-', '', regex.error, self.MISSING_RPAREN),
+            ('(?i)((a))', 'ABC', '0,1,2', repr(('A', 'A', 'A'))),
+            ('(?i)(a)b(c)', 'ABC', '0,1,2', repr(('ABC', 'A', 'C'))),
+            ('(?i)a+b+c', 'AABBABC', '0', repr('ABC')),
+
+            ('(?i)a{1,}b{1,}c', 'AABBABC', '0', repr('ABC')),
+            ('(?i)a**', '-', '', regex.error, self.MULTIPLE_REPEAT),
+            ('(?i)a.+?c', 'ABCABC', '0', repr('ABC')),
+            ('(?i)a.*?c', 'ABCABC', '0', repr('ABC')),
+            ('(?i)a.{0,5}?c', 'ABCABC', '0', repr('ABC')),
+            ('(?i)(a+|b)*', 'AB', '0,1', repr(('AB', 'B'))),
+            ('(?i)(a+|b){0,}', 'AB', '0,1', repr(('AB', 'B'))),
+            ('(?i)(a+|b)+', 'AB', '0,1', repr(('AB', 'B'))),
+            ('(?i)(a+|b){1,}', 'AB', '0,1', repr(('AB', 'B'))),
+            ('(?i)(a+|b)?', 'AB', '0,1', repr(('A', 'A'))),
+
+            ('(?i)(a+|b){0,1}', 'AB', '0,1', repr(('A', 'A'))),
+            ('(?i)(a+|b){0,1}?', 'AB', '0,1', repr(('', None))),
+            ('(?i))(', '-', '', regex.error, self.TRAILING_CHARS),
+            ('(?i)[^ab]*', 'CDE', '0', repr('CDE')),
+            ('(?i)abc', '', '', repr(None)),
+            ('(?i)a*', '', '0', repr('')),
+            ('(?i)([abc])*d', 'ABBBCD', '0,1', repr(('ABBBCD', 'C'))),
+            ('(?i)([abc])*bcd', 'ABCD', '0,1', repr(('ABCD', 'A'))),
+            ('(?i)a|b|c|d|e', 'E', '0', repr('E')),
+            ('(?i)(a|b|c|d|e)f', 'EF', '0,1', repr(('EF', 'E'))),
+
+            ('(?i)abcd*efg', 'ABCDEFG', '0', repr('ABCDEFG')),
+            ('(?i)ab*', 'XABYABBBZ', '0', repr('AB')),
+            ('(?i)ab*', 'XAYABBBZ', '0', repr('A')),
+            ('(?i)(ab|cd)e', 'ABCDE', '0,1', repr(('CDE', 'CD'))),
+            ('(?i)[abhgefdc]ij', 'HIJ', '0', repr('HIJ')),
+            ('(?i)^(ab|cd)e', 'ABCDE', '', repr(None)),
+            ('(?i)(abc|)ef', 'ABCDEF', '0,1', repr(('EF', ''))),
+            ('(?i)(a|b)c*d', 'ABCD', '0,1', repr(('BCD', 'B'))),
+            ('(?i)(ab|ab*)bc', 'ABC', '0,1', repr(('ABC', 'A'))),
+            ('(?i)a([bc]*)c*', 'ABC', '0,1', repr(('ABC', 'BC'))),
+
+            ('(?i)a([bc]*)(c*d)', 'ABCD', '0,1,2', repr(('ABCD', 'BC', 'D'))),
+            ('(?i)a([bc]+)(c*d)', 'ABCD', '0,1,2', repr(('ABCD', 'BC', 'D'))),
+            ('(?i)a([bc]*)(c+d)', 'ABCD', '0,1,2', repr(('ABCD', 'B', 'CD'))),
+            ('(?i)a[bcd]*dcdcde', 'ADCDCDE', '0', repr('ADCDCDE')),
+            ('(?i)a[bcd]+dcdcde', 'ADCDCDE', '', repr(None)),
+            ('(?i)(ab|a)b*c', 'ABC', '0,1', repr(('ABC', 'AB'))),
+            ('(?i)((a)(b)c)(d)', 'ABCD', '1,2,3,4', repr(('ABC', 'A', 'B',
+              'D'))),
+            ('(?i)[a-zA-Z_][a-zA-Z0-9_]*', 'ALPHA', '0', repr('ALPHA')),
+            ('(?i)^a(bc+|b[eh])g|.h$', 'ABH', '0,1', repr(('BH', None))),
+            ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'EFFGZ', '0,1,2', repr(('EFFGZ',
+              'EFFGZ', None))),
+
+            ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'IJ', '0,1,2', repr(('IJ', 'IJ',
+              'J'))),
+            ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'EFFG', '', repr(None)),
+            ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'BCDD', '', repr(None)),
+            ('(?i)(bc+d$|ef*g.|h?i(j|k))', 'REFFGZ', '0,1,2', repr(('EFFGZ',
+              'EFFGZ', None))),
+            ('(?i)((((((((((a))))))))))', 'A', '10', repr('A')),
+            ('(?i)((((((((((a))))))))))\\10', 'AA', '0', repr('AA')),
+            #('(?i)((((((((((a))))))))))\\41', 'AA', '', repr(None)),
+            #('(?i)((((((((((a))))))))))\\41', 'A!', '0', repr('A!')),
+            ('(?i)(((((((((a)))))))))', 'A', '0', repr('A')),
+            ('(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))', 'A', '1',
+              repr('A')),
+            ('(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))', 'C', '1',
+              repr('C')),
+            ('(?i)multiple words of text', 'UH-UH', '', repr(None)),
+
+            ('(?i)multiple words', 'MULTIPLE WORDS, YEAH', '0',
+             repr('MULTIPLE WORDS')),
+            ('(?i)(.*)c(.*)', 'ABCDE', '0,1,2', repr(('ABCDE', 'AB', 'DE'))),
+            ('(?i)\\((.*), (.*)\\)', '(A, B)', '2,1', repr(('B', 'A'))),
+            ('(?i)[k]', 'AB', '', repr(None)),
+        #    ('(?i)abcd', 'ABCD', SUCCEED, 'found+"-"+\\found+"-"+\\\\found', repr(ABCD-$&-\\ABCD)),
+        #    ('(?i)a(bc)d', 'ABCD', SUCCEED, 'g1+"-"+\\g1+"-"+\\\\g1', repr(BC-$1-\\BC)),
+            ('(?i)a[-]?c', 'AC', '0', repr('AC')),
+            ('(?i)(abc)\\1', 'ABCABC', '1', repr('ABC')),
+            ('(?i)([a-c]*)\\1', 'ABCABC', '1', repr('ABC')),
+            ('a(?!b).', 'abad', '0', repr('ad')),
+            ('a(?=d).', 'abad', '0', repr('ad')),
+            ('a(?=c|d).', 'abad', '0', repr('ad')),
+
+            ('a(?:b|c|d)(.)', 'ace', '1', repr('e')),
+            ('a(?:b|c|d)*(.)', 'ace', '1', repr('e')),
+            ('a(?:b|c|d)+?(.)', 'ace', '1', repr('e')),
+            ('a(?:b|(c|e){1,2}?|d)+?(.)', 'ace', '1,2', repr(('c', 'e'))),
+
+            # Lookbehind: split by : but not if it is escaped by -.
+            ('(?<!-):(.*?)(?<!-):', 'a:bc-:de:f', '1', repr('bc-:de')),
+            # Escaping with \ as we know it.
+            ('(?<!\\\):(.*?)(?<!\\\):', 'a:bc\\:de:f', '1', repr('bc\\:de')),
+            # Terminating with ' and escaping with ? as in edifact.
+            ("(?<!\\?)'(.*?)(?<!\\?)'", "a'bc?'de'f", '1', repr("bc?'de")),
+
+            # Comments using the (?#...) syntax.
+
+            ('w(?# comment', 'w', '', regex.error, self.MISSING_RPAREN),
+            ('w(?# comment 1)xy(?# comment 2)z', 'wxyz', '0', repr('wxyz')),
+
+            # Check odd placement of embedded pattern modifiers.
+
+            # Not an error under PCRE/PRE:
+            # When the new behaviour is turned on positional inline flags affect
+            # only what follows.
+            ('w(?i)', 'W', '0', repr('W')),
+            ('w(?iV1)', 'W', '0', repr(None)),
+            ('w(?i)', 'w', '0', repr('w')),
+            ('w(?iV1)', 'w', '0', repr('w')),
+            ('(?i)w', 'W', '0', repr('W')),
+            ('(?iV1)w', 'W', '0', repr('W')),
+
+            # Comments using the x embedded pattern modifier.
+            ("""(?x)w# comment 1
+x y
+# comment 2
+z""", 'wxyz', '0', repr('wxyz')),
+
+            # Using the m embedded pattern modifier.
+            ('^abc', """jkl
+abc
+xyz""", '', repr(None)),
+            ('(?m)^abc', """jkl
+abc
+xyz""", '0', repr('abc')),
+
+            ('(?m)abc$', """jkl
+xyzabc
+123""", '0', repr('abc')),
+
+            # Using the s embedded pattern modifier.
+            ('a.b', 'a\nb', '', repr(None)),
+            ('(?s)a.b', 'a\nb', '0', repr('a\nb')),
+
+            # Test \w, etc. both inside and outside character classes.
+            ('\\w+', '--ab_cd0123--', '0', repr('ab_cd0123')),
+            ('[\\w]+', '--ab_cd0123--', '0', repr('ab_cd0123')),
+            ('\\D+', '1234abc5678', '0', repr('abc')),
+            ('[\\D]+', '1234abc5678', '0', repr('abc')),
+            ('[\\da-fA-F]+', '123abc', '0', repr('123abc')),
+            # Not an error under PCRE/PRE:
+            # ('[\\d-x]', '-', '', regex.error, self.BAD_CHAR_RANGE),
+            (r'([\s]*)([\S]*)([\s]*)', ' testing!1972', '3,2,1', repr(('',
+              'testing!1972', ' '))),
+            (r'(\s*)(\S*)(\s*)', ' testing!1972', '3,2,1', repr(('',
+              'testing!1972', ' '))),
+
+            #
+            # Post-1.5.2 additions.
+
+            # xmllib problem.
+            (r'(([a-z]+):)?([a-z]+)$', 'smil', '1,2,3', repr((None, None,
+              'smil'))),
+            # Bug 110866: reference to undefined group.
+            (r'((.)\1+)', '', '', regex.error, self.OPEN_GROUP),
+            # Bug 111869: search (PRE/PCRE fails on this one, SRE doesn't).
+            (r'.*d', 'abc\nabd', '0', repr('abd')),
+            # Bug 112468: various expected syntax errors.
+            (r'(', '', '', regex.error, self.MISSING_RPAREN),
+            (r'[\41]', '!', '0', repr('!')),
+            # Bug 114033: nothing to repeat.
+            (r'(x?)?', 'x', '0', repr('x')),
+            # Bug 115040: rescan if flags are modified inside pattern.
+            # If the new behaviour is turned on then positional inline flags
+            # affect only what follows.
+            (r' (?x)foo ', 'foo', '0', repr('foo')),
+            (r' (?V1x)foo ', 'foo', '0', repr(None)),
+            (r'(?x) foo ', 'foo', '0', repr('foo')),
+            (r'(?V1x) foo ', 'foo', '0', repr('foo')),
+            (r'(?x)foo ', 'foo', '0', repr('foo')),
+            (r'(?V1x)foo ', 'foo', '0', repr('foo')),
+            # Bug 115618: negative lookahead.
+            (r'(?<!abc)(d.f)', 'abcdefdof', '0', repr('dof')),
+            # Bug 116251: character class bug.
+            (r'[\w-]+', 'laser_beam', '0', repr('laser_beam')),
+            # Bug 123769+127259: non-greedy backtracking bug.
+            (r'.*?\S *:', 'xx:', '0', repr('xx:')),
+            (r'a[ ]*?\ (\d+).*', 'a   10', '0', repr('a   10')),
+            (r'a[ ]*?\ (\d+).*', 'a    10', '0', repr('a    10')),
+            # Bug 127259: \Z shouldn't depend on multiline mode.
+            (r'(?ms).*?x\s*\Z(.*)','xx\nx\n', '1', repr('')),
+            # Bug 128899: uppercase literals under the ignorecase flag.
+            (r'(?i)M+', 'MMM', '0', repr('MMM')),
+            (r'(?i)m+', 'MMM', '0', repr('MMM')),
+            (r'(?i)[M]+', 'MMM', '0', repr('MMM')),
+            (r'(?i)[m]+', 'MMM', '0', repr('MMM')),
+            # Bug 130748: ^* should be an error (nothing to repeat).
+            # In 'regex' we won't bother to complain about this.
+            # (r'^*', '', '', regex.error, self.NOTHING_TO_REPEAT),
+            # Bug 133283: minimizing repeat problem.
+            (r'"(?:\\"|[^"])*?"', r'"\""', '0', repr(r'"\""')),
+            # Bug 477728: minimizing repeat problem.
+            (r'^.*?$', 'one\ntwo\nthree\n', '', repr(None)),
+            # Bug 483789: minimizing repeat problem.
+            (r'a[^>]*?b', 'a>b', '', repr(None)),
+            # Bug 490573: minimizing repeat problem.
+            (r'^a*?$', 'foo', '', repr(None)),
+            # Bug 470582: nested groups problem.
+            (r'^((a)c)?(ab)$', 'ab', '1,2,3', repr((None, None, 'ab'))),
+            # Another minimizing repeat problem (capturing groups in assertions).
+            ('^([ab]*?)(?=(b)?)c', 'abc', '1,2', repr(('ab', None))),
+            ('^([ab]*?)(?!(b))c', 'abc', '1,2', repr(('ab', None))),
+            ('^([ab]*?)(?<!(a))c', 'abc', '1,2', repr(('ab', None))),
+            # Bug 410271: \b broken under locales.
+            (r'\b.\b', 'a', '0', repr('a')),
+            (ur'(?u)\b.\b', u'\N{LATIN CAPITAL LETTER A WITH DIAERESIS}', '0',
+              repr(u'\xc4')),
+            (ur'(?u)\w', u'\N{LATIN CAPITAL LETTER A WITH DIAERESIS}', '0',
+              repr(u'\xc4')),
+        ]
+
+        for t in tests:
+            excval = None
+            try:
+                if len(t) == 4:
+                    pattern, string, groups, expected = t
+                else:
+                    pattern, string, groups, expected, excval = t
+            except ValueError:
+                fields = ", ".join([repr(f) for f in t[ : 3]] + ["..."])
+                self.fail("Incorrect number of test fields: (%s)" % fields)
+            else:
+                group_list = []
+                if groups:
+                    for group in groups.split(","):
+                        try:
+                            group_list.append(int(group))
+                        except ValueError:
+                            group_list.append(group)
+
+                if excval is not None:
+                    self.assertRaisesRegex(expected, excval, regex.search,
+                      pattern, string)
+                else:
+                    m = regex.search(pattern, string)
+                    if m:
+                        if group_list:
+                            actual = repr(m.group(*group_list))
+                        else:
+                            actual = repr(m[:])
+                    else:
+                        actual = repr(m)
+
+                    self.assertEqual(actual, expected)
+
+    def test_replacement(self):
+        self.assertEqual(regex.sub("test\?", "result\?\.\a\q\m\n", "test?"),
+          "result\?\.\a\q\m\n")
+        self.assertEqual(regex.sub(r"test\?", "result\?\.\a\q\m\n", "test?"),
+          "result\?\.\a\q\m\n")
+
+        self.assertEqual(regex.sub('(.)', r"\1\1", 'x'), 'xx')
+        self.assertEqual(regex.sub('(.)', regex.escape(r"\1\1"), 'x'), r"\1\1")
+        self.assertEqual(regex.sub('(.)', r"\\1\\1", 'x'), r"\1\1")
+        self.assertEqual(regex.sub('(.)', lambda m: r"\1\1", 'x'), r"\1\1")
+
+    def test_common_prefix(self):
+        # Very long common prefix
+        all = string.ascii_lowercase + string.digits + string.ascii_uppercase
+        side = all * 4
+        regexp = '(' + side + '|' + side + ')'
+        self.assertEqual(repr(type(regex.compile(regexp))), self.PATTERN_CLASS)
+
+    def test_captures(self):
+        self.assertEqual(regex.search(r"(\w)+", "abc").captures(1), ['a', 'b',
+          'c'])
+        self.assertEqual(regex.search(r"(\w{3})+", "abcdef").captures(0, 1),
+          (['abcdef'], ['abc', 'def']))
+        self.assertEqual(regex.search(r"^(\d{1,3})(?:\.(\d{1,3})){3}$",
+          "192.168.0.1").captures(1, 2), (['192', ], ['168', '0', '1']))
+        self.assertEqual(regex.match(r"^([0-9A-F]{2}){4} ([a-z]\d){5}$",
+          "3FB52A0C a2c4g3k9d3").captures(1, 2), (['3F', 'B5', '2A', '0C'],
+          ['a2', 'c4', 'g3', 'k9', 'd3']))
+        self.assertEqual(regex.match("([a-z]W)([a-z]X)+([a-z]Y)",
+          "aWbXcXdXeXfY").captures(1, 2, 3), (['aW'], ['bX', 'cX', 'dX', 'eX'],
+          ['fY']))
+
+        self.assertEqual(regex.search(r".*?(?=(.)+)b", "ab").captures(1),
+          ['b'])
+        self.assertEqual(regex.search(r".*?(?>(.){0,2})d", "abcd").captures(1),
+          ['b', 'c'])
+        self.assertEqual(regex.search(r"(.)+", "a").captures(1), ['a'])
+
+    def test_guards(self):
+        m = regex.search(r"(X.*?Y\s*){3}(X\s*)+AB:",
+          "XY\nX Y\nX  Y\nXY\nXX AB:")
+        self.assertEqual(m.span(0, 1, 2), ((3, 21), (12, 15), (16, 18)))
+
+        m = regex.search(r"(X.*?Y\s*){3,}(X\s*)+AB:",
+          "XY\nX Y\nX  Y\nXY\nXX AB:")
+        self.assertEqual(m.span(0, 1, 2), ((0, 21), (12, 15), (16, 18)))
+
+        m = regex.search(r'\d{4}(\s*\w)?\W*((?!\d)\w){2}', "9999XX")
+        self.assertEqual(m.span(0, 1, 2), ((0, 6), (-1, -1), (5, 6)))
+
+        m = regex.search(r'A\s*?.*?(\n+.*?\s*?){0,2}\(X', 'A\n1\nS\n1 (X')
+        self.assertEqual(m.span(0, 1), ((0, 10), (5, 8)))
+
+        m = regex.search('Derde\s*:', 'aaaaaa:\nDerde:')
+        self.assertEqual(m.span(), (8, 14))
+        m = regex.search('Derde\s*:', 'aaaaa:\nDerde:')
+        self.assertEqual(m.span(), (7, 13))
+
+    def test_turkic(self):
+        # Turkish has dotted and dotless I/i.
+        pairs = u"I=i;I=\u0131;i=\u0130"
+
+        all_chars = set()
+        matching = set()
+        for pair in pairs.split(";"):
+            ch1, ch2 = pair.split("=")
+            all_chars.update((ch1, ch2))
+            matching.add((ch1, ch1))
+            matching.add((ch1, ch2))
+            matching.add((ch2, ch1))
+            matching.add((ch2, ch2))
+
+        for ch1 in all_chars:
+            for ch2 in all_chars:
+                m = regex.match(ur"(?iu)\A" + ch1 + ur"\Z", ch2)
+                if m:
+                    if (ch1, ch2) not in matching:
+                        self.fail("%s matching %s" % (repr(ch1), repr(ch2)))
+                else:
+                    if (ch1, ch2) in matching:
+                        self.fail("%s not matching %s" % (repr(ch1),
+                          repr(ch2)))
+
+    def test_named_lists(self):
+        options = [u"one", u"two", u"three"]
+        self.assertEqual(regex.match(ur"333\L<bar>444", u"333one444",
+          bar=options).group(), u"333one444")
+        self.assertEqual(regex.match(ur"(?i)333\L<bar>444", u"333TWO444",
+          bar=options).group(), u"333TWO444")
+        self.assertEqual(regex.match(ur"333\L<bar>444", u"333four444",
+          bar=options), None)
+
+        options = ["one", "two", "three"]
+        self.assertEqual(regex.match(r"333\L<bar>444", "333one444",
+          bar=options).group(), "333one444")
+        self.assertEqual(regex.match(r"(?i)333\L<bar>444", "333TWO444",
+          bar=options).group(), "333TWO444")
+        self.assertEqual(regex.match(r"333\L<bar>444", "333four444",
+          bar=options), None)
+
+        self.assertEqual(repr(type(regex.compile(r"3\L<bar>4\L<bar>+5",
+          bar=["one", "two", "three"]))), self.PATTERN_CLASS)
+
+        self.assertEqual(regex.findall(r"^\L<options>", "solid QWERT",
+          options=set(['good', 'brilliant', '+s\\ol[i}d'])), [])
+        self.assertEqual(regex.findall(r"^\L<options>", "+solid QWERT",
+          options=set(['good', 'brilliant', '+solid'])), ['+solid'])
+
+        options = [u"STRASSE"]
+        self.assertEqual(regex.match(ur"(?fiu)\L<words>",
+          u"stra\N{LATIN SMALL LETTER SHARP S}e", words=options).span(), (0,
+          6))
+
+        options = [u"STRASSE", u"stress"]
+        self.assertEqual(regex.match(ur"(?fiu)\L<words>",
+          u"stra\N{LATIN SMALL LETTER SHARP S}e", words=options).span(), (0,
+          6))
+
+        options = [u"stra\N{LATIN SMALL LETTER SHARP S}e"]
+        self.assertEqual(regex.match(ur"(?fiu)\L<words>", u"STRASSE",
+          words=options).span(), (0, 7))
+
+        options = ["kit"]
+        self.assertEqual(regex.search(ur"(?iu)\L<words>", u"SKITS",
+          words=options).span(), (1, 4))
+        self.assertEqual(regex.search(ur"(?iu)\L<words>",
+          u"SK\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}TS",
+          words=options).span(), (1, 4))
+
+        self.assertEqual(regex.search(ur"(?fiu)\b(\w+) +\1\b",
+          u" stra\N{LATIN SMALL LETTER SHARP S}e STRASSE ").span(), (1, 15))
+        self.assertEqual(regex.search(ur"(?fiu)\b(\w+) +\1\b",
+          u" STRASSE stra\N{LATIN SMALL LETTER SHARP S}e ").span(), (1, 15))
+
+        self.assertEqual(regex.search(r"^\L<options>$", "", options=[]).span(),
+          (0, 0))
+
+    def test_fuzzy(self):
+        # Some tests borrowed from TRE library tests.
+        self.assertEqual(repr(type(regex.compile('(fou){s,e<=1}'))),
+          self.PATTERN_CLASS)
+        self.assertEqual(repr(type(regex.compile('(fuu){s}'))),
+          self.PATTERN_CLASS)
+        self.assertEqual(repr(type(regex.compile('(fuu){s,e}'))),
+          self.PATTERN_CLASS)
+        self.assertEqual(repr(type(regex.compile('(anaconda){1i+1d<1,s<=1}'))),
+          self.PATTERN_CLASS)
+        self.assertEqual(repr(type(regex.compile('(anaconda){1i+1d<1,s<=1,e<=10}'))),
+          self.PATTERN_CLASS)
+        self.assertEqual(repr(type(regex.compile('(anaconda){s<=1,e<=1,1i+1d<1}'))),
+          self.PATTERN_CLASS)
+
+        text = 'molasses anaconda foo bar baz smith anderson '
+        self.assertEqual(regex.search('(znacnda){s<=1,e<=3,1i+1d<1}', text),
+          None)
+        self.assertEqual(regex.search('(znacnda){s<=1,e<=3,1i+1d<2}',
+          text).span(0, 1), ((9, 17), (9, 17)))
+        self.assertEqual(regex.search('(ananda){1i+1d<2}', text), None)
+        self.assertEqual(regex.search(r"(?:\bznacnda){e<=2}", text)[0],
+          "anaconda")
+        self.assertEqual(regex.search(r"(?:\bnacnda){e<=2}", text)[0],
+          "anaconda")
+
+        text = 'anaconda foo bar baz smith anderson'
+        self.assertEqual(regex.search('(fuu){i<=3,d<=3,e<=5}', text).span(0,
+          1), ((0, 0), (0, 0)))
+        self.assertEqual(regex.search('(?b)(fuu){i<=3,d<=3,e<=5}',
+          text).span(0, 1), ((9, 10), (9, 10)))
+        self.assertEqual(regex.search('(fuu){i<=2,d<=2,e<=5}', text).span(0,
+          1), ((7, 10), (7, 10)))
+        self.assertEqual(regex.search('(?e)(fuu){i<=2,d<=2,e<=5}',
+          text).span(0, 1), ((9, 10), (9, 10)))
+        self.assertEqual(regex.search('(fuu){i<=3,d<=3,e}', text).span(0, 1),
+          ((0, 0), (0, 0)))
+        self.assertEqual(regex.search('(?b)(fuu){i<=3,d<=3,e}', text).span(0,
+          1), ((9, 10), (9, 10)))
+
+        self.assertEqual(repr(type(regex.compile('(approximate){s<=3,1i+1d<3}'))),
+          self.PATTERN_CLASS)
+
+        # No cost limit.
+        self.assertEqual(regex.search('(foobar){e}',
+          'xirefoabralfobarxie').span(0, 1), ((0, 6), (0, 6)))
+        self.assertEqual(regex.search('(?e)(foobar){e}',
+          'xirefoabralfobarxie').span(0, 1), ((0, 3), (0, 3)))
+        self.assertEqual(regex.search('(?b)(foobar){e}',
+          'xirefoabralfobarxie').span(0, 1), ((11, 16), (11, 16)))
+
+        # At most two errors.
+        self.assertEqual(regex.search('(foobar){e<=2}',
+          'xirefoabrzlfd').span(0, 1), ((4, 9), (4, 9)))
+        self.assertEqual(regex.search('(foobar){e<=2}', 'xirefoabzlfd'), None)
+
+        # At most two inserts or substitutions and max two errors total.
+        self.assertEqual(regex.search('(foobar){i<=2,s<=2,e<=2}',
+          'oobargoobaploowap').span(0, 1), ((5, 11), (5, 11)))
+
+        # Find best whole word match for "foobar".
+        self.assertEqual(regex.search('\\b(foobar){e}\\b', 'zfoobarz').span(0,
+          1), ((0, 8), (0, 8)))
+        self.assertEqual(regex.search('\\b(foobar){e}\\b',
+          'boing zfoobarz goobar woop').span(0, 1), ((0, 6), (0, 6)))
+        self.assertEqual(regex.search('(?b)\\b(foobar){e}\\b',
+          'boing zfoobarz goobar woop').span(0, 1), ((15, 21), (15, 21)))
+
+        # Match whole string, allow only 1 error.
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'foobar').span(0, 1),
+          ((0, 6), (0, 6)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'xfoobar').span(0,
+          1), ((0, 7), (0, 7)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'foobarx').span(0,
+          1), ((0, 7), (0, 7)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'fooxbar').span(0,
+          1), ((0, 7), (0, 7)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'foxbar').span(0, 1),
+          ((0, 6), (0, 6)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'xoobar').span(0, 1),
+          ((0, 6), (0, 6)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'foobax').span(0, 1),
+          ((0, 6), (0, 6)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'oobar').span(0, 1),
+          ((0, 5), (0, 5)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'fobar').span(0, 1),
+          ((0, 5), (0, 5)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'fooba').span(0, 1),
+          ((0, 5), (0, 5)))
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'xfoobarx'), None)
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'foobarxx'), None)
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'xxfoobar'), None)
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'xfoxbar'), None)
+        self.assertEqual(regex.search('^(foobar){e<=1}$', 'foxbarx'), None)
+
+        # At most one insert, two deletes, and three substitutions.
+        # Additionally, deletes cost two and substitutes one, and total
+        # cost must be less than 4.
+        self.assertEqual(regex.search('(foobar){i<=1,d<=2,s<=3,2d+1s<4}',
+          '3oifaowefbaoraofuiebofasebfaobfaorfeoaro').span(0, 1), ((6, 13), (6,
+          13)))
+        self.assertEqual(regex.search('(?b)(foobar){i<=1,d<=2,s<=3,2d+1s<4}',
+          '3oifaowefbaoraofuiebofasebfaobfaorfeoaro').span(0, 1), ((34, 39),
+          (34, 39)))
+
+        # Partially fuzzy matches.
+        self.assertEqual(regex.search('foo(bar){e<=1}zap', 'foobarzap').span(0,
+          1), ((0, 9), (3, 6)))
+        self.assertEqual(regex.search('foo(bar){e<=1}zap', 'fobarzap'), None)
+        self.assertEqual(regex.search('foo(bar){e<=1}zap', 'foobrzap').span(0,
+          1), ((0, 8), (3, 5)))
+
+        text = ('www.cnn.com 64.236.16.20\nwww.slashdot.org 66.35.250.150\n'
+          'For useful information, use www.slashdot.org\nthis is demo data!\n')
+        self.assertEqual(regex.search(r'(?s)^.*(dot.org){e}.*$', text).span(0,
+          1), ((0, 120), (120, 120)))
+        self.assertEqual(regex.search(r'(?es)^.*(dot.org){e}.*$', text).span(0,
+          1), ((0, 120), (93, 100)))
+        self.assertEqual(regex.search(r'^.*(dot.org){e}.*$', text).span(0, 1),
+          ((0, 119), (24, 101)))
+
+        # Behaviour is unexpected, but arguably not wrong. It first finds the
+        # best match, then the best in what follows, etc.
+        self.assertEqual(regex.findall(r"\b\L<words>{e<=1}\b",
+          " book cot dog desk ", words="cat dog".split()), ["cot", "dog"])
+        self.assertEqual(regex.findall(r"\b\L<words>{e<=1}\b",
+          " book dog cot desk ", words="cat dog".split()), [" dog", "cot"])
+        self.assertEqual(regex.findall(r"(?e)\b\L<words>{e<=1}\b",
+          " book dog cot desk ", words="cat dog".split()), ["dog", "cot"])
+        self.assertEqual(regex.findall(r"(?r)\b\L<words>{e<=1}\b",
+          " book cot dog desk ", words="cat dog".split()), ["dog ", "cot"])
+        self.assertEqual(regex.findall(r"(?er)\b\L<words>{e<=1}\b",
+          " book cot dog desk ", words="cat dog".split()), ["dog", "cot"])
+        self.assertEqual(regex.findall(r"(?r)\b\L<words>{e<=1}\b",
+          " book dog cot desk ", words="cat dog".split()), ["cot", "dog"])
+        self.assertEqual(regex.findall(ur"\b\L<words>{e<=1}\b",
+          u" book cot dog desk ", words=u"cat dog".split()), [u"cot", u"dog"])
+        self.assertEqual(regex.findall(ur"\b\L<words>{e<=1}\b",
+          u" book dog cot desk ", words=u"cat dog".split()), [u" dog", u"cot"])
+        self.assertEqual(regex.findall(ur"(?e)\b\L<words>{e<=1}\b",
+          u" book dog cot desk ", words=u"cat dog".split()), [u"dog", u"cot"])
+        self.assertEqual(regex.findall(ur"(?r)\b\L<words>{e<=1}\b",
+          u" book cot dog desk ", words=u"cat dog".split()), [u"dog ", u"cot"])
+        self.assertEqual(regex.findall(ur"(?er)\b\L<words>{e<=1}\b",
+          u" book cot dog desk ", words=u"cat dog".split()), [u"dog", u"cot"])
+        self.assertEqual(regex.findall(ur"(?r)\b\L<words>{e<=1}\b",
+          u" book dog cot desk ", words=u"cat dog".split()), [u"cot", u"dog"])
+
+        self.assertEqual(regex.search(r"(\w+) (\1{e<=1})", "foo fou").groups(),
+          ("foo", "fou"))
+        self.assertEqual(regex.search(r"(?r)(\2{e<=1}) (\w+)",
+          "foo fou").groups(), ("foo", "fou"))
+        self.assertEqual(regex.search(ur"(\w+) (\1{e<=1})",
+          u"foo fou").groups(), (u"foo", u"fou"))
+
+        self.assertEqual(regex.findall(r"(?:(?:QR)+){e}","abcde"), ["abcde",
+          ""])
+        self.assertEqual(regex.findall(r"(?:Q+){e}","abc"), ["abc", ""])
+
+        # Hg issue 41.
+        self.assertEqual(regex.match(r"(?:service detection){0<e<5}",
+          "servic detection").span(), (0, 16))
+        self.assertEqual(regex.match(r"(?:service detection){0<e<5}",
+          "service detect").span(), (0, 14))
+        self.assertEqual(regex.match(r"(?:service detection){0<e<5}",
+          "service detecti").span(), (0, 15))
+        self.assertEqual(regex.match(r"(?:service detection){0<e<5}",
+          "service detection"), None)
+        self.assertEqual(regex.match(r"(?:service detection){0<e<5}",
+          "in service detection").span(), (0, 20))
+
+        # Hg issue 109.
+        self.assertEqual(regex.fullmatch(r"(?:cats|cat){e<=1}",
+          "cat").fuzzy_counts, (0, 0, 1))
+        self.assertEqual(regex.fullmatch(r"(?e)(?:cats|cat){e<=1}",
+          "cat").fuzzy_counts, (0, 0, 0))
+
+        self.assertEqual(regex.fullmatch(r"(?:cat|cats){e<=1}",
+          "cats").fuzzy_counts, (0, 1, 0))
+        self.assertEqual(regex.fullmatch(r"(?e)(?:cat|cats){e<=1}",
+          "cats").fuzzy_counts, (0, 0, 0))
+
+        self.assertEqual(regex.fullmatch(r"(?:cat){e<=1} (?:cat){e<=1}",
+          "cat cot").fuzzy_counts, (1, 0, 0))
+
+    def test_recursive(self):
+        self.assertEqual(regex.search(r"(\w)(?:(?R)|(\w?))\1", "xx")[ : ],
+          ("xx", "x", ""))
+        self.assertEqual(regex.search(r"(\w)(?:(?R)|(\w?))\1", "aba")[ : ],
+          ("aba", "a", "b"))
+        self.assertEqual(regex.search(r"(\w)(?:(?R)|(\w?))\1", "abba")[ : ],
+          ("abba", "a", None))
+        self.assertEqual(regex.search(r"(\w)(?:(?R)|(\w?))\1", "kayak")[ : ],
+          ("kayak", "k", None))
+        self.assertEqual(regex.search(r"(\w)(?:(?R)|(\w?))\1", "paper")[ : ],
+          ("pap", "p", "a"))
+        self.assertEqual(regex.search(r"(\w)(?:(?R)|(\w?))\1", "dontmatchme"),
+          None)
+
+        self.assertEqual(regex.search(r"(?r)\2(?:(\w?)|(?R))(\w)", "xx")[ : ],
+          ("xx", "", "x"))
+        self.assertEqual(regex.search(r"(?r)\2(?:(\w?)|(?R))(\w)", "aba")[ : ],
+          ("aba", "b", "a"))
+        self.assertEqual(regex.search(r"(?r)\2(?:(\w?)|(?R))(\w)", "abba")[ :
+          ], ("abba", None, "a"))
+        self.assertEqual(regex.search(r"(?r)\2(?:(\w?)|(?R))(\w)", "kayak")[ :
+          ], ("kayak", None, "k"))
+        self.assertEqual(regex.search(r"(?r)\2(?:(\w?)|(?R))(\w)", "paper")[ :
+          ], ("pap", "a", "p"))
+        self.assertEqual(regex.search(r"(?r)\2(?:(\w?)|(?R))(\w)",
+          "dontmatchme"), None)
+
+        self.assertEqual(regex.search(r"\(((?>[^()]+)|(?R))*\)", "(ab(cd)ef)")[
+          : ], ("(ab(cd)ef)", "ef"))
+        self.assertEqual(regex.search(r"\(((?>[^()]+)|(?R))*\)",
+          "(ab(cd)ef)").captures(1), ["ab", "cd", "(cd)", "ef"])
+
+        self.assertEqual(regex.search(r"(?r)\(((?R)|(?>[^()]+))*\)",
+          "(ab(cd)ef)")[ : ], ("(ab(cd)ef)", "ab"))
+        self.assertEqual(regex.search(r"(?r)\(((?R)|(?>[^()]+))*\)",
+          "(ab(cd)ef)").captures(1), ["ef", "cd", "(cd)", "ab"])
+
+        self.assertEqual(regex.search(r"\(([^()]+|(?R))*\)",
+          "some text (a(b(c)d)e) more text")[ : ], ("(a(b(c)d)e)", "e"))
+
+        self.assertEqual(regex.search(r"(?r)\(((?R)|[^()]+)*\)",
+          "some text (a(b(c)d)e) more text")[ : ], ("(a(b(c)d)e)", "a"))
+
+        self.assertEqual(regex.search(r"(foo(\(((?:(?>[^()]+)|(?2))*)\)))",
+          "foo(bar(baz)+baz(bop))")[ : ], ("foo(bar(baz)+baz(bop))",
+          "foo(bar(baz)+baz(bop))", "(bar(baz)+baz(bop))",
+          "bar(baz)+baz(bop)"))
+
+        self.assertEqual(regex.search(r"(?r)(foo(\(((?:(?2)|(?>[^()]+))*)\)))",
+          "foo(bar(baz)+baz(bop))")[ : ], ("foo(bar(baz)+baz(bop))",
+          "foo(bar(baz)+baz(bop))", "(bar(baz)+baz(bop))",
+          "bar(baz)+baz(bop)"))
+
+        rgx = regex.compile(r"""^\s*(<\s*([a-zA-Z:]+)(?:\s*[a-zA-Z:]*\s*=\s*(?:'[^']*'|"[^"]*"))*\s*(/\s*)?>(?:[^<>]*|(?1))*(?(3)|<\s*/\s*\2\s*>))\s*$""")
+        self.assertEqual(bool(rgx.search('<foo><bar></bar></foo>')), True)
+        self.assertEqual(bool(rgx.search('<foo><bar></foo></bar>')), False)
+        self.assertEqual(bool(rgx.search('<foo><bar/></foo>')), True)
+        self.assertEqual(bool(rgx.search('<foo><bar></foo>')), False)
+        self.assertEqual(bool(rgx.search('<foo bar=baz/>')), False)
+
+        self.assertEqual(bool(rgx.search('<foo bar="baz">')), False)
+        self.assertEqual(bool(rgx.search('<foo bar="baz"/>')), True)
+        self.assertEqual(bool(rgx.search('<    fooo   /  >')), True)
+        # The next regex should and does match. Perl 5.14 agrees.
+        #self.assertEqual(bool(rgx.search('<foo/>foo')), False)
+        self.assertEqual(bool(rgx.search('foo<foo/>')), False)
+
+        self.assertEqual(bool(rgx.search('<foo>foo</foo>')), True)
+        self.assertEqual(bool(rgx.search('<foo><bar/>foo</foo>')), True)
+        self.assertEqual(bool(rgx.search('<a><b><c></c></b></a>')), True)
+
+    def test_copy(self):
+        # PatternObjects are immutable, therefore there's no need to clone them.
+        r = regex.compile("a")
+        self.assert_(copy.copy(r) is r)
+        self.assert_(copy.deepcopy(r) is r)
+
+        # MatchObjects are normally mutable because the target string can be
+        # detached. However, after the target string has been detached, a
+        # MatchObject becomes immutable, so there's no need to clone it.
+        m = r.match("a")
+        self.assert_(copy.copy(m) is not m)
+        self.assert_(copy.deepcopy(m) is not m)
+
+        self.assert_(m.string is not None)
+        m2 = copy.copy(m)
+        m2.detach_string()
+        self.assert_(m.string is not None)
+        self.assert_(m2.string is None)
+
+        # The following behaviour matches that of the re module.
+        it = regex.finditer(".", "ab")
+        it2 = copy.copy(it)
+        self.assertEqual(it.next().group(), "a")
+        self.assertEqual(it2.next().group(), "b")
+
+        # The following behaviour matches that of the re module.
+        it = regex.finditer(".", "ab")
+        it2 = copy.deepcopy(it)
+        self.assertEqual(it.next().group(), "a")
+        self.assertEqual(it2.next().group(), "b")
+
+        # The following behaviour is designed to match that of copying 'finditer'.
+        it = regex.splititer(" ", "a b")
+        it2 = copy.copy(it)
+        self.assertEqual(it.next(), "a")
+        self.assertEqual(it2.next(), "b")
+
+        # The following behaviour is designed to match that of copying 'finditer'.
+        it = regex.splititer(" ", "a b")
+        it2 = copy.deepcopy(it)
+        self.assertEqual(it.next(), "a")
+        self.assertEqual(it2.next(), "b")
+
+    def test_format(self):
+        self.assertEqual(regex.subf(r"(\w+) (\w+)", "{0} => {2} {1}",
+          "foo bar"), "foo bar => bar foo")
+        self.assertEqual(regex.subf(r"(?<word1>\w+) (?<word2>\w+)",
+          "{word2} {word1}", "foo bar"), "bar foo")
+
+        self.assertEqual(regex.subfn(r"(\w+) (\w+)", "{0} => {2} {1}",
+          "foo bar"), ("foo bar => bar foo", 1))
+        self.assertEqual(regex.subfn(r"(?<word1>\w+) (?<word2>\w+)",
+          "{word2} {word1}", "foo bar"), ("bar foo", 1))
+
+        self.assertEqual(regex.match(r"(\w+) (\w+)",
+          "foo bar").expandf("{0} => {2} {1}"), "foo bar => bar foo")
+
+    def test_fullmatch(self):
+        self.assertEqual(bool(regex.fullmatch(r"abc", "abc")), True)
+        self.assertEqual(bool(regex.fullmatch(r"abc", "abcx")), False)
+        self.assertEqual(bool(regex.fullmatch(r"abc", "abcx", endpos=3)), True)
+
+        self.assertEqual(bool(regex.fullmatch(r"abc", "xabc", pos=1)), True)
+        self.assertEqual(bool(regex.fullmatch(r"abc", "xabcy", pos=1)), False)
+        self.assertEqual(bool(regex.fullmatch(r"abc", "xabcy", pos=1,
+          endpos=4)), True)
+
+        self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "abc")), True)
+        self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "abcx")), False)
+        self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "abcx", endpos=3)),
+          True)
+
+        self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "xabc", pos=1)),
+          True)
+        self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "xabcy", pos=1)),
+          False)
+        self.assertEqual(bool(regex.fullmatch(r"(?r)abc", "xabcy", pos=1,
+          endpos=4)), True)
+
+    def test_hg_bugs(self):
+        # Hg issue 28.
+        self.assertEqual(bool(regex.compile("(?>b)", flags=regex.V1)), True)
+
+        # Hg issue 29.
+        self.assertEqual(bool(regex.compile(r"^((?>\w+)|(?>\s+))*$",
+          flags=regex.V1)), True)
+
+        # Hg issue 31.
+        self.assertEqual(regex.findall(r"\((?:(?>[^()]+)|(?R))*\)",
+          "a(bcd(e)f)g(h)"), ['(bcd(e)f)', '(h)'])
+        self.assertEqual(regex.findall(r"\((?:(?:[^()]+)|(?R))*\)",
+          "a(bcd(e)f)g(h)"), ['(bcd(e)f)', '(h)'])
+        self.assertEqual(regex.findall(r"\((?:(?>[^()]+)|(?R))*\)",
+          "a(b(cd)e)f)g)h"), ['(b(cd)e)'])
+        self.assertEqual(regex.findall(r"\((?:(?>[^()]+)|(?R))*\)",
+          "a(bc(d(e)f)gh"), ['(d(e)f)'])
+        self.assertEqual(regex.findall(r"(?r)\((?:(?>[^()]+)|(?R))*\)",
+          "a(bc(d(e)f)gh"), ['(d(e)f)'])
+        self.assertEqual([m.group() for m in
+          regex.finditer(r"\((?:[^()]*+|(?0))*\)", "a(b(c(de)fg)h")],
+          ['(c(de)fg)'])
+
+        # Hg issue 32.
+        self.assertEqual(regex.search("a(bc)d", "abcd", regex.I |
+          regex.V1).group(0), "abcd")
+
+        # Hg issue 33.
+        self.assertEqual(regex.search("([\da-f:]+)$", "E", regex.I |
+          regex.V1).group(0), "E")
+        self.assertEqual(regex.search("([\da-f:]+)$", "e", regex.I |
+          regex.V1).group(0), "e")
+
+        # Hg issue 34.
+        self.assertEqual(regex.search("^(?=ab(de))(abd)(e)", "abde").groups(),
+          ('de', 'abd', 'e'))
+
+        # Hg issue 35.
+        self.assertEqual(bool(regex.match(r"\ ", " ", flags=regex.X)), True)
+
+        # Hg issue 36.
+        self.assertEqual(regex.search(r"^(a|)\1{2}b", "b").group(0, 1), ('b',
+          ''))
+
+        # Hg issue 37.
+        self.assertEqual(regex.search("^(a){0,0}", "abc").group(0, 1), ('',
+          None))
+
+        # Hg issue 38.
+        self.assertEqual(regex.search("(?>.*/)b", "a/b").group(0), "a/b")
+
+        # Hg issue 39.
+        self.assertEqual(regex.search(r"(?V0)((?i)blah)\s+\1",
+          "blah BLAH").group(0, 1), ("blah BLAH", "blah"))
+        self.assertEqual(regex.search(r"(?V1)((?i)blah)\s+\1", "blah BLAH"),
+          None)
+
+        # Hg issue 40.
+        self.assertEqual(regex.search(r"(\()?[^()]+(?(1)\)|)",
+          "(abcd").group(0), "abcd")
+
+        # Hg issue 42.
+        self.assertEqual(regex.search("(a*)*", "a").span(1), (1, 1))
+        self.assertEqual(regex.search("(a*)*", "aa").span(1), (2, 2))
+        self.assertEqual(regex.search("(a*)*", "aaa").span(1), (3, 3))
+
+        # Hg issue 43.
+        self.assertEqual(regex.search("a(?#xxx)*", "aaa").group(), "aaa")
+
+        # Hg issue 44.
+        self.assertEqual(regex.search("(?=abc){3}abc", "abcabcabc").span(), (0,
+          3))
+
+        # Hg issue 45.
+        self.assertEqual(regex.search("^(?:a(?:(?:))+)+", "a").span(), (0, 1))
+        self.assertEqual(regex.search("^(?:a(?:(?:))+)+", "aa").span(), (0, 2))
+
+        # Hg issue 46.
+        self.assertEqual(regex.search("a(?x: b c )d", "abcd").group(0), "abcd")
+
+        # Hg issue 47.
+        self.assertEqual(regex.search("a#comment\n*", "aaa",
+          flags=regex.X).group(0), "aaa")
+
+        # Hg issue 48.
+        self.assertEqual(regex.search(r"(?V1)(a(?(1)\1)){1}",
+          "aaaaaaaaaa").span(0, 1), ((0, 1), (0, 1)))
+        self.assertEqual(regex.search(r"(?V1)(a(?(1)\1)){2}",
+          "aaaaaaaaaa").span(0, 1), ((0, 3), (1, 3)))
+        self.assertEqual(regex.search(r"(?V1)(a(?(1)\1)){3}",
+          "aaaaaaaaaa").span(0, 1), ((0, 6), (3, 6)))
+        self.assertEqual(regex.search(r"(?V1)(a(?(1)\1)){4}",
+          "aaaaaaaaaa").span(0, 1), ((0, 10), (6, 10)))
+
+        # Hg issue 49.
+        self.assertEqual(regex.search("(?V1)(a)(?<=b(?1))", "baz").group(0),
+          "a")
+
+        # Hg issue 50.
+        self.assertEqual(regex.findall(ur'(?fi)\L<keywords>',
+          u'POST, Post, post, po\u017Ft, po\uFB06, and po\uFB05',
+          keywords=['post','pos']), [u'POST', u'Post', u'post', u'po\u017Ft',
+          u'po\uFB06', u'po\uFB05'])
+        self.assertEqual(regex.findall(ur'(?fi)pos|post',
+          u'POST, Post, post, po\u017Ft, po\uFB06, and po\uFB05'), [u'POS',
+          u'Pos', u'pos', u'po\u017F', u'po\uFB06', u'po\uFB05'])
+        self.assertEqual(regex.findall(ur'(?fi)post|pos',
+          u'POST, Post, post, po\u017Ft, po\uFB06, and po\uFB05'), [u'POST',
+          u'Post', u'post', u'po\u017Ft', u'po\uFB06', u'po\uFB05'])
+        self.assertEqual(regex.findall(ur'(?fi)post|another',
+          u'POST, Post, post, po\u017Ft, po\uFB06, and po\uFB05'), [u'POST',
+          u'Post', u'post', u'po\u017Ft', u'po\uFB06', u'po\uFB05'])
+
+        # Hg issue 51.
+        self.assertEqual(regex.search("(?V1)((a)(?1)|(?2))", "a").group(0, 1,
+          2), ('a', 'a', None))
+
+        # Hg issue 52.
+        self.assertEqual(regex.search(r"(?V1)(\1xx|){6}", "xx").span(0, 1),
+          ((0, 2), (2, 2)))
+
+        # Hg issue 53.
+        self.assertEqual(regex.search("(a|)+", "a").group(0, 1), ("a", ""))
+
+        # Hg issue 54.
+        self.assertEqual(regex.search(r"(a|)*\d", "a" * 80), None)
+
+        # Hg issue 55.
+        self.assertEqual(regex.search("^(?:a?b?)*$", "ac"), None)
+
+        # Hg issue 58.
+        self.assertRaisesRegex(regex.error, self.UNDEF_CHAR_NAME, lambda:
+          regex.compile("\\N{1}"))
+
+        # Hg issue 59.
+        self.assertEqual(regex.search("\\Z", "a\na\n").span(0), (4, 4))
+
+        # Hg issue 60.
+        self.assertEqual(regex.search("(q1|.)*(q2|.)*(x(a|bc)*y){2,}",
+          "xayxay").group(0), "xayxay")
+
+        # Hg issue 61.
+        self.assertEqual(regex.search("(?i)[^a]", "A"), None)
+
+        # Hg issue 63.
+        self.assertEqual(regex.search(u"(?iu)[[:ascii:]]", u"\N{KELVIN SIGN}"),
+          None)
+
+        # Hg issue 66.
+        self.assertEqual(regex.search("((a|b(?1)c){3,5})", "baaaaca").group(0,
+          1, 2), ('aaaa', 'aaaa', 'a'))
+
+        # Hg issue 71.
+        self.assertEqual(regex.findall(r"(?<=:\S+ )\w+", ":9 abc :10 def"),
+          ['abc', 'def'])
+        self.assertEqual(regex.findall(r"(?<=:\S* )\w+", ":9 abc :10 def"),
+          ['abc', 'def'])
+        self.assertEqual(regex.findall(r"(?<=:\S+? )\w+", ":9 abc :10 def"),
+          ['abc', 'def'])
+        self.assertEqual(regex.findall(r"(?<=:\S*? )\w+", ":9 abc :10 def"),
+          ['abc', 'def'])
+
+        # Hg issue 73.
+        self.assertEqual(regex.search(r"(?:fe)?male", "female").group(),
+          "female")
+        self.assertEqual([m.group() for m in
+          regex.finditer(r"(fe)?male: h(?(1)(er)|(is)) (\w+)",
+          "female: her dog; male: his cat. asdsasda")], ['female: her dog',
+          'male: his cat'])
+
+        # Hg issue 78.
+        self.assertEqual(regex.search(r'(?<rec>\((?:[^()]++|(?&rec))*\))',
+          'aaa(((1+0)+1)+1)bbb').captures('rec'), ['(1+0)', '((1+0)+1)',
+          '(((1+0)+1)+1)'])
+
+        # Hg issue 80.
+        self.assertRaisesRegex(regex.error, self.BAD_ESCAPE, lambda:
+          regex.sub('x', '\\', 'x'), )
+
+        # Hg issue 82.
+        fz = "(CAGCCTCCCATTTCAGAATATACATCC){1<e<=2}"
+        seq = "tcagacgagtgcgttgtaaaacgacggccagtCAGCCTCCCATTCAGAATATACATCCcgacggccagttaaaaacaatgccaaggaggtcatagctgtttcctgccagttaaaaacaatgccaaggaggtcatagctgtttcctgacgcactcgtctgagcgggctggcaagg"
+        self.assertEqual(regex.search(fz, seq, regex.BESTMATCH)[0],
+          "tCAGCCTCCCATTCAGAATATACATCC")
+
+        # Hg issue 83.
+        self.assertEqual(regex.findall(r"c..+/c", "cA/c\ncAb/c"), ['cAb/c'])
+
+        # Hg issue 85.
+        self.assertEqual(repr(regex.sub(ur"(?u)(\w+)", ur"[\1]",
+          u'\u0905\u0928\u094d\u200d\u0928 \u0d28\u0d4d\u200d \u0915\u093f\u0928',
+          regex.WORD)),
+          repr(u'[\u0905\u0928\u094d\u200d\u0928] [\u0d28\u0d4d\u200d] [\u0915\u093f\u0928]'))
+
+        # Hg issue 88.
+        self.assertEqual(regex.match(r".*a.*ba.*aa", "ababba"), None)
+
+        # Hg issue 87.
+        self.assertEqual(regex.match(r'(?<x>a(?<x>b))', "ab").spans("x"), [(1,
+          2), (0, 2)])
+
+        # Hg issue 91.
+        # Check that the replacement cache works.
+        self.assertEqual(regex.sub(r'(-)', lambda m: m.expand(r'x'), 'a-b-c'),
+          'axbxc')
+
+        # Hg issue 94.
+        rx = regex.compile(r'\bt(est){i<2}', flags=regex.V1)
+        self.assertEqual(rx.search("Some text"), None)
+        self.assertEqual(rx.findall("Some text"), [])
+
+        # Hg issue 95.
+        self.assertRaisesRegex(regex.error, self.MULTIPLE_REPEAT, lambda:
+          regex.compile(r'.???'))
+
+        # Hg issue 97.
+        self.assertEqual(regex.escape(u'foo!?'), u'foo\\!\\?')
+        self.assertEqual(regex.escape(u'foo!?', special_only=True), u'foo!\\?')
+
+        self.assertEqual(regex.escape('foo!?'), 'foo\\!\\?')
+        self.assertEqual(regex.escape('foo!?', special_only=True),
+          'foo!\\?')
+
+        # Hg issue 100.
+        self.assertEqual(regex.search('^([^z]*(?:WWWi|W))?$',
+          'WWWi').groups(), ('WWWi', ))
+        self.assertEqual(regex.search('^([^z]*(?:WWWi|w))?$',
+          'WWWi').groups(), ('WWWi', ))
+        self.assertEqual(regex.search('^([^z]*?(?:WWWi|W))?$',
+          'WWWi').groups(), ('WWWi', ))
+
+        # Hg issue 101.
+        pat = regex.compile(r'xxx', flags=regex.FULLCASE | regex.UNICODE)
+        self.assertEqual([x.group() for x in pat.finditer('yxxx')], ['xxx'])
+        self.assertEqual(pat.findall('yxxx'), ['xxx'])
+
+        raw = 'yxxx'
+        self.assertEqual([x.group() for x in pat.finditer(raw)], ['xxx'])
+        self.assertEqual(pat.findall(raw), ['xxx'])
+
+        pat = regex.compile(r'xxx', flags=regex.FULLCASE | regex.IGNORECASE |
+          regex.UNICODE)
+        self.assertEqual([x.group() for x in pat.finditer('yxxx')], ['xxx'])
+        self.assertEqual(pat.findall('yxxx'), ['xxx'])
+
+        raw = 'yxxx'
+        self.assertEqual([x.group() for x in pat.finditer(raw)], ['xxx'])
+        self.assertEqual(pat.findall(raw), ['xxx'])
+
+        # Hg issue 106.
+        self.assertEqual(regex.sub('(?V0).*', 'x', 'test'), 'x')
+        self.assertEqual(regex.sub('(?V1).*', 'x', 'test'), 'xx')
+
+        self.assertEqual(regex.sub('(?V0).*?', '|', 'test'), '|t|e|s|t|')
+        self.assertEqual(regex.sub('(?V1).*?', '|', 'test'), '|||||||||')
+
+        # Hg issue 112.
+        self.assertEqual(regex.sub(r'^(@)\n(?!.*?@)(.*)',
+          r'\1\n==========\n\2', '@\n', flags=regex.DOTALL), '@\n==========\n')
+
+        # Hg issue 109.
+        self.assertEqual(regex.match(r'(?:cats|cat){e<=1}',
+         'caz').fuzzy_counts, (1, 0, 0))
+        self.assertEqual(regex.match(r'(?e)(?:cats|cat){e<=1}',
+          'caz').fuzzy_counts, (1, 0, 0))
+        self.assertEqual(regex.match(r'(?b)(?:cats|cat){e<=1}',
+          'caz').fuzzy_counts, (1, 0, 0))
+
+        self.assertEqual(regex.match(r'(?:cat){e<=1}', 'caz').fuzzy_counts,
+          (1, 0, 0))
+        self.assertEqual(regex.match(r'(?e)(?:cat){e<=1}',
+          'caz').fuzzy_counts, (1, 0, 0))
+        self.assertEqual(regex.match(r'(?b)(?:cat){e<=1}',
+          'caz').fuzzy_counts, (1, 0, 0))
+
+        self.assertEqual(regex.match(r'(?:cats){e<=2}', 'c ats').fuzzy_counts,
+          (1, 1, 0))
+        self.assertEqual(regex.match(r'(?e)(?:cats){e<=2}',
+          'c ats').fuzzy_counts, (0, 1, 0))
+        self.assertEqual(regex.match(r'(?b)(?:cats){e<=2}',
+          'c ats').fuzzy_counts, (0, 1, 0))
+
+        self.assertEqual(regex.match(r'(?:cats){e<=2}',
+          'c a ts').fuzzy_counts, (0, 2, 0))
+        self.assertEqual(regex.match(r'(?e)(?:cats){e<=2}',
+          'c a ts').fuzzy_counts, (0, 2, 0))
+        self.assertEqual(regex.match(r'(?b)(?:cats){e<=2}',
+          'c a ts').fuzzy_counts, (0, 2, 0))
+
+        self.assertEqual(regex.match(r'(?:cats){e<=1}', 'c ats').fuzzy_counts,
+          (0, 1, 0))
+        self.assertEqual(regex.match(r'(?e)(?:cats){e<=1}',
+          'c ats').fuzzy_counts, (0, 1, 0))
+        self.assertEqual(regex.match(r'(?b)(?:cats){e<=1}',
+          'c ats').fuzzy_counts, (0, 1, 0))
+
+        # Hg issue 115.
+        self.assertEqual(regex.findall(r'\bof ([a-z]+) of \1\b',
+          'To make use of one of these modules'), [])
+
+        # Hg issue 125.
+        self.assertEqual(regex.sub(r'x', r'\g<0>', 'x'), 'x')
+
+        # Unreported issue: no such builtin as 'ascii' in Python 2.
+        self.assertEqual(bool(regex.match(r'a', 'a', regex.DEBUG)), True)
+
+        # Hg issue 131.
+        self.assertEqual(regex.findall(r'(?V1)[[b-e]--cd]', 'abcdef'), ['b',
+          'e'])
+        self.assertEqual(regex.findall(r'(?V1)[b-e--cd]', 'abcdef'), ['b',
+          'e'])
+        self.assertEqual(regex.findall(r'(?V1)[[bcde]--cd]', 'abcdef'), ['b',
+          'e'])
+        self.assertEqual(regex.findall(r'(?V1)[bcde--cd]', 'abcdef'), ['b',
+          'e'])
+
+        # Hg issue 132.
+        self.assertRaisesRegex(regex.error, '^unknown property at position 4$',
+          lambda: regex.compile(ur'\p{}'))
+
+        # Issue 23692.
+        self.assertEqual(regex.match('(?:()|(?(1)()|z)){2}(?(2)a|z)',
+          'a').group(0, 1, 2), ('a', '', ''))
+        self.assertEqual(regex.match('(?:()|(?(1)()|z)){0,2}(?(2)a|z)',
+          'a').group(0, 1, 2), ('a', '', ''))
+
+        # Hg issue 137: Posix character class :punct: does not seem to be
+        # supported.
+
+        # Posix compatibility as recommended here:
+        # http://www.unicode.org/reports/tr18/#Compatibility_Properties
+
+        # Posix in Unicode.
+        chars = u''.join(unichr(c) for c in range(0x10000))
+
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:alnum:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)[\p{Alpha}\p{PosixDigit}]+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:alpha:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)\p{Alpha}+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:ascii:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)[\p{InBasicLatin}]+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:blank:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)[\p{gc=Space_Separator}\t]+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:cntrl:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)\p{gc=Control}+''', chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:digit:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)[0-9]+''', chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:graph:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)[^\p{Space}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:lower:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)\p{Lower}+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:print:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?uV1)[\p{Graph}\p{Blank}--\p{Cntrl}]+''', chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:punct:]]+''',
+          chars))),
+          repr(u''.join(regex.findall(ur'''(?uV1)[\p{gc=Punctuation}\p{gc=Symbol}--\p{Alpha}]+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:space:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)\p{Whitespace}+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:upper:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)\p{Upper}+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:word:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)[\p{Alpha}\p{gc=Mark}\p{Digit}\p{gc=Connector_Punctuation}\p{Join_Control}]+''',
+          chars))))
+        self.assertEqual(repr(u''.join(regex.findall(ur'''(?u)[[:xdigit:]]+''',
+          chars))), repr(u''.join(regex.findall(ur'''(?u)[0-9A-Fa-f]+''',
+          chars))))
+
+        # Posix in ASCII.
+        chars = ''.join(chr(c) for c in range(0x100))
+
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:alnum:]]+''',
+          chars))), repr(''.join(regex.findall(r'''[\p{Alpha}\p{PosixDigit}]+''',
+          chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:alpha:]]+''',
+          chars))), repr(''.join(regex.findall(r'''\p{Alpha}+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:ascii:]]+''',
+          chars))), repr(''.join(regex.findall(r'''[\x00-\x7F]+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:blank:]]+''',
+          chars))), repr(''.join(regex.findall(r'''[\p{gc=Space_Separator}\t]+''',
+          chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:cntrl:]]+''',
+          chars))), repr(''.join(regex.findall(r'''\p{gc=Control}+''',
+          chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:digit:]]+''',
+          chars))), repr(''.join(regex.findall(r'''[0-9]+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:graph:]]+''',
+          chars))), repr(''.join(regex.findall(r'''[^\p{Space}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:lower:]]+''',
+          chars))), repr(''.join(regex.findall(r'''\p{Lower}+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:print:]]+''',
+          chars))), repr(''.join(regex.findall(r'''(?V1)[\p{Graph}\p{Blank}--\p{Cntrl}]+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:punct:]]+''',
+          chars))), repr(''.join(regex.findall(r'''(?V1)[\p{gc=Punctuation}\p{gc=Symbol}--\p{Alpha}]+''',
+          chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:space:]]+''',
+          chars))), repr(''.join(regex.findall(r'''\p{Whitespace}+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:upper:]]+''',
+          chars))), repr(''.join(regex.findall(r'''\p{Upper}+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:word:]]+''',
+          chars))), repr(''.join(regex.findall(r'''[\p{Alpha}\p{gc=Mark}\p{Digit}\p{gc=Connector_Punctuation}\p{Join_Control}]+''', chars))))
+        self.assertEqual(repr(''.join(regex.findall(r'''[[:xdigit:]]+''',
+          chars))), repr(''.join(regex.findall(r'''[0-9A-Fa-f]+''', chars))))
+
+        # Hg issue 138: grapheme anchored search not working properly.
+        self.assertEqual(repr(regex.search(ur'(?u)\X$', u'ab\u2103').group()),
+          repr(u'\u2103'))
+
+        # Hg issue 139: Regular expression with multiple wildcards where first
+        # should match empty string does not always work.
+        self.assertEqual(regex.search("([^L]*)([^R]*R)", "LtR").groups(), ('',
+          'LtR'))
+
+        # Hg issue 140: Replace with REVERSE and groups has unexpected
+        # behavior.
+        self.assertEqual(regex.sub(r'(.)', r'x\1y', 'ab'), 'xayxby')
+        self.assertEqual(regex.sub(r'(?r)(.)', r'x\1y', 'ab'), 'xayxby')
+
+        # Hg issue 141: Crash on a certain partial match.
+        self.assertEqual(regex.fullmatch('(a)*abc', 'ab',
+          partial=True).span(), (0, 2))
+        self.assertEqual(regex.fullmatch('(a)*abc', 'ab',
+          partial=True).partial, True)
+
+        # Hg Issue #143: Partial matches have incorrect span if prefix is '.'
+        # wildcard.
+        self.assertEqual(regex.search('OXRG', 'OOGOX', partial=True).span(),
+          (3, 5))
+        self.assertEqual(regex.search('.XRG', 'OOGOX', partial=True).span(),
+          (3, 5))
+        self.assertEqual(regex.search('.{1,3}XRG', 'OOGOX',
+          partial=True).span(), (1, 5))
+
+        # Hg issue 144: Latest version problem with matching 'R|R'.
+        self.assertEqual(regex.match('R|R', 'R').span(), (0, 1))
+
+        # Hg issue 146: Forced-fail (?!) works improperly in conditional.
+        self.assertEqual(regex.match(r'(.)(?(1)(?!))', 'xy'), None)
+
+        # Groups cleared after failure.
+        self.assertEqual(regex.findall(r'(y)?(\d)(?(1)\b\B)', 'ax1y2z3b'),
+          [('', '1'), ('', '2'), ('', '3')])
+        self.assertEqual(regex.findall(r'(y)?+(\d)(?(1)\b\B)', 'ax1y2z3b'),
+          [('', '1'), ('', '2'), ('', '3')])
+
+        # Hg issue 147: Fuzzy match can return match points beyond buffer end.
+        self.assertEqual([m.span() for m in
+          regex.finditer(r'(?i)(?:error){e}', 'regex failure')], [(0, 5), (5,
+          10), (10, 13), (13, 13)])
+        self.assertEqual([m.span() for m in
+          regex.finditer(r'(?fi)(?:error){e}', 'regex failure')], [(0, 5), (5,
+          10), (10, 13), (13, 13)])
+
+        # Hg issue 151: Request: \K.
+        self.assertEqual(regex.search(r'(ab\Kcd)', 'abcd').group(0, 1), ('cd',
+          'abcd'))
+        self.assertEqual(regex.findall(r'\w\w\K\w\w', 'abcdefgh'), ['cd',
+          'gh'])
+        self.assertEqual(regex.findall(r'(\w\w\K\w\w)', 'abcdefgh'), ['abcd',
+          'efgh'])
+
+        self.assertEqual(regex.search(r'(?r)(ab\Kcd)', 'abcd').group(0, 1),
+          ('ab', 'abcd'))
+        self.assertEqual(regex.findall(r'(?r)\w\w\K\w\w', 'abcdefgh'), ['ef',
+          'ab'])
+        self.assertEqual(regex.findall(r'(?r)(\w\w\K\w\w)', 'abcdefgh'),
+          ['efgh', 'abcd'])
+
+        # Hg issue 153: Request: (*SKIP).
+        self.assertEqual(regex.search(r'12(*FAIL)|3', '123')[0], '3')
+        self.assertEqual(regex.search(r'(?r)12(*FAIL)|3', '123')[0], '3')
+
+        self.assertEqual(regex.search(r'\d+(*PRUNE)\d', '123'), None)
+        self.assertEqual(regex.search(r'\d+(?=(*PRUNE))\d', '123')[0], '123')
+        self.assertEqual(regex.search(r'\d+(*PRUNE)bcd|[3d]', '123bcd')[0],
+          '123bcd')
+        self.assertEqual(regex.search(r'\d+(*PRUNE)bcd|[3d]', '123zzd')[0],
+          'd')
+        self.assertEqual(regex.search(r'\d+?(*PRUNE)bcd|[3d]', '123bcd')[0],
+          '3bcd')
+        self.assertEqual(regex.search(r'\d+?(*PRUNE)bcd|[3d]', '123zzd')[0],
+          'd')
+        self.assertEqual(regex.search(r'\d++(?<=3(*PRUNE))zzd|[4d]$',
+          '123zzd')[0], '123zzd')
+        self.assertEqual(regex.search(r'\d++(?<=3(*PRUNE))zzd|[4d]$',
+          '124zzd')[0], 'd')
+        self.assertEqual(regex.search(r'\d++(?<=(*PRUNE)3)zzd|[4d]$',
+          '124zzd')[0], 'd')
+        self.assertEqual(regex.search(r'\d++(?<=2(*PRUNE)3)zzd|[3d]$',
+          '124zzd')[0], 'd')
+
+        self.assertEqual(regex.search(r'(?r)\d(*PRUNE)\d+', '123'), None)
+        self.assertEqual(regex.search(r'(?r)\d(?<=(*PRUNE))\d+', '123')[0],
+          '123')
+        self.assertEqual(regex.search(r'(?r)\d+(*PRUNE)bcd|[3d]',
+          '123bcd')[0], '123bcd')
+        self.assertEqual(regex.search(r'(?r)\d+(*PRUNE)bcd|[3d]',
+          '123zzd')[0], 'd')
+        self.assertEqual(regex.search(r'(?r)\d++(?<=3(*PRUNE))zzd|[4d]$',
+          '123zzd')[0], '123zzd')
+        self.assertEqual(regex.search(r'(?r)\d++(?<=3(*PRUNE))zzd|[4d]$',
+          '124zzd')[0], 'd')
+        self.assertEqual(regex.search(r'(?r)\d++(?<=(*PRUNE)3)zzd|[4d]$',
+          '124zzd')[0], 'd')
+        self.assertEqual(regex.search(r'(?r)\d++(?<=2(*PRUNE)3)zzd|[3d]$',
+          '124zzd')[0], 'd')
+
+        self.assertEqual(regex.search(r'\d+(*SKIP)bcd|[3d]', '123bcd')[0],
+          '123bcd')
+        self.assertEqual(regex.search(r'\d+(*SKIP)bcd|[3d]', '123zzd')[0],
+          'd')
+        self.assertEqual(regex.search(r'\d+?(*SKIP)bcd|[3d]', '123bcd')[0],
+          '3bcd')
+        self.assertEqual(regex.search(r'\d+?(*SKIP)bcd|[3d]', '123zzd')[0],
+          'd')
+        self.assertEqual(regex.search(r'\d++(?<=3(*SKIP))zzd|[4d]$',
+          '123zzd')[0], '123zzd')
+        self.assertEqual(regex.search(r'\d++(?<=3(*SKIP))zzd|[4d]$',
+          '124zzd')[0], 'd')
+        self.assertEqual(regex.search(r'\d++(?<=(*SKIP)3)zzd|[4d]$',
+          '124zzd')[0], 'd')
+        self.assertEqual(regex.search(r'\d++(?<=2(*SKIP)3)zzd|[3d]$',
+          '124zzd')[0], 'd')
+
+        self.assertEqual(regex.search(r'(?r)\d+(*SKIP)bcd|[3d]', '123bcd')[0],
+          '123bcd')
+        self.assertEqual(regex.search(r'(?r)\d+(*SKIP)bcd|[3d]', '123zzd')[0],
+          'd')
+        self.assertEqual(regex.search(r'(?r)\d++(?<=3(*SKIP))zzd|[4d]$',
+          '123zzd')[0], '123zzd')
+        self.assertEqual(regex.search(r'(?r)\d++(?<=3(*SKIP))zzd|[4d]$',
+          '124zzd')[0], 'd')
+        self.assertEqual(regex.search(r'(?r)\d++(?<=(*SKIP)3)zzd|[4d]$',
+          '124zzd')[0], 'd')
+        self.assertEqual(regex.search(r'(?r)\d++(?<=2(*SKIP)3)zzd|[3d]$',
+          '124zzd')[0], 'd')
+
+        # Hg issue 152: Request: Request: (?(DEFINE)...).
+        self.assertEqual(regex.search(r'(?(DEFINE)(?<quant>\d+)(?<item>\w+))(?&quant) (?&item)',
+          '5 elephants')[0], '5 elephants')
+
+        # Hg issue 150: Have an option for POSIX-compatible longest match of
+        # alternates.
+        self.assertEqual(regex.search(r'(?p)\d+(\w(\d*)?|[eE]([+-]\d+))',
+          '10b12')[0], '10b12')
+        self.assertEqual(regex.search(r'(?p)\d+(\w(\d*)?|[eE]([+-]\d+))',
+          '10E+12')[0], '10E+12')
+
+        self.assertEqual(regex.search(r'(?p)(\w|ae|oe|ue|ss)', 'ae')[0], 'ae')
+        self.assertEqual(regex.search(r'(?p)one(self)?(selfsufficient)?',
+          'oneselfsufficient')[0], 'oneselfsufficient')
+
+        # Hg issue 156: regression on atomic grouping
+        self.assertEqual(regex.match('1(?>2)', '12').span(), (0, 2))
+
+        # Hg issue 157: regression: segfault on complex lookaround
+        self.assertEqual(regex.match(r'(?V1w)(?=(?=[^A-Z]*+[A-Z])(?=[^a-z]*+[a-z]))(?=\D*+\d)(?=\p{Alphanumeric}*+\P{Alphanumeric})\A(?s:.){8,255}+\Z',
+          'AAaa11!!')[0], 'AAaa11!!')
+
+        # Hg issue 158: Group issue with (?(DEFINE)...)
+        TEST_REGEX = regex.compile(r'''(?smx)
+(?(DEFINE)
+  (?<subcat>
+   ^,[^,]+,
+   )
+)
+
+# Group 2 is defined on this line
+^,([^,]+),
+
+(?:(?!(?&subcat)[\r\n]+(?&subcat)).)+
+''')
+
+        TEST_DATA = '''
+,Cat 1,
+,Brand 1,
+some
+thing
+,Brand 2,
+other
+things
+,Cat 2,
+,Brand,
+Some
+thing
+'''
+
+        self.assertEqual([m.span(1, 2) for m in
+          TEST_REGEX.finditer(TEST_DATA)], [((-1, -1), (2, 7)), ((-1, -1), (54,
+          59))])
+
+        # Hg issue 161: Unexpected fuzzy match results
+        self.assertEqual(regex.search('(abcdefgh){e}',
+          '******abcdefghijklmnopqrtuvwxyz', regex.BESTMATCH).span(), (6, 14))
+        self.assertEqual(regex.search('(abcdefghi){e}',
+          '******abcdefghijklmnopqrtuvwxyz', regex.BESTMATCH).span(), (6, 15))
+
+        # Hg issue 163: allow lookarounds in conditionals.
+        self.assertEqual(regex.match(r'(?:(?=\d)\d+\b|\w+)', '123abc').span(),
+          (0, 6))
+        self.assertEqual(regex.match(r'(?(?=\d)\d+\b|\w+)', '123abc'), None)
+        self.assertEqual(regex.search(r'(?(?<=love\s)you|(?<=hate\s)her)',
+          "I love you").span(), (7, 10))
+        self.assertEqual(regex.findall(r'(?(?<=love\s)you|(?<=hate\s)her)',
+          "I love you but I don't hate her either"), ['you', 'her'])
+
+        # Hg issue #180: bug of POSIX matching.
+        self.assertEqual(regex.search(r'(?p)a*(.*?)', 'aaabbb').group(0, 1),
+          ('aaabbb', 'bbb'))
+        self.assertEqual(regex.search(r'(?p)a*(.*)', 'aaabbb').group(0, 1),
+          ('aaabbb', 'bbb'))
+        self.assertEqual(regex.sub(r'(?p)a*(.*?)', r'\1', 'aaabbb'), 'bbb')
+        self.assertEqual(regex.sub(r'(?p)a*(.*)', r'\1', 'aaabbb'), 'bbb')
+
+    def test_subscripted_captures(self):
+        self.assertEqual(regex.match(r'(?P<x>.)+',
+          'abc').expandf('{0} {0[0]} {0[-1]}'), 'abc abc abc')
+        self.assertEqual(regex.match(r'(?P<x>.)+',
+          'abc').expandf('{1} {1[0]} {1[1]} {1[2]} {1[-1]} {1[-2]} {1[-3]}'),
+          'c a b c c b a')
+        self.assertEqual(regex.match(r'(?P<x>.)+',
+          'abc').expandf('{x} {x[0]} {x[1]} {x[2]} {x[-1]} {x[-2]} {x[-3]}'),
+          'c a b c c b a')
+
+        self.assertEqual(regex.subf(r'(?P<x>.)+', r'{0} {0[0]} {0[-1]}',
+          'abc'), 'abc abc abc')
+        self.assertEqual(regex.subf(r'(?P<x>.)+',
+          '{1} {1[0]} {1[1]} {1[2]} {1[-1]} {1[-2]} {1[-3]}', 'abc'),
+          'c a b c c b a')
+        self.assertEqual(regex.subf(r'(?P<x>.)+',
+          '{x} {x[0]} {x[1]} {x[2]} {x[-1]} {x[-2]} {x[-3]}', 'abc'),
+          'c a b c c b a')
+
+if not hasattr(str, "format"):
+    # Strings don't have the .format method (below Python 2.6).
+    del RegexTests.test_format
+    del RegexTests.test_subscripted_captures
+
+def test_main():
+    run_unittest(RegexTests)
+
+if __name__ == "__main__":
+    test_main()
-- 
GitLab