From d7396896b55a88b2cbea364a8bc6205bb4e8ec66 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 03:35:11 -0700 Subject: [PATCH] Added in regex matching with fuzzy matching. Shows now display Indexer absolute numbering. Improved speed of parsing search results. Fixed episode naming issues. --- gui/slick/interfaces/default/displayShow.tmpl | 5 +- lib/fuzzywuzzy/StringMatcher.py | 78 + lib/fuzzywuzzy/__init__.py | 0 lib/fuzzywuzzy/fuzz.py | 263 + lib/fuzzywuzzy/process.py | 119 + lib/fuzzywuzzy/string_processing.py | 41 + lib/fuzzywuzzy/utils.py | 76 + lib/regex/Python25/__init__.py | 1 + lib/regex/Python25/_regex.pyd | Bin 0 -> 302080 bytes lib/regex/Python26/__init__.py | 1 + lib/regex/Python26/_regex.pyd | Bin 0 -> 304128 bytes lib/regex/Python27/__init__.py | 1 + lib/regex/Python27/_regex.pyd | Bin 0 -> 304128 bytes lib/regex/__init__.py | 1 + lib/regex/_regex.c | 22557 ++++++++++++++++ lib/regex/_regex.h | 228 + lib/regex/_regex_core.py | 4086 +++ lib/regex/_regex_unicode.c | 12748 +++++++++ lib/regex/_regex_unicode.h | 218 + lib/regex/regex.py | 684 + lib/regex/test_regex.py | 3230 +++ sickbeard/name_parser/parser.py | 231 +- sickbeard/naming.py | 37 +- sickbeard/properFinder.py | 4 +- sickbeard/providers/generic.py | 4 +- sickbeard/tv.py | 37 +- 26 files changed, 44507 insertions(+), 143 deletions(-) create mode 100644 lib/fuzzywuzzy/StringMatcher.py create mode 100644 lib/fuzzywuzzy/__init__.py create mode 100644 lib/fuzzywuzzy/fuzz.py create mode 100644 lib/fuzzywuzzy/process.py create mode 100644 lib/fuzzywuzzy/string_processing.py create mode 100644 lib/fuzzywuzzy/utils.py create mode 100644 lib/regex/Python25/__init__.py create mode 100644 lib/regex/Python25/_regex.pyd create mode 100644 lib/regex/Python26/__init__.py create mode 100644 lib/regex/Python26/_regex.pyd create mode 100644 lib/regex/Python27/__init__.py create mode 100644 lib/regex/Python27/_regex.pyd 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_core.py create mode 100644 lib/regex/_regex_unicode.c create mode 100644 lib/regex/_regex_unicode.h create mode 100644 lib/regex/regex.py create mode 100644 lib/regex/test_regex.py diff --git a/gui/slick/interfaces/default/displayShow.tmpl b/gui/slick/interfaces/default/displayShow.tmpl index 74316b3f..5d592dee 100644 --- a/gui/slick/interfaces/default/displayShow.tmpl +++ b/gui/slick/interfaces/default/displayShow.tmpl @@ -302,7 +302,7 @@

#if int($epResult["season"]) == 0 then "Specials" else "Season "+str($epResult["season"])#

- NFOTBNEpisode#if $scene then "Scene #" else ""# #if $scene_anime then "Scene Absolute #" else ""#NameAirdateFilename#if $sickbeard.USE_SUBTITLES and $show.subtitles then "Subtitles" else ""#StatusSearch + NFOTBNEpisode#if $show.is_anime then "Absolute" else ""# #if $scene then "Scene #" else ""# #if $scene_anime then "Scene Absolute" else ""#NameAirdateFilename#if $sickbeard.USE_SUBTITLES and $show.subtitles then "Subtitles" else ""#StatusSearch #set $curSeason = int($epResult["season"]) #end if @@ -317,6 +317,9 @@ \"Y" \"Y" $epResult["episode"] + #if $show.is_anime: + $epResult["absolute_number"] + #end if #if $scene: diff --git a/lib/fuzzywuzzy/StringMatcher.py b/lib/fuzzywuzzy/StringMatcher.py new file mode 100644 index 00000000..9dccfe7e --- /dev/null +++ b/lib/fuzzywuzzy/StringMatcher.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +StringMatcher.py + +ported from python-Levenshtein +[https://github.com/miohtama/python-Levenshtein] +""" + +from Levenshtein import * +from warnings import warn + +class StringMatcher: + """A SequenceMatcher-like class built on the top of Levenshtein""" + + def _reset_cache(self): + self._ratio = self._distance = None + self._opcodes = self._editops = self._matching_blocks = None + + def __init__(self, isjunk=None, seq1='', seq2=''): + if isjunk: + warn("isjunk not NOT implemented, it will be ignored") + self._str1, self._str2 = seq1, seq2 + self._reset_cache() + + def set_seqs(self, seq1, seq2): + self._str1, self._str2 = seq1, seq2 + self._reset_cache() + + def set_seq1(self, seq1): + self._str1 = seq1 + self._reset_cache() + + def set_seq2(self, seq2): + self._str2 = seq2 + self._reset_cache() + + def get_opcodes(self): + if not self._opcodes: + if self._editops: + self._opcodes = opcodes(self._editops, self._str1, self._str2) + else: + self._opcodes = opcodes(self._str1, self._str2) + return self._opcodes + + def get_editops(self): + if not self._editops: + if self._opcodes: + self._editops = editops(self._opcodes, self._str1, self._str2) + else: + self._editops = editops(self._str1, self._str2) + return self._editops + + def get_matching_blocks(self): + if not self._matching_blocks: + self._matching_blocks = matching_blocks(self.get_opcodes(), + self._str1, self._str2) + return self._matching_blocks + + def ratio(self): + if not self._ratio: + self._ratio = ratio(self._str1, self._str2) + return self._ratio + + def quick_ratio(self): + # This is usually quick enough :o) + if not self._ratio: + self._ratio = ratio(self._str1, self._str2) + return self._ratio + + def real_quick_ratio(self): + len1, len2 = len(self._str1), len(self._str2) + return 2.0 * min(len1, len2) / (len1 + len2) + + def distance(self): + if not self._distance: + self._distance = distance(self._str1, self._str2) + return self._distance \ No newline at end of file diff --git a/lib/fuzzywuzzy/__init__.py b/lib/fuzzywuzzy/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/fuzzywuzzy/fuzz.py b/lib/fuzzywuzzy/fuzz.py new file mode 100644 index 00000000..26274b9a --- /dev/null +++ b/lib/fuzzywuzzy/fuzz.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +fuzz.py + +Copyright (c) 2011 Adam Cohen + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" +from __future__ import unicode_literals + +try: + from StringMatcher import StringMatcher as SequenceMatcher +except: + from difflib import SequenceMatcher + +from . import utils + + +########################### +# Basic Scoring Functions # +########################### + + +def ratio(s1, s2): + + if s1 is None: + raise TypeError("s1 is None") + if s2 is None: + raise TypeError("s2 is None") + s1, s2 = utils.make_type_consistent(s1, s2) + if len(s1) == 0 or len(s2) == 0: + return 0 + + m = SequenceMatcher(None, s1, s2) + return utils.intr(100 * m.ratio()) + + +# todo: skip duplicate indexes for a little more speed +def partial_ratio(s1, s2): + + if s1 is None: + raise TypeError("s1 is None") + if s2 is None: + raise TypeError("s2 is None") + s1, s2 = utils.make_type_consistent(s1, s2) + if len(s1) == 0 or len(s2) == 0: + return 0 + + if len(s1) <= len(s2): + shorter = s1 + longer = s2 + else: + shorter = s2 + longer = s1 + + m = SequenceMatcher(None, shorter, longer) + blocks = m.get_matching_blocks() + + # each block represents a sequence of matching characters in a string + # of the form (idx_1, idx_2, len) + # the best partial match will block align with at least one of those blocks + # e.g. shorter = "abcd", longer = XXXbcdeEEE + # block = (1,3,3) + # best score === ratio("abcd", "Xbcd") + scores = [] + for block in blocks: + long_start = block[1] - block[0] if (block[1] - block[0]) > 0 else 0 + long_end = long_start + len(shorter) + long_substr = longer[long_start:long_end] + + m2 = SequenceMatcher(None, shorter, long_substr) + r = m2.ratio() + if r > .995: + return 100 + else: + scores.append(r) + + return int(100 * max(scores)) + + +############################## +# Advanced Scoring Functions # +############################## + +# Sorted Token +# find all alphanumeric tokens in the string +# sort those tokens and take ratio of resulting joined strings +# controls for unordered string elements +def _token_sort(s1, s2, partial=True, force_ascii=True): + + if s1 is None: + raise TypeError("s1 is None") + if s2 is None: + raise TypeError("s2 is None") + + # pull tokens + tokens1 = utils.full_process(s1, force_ascii=force_ascii).split() + tokens2 = utils.full_process(s2, force_ascii=force_ascii).split() + + # sort tokens and join + sorted1 = " ".join(sorted(tokens1)) + sorted2 = " ".join(sorted(tokens2)) + + sorted1 = sorted1.strip() + sorted2 = sorted2.strip() + + if partial: + return partial_ratio(sorted1, sorted2) + else: + return ratio(sorted1, sorted2) + + +def token_sort_ratio(s1, s2, force_ascii=True): + return _token_sort(s1, s2, partial=False, force_ascii=force_ascii) + + +def partial_token_sort_ratio(s1, s2, force_ascii=True): + return _token_sort(s1, s2, partial=True, force_ascii=force_ascii) + + +# Token Set +# find all alphanumeric tokens in each string...treat them as a set +# construct two strings of the form +# +# take ratios of those two strings +# controls for unordered partial matches +def _token_set(s1, s2, partial=True, force_ascii=True): + + if s1 is None: + raise TypeError("s1 is None") + if s2 is None: + raise TypeError("s2 is None") + + p1 = utils.full_process(s1, force_ascii=force_ascii) + p2 = utils.full_process(s2, force_ascii=force_ascii) + + if not utils.validate_string(p1): + return 0 + if not utils.validate_string(p2): + return 0 + + # pull tokens + tokens1 = set(utils.full_process(p1).split()) + tokens2 = set(utils.full_process(p2).split()) + + intersection = tokens1.intersection(tokens2) + diff1to2 = tokens1.difference(tokens2) + diff2to1 = tokens2.difference(tokens1) + + sorted_sect = " ".join(sorted(intersection)) + sorted_1to2 = " ".join(sorted(diff1to2)) + sorted_2to1 = " ".join(sorted(diff2to1)) + + combined_1to2 = sorted_sect + " " + sorted_1to2 + combined_2to1 = sorted_sect + " " + sorted_2to1 + + # strip + sorted_sect = sorted_sect.strip() + combined_1to2 = combined_1to2.strip() + combined_2to1 = combined_2to1.strip() + + pairwise = [ + ratio(sorted_sect, combined_1to2), + ratio(sorted_sect, combined_2to1), + ratio(combined_1to2, combined_2to1) + ] + return max(pairwise) + + +def token_set_ratio(s1, s2, force_ascii=True): + return _token_set(s1, s2, partial=False, force_ascii=force_ascii) + + +def partial_token_set_ratio(s1, s2, force_ascii=True): + return _token_set(s1, s2, partial=True, force_ascii=force_ascii) + + +# TODO: numerics + +################### +# Combination API # +################### + +# q is for quick +def QRatio(s1, s2, force_ascii=True): + + p1 = utils.full_process(s1, force_ascii=force_ascii) + p2 = utils.full_process(s2, force_ascii=force_ascii) + + if not utils.validate_string(p1): + return 0 + if not utils.validate_string(p2): + return 0 + + return ratio(p1, p2) + + +def UQRatio(s1, s2): + return QRatio(s1, s2, force_ascii=False) + + +# w is for weighted +def WRatio(s1, s2, force_ascii=True): + + p1 = utils.full_process(s1, force_ascii=force_ascii) + p2 = utils.full_process(s2, force_ascii=force_ascii) + + if not utils.validate_string(p1): + return 0 + if not utils.validate_string(p2): + return 0 + + # should we look at partials? + try_partial = True + unbase_scale = .95 + partial_scale = .90 + + base = ratio(p1, p2) + len_ratio = float(max(len(p1), len(p2))) / min(len(p1), len(p2)) + + # if strings are similar length, don't use partials + if len_ratio < 1.5: + try_partial = False + + # if one string is much much shorter than the other + if len_ratio > 8: + partial_scale = .6 + + if try_partial: + partial = partial_ratio(p1, p2) * partial_scale + ptsor = partial_token_sort_ratio(p1, p2, force_ascii=force_ascii) \ + * unbase_scale * partial_scale + ptser = partial_token_set_ratio(p1, p2, force_ascii=force_ascii) \ + * unbase_scale * partial_scale + + return int(max(base, partial, ptsor, ptser)) + else: + tsor = token_sort_ratio(p1, p2, force_ascii=force_ascii) * unbase_scale + tser = token_set_ratio(p1, p2, force_ascii=force_ascii) * unbase_scale + + return int(max(base, tsor, tser)) + + +def UWRatio(s1, s2): + return WRatio(s1, s2, force_ascii=False) diff --git a/lib/fuzzywuzzy/process.py b/lib/fuzzywuzzy/process.py new file mode 100644 index 00000000..7571664e --- /dev/null +++ b/lib/fuzzywuzzy/process.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +process.py + +Copyright (c) 2011 Adam Cohen + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" +import itertools + +from . import fuzz +from . import utils + + +def extract(query, choices, processor=None, scorer=None, limit=5): + """Find best matches in a list of choices, return a list of tuples + containing the match and it's score. + + Arguments: + query -- an object representing the thing we want to find + choices -- a list of objects we are attempting to extract + values from + scorer -- f(OBJ, QUERY) --> INT. We will return the objects + with the highest score by default, we use + score.WRatio() and both OBJ and QUERY should be + strings + processor -- f(OBJ_A) --> OBJ_B, where the output is an input + to scorer for example, "processor = lambda x: + x[0]" would return the first element in a + collection x (of, say, strings) this would then + be used in the scoring collection by default, we + use utils.full_process() + + """ + if choices is None or len(choices) == 0: + return [] + + # default, turn whatever the choice is into a workable string + if processor is None: + processor = lambda x: utils.full_process(x) + + # default: wratio + if scorer is None: + scorer = fuzz.WRatio + + sl = list() + + for choice in choices: + processed = processor(choice) + score = scorer(query, processed) + tuple = (choice, score) + sl.append(tuple) + + sl.sort(key=lambda i: i[1], reverse=True) + return sl[:limit] + + +def extractBests(query, choices, processor=None, scorer=None, score_cutoff=0, limit=5): + """Find best matches above a score in a list of choices, return a + list of tuples containing the match and it's score. + + Convenience method which returns the choices with best scores, see + extract() for full arguments list + + Optional parameter: score_cutoff. + If the choice has a score of less than or equal to score_cutoff + it will not be included on result list + + """ + + best_list = extract(query, choices, processor, scorer, limit) + if len(best_list) > 0: + return list(itertools.takewhile(lambda x: x[1] > score_cutoff, best_list)) + else: + return [] + + +def extractOne(query, choices, processor=None, scorer=None, score_cutoff=0): + """Find the best match above a score in a list of choices, return a + tuple containing the match and it's score if it's above the treshold + or None. + + Convenience method which returns the single best choice, see + extract() for full arguments list + + Optional parameter: score_cutoff. + If the best choice has a score of less than or equal to + score_cutoff we will return none (intuition: not a good enough + match) + + """ + + best_list = extract(query, choices, processor, scorer, limit=1) + if len(best_list) > 0: + best = best_list[0] + if best[1] > score_cutoff: + return best + else: + return None + else: + return None diff --git a/lib/fuzzywuzzy/string_processing.py b/lib/fuzzywuzzy/string_processing.py new file mode 100644 index 00000000..7c706d98 --- /dev/null +++ b/lib/fuzzywuzzy/string_processing.py @@ -0,0 +1,41 @@ +from __future__ import unicode_literals +import re + + +class StringProcessor(object): + """ + This class defines method to process strings in the most + efficient way. Ideally all the methods below use unicode strings + for both input and output. + """ + + @classmethod + def replace_non_letters_non_numbers_with_whitespace(cls, a_string): + """ + This function replaces any sequence of non letters and non + numbers with a single white space. + """ + regex = re.compile(r"(?ui)\W") + return regex.sub(" ", a_string) + + @classmethod + def strip(cls, a_string): + """ + This function strips leading and trailing white space. + """ + + return a_string.strip() + + @classmethod + def to_lower_case(cls, a_string): + """ + This function returns the lower-cased version of the string given. + """ + return a_string.lower() + + @classmethod + def to_upper_case(cls, a_string): + """ + This function returns the upper-cased version of the string given. + """ + return a_string.upper() diff --git a/lib/fuzzywuzzy/utils.py b/lib/fuzzywuzzy/utils.py new file mode 100644 index 00000000..2d3ae3e4 --- /dev/null +++ b/lib/fuzzywuzzy/utils.py @@ -0,0 +1,76 @@ +from __future__ import unicode_literals +import sys + +from fuzzywuzzy.string_processing import StringProcessor + + +PY3 = sys.version_info[0] == 3 + + +def validate_string(s): + try: + if len(s) > 0: + return True + else: + return False + except: + return False + +bad_chars = str('') # ascii dammit! +for i in range(128, 256): + bad_chars += chr(i) +if PY3: + translation_table = dict((ord(c), None) for c in bad_chars) + + +def asciionly(s): + if PY3: + return s.translate(translation_table) + else: + return s.translate(None, bad_chars) + + +def asciidammit(s): + if type(s) is str: + return asciionly(s) + elif type(s) is unicode: + return asciionly(s.encode('ascii', 'ignore')) + else: + return asciidammit(unicode(s)) + + +def make_type_consistent(s1, s2): + if isinstance(s1, str) and isinstance(s2, str): + return s1, s2 + + elif isinstance(s1, unicode) and isinstance(s2, unicode): + return s1, s2 + + else: + return unicode(s1), unicode(s2) + + +def full_process(s, force_ascii=False): + """Process string by + -- removing all but letters and numbers + -- trim whitespace + -- force to lower case + if force_ascii == True, force convert to ascii""" + + if s is None: + return "" + + if force_ascii: + s = asciidammit(s) + # Keep only Letters and Numbres (see Unicode docs). + string_out = StringProcessor.replace_non_letters_non_numbers_with_whitespace(s) + # Force into lowercase. + string_out = StringProcessor.to_lower_case(string_out) + # Remove leading and trailing whitespaces. + string_out = StringProcessor.strip(string_out) + return string_out + + +def intr(n): + '''Returns a correctly rounded integer''' + return int(round(n)) diff --git a/lib/regex/Python25/__init__.py b/lib/regex/Python25/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/lib/regex/Python25/__init__.py @@ -0,0 +1 @@ + diff --git a/lib/regex/Python25/_regex.pyd b/lib/regex/Python25/_regex.pyd new file mode 100644 index 0000000000000000000000000000000000000000..ad8e1c76f832426900788ce60022ac7a6f877b4d GIT binary patch literal 302080 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ɯQUedWmdZk8skkI|6R57Z-wWZH}M9ke0Nw5$iU z_*$prwA0I^2T++}w91yAr9PRW~?aMBo+ zVZ;h9G5vQ8yyKe7uzrm1i8q&>+y36rTKxv9T|h7M8kbl4FRxl$7Iuu(D-c$pj>n|j zsHl!!E?f0Vy`tKVcu z7?5{i^{3KdEXu(hK2FjAyI|iW$bW(4+u)0h<>6Txr>XVzh1lN0mvb1)O}kx+Z@R!- zawPv9YwyRp+Q8ZsmHDi_=dxMwn;dIe+b>#V^2!GM)Csf8>>a9 zl-ldZ+3Vyc@X`jz`VACB^$gZ1&dVEgt& zuSPTRc`aiq@cd`c&gTcj(K(?v;@0>`2CQOh;f#UuLUyqdq%7HS3@gxI2~Rt&9htgh zsQAPu<YCG6Gg+}u{vT-mz0=0c~o+{DYz9X8?eqinqVP(Q`XC;on}^ErERx<8Of zc#;V-|75CuAh5ZqzU-Y{ zZNjUc-`wJQs;%lJ_ekTpnZzv;V0KZwX~GxrVXwxU&io=?`D)8rnai>wgYZCbC*@Ub znR|vitAM~n=X0+4Npy=RLp9Eb+*CKz7Iz?<47tu^o$`>>O=Y;S{e{1ZUagb&tQPqsGjAfX9}6t-yfyJM$NGp-P~gxo`JEAY0OR|dLY0_>e;7K5yf_*W zAWg`s!A#+$Zr|hq_i$8ut*w8{wx`^~F@^O>o^-DspGW8=r5Iy(iFd=6qZKgGb`J{&gHqTF?pAep(I{DWy9b5lx+>iG-#Ak zQC(w{xU4Q?70b%tZD+WNR{lH_e%SVJY@HqRBl!9}M|Tcw$%R zzHU9WKPqy1BS~pj&8IbTuuZ43{H_;FvBwKa+~dbqd66kjL#QiCSz`l{H#EzJ6Zm1d zJ%!cERSx{Gj$fBUyf9kysY8;d{nJz%QkIH_1fkAoqxA(%CGu( z-tMYD&lxbnX`Ys1Z}p`>A&W4wPEVYHPb&3mL#4>sR<;`xPP|~3wFW_lJg0uTbKcah zM_}W}Qg(Q?(^U1^+@PH~YNx-`T$I*K!4&pB-1^ChxBiuE;@i&FvR%edgj3EEOf-4% zf@SHAO?J*}>UxmI*4jQTM2V_Np0o0|8iqWzPD4KNkSa!OFq7r5E*K*wlzUJ|*cdR~ z{MOIUnin>c1ona_78an}b{1%Q)hTd)t+X@Z2f^C|C4fPMrF%0l%L~04PU|&K=yaK$vhj5 zZP5VAvHTlv%&U4ey!2(Ja`x6hF}}wf>@zfxCg=mR?pRUeI6-8tes!P_5Ovm=9WH?- z->bJCVri1~@o$!oF{jXGbkvnxEH8jdfV5;xLUv07z<2>rk1uyq$;FOrM`K!t9ukg? z2M7ku#kmuY=I4^!iO00A4>>tLG}IhG1BW2BvJy9ZYzg;onnfy2lk&_pd0|5)r0p2G$YyFfVmh&;sCXt~zP~>lz{V0PV3Nbgrmps=GGhV?$w90^M|Y_ zWa&kR=T zo&osIoRBj+)H$5)&|Ah9KknSzYAo5yJ{N^Qh#VTPyYvfpF@tXzcbUV*5iBW4nsjn! zk~xu!)@k{l2a(s{{re0dn7j$&-o(7mu)biP$cltIYLCwDF$!q)ka!cV&YsL9#=7hb zhoxh`BtyI;F~QJt8Z1))k$b2*d#^swaU_`G4YM#1=E?}V1w z6Z4k$BFY%6%NtK<`Me)@lnh|0XP%q)cN_9qO#joa*s2*YhMzM~NCe!oea=o{@%j&g zk++LPMjqs^aL+1r`{7zQ%4i%Da&hGFJMNb^Ol`OIgSmDr6^Rsgs~RRfRbzx{t)%8C zx!+ASiDeRUM`=jQQU^aJ#csB8&apWU(lqpE7{VEm?{zZ&AxkPHOJ*{XG#^_@N`^p| zI6K!J!CT^q5A1;Ub07}Vax^K&uax6S@wpnw0$>5YOUybk*IgPVk0LTJ*Mo9_4&1}W zmf|dgKSHi^S)PmFxeVeLI+tN@D0VKxdV_aDp4(7>kAmA!TTbb@8 zrkg&YY<`{cK1unw895V7n7XH)SwJcNglXobJ0yydB9z6sgyJ$mwmui>w^R`&_CAXC z@7gPF7#vxNci&6lW+b>3Zj6mRsky<$7DCf>I)j0PF^_|cC0(-uh|LtQyE%M_C1H6B z28=(p!AVo%Qd(APCcd=o`+E?DnyNlq+{gJ$wY&Xv@G{)`5Fc81ewc%J#jwejZ@c?(qUCICbNA` z-D9cTbn`kM=z^WPb*G2*&saRDAK}ODF-9+p%vbo$>rP4OW5HU+6Isn#29qu9eH-c< z_MBdpVd_cZM86tycQsg|8qEx`52W?=@jQN@0egQXEG_;mk++cJ3E|id3B7a<@;C__SKjCV~#3>KrnbZM{{K{?Hi(+jAmbvLSPUn+?YN0rT9kmo%` zJJ=cPv%CS8v3lpJ(eGMf-AN`NTPJGS@C-NrTi#C9$vR4#LNDzwTko-dK@Q7&i)f^s zZ@UuX{ci^(zx~jB`v{BDFZ^$H0BXzC^9{Nl2q~d!!6}SnG|<@z=O3iAZKyGO6c9N( z%XYu;cD!J|znZo?x}{FzY-jdN?;l#_5A_bDTBpMMomOcZ0rLrTEP3j_LG9k#Xm*0X zk9V9<+#9)#jH*@3`&jCHQ{T-}Cq}h`Z;|+L?}Rq1oBs41VnbP0H;ud`34Sgr6zj!{ zb4MS|&n3B|?V?YrV;0zl1<5+q9h;@uzMEH;Eu{EU;ASPj1Azd&TkkCLVA33KBJI%M zLxjJ4?=xWsE_h47rQVbJ$@cyS<-|;^72a|l?E;AL-MhFmeK`ZPCi@cQMSa<0rN+3f z+JR`@0ZD`P*$_cDHlLJf?hrB8;Yv6w-BHG< znt2Vj2bEGj?YBlA)wh%Q#mB!m9D5k{Yx(?)@UnY&fa9@?+?cod0;`d)Z~Y75(I->5 zqHXvILLNdUqUBFTYVA;gu3^__2TE7(D80<10Zkl90^kZfBui4fYF*3n?MCLFznyu^f^iA%vz1=@7wgoE>H*Fo4q z^;EugWYuSpF+puLd2VQ}+Ioo@dslb!_U?gCSf7v=VDAP;+s)e1#3zQ?s5{Yq3ElwP zovl|sA-oyW8E019>kN8a4pPttUKK~)qFQ*V6NKGc0^sgL_I3|k%Qpr}BQ`%|PJav93j z76)#%K6Pr#`D92|Tfvi|V{N4&z+LJ^?NFR7ZACSHMTYFPb)B^hHhql!u|29a9qOz# zCY#RMsrK76`!n7C%(OqV?axB<)7qjR{yJO56#DCEm8U`$_`R7Q=UVYiXRG)?e=JA^b$vUCKjR)!YARV4q7%ut`LLZ?eF_V6a6U!SUOz@ zOOZZgySIgrrh5Q0dFHlI^N`zGnvZoSgl=hptW_H$0|CsquMU*orl>6K4)Bc|$}szE z+*c}irjeOWZ3G2qNn2|>;B~Yrpq)-^&DONOV9b#9Lq2Hdo~{yiVxyb4luHv{jPz~! z=?VQJr?_XaZ1P_Q)Kqm|{)P#rJ6J`!o^AbUepa)`Wr1hq8#i3)s_A+i9Z~5|kUqd9 zcRhqoW9sYQbug*+g+=-Be9Yz_vTFM06yO|Pf}jK)af27FOkZZi3>zCvjS-oJ|oHwZ=am#tsRy&n4hfu~8NW@7a$J9ChbZhb13r9V0Krgx> z_Za6bXOr$qbIN~SJFtze)jaZgenbZ_Y?D!gsdMChPfTdY3+Rei=Als-@H zD%KgMaN7pb8mMXv96t1b*3P`@ONzs-_mS$>${TJ>y}W5KNTwp4T2rJinK3m~2-1Pq zApu<9E9SRJub3L^u~XA^t+SQe42103G4Pqdxe)Gz0IzoSr~eQ~co)N#KZYt-FqN4W zTsQwCUZ0=n%UjnQZhgL*(lDwQr|8LR7KhLw@8?WjdT`k<-<2pi8^qTZwk$b;xOSeYZ~y`=qnj zdpHJs3H8k9P3uPU2^QY^7wR?w$IKu4EbuZ0v#BbctZF({y_{av2wPP=Syk8l>7OM+ zX=zsK^Y!VUN7>Kglb=m=)ASr8ZI17xa!e4u(>ime&2eBVhY=ycnGK_&fa9r2rt{{Z z5d|^x)=W>A@Itdf-O#IAH98a213C&Ih>v#xM#zz;%Cvh=JkxiBqH{PS1 z!5C4B&w(?dT%&75g|-FFF>82hQZ6<86<(HAd{<&CPioVArv2nzrn~kLFhm?jfejKC zvopbCu1-8NzV9ux1c2F>{4X6c7sQ>hPc{nZpr0;^C7^Y zC1wBun!xcRfK_;X3H&mm@{yW(Zi{kCMBFY?&j`uZb+1_CJkBqLqb*8hbJZSZ%cU>h zanH-6eRoumy0edd;1S&X7wDYlexD#Ekt)-P=ezo~k7(UgS#^2IyyKj0Zm1*&pRBX< zvtOr`P~v1HOmuzon<>`|;i{m-xm{qUwrtxe=-#H2K)@So1PkO_S73n+CFZS%+1T8R zJc$08=MFEz<3O%;YT{gdtJgWqJogOaO<&Ni?O%O6-F(aE02^38i}GV_w&29Tr+BLD zz|GH8n)1X4e*Xh_St>};>^uDvbL%66of#p|SliUbHOOKLnD(yX*?G@AF5r>%(2;Zn z8auyN-#o<@F!wZ+x<@##Z+I{NyHcBopG!x-D-|SOi`sJsZ^*mL!&mN>$HKg0guT)! zn_A!FI^pbjp7XTEZRr$m|8otV+@l(pKw7J_BUKUv8siR4YRq2tH^|Kc;&Lzw_dN!DPLB!z$bO0#8nK#*Qzb4uK4P#9E`dICM{ATjwxUuT1 z0Af-WK#6ylM7vg?EATvZFth%*EuHn=KB&7}N4LY*ulK?v2mJk{^OCa}`c$}M@r^UL ztXB>l%{{JlTq*FVb~N3wxx~e{KJu-*Ly>hB&R-UQ z;rAf`0$;>b-zj+ncPFveb%-uWG6jbQ1%3F_I`5aYeK+@#e@Nfwa(DW;FKyv}qi&ea z|Gj7D+Z9TKTVI`5V^1v(S2q+aIaxxUbfNMQuTV|v>`9H9hREMoXj#PgQlj}Dfh~i2n*G-xoTVU zQ;ahlsy4b0nD|kjhOgV$c39VgU)6T=0+hQ}$_4}99Z^`e*}|B;6{HvlC;rroQ|{iG zlwbBb;gn+MFvN&5ewCEQ*2mN&C-rF290J~FU3V^|#ryG3&U42}FHqETvj^>L8#GP< z9E+;Fc{)&xPtPFUL?2CcFK~of@e*orSTo@%tZdi^UI#|Vc`KuHpYVJcgwD>0L3U3az zrTX7%zC(zb?~O9~6hCW(T(Ju9?c+z=)#e17vlWIUp%8)#<%J|DH~B|ad2pw|R^%SR1%CzMi&rQ2RBF?8FJI2-RuuV{~Qf_iI`(-8Bb@{YvwE#$t2 z+|VO{yRZk`J&RgshYxN;3E&Khf%e)Z>c6cgor>ur=)pzg`L@k7Nsf;J<}D`{`kYv3 zII+;sGx0b0*Bb|^n1@nhvkL#eS`rx(%dX&;0O6;YJU(s0S8d?cNqFn{!PhgbtxO)1 zOh~-Ts7wvE=(V=OzeD+yeEYih9+`WJo@T$IhZtkbTUpuRykw-;0fC?lWY_wGkX?%O zf~53zAOeEtVe@f09G4%CKhMNmJ+5$(4FCj-Aw;j&*<$wrUxG?beZe?vKdqKIcRfzK zT|aL(Wv}(iIvQ4D&tA)(OjF6C-c*JuaAPfB`3VERdR#$x84FK>Cr9`q{@6Wb$6w)f515nf zwFd2Z{b+`DKCm_fu>PE)d%}9X!4(5QKFVfYb+GrG-)1!S0FwEcbr7;pS*#i#ifRpKPBl*56vz`pW9}p zswrkM>(j^FY37Zw^#;uhr8lU|2O9{z<$Mh0>M_y?9In6$eLC_x#m(QwG%^k~Fcz>kk?ag6$-|gdnA8)_6`Z24dq9#UOWBSBqN%Olb3{B3%a%SaG zS&*-KG-E`uE5O%i;j8NfY-B?1V|X_NsO@^h)K^V?U3Z(uh#r4y9v{`?FI;mT-=BZF z8$+j!3$^?tVJ$AaWX1uLREi(E4#(;!l4f!NW2epj|PbUzGgV$w$K+ z*O-bCDzc>Y?13K>L6|lc90cUSLSS?anc?$VQy5sssIVB|&lrTfi>cha?fitdsl17J zaz2E3;gtuH*(YGv)dqyNdd)sOC zADZk0k;Ip`l{dk#85@&Jj0JHFI4s}M{vik!OgZuX+8F98+0H$1*5J3GP1 zD`5Tb-e<4dNU+$6P?BfjK92s@btrc10(`CHKCo+KbuA@Nprkv7W9*TK{*yLrU#aSd zVD0z5P|GyCqy$S;q5H6=Z=Q-RsP6osyvP@^Fs4`tFipC2Hk3pX+JQs%WEi6#LQ=+p`mWw#^m*{$if+{WvUpbZ}z0gdc2H*>i zPrTw3_-AEHXdoZ+y&}*yJyMCxD@qK;K7wWF7j)q?b>SSH^)1v$Np-;l6>)!RyTDRI zOgLXAe!3GMv-UsgP_iRzNch3jO;II}`!# z2^4d7jjyhy3f*Oa-9HoJd}a-;w+a%S7?#0vCvd%pc=4Guz;OT*tlHPW1j9W_wt!XB zAo4lZ=T@K*uL4U46J)@vOVz^6$NrOny%a3fDOg4*=Q(D;nCK+xJ^S)2Tc{1pEI!|2 zWee#Hm$LVI8!X!U(RhiBu(()!JgbL%w{l%NE;LSv4(`2z@*zRu>F5;uY!917uhm2T zhI&n1Sm%ovg~cfMFa(N)RR`>J_&9mQZ^@77yfU*cAzg?zB}Q6B!@EX_@)c$ejwFM2sR-wcB&td-yFS`XCx!JBP z?CzvGZYp*Qv}48vvf*e<-^i*nyE>E7bUmieaP%i)k`VU3$UM`X;2={wmhA@Xwh+Bp zc_ay#s8}BTG#sY zb`PAP{q;J0FxN-k0MH_*fDN!Zn~0e*@&L`d{r`iN5^5E6zd+J5GoU4xo^;qa95_|E zwY3-dF(>X%Z6C>Z8?-=QC+n+@LRv1MDRpSzG?M*O@ev}(&OcrQxFNjq-%Nz`8fhJQ za9r2@?nJYWMPk_9xBRY`+VO2aFo~zgWrEu6)8NQ@8VjLO5Ew|kXe{(Tr802wgP|M# zrr2xGUk^Do42zwns|+2?rHaJ6akiOgX3%G49#tD!dQ$|-86hW6bs7A5O(a1h6DXpw zkZYfVM|=NP3KFi244_bb`Ou@-t)p@|jON+ns-B`c!{_3uE8o`!KZKYDn@n#TQ*s=K z0k1Ol)S96r*STgP$j1h2=czG9*258)7+LXc=Hbl9z{jbPi{r0+LbVz5CG{hcOBGiD zL``>xm*NKqDTi7=eF^_*iPNz=@le^iK8LoZhVNvPC~*s`Bi<&9gEm-RoSIl+6DyS1 zM4KkaPX)c23IZop;xlwy7BNrB4yarMlwbA&jm>Z;DG*$FnQr8fzm$Bt1y_@PnThbc zv3F$?aV@-Z0u__Q<~CW1$&n?`)vWN!Tlr6z(FhFI$S9Z$ZE1x%HHS31XBY)qTa`0| zsjkjI6zNk&+?K^d*dEe=no4XCE$YGeJ|ka@*@o>ftTJjt0HI1P!AtXzz~K zhsEzQ@V+BDo7f(QSiaJ`iS3b-e6J85A4h{RD0djzscWDn^J?ycnwB_-y@CubY6nF# z22D~3tucT;L#ys`fkqp~kA&YQYVA(D7o>(x1!90Qav>`MiKU4<9yU&Kkz<+vi@lR5 z#hRD8hJ4`ZxLLb_&jivlQ7Cnx!*N;c@gYCUCRG}fsNr*OsO`ths;e}4gk!n{CAPi! zTaV)k*6kgkue6XouF{AO94yfPn(78%mJ}eG}hCvYX>`ZGWc<_jHQQY~7$} zMP|UTnY0R_E}>dO$F+w#mCi{DsAJez?Au5rLWN-iNCgXR`E zo#Ux-sBRdqp@}iVE58La-p%zCLl^59%}_!l{fMe-jGIQ0TvP1*oz}9{go10Pwi2o} zCP(rX+NAOv^oX3PB?a}mEu;A<<8LAEsUeJcL40v{_)aopcfvL`K8U){o;h$RTv@|C z3_}<9<3Bzq=Ad+r+fWyvARjs5hT3VAFjO|)G&w7l)FKx&=qtOpuVJJ~(tQxQMwko} zr3VHNxvtopw-yk>bfL1D(rMj+LNci+s499K5CvTK>KUzeNl zAGSOt+MDs;t@YKstn9g!<`NOvOuM~_{3CX$_{AK7HnMa~)wOmg=_n{&!LP5m-#Rm# zbm;^*sAJ4<1M(;GN(ow{2A0cs|5DY)@Tx9-nORa=_9ppD$sh~A@dm7V z9k${UmvGeNQEPoIYYkPiDb^x7OgK6X!jZdT$;s4H)YT6fNRC%5`Ib|O9SJZ>fv-Gq zlFvVLR6N@;cE~v#nV}f~Iv83kZmwo6@73H#xC)9%_1LKjS z6!*u#E$;Dj$lTeqM{+sI?an46AK@uyw?WWTk=(K$RCZk{p7}wgH%}A>0s0n*+H9o( zzm(Zlp$m;7kfvKPlvv&vrd)^81C5?xmP33*MM#rAgj5Aiix1)AxFk<>Tb{UqAE5;Z zG$EEpjx8JEbAe7PSO!+8ZObZ8@su58c!U?RNa23|}|0p*5>d zcVBl>F+pZ8>l|6BLe4oAat<6>s4(Fpi&`F56woZL!9=`{ES8fDc8l6#hn072i8GSR z&suF5rgqh7{3E$?exm!`Eoji)`zJp$epQwlsHdds5xo~BvTg%=BhjiN`vFGRQg{Cb zXMf&8C=9<*gaTsC5x}-v_l%<*ZBG39d#rW3yBugA?0d`B`+WMXt8<{JObKbXuAUE; z+<`5CM5N6D{&(HS8jhMc4z;=Xu(#$!I2_0H!j{YN(cQ28t#%3;77J8>FS?Gd171k||a7UHYp z4wuzNtCkDgiz_u1@>%OJxuDPQTeS&LH@WqAFY&TrQ6FN;F3RONY6bUj%?^X-njd5RKRpwQyU@M(>EmV9asaQmI< zDA-c9Ky!xYIp^l%p-ub_N8YbTC}-yxxq>Zu2fXj}MYu<1;|Yab+u7=Ia0$|y>nv^l z<#*i^#Cu@UsUSsKdYkU1uCA>JFT0Bez?dDMN$kkEmGSZq6|C@p zJW0n4tzjkGQq4q;Rt2L=s9<8TtwDYf!1kEh!%Z$=iDZ1r`w&s-m8K7gEy*!p!VD&t z%%)db(H^#LSN`S;5;H4}Nr!2%!O0;x-ETp{1NLHwu`%HLGB6OC{Qk;L8!mEBulsRd zkhC@NZBt8Roo-Owns~x~y<=U$0P{81eqG~osB@e;I7uBG!CfOv=0b7gN`vu6Vf;xS zU*YI15G0Q?@v+fk#OhgwDjc;N#i*8T((tiN2t&3}Ty2U)z@pJ=E zEsGnnA_eOPTcGBmyJK>V=1^|k={D_rKTSJP41>^2dI#oy-v?o3<6fH6|5Eg|CvJdV z3qXOt?VeHSd@DgXX0(979uUN+^RA|*bw}IA|9YYYNc;Kjq+#H3VZBY!t)&5`AMta^ z&hJjDA=e~7m-a4#T-W=#zHM^Vk*mVbRiIoKTdK|Wb1A;Ar%-K42J)hMOWFst$pAn3 z{-UojkcyWxFSa$6gx!-R%Bwz(9Kg=qe$@@d^A1M|3TJVD)>DcT(rSG|FJ+O^9$*2gA8NH(A`(NclI8eNfRd`NY1Wqthl_9!Cx7lI)QiqmGPpt+(YcDO*t+fVIuXFHqESgy`8%BIV@(eS_uEKG3mneNC6 z^M0LSWKybJqQrg*F19OHq*HfOp7U|lxIT|pu|W+&K=ZX z4vCzBmn+i!H1!IGPxmo59X0t(^=stvXWh#qM*?-8b%JkCO5_p{4{S-#^MKd8UJT;( zb(o5F$SSuY56l-vmAm;x^X*w^h!)?Sxa(9lMIQ_H zcFXPFE{7~?h)i`1DnT2WoK7`UMF$7CeXDlOIYzS7muE2RF<9mIm`6tc@r&s7fqs{{Af@8WxP8A{iTq0`93^N zf8qXLeR;%wQFJRKvvkw^k>-o9^Bk1+CGzd|_{55MZGk^!I6D(JGyKH{nhahGW+CUJ zwYva2G58b)(fY0g@cX(3Sqss+w0OEWH}*kuu|z5IS7tGPiCko_@$m86`bBnRH1-G% zF9>&<5Z;b`u=q_z%>ho`FY{`vx*}WLrvJ7JGAc>fxRT9(4dzx3rKHhRR&2FSPM^-+ zAL#;dwo@u&3-CTPw80n_wa^NAr_-AY+aDTpW?I_uHmz<{TH2vDZAP(nvK#^QIzb0~RP}eov_g$-aP9 znbCCrQ=L0YoN$EOU$cc-8x{pM9ZXH^p}+$ZGkM@Nc;J+D9w-wJ_-tuwqKTq}g3W@B zZ2>b>q%#BlRj^-;VL#KjiUdtBqol@N8eixxNXy4#f_Y#V^T04VV&;L6KM#zu^S}(! zH4jX8q%zuhfQTS8*FErNNjMWl%0wg3!T90GTZBe9`Zzf>od_-sk8`90sETqC82!wT zNLhndeR$pcN@F|XW93?Anx+6fELok80Bl;~S5}LZ zY_}_h@)91)y9eGT8P}0-gKii39SQ(@ z9p=+7hHM8`!!+!wB@#c;hMJHl)lZYs8mhw9XYB6f3t#a#eAeyb-xp;a#!|(qYz&`* zwOBf5$S0rvGS~yo&=%NNaE3AdSkBm;;tYI2crp7CHU6E|s=0Ne4BtgQ&n&b&v(YbR zcxHwVvxyw7HB(VSr^P|iIAM*18jzHD;3Kmd>A^vUIYz0Uj zro!Jcx^oAC(MOB`&ZxNJ6i?X)Eb%4ACzGzIu^+5-*!%^9$NSmB^TWQ9;dbdrQ3Ih&JyvpJVrR;mR z?C9U)y!2m!gy6h1d^WIz`pbkQ-L{0%;)Xcms{Z@zW?6+K=o zH54NF@v@Eg74$RfqY9?G8bBZD?=aXcnol-<94Z6AvVthhv zB$g*yVH~^N^R^n89qxh5X+c7O%y3kTUxQ34Ft%L#3YwMG{5=AAw3hPN*;=jy{yJMLl24U91$3x@4x4DF zRP}qfby!`vsOvFsYN=teWZ=ESA1_zF|2|cNvI@xF*fyqQ7T1=j>b9vRm%63y{n~}X znmpM(PXYS1DS9dPfCK0tgc|0~Q#iJ%Nd2kHN1ib3&~Ws3L{%JC7dghg$#_3aEg94D zsI_vQ1dJHs8U8~qZ1)qxv1#OY$5vvUjjcV{oIszIl`5+u>L&pkHuIy>E>JB0g&b-D zai|$!6^Z@u*pM~ix^ucv&s zGDlz?XuB8vP(amdM|)OQI9hiQC@^nBc{`eKtXRwrC>sTh%yD3k4ZFFO%db^Wxg+za z>bV7rj!*Y%x$+6&*^HR>>bZrB`}-fm(Z5u4U>8r?aO~y&w3^ehww;_=&3+Cf!*!&` z-6uo{EbZLS8vPX+T$2)eYJNf0pO)mi?q_z%YyGOmTQaQqFpZUmGyE2&rHADe&zm9j3EFQoThu!|%YxUt2?^cs$y4(76V z#-q01p%Qav-pMa%|1K-MVg`aX96N$M0pY^YP+nHnIH(tn8#~gy+7YAv*f8>17v2+j zg68I)&q|%SPKC%pgjPD7I@p=GjEz;Nqq;VKVT#a2rvW1Onub?RqI%0H zAs3|cW?k62q&zF!b_@*X;zwxw@G9finU9jvJZ=@~v~H>?kf1}6q6*zBQsMSZY`j3t z3LmwXLApn5t>M@p-h`b~m`(i1n83>;NcV^v@pzcdE>Xxspt@}v7ZhzZeGiasrB(gvr zQAvi497*5AUMmlS#^cgIC3)GYq*B=9seglG!}sgxcMrZd>ww;HG>CqDCGRvA!a@P> zBxX(vI`^;i&c*uwm*JY|1xkS1})XQdS*E1(|)=oj)WaxrcI z7aLT3(KWz$bq+Y&45(;6zs_gzd5T;Scy}6iU7XFEUva*4{;8qul?tsRjQJ$pmD*f( zm&Z4QpWD#wM#Mf{@+zDk{gk!=!DU$tu9-lr?Zm|7Fd^!TF82_gdx#c2RAa-vnh=*fPgvmI?TVk#x~;mC2L>eNIt}oEaErOaBdnY6hHX<)5$H zv;4Cs`{jjW`uS^H9s{IE;b;=*2(MU8F1EVf12oAhiHel0G75>2RSZxBh_gFUg(HIP z-De0qBc)dSk-{`EoCfUqI7ukgWyc)->#hz;4WX35<9u7FKZVlpnBJ$;_Uuz-(5KUE z>F0M@88A_7x=*-ok+V_{4DYD)d$6htDCj{8)dlV}d0#ayFQ6xT8JBBpbwjAmj?2@@ z+snA@m4EKt6yR#CCQR|%7+c@ltc!ccRqMt*dsjs74F4QtOaGeEd*h!en8tfz=jN0A z@_(WmAm;*GKERLM-}foEE(Q9%;Af$&ae(?`#^q_`{o433uu6tJr?WA_Pr0pc1BUAM z<>Lo)d;-i`<~1B`c$ZkE_}5t8-5!+u2oUJoGD?D*o@I3?(=Yo+d@FilsO>}_LwDF( z6dOM|-!m(lDW58|NC@KjJK7)^REe#5k zeK>j;U(+WCBFmFPUxb*II$6|%2HwZEukPri;rSy*=odzU2&?D!^|AUY8NtmZG)#T& z=)%B!q5M0Il*@#9#SkAKYi!9Ol-xt6SRp$m(0>j{O3P<;)J0m)it}vok3KOnskgan z6?rq};6T3Z6>Z;q_g=2vwr zI?$~hs;TmE0jt9s11&@o46Gwme&sBlgN0hGiWkdggLx9HJJqAlc^Txdf(pVbCQpKg zlZ!QP5?|dM?{a?HtLiJmvDth_xovc=GhzSSSRRuI_wktD3t5AH%Uxpw0>0j|;Dqz$ z^;^qgq1$@|KfLe*wK`9E$H6*JDQ&v-SUwHB591vEB}$k;LUeoN(Y5FX-Ci4II_g-$ zy7!y4I8mz*S!N0D{b2{*c6MPNj;`Q^pj5yYd49>Mk^ zq0WKa9qb7qT#vb^A3vDWypR4#RjKYRU#%4}*&EO|8oL_60fPOITC|h;ik2(1;`|)d zzpB1G^8J=abI)Y=)cUAa zXxZWDI~N;%x{j`xQx$2wXnE8uVVj@qTH`z4&mz}_z*1-`@46+qhCivZHF?SP^(%me zz4Ly{ho8`z7%^-=!j0%w@UZg^orHHwsl{HMR8p|{0`_3O%nGku-e};+;~U(y@^UNm zzMup$6NX#d-<_E6>>$YbiZQIls&uUE7nnGxZ>w-OH@`|t-8DApNtLUvm z|KPnK?G^CvwuJc3YF=wY?@LlRo8*@%W1xF={7WnIkm`9kv!18Ol3CCDq@?QkF`Ajz z!avts$_y4_a-6o~;TWK#{?w;y(M{~9kosi&N^v%ceTy00roaDTdQ}^cfHwW*jPwWL zW1Id+M*3mNdTv#^YgXx4kbaY#3RYy~S9nxgPb4EfJDEN;BmLjW^g7awa^d_pJ%LCk zkw9N1gI3s-V@cucuXi}V_Iy$}`LrKTeEO1b>im3We|Fd(&;I`#aN zdEEZ2wLf>;pWE%vukFtoew;1dA6YswKI3-fFONE_up8-+7tszxxb2dQ(x%VYVJd03 z-ZdQWY#21E#Bs$^?)7bE2!z{o5pp(eS(S2;-Oaj-w%&SwA8l>@FST{Wjr2O32HFLb zHF8M#lJx`^LW!)w3RwnFhhzY?l)BS_awn8zZ*;EB1Zoy=lx=Z*uvYxYf;EL7MZ1_# zlEOkBZ5zW0`lDS90YW7ppz^GoU;+5!h3QzyP66QCTrwMXv_0*;4}bb?B|DedmeDnn zZS^_Jw$+f)*6OZgXM1n!FiGapv1oV$O=RVtd@@~D2WkX}Ut9WnFLzQ_DV$Vyf)?&?O0x=Zu; z-w@ARA1_+&+$4~=bK|`5Rl|?-uO#rEc#mEK&QLCjidQZpfMvY$E_Ymcu*O1pm3`PZ zFa7))+r{UmQ~8KeZhR|sSO14@cbkjW0jm}k6^Y~L+CI%vpU4wm z$h~(3U%D}&%dFxXa``ED8uGMpn2RY-aJZM1y7O|KkK1tKnv>6sGaKIRBa3~`;>j&b za%J6)9HtV^>d12X7rRpWam0mxrTU&Vqxi8o^D`KjOu1S6qx~I;rhE3cae) zD`L}Ryc73$KS-GIQm@&4n5RL>EJ`8v+Z(5Ez2g87ejS zvh^Y1z<#E#*iiuI?UF=_X(PowTQ2=}mo}eREPhV>q}7xHaz~#bv)>d=WcAY2n=phV z=I`I7+Eh~t;O*&tPsUu&wg>h#Q}MyjcAP#PJtM_a^`NVYWy zNnpG63DRrd-RkSN_2NG=y0x9D*n5D|v<3DOiBHGb?%z(n2131KNA%mXEiF&Av=>^f zfnSBd8JR6zrk2J?$}$|Y%*FI$i{haTxIr=~+D_D$#)5d!>x}fxkOqaO?H+g~-dw5M zXII8ZGmI#sf1sAG`GJ@TbKjBJxH8~8-%1=4JSv_vnCHfA<%UgUXiIX~@@5P5NXjKG z`_VGqe0T)Jss;2peY4Ep;*oYJmi1PAOfNKA^1~~ZH6X46Ku^bV`)RE>@J#eNpHvzg zy>Q@^%Pc6z{hi9}Xx9E+1$BD|sx-P_eWiQ0F$v#40r9&fyy~}%P1`^M?Qq|t>GRpP zfsS`*AjRU(e?$YfQ##;<31e)&|0W;2@Qmb^&2D*N@mIFg?zc2Gv!x%ar5Z|Go;$&B z=M>w{m2@eiokLUY>;+||emkH1Eu%+Ypsaga(PqVSToGGp=NU7ledNzGyJ?(xJ9f9S z`Sffgl88A7NPhT}o!RnW4~c6vDp@QnfiZ?`uRb>vUiv9?MingQ`j$vZMb|NkJ^B~Y zMyG14BHyxSNmG3_#o;?QWp7B$cYPDh28QM*oiEwyEnhcTtggu^KGTZ+Q>Vcwp?O?{ zse8^=o2kh%hSSfPQ|Qhvcjj=D5*McB38RhW&g9bYo!>9!D%-OwQ&Y`{teX5C-QV4A zYd(env<{2AZSN?*y>2F-0Qw|v-$m&?2H*ieW(MGzQShIU<}+kUv(kJo)cWZx%U7?{ zxZjMVx$f-nj;A#IXU0(4K)>O9zny=a8MKr2mF*ntw=+ZSJYq(uu1tBCg@w0~sl&8G z%PZF*v^8g~I%RB7`>*)E?@@H$rM4G^LYCEgG`l;heY$FIUBIHcZ5efQ+$c?|U8Ix+ zrSbDBxmaKxT@?ub^Bo_Aqj>Ottvp(4WH3iP? zt-y~dV2A!6uxe?ts3tQare3H?7coateBaFU9e7qX?EW)#rpVBTCcHP9b9$LWL+QG~ z$!Lle(RY&DZ;JuZn`GW_iES&cwo-!gdX`|G<~N^j!|_GKMa^O1XoLqVme2ai+Ar{H zADmhHP}P2jN)snIHyEmOX4nDTt{KWGtIJp0B}T~CU5#dL?)9ul6v7i)oJ>~kn;NAn z-K)g`w!L!q(P?@@t}TzrlGBED-F@^C(mKq0KoGYv-(L<4dCEwqBj03Ur6VV8i{47& zLpL}k61QP?a!eh|aq??ht$Gn{m5y!8LLiy>u%H+hj-8~5)0e(UiF5kQ zv$n10bW=(9YMI>3Hsz1_lEE?wCYODa@pFGs+(8G@$oM?VI`4K$BNz72yNHzJXAQ?T z)CDZF@GIL|>9=*R+Dgfw3)I%>wym*RyRU_?bj*1j?0s~%WwUQnhCxx0nh)KY{9u$G zOAS79j`LOSRi_9rBZU9P%(rjx^)DDmv~!tl(va{pD?;x#lx}~>Op`heSCP2y5r0r$ z`-Y@IjPHIK!T?&bdF_-;FB1&}!TF}lS-q8++OrJXc*c2TkSTLiZ)Hj;W9A3czWk8@ z-zR|JAbr_`a>P$dQtn410?KV}deLJjH@Wv~C?|*U zG&_tL+S6SwEN8sAiwZT+FI?nBzT8+AkOBV{5V+^CFWJVh=M+S^ z?W)(4m|@uKhPp)Je+Uf2R8%9yL;F=@3xU7fsV^XLy0cnhWjPlwwZ$b890RXo#ev*I zTO|(shFj(j&I(7Tem5&?JYztMQlh;y6rl=7_hXKA`#Lf8*4w4Yq^G`c1?v_=i+hu_ z*g`&^;(MXRUw>>VK0USQ5yc;T7g}6H=?mNaIlUD&%AC{JDP^wa^sXODKTn^-9yv2@ z0#BL__dbDl`y=zGluJ$EQ+Z2H;Ng`uYS79?_ghAFSiIa_c>RCUg(MM0syf3lY=zx^ z$x-Z!Y=-3BV=K9D#VEz+m9CTjs^PMu@C*}|y@15=_06JIJDoVQ3l-72G0&Y?uB*N# zRyd6XM%l~_?*AEE>5MLSt-YgGSN~{91Y>aNfz+;x5Y*@~-7dkZSh(X(=)s zixEezCM3{($HvZ@Li<+i=dUFH8>}htiJb0+b|mHEx}(Wwpm=$OL^u#@RY6;|*QfN5&Ybb?(xX_pO2+R~u4cC&yas)djE4Nvm zV)dG)dFPnPrEpP;TW|x*=JK>jSo{S+!!ezK_3IfPa9Dk1*B|_@y@C?tPASnc3It7d zrwrw>lG#wK2x~a+SJ4~mgKCf(EqPYI{J|Sf4f)hPw-jsh&Ac$2CREd2h9X^v$hrh#97L7-Rq*N9y(3tbV6d`p_XCVib=EC&cKmU z+2LzdP{X97Uv{BZT`U$r0tv7c$n!uCHHu$sIRiIM&*sAV74@2^lKS>JELwd`JtRzV ze^C-k<*2j|TT4z1aFCcS=~??gMxhgE*5*|D=>Dr6MlUPi)kpmU;^0<&eb)_M?;9pR{o;!p7C<+qlN@(VdNr>n$Hr*|>5T<=D8oevpBbJLyhx zeD4)0Df87cNNx$rODUH^%5S6|`QuwQw827BPs)t*DHE4*ONKGms@RNfPKVZ4W)3Dz zC=0l)%TTbq2}<) zd6r|%Xy3H>NNQKQyW%=ET(!ao4&skdK7)imfj=!H714MWJ(3eLfXb)8fLGPRYd(*r zUw9xhili5)DZfW$msi{>)1yDFCKdcUS>1rl&{B{!@@nJP!D#H z7&;#;_%#KX(Ny(&cWimp*vfG9ReUk6?d6rfCS^LL&5B#jMzADD*SkJt?tP9r?PtmK zM_BuLH>mX9Wcp9}xCj1@q*KWB>O+#|y=Ty|jfL^GBMq@rEH<6INvwViN&og#i`8#X zE``;ng+|LX)rTxuo;J4k7{&>$+M4sLnk&Qc+$4(bVfON;y}h95iOII%_GdFt^fRjS zBAQa0byQ^Key0RjKmRMMyv(oiyQ(r}yBnb@kEJv|J*6D|F`L7Zq1Yrbv2zlm?qsV< z|K~4BShUcX6Ow^_etuxA2cFn$M%R!}tLEf}mlfj}6~1$JadvZMYG`a@IqNgvi_AoZ zNN1`K#*Xp}8rZis@W*p3TE=RwP4!_Z)q3YqS~fuq>v~i&Q~6y(g33?-%E}x4$_pEk zTqCypmMYJp^tvO!3R+!7;zvzZrOVTVVD|c9s$8v6;<4xfpiWM?MJ0&|^OH4k>pEzt zEdoI9K#Z@J=fOkyl(4s3cgAicL4Q6AIi{i%=6<;q%{H+cwql6iuZz z*q&!K=G{(dvoDaj3Yr31jrzK3a6rA5R6F9$Ub=LR-%g`wlCu3>q;`h)-p*Sn4W^v} zjZDLWg_=we>#_h}{Z0t_(U@vzFZdD}x(}RV~1^rAZBN+25JDRZoYPUXGYJBOIO04|SG{$*^Z=&oERq8i$r6lpCXNqg+*t zfx@_|6sCS;)~HA6ju zbO<7$a+90o)|BvQB3CSICk<)n=gNbTHAa-bkYw(;Oj$mX z$lRL?OYAI*qzBdC)I4$SOVoWbrGt4QC#d}CWaWo`W#y%Q6(_zEu;P#)FHg zuQ-d=#rG$Uv)H^-VUO?{^WnQ!WA25@WY(~~vzEn`q< zoNQoi&S+c@=)R?&wbjZP2Yup1R6kgpz>7_xnn|brAeN-P%4d_=0f5%dJA56@15Op|NHA zwPPUj)yM*X99vlSf;(RqOU!VWDB5*7=d-6(?VcCnc^X-#h3_PPwxXbyqx4ztzNY0h zgW0{9j%GiDTg3IB$P1sIA=exCAb4gf+YD@o5GO$^mFa9*{PJ3V0rkL!?(WE`tY0g$ zKX%^2;%J07A%?c0S_^Sxo^-t(#>>ge-rVH}BMLBmHQ!CKCYS)?;upz{ym|7D?467w zG(#oHIFvUZ-`~-PlT2isibTkvrB4Yxl}PMpe_QWOS4h>=kV&r+&Kkug}qk& zn{$A6$*bq*W@^EhGvsZk!gR~U#`VXGsIzWA6M3f!u)hfVif z)4c=AT=fnmMu8l@C44a=bxG3d4Q(q*WOA0-Nj0~A-e>V3?_Ne=1Jc{H6@4IV?dazF zu0G*a*YTOJYTgNzn9byP6L%7DU(|6Lc2{h&lD+?9^mKGCf<;Q5$me?|sQZbJe{83= zGG@}faQqX@8mSTZ0B=6W|3M%2AxNhbINz^GNzR4Jo|K%kQuSP*59#cfK?}o@HHHpN z>2w&;->{Mmd=q|b#6i$v1-;`jk4HqrIzuH1-N%J|ScEemb{hST@*aWRkc9#yjj-WW zw~`K(ZrP^M6M54o+6kprRw_AJ8}@K zHO_g8z|cfw4KsULt_2^P0fS20_~GqYe!K&!XYII_Snf4{egu-Wk04gYFbPCK4B2$@ku8%z})feN#pM zjm@)nMPpHE_UA~ua`&g@4ktC{DA>HOZPdU`XdKMc*db`uelVAVP z%9GOv8|F7WNJM&QTGbE=M{BLvYmzonldWq8D!ILpQ_*dxC}xq;WCGAcKg*>&lJ~Pe zOM!7d8^m+`KC5KRESUiwr#l~a4dfOjjF;mySy-)uAa2u$*ub5$yMbp$;-$ETRphn6 zgLF5ewu$vj1)4$P_-~j+%R1g?Fm|SM?KI~i+wugvH9^pLC5OGMhvSnfW1R%4l&kUO z?&v&+6RGh=iHV=(@qe^qez^JLFxN2(;!~0Sj?JKco@J_8+AOQ7s@)$3F^W=irPso0 z5UO6iWUo{`UB!|NQNf$f5Z}@VymjXm0$dLf?`uZ~O|wL4IU%`z=}kG^3qL&}gJZJg z2Y3tQzaA5bHlp4yuMM>sXBha)Dqg+w=KPGhE>6{TzCP?t=l+qFlgXK*i8mjDGkM(m za@(3euRPWY*6*f#MYSOK@EMkS2T;D9EhfNMgTlg~UT*Aomo5SrAl=7avKiRQfY!>#=&uzuF zV^0mDx}?P{I#3;}c!KSX$0i*_oOaD#-UFWlwC4Nmx>+XuobK%;a0n>+FD3(fR`(6s zMudqqtx@Ct<6#?PBrK2$7*B5O=#oMO0@7@P_~_xKLl^CVlx4LR&~Jz5918+^Y-lhllRKRqj3Tukls(OsO^3f8eEaYlWd3jA?;LL7 zpOgXrP~Lp_@vSgBi9YztWQ1gH8j)Mpx&pyaW~c6R3d479u?k0-nYP1sjw~$eq4KsG zd6K!7ZO#w)Ez;L98Q8KAdGzNU^)J~&R-1FDEPG#ozE<%oxDPr;Zs_Ud#34oN*+6Wl z4WDR^3`f^W1G76KX}d$7Lo#&GieT8)O#bP+-N{;ZCl>g%O!#xMmS6*w{Z(U-cJB|O zSJhFcg)ee1+2g@^*^98-*z~ESKQ2Of&ZphocV~NVeL_aWwmJNqH|%@it7f4Z1dG!y z-D!nU>NflzlgrdyQGb~lrZP^I^9=#NkEQA#SOdasZLctL8=C(ZOc(MLpMkWlaQ9FA z=SVYKTunty{!B4`FmSMUMR3;e(if4g?nJw&oy2-S&zZ!LKSR&unjg+|%n!F_4!mQCpdN=w<)#=(W_4GnDk8Lh$$W|}`rW|c5IRwd1zMD}X4=vytm%U*33 zeXHBevsv^7Mj6p16h<7m%+ocw+(&X+oQvvcecvY&-ZsVM*1;368l<`3Lzcp6xT=llLXZLiT=sC*MSgi0P z%cvjzjmr0A)W? zo%d%cImzS40jA~g`FEwKpTxeXO`k?O(FhRvh>;HbSQK{B17vIHv7<^r;&t3YsR zjUzP(YW<1PAm;8v?G4R;3YgpKLUuAa=5WK@_fTxQr(2a6_g`BUX>9@iu=_IY{9hFN z(f?hsK@{_)KPwHRYbT(m#pI!P22XiB1zk=b&*g=u6LsqpNb z{RnLt+u2uw)h`3A|7=WxwUfv2W8)6uxdr+VG zBe@?~PrQ%&2AVk2P44g#j?`sulzOp9wvuv95@j3E=cmJ!W^a4SF${jX8eX}HnKC}E zJHEyW5tcyWGMH0B-Do9WoJ8ZBlDa|c{4!&;ZF4l^E;%8GJ-BbleXu#VtE7D#S5zEr z!lxw?`Ad8`e;hD2|GnztaO`Z#1mu?0QkuQaNPqWGOYUi6)QhBTsP(VWk(qL}Fdg|E zu=d@NnS(PsavZ>DgV@FY^1d>JLGG9;HZc{rL?_B@#5oj#an!JUXzYi?-X@vO;C9 zF*e2cf8Zx|O!I!%D8{O#$=x{r`^=CNG088u{m^B=76*mgT(%&zd+ z%NP0xSV>g`I^fHmuxMFq)Ul?-sa;=opJre>*2471Buu}yFxBq~Q(;4j-aTLvelnT*#$Uj85WY~Deu$K0vlfW7*0I_9osWuyb)fqFm8W0N!9NJFxD9uH}Itgj36N(Y4iW|2HS88 z+clnzpH^R(LYt&jCJ-MafjCh6quQw$%^prkJT0uo8XLj`2SmP$BSY~K*=R<-sQGRG z%u#a@6=~G0g9dig>?}4?;DD}gUD%#JZfbt&6XcxR%(!_g9E(w?w@zI;z>b^KHEwP| zEBxQefrFAA{RU0M$L&iF%r4IC(eac}j}p{jdvqPc69J7}OYhI@EByW}`&}Rh?x#p^ z{kbVWO%8N2(`mKLV6#I`bdtwZ$6wLd25C1mki}%gm`|?8A_GJ{b0Y=vIAA`S)1r$Q}W;!Wl6VQy0<|gm?Cj*_s1C(V#Ui0csvEBL8j^Iuq6OUI2c&n@g<1j8u%r9b0%2d?G3CdWTW7EZ~wi*HNc0fItAAwvv&sCh>O302793ER3EMhwB&RQ0%LpN>k3#`tBqghD*)Zc;Z@&O zA7o11*$ck@{OvvA>i)IhvO>A0D-VAT?5BqcoG;^xv$eoW$$my(jh!l|HNP6bViyh8 zwDw+}z-eCReCcg?&#otR!Sb0yr3cb`upIq9V~O)XR0X$Z#aCFa$J$FYrT>iGXa(706!yQ~pxWmZ%RX_a1tV_3Q5JjkBrqOj~zTU&vK-lvdvuk?NpWvwS4h6NP% z9@kvo9uVb0JZ%3T5CwD~395D=2P{!mJd0fdo;`)BJ%Nq|B zU9zFeit);9Vvz5JE*f5zF6DjGP~g)g?-tAQLxl%>or+yL_e0l!`{Ur$gs4n$KC5OK zA8Haea{~ry*|g@D1OC^NqDc$}7rb|X;s3Q>#}4T`{;-1ZLzJcf9lKL1u(|SqiY25_sfTR_PA2UiML$AOcIQ_Whs2=Av9Zp$>qfh6c;2DCc!wN=W1vbPRLS*_vgw%z+N zw%T+~4OZ^03~H?q6%N%~%tXUER6hV(`T~EdpY3sFYew9{dsf-$cN5%#?1j~*du1Q; z61ZD=`_p*pZTIbjaVJDle9?nasW8JNGrq+q&Q_m}SmMf3cS4c2{<&0o^|S*>N!nE( zB%5!COP#gZP)U%<(4B&@AUiXQeOyF1^wYy#<8y*7DYa%>dWuMnPTu zPG$qg$S0u()N}t2d+z}rMb$t4&Y9VSY*>;dBoH953j_!f5HLWH0HGsAI#PuYLQ$HK zC@3nBL|B(VRO|&*Y}il{u~Q;oM^r>XK}F3Pe8q++YVPMdWwQZ%%kTF-_ul_~?mo|F zPjBB-=giC*A~}0LIZJb#tE=K1DG!bPK>RJ+GNtH=`_7D{?U^}o@-Z-tD3}^0=tH#K z)6@Uy!N?+gRn7Dfrqc^3*L8M7Hs2Cqg~(TmD(l+mnd#j4;+g3LCFWi+@(8QkVjIQ6 zRVJwQJ*?4vc@iDadI&Z2+Y^yl8c{7veK4I}TqDxxN@ELmwxbRbn85e(NK9m=jy!v2 zrcTJkU$raMvx%+ySwg-fmtto=%0GOz*?qVPeeV0__|8^^M%!Ov-c);t?j^JFDH*kF zAr4CmRY;9Gacz?T=542_a9k%}Iint`@@Y4cTGblKK-mmGt);oiGE+&l93|N~`mB16 z=8~X&dNb#rF>8bxQzxf21t$yPPMTIFakG=2I!k{ll1s&KC%qigzlwF=WI{xAef=z5 zzb)}pugB^gvHPdtwqWM$rMJ!$&$nDG{ zC9j_4pgh?dQS9qpKQp<`66KkFYH*g-%xc!D>Qj9lt5&+IQ<9Fd18cWM>j8)z%npD5 zn2Ge+5B%00w)JaC-pZmpgZ>B$<4}>zE#VRJ7OYMyWmT)G-d&r07%s0lhOBw|%<}dp zy3?xYEW;6_KxG{}88fQ7XQ`<_xCR@ z(T*}Qy=Bl-HO_fY*Fxi@)Xtjg{!cLQs!p+WdU(pq7_Euje5;?U+cS^62u1%Yl8Rh| zjW=^BamWjq#p~&k5z!2mXcnf1?!?-jx+Od9_l3Tc!MDT=$Gfh@bDxh47r0D}#pb!? zeKR8F{Hi|r#d>^LtAmQq_;jv)CoYqK)f4hdj$Sqsx|)Q>NxD_#T*G)I85||nRno{5 zX>2x^8tibcG^F*(SMDy)WZxk@)Q>%^s!N@|Tp(H1((y(s7Fn(~VX~9uD!Fl%Np@}9 zOF%jJBJ_o%8?N9?S+#LlS{bUi!CG&G3l@|~(X1=;I{}x7FcMx1Pb5zE~AWAV%Lxu_m;!iIKtx1a+!upuy^>(t~o@|ejAM`gJX+c$BCxK!_vj; z(bLq@&AR1mLU9Vm_I)_Ex>h>j96Zh%*h=S*QbMp>L}!~BYWT(3v;X})cnSx8lPeP| z@T&yox}wTy5{oL!X#-AY>n9tCDxz71@~wH&nRlEsobTq~0htL$%a)$i*h0U^{8W7v z+DSs+W$y9v;KG`gVmw{;9Y_%wSG@}C%(h+ZG&agMk`*eHM@NrHBlMw6M^^d~)>WP1 zLoTKw96}G^-x9$6YpS~haf$SKRoLfZd^-2H;)~PEofvYk=UqGNW?X#nbySWO^#B|! zU3Upu$6j}bzNblZ3|xg=uoSa%Trwzwy~p$t>#^LD$IR|fQN!*GG@C@~sInw{#;y4T z8{2a7%8Vzkz32`icJ|fci>}0k?4+M@;L8J*e1gIn@IzM+bwqj3 zsFpkLs^%WLROYI1QL<@BG|Oz7Wk$e!D=+l*Kd>67@lBSxo8*eK*!W_oCCi`iz)&pYioYr>hSIRBAYRI-ra;$QbHSw;VwJ*%L;)w8@rT-CGgmxnU!jf~?< z9;obHt!J67ZYXU%Qj}@T%#r3~%$8{ClK)7Tzt)+e{Q=oUT7QG}3oIzC-K+~39%Kw| z7nY#iEO;i4(?Ly{ngW#zzO!%NZMn_K!P@I-*Umh1?|Y8*)mTU7AdehaSsyX1r9?#e9aAK)LSXz?@g?4V&TM#28c0%V!= z9J5%92us#3Ly5>*fDZu5jlKnA$d>GBRnOK2D_dO`xZ(@P%A)DaEfwno&c^M{YAlW= zS5|s4l2=oVXLR?cCYfTCTQNoL*(sIft8ymbWfH>=QW3jWRQ+o_dc zwVg@QSzHrJT!kfxD}p6st1cr0DljfNI6gfvE`~$e0^>a7C@_%YsMA6>zC<$&Z_niCow&;8`Q!J_*paA0@fW7}(Xpz-d0E&^-v zV*2IcxX=}PYP*?-^A4NJ&t!!hjpnkzlJ3kEj_zV~RlDq4Nk%&4pG5dSk;LD2)A*Ya zhCOe8vymj5IAZ8)Cpns(e=EuBC#KF@Io3HUSZ-T72R4R`Z_V#o@r@39#WsvNKJaPa z{m34^yTU2lvg>f=z1aJB-9RF}+kDMYVtiKKX%3B(N%9wIZWoEq)8aWHwfbpf%&o%y zTZ;dM?fAS4wUrq#khxuU`)gUD+wnn{`>U8F%s%)tx}bC26Y_GIVI_S?e3+ToCpsC{ zLwnE>c)M7bfu9qd*)blsoF254bz*M@z8PKB=ayE8z3KmIbfs1#3&Ngfisx`%YEjTC z(@JD)McE5qtl_fBkruk<%Lv0ETDlcy<8YjbqBC^fAPEfS{ohWj2$3$ml`3upR z{tlq4%E1@p$Fkpsef27MP-aXs^acrS3g?b+Jf)&DU9Su4mV|W+!v1E4br*+qqr(0M zhV8P$x=vwTdRW&qtV<5-;=(#tSoeFOQ=a2t-Pd8=A<>y~+lNjToPpkHq1^YJFfWCD zJ}o-4bPtQpEc-oS*R^5Y^!zY(ve~%TNoqJ2@lTHRt4SG_{IkWc z8NO3ERC?I1Y1l3~tcwflTw&es%bf&{hjm|z&W!m`*lwTb%u?+^Cu3)*ALE#eha!^m z-*BRNBpi4hI{VlpE61zF$!t?aVcnHs-F$TPt65=-$zk2-ux^m(%&hec+jS1>+Js%3 zh3)F2lk5h}p+1!H60O!c!sXOcf7wO)WtmgB3Upl4j=pHj$iibw*iC8|*w2PlpVU!oS;m$u;YR$DR5^b+H83{g`cbKaR+dUsL_IjLQeNWN zy>u}D@?)*FbfUztLhk+TULjMwX+JqVFu7f@9uF1s%3(V9=nJ>G+P}WrbmZGsWR;_H z6UDeYJ4H-A3%6x-9hkb{Q1Iy@Y&pT8iz%&T4-=&sn0oo=;nTWaFF_Z499)n>_%`gT zrw03{w155dvwB(5O1fS<-Q+Gm6nq*SIE5p7<@L^gADf^XYzGmpF? ziELH{B(!^lyv8fPr#zT5utk8omp*3O?q0gd*6mtqeuQiHQkm!EH+}a~`P?KDE|rQa z-d9koaI0MS^Ps@_GTTd2818&Q7SmXwZdd;P)imWksafX3((-Z7_@a*dbGk$UYd3Cq z57gp|bxV5zj>$MaPji#^D3aM$%lPR5$zpI=yDr0c_Tx9JC1%Px<{QR5Qxcc8>+)HA zQ8yy7&J%y=37S5Mn|;FiJXSi>O z%aDL;Y2!Y3dy7yV^e~LT=w_X0;65LQPg#` z=khJvzc7fbyqV9saw;SNoC2dg92Z`3rzxAt$N!S)F-sE1BCD`$$%Kn1PueN_RU*4r zahF;P(n#lJ1Xq}HrvSH#5TwU0m)aT-SS}8TQsh^`@VE2@v&(bt6Cw#*k{B4D9C{yn zE8g^Awkd|+aU}Lk4%cXuazBp>&Q49|nV7@?PdC2buW)yA*MgJ<-;+*eAQ2lgM{TSe zNxx4GEKbC3SfHnzQ;%z*hr#?< zOIG5GiZ8waeb2%j$#RinJo%_yt~7a2p_f@XFXD}R<#yF@DV@TDcYVoArddCuQd9Z`d#6xIU3M+_ z#%ze38DW1nSmroic`Ki+!8Plz#)=0(dLc4qVrG9qzOcjNq^a&0f8@$3V z2TQdO`Aci-#fjptn(niChW^}AzUWtca8a9J{Vu1jY1u0<+P{<|7~+d=AkM(()WBf` zQ@Gv3p~=^MDPl`5KDhX;UKJsE&O9|RE-^4GIn?cU**_eWIug zs|@DE_5g;6J~B!wFVJ5O+#eRWNQQs2jjY43Dem~9HssK5b4}5PW{@`L;T#Ul!Nj%V z1zKp@!4krncf;Tq-q~GyXBAu=yeUnh_??Hzuvfd{O0D83 zt2m)_tW3#=lF-@mym^+>7${ISSD}R6K3 zbgFspUa17lv>RqVu|6WX;@fbzMSl~nM*D3Nq?AK@q;-!-ZojSKFlBMl%l?~iiT561 zXlKGDP|_Z>5-uD`#pl*qH6^e!@KMQpk364CeaMc5MzfD8|1L|)DeYJq{Y_Y#jsAKx z(&+C)4V;YMvX_<^Q|@AE9k4ww>K?o_Ca^v5BUkBzr(nNJj#ta?v-HIjBGdA_TFru` zXWbXpxPJGM&N>|?3xQOq_JC`z4=9wi@z&5T7T z^225c+7e4)B=e&cN3cf_k?1O9& ztu&=o)`Fqv1BNZiY(-Um<2>qVXW>ca(?@aO-ZK?MqqVSlKJzjkPqT zApS|yS@}c5BHcjaJ@l;0CQ(hHp#yqz*1mXC)*1 zT^U3x76@e;c}Gk$QRK&MLs2S|T+}b|m@_Ka^d0mPFkIPSq zU-N>cn-;%n6FO@gwjwV#eq@R}$@8ZDNHxAluC0Q7{gkfwHMDlTILIP`QY;ns!Kq7# zUUFVO@nVsXbhKzZNU?(UWR|3n$6(!ofx48sXd12}vLl2i(uqFHA`^(s73g<+ImDe%W%_c0+#7Akt;Oky?<&$3HRJm!fvgUg>{ zBre`o@OrSufItnA!ef#?%iN$oAfSuIs}hUU?(dAXf0IM$qgLs=B8d34mIy-GlqO`+M^#9FEI%2^iN5wJeS+RX8-&| zA}o?68`1YSqc3V;ML(0;oyNCKi#A%WR^ml*m^hKql6U#j<7J!^!AT$IDnJ@a<%hvK z0|RxWhjzku@wP>m2Z#Du4Hliklk|D5A`aUrypQ9LU;Z^_(i%nqto4swm-L5^DP~6b zy_2OL^4n8hyB+#TViXs;u@?klIsM`p`8G5+pcvsRhf4!xs9Ag;>!0WWfoSP3ACZJ9 z{WtEF*)DK=S(&sn=UUcoYEoyRN?ItFD}Bg~EO?}Mr4d>S-9@XFK7~}OszT<zIFUz)S8v7dX(^RfQYpke(~)(42M!vU7GLx_@iRmX5c!9C+39e(&f8#8B(u-? zLz{7!UTXVOp$4|Uex}IjM-9pC^ipC>%TF@TE9{dxGaTzNisfXxU;u+{pQ=oMH`b}d zH;L1!L~E$EDl)$dQe4S(bEPT8BGwF{=fv;F=9DMRyZj+DmWr*2KV8W-+{{oKIg)LM zYUQZdTx#|8RfG!cyxy8i*y)k%>FlQ5KS%mL~JMJT5Pd>JA!I z$^U$gKgL)=^~rLAOv}l1=D-x5*prAJcgYOPrRP~Y*^~D_sI6)f``zO9nmMumh#P?< z&*lFR>m4G%H!NGpJhN$L`4QUGvTrJ}Wv4KOmX<7i1J#`Dc}J2Ad1-K&_?F89b9CX^ z5~*=#mj8qr8C>2kT1J)p*d}Dh1TX)TLulS5U*l|5o)`dH)#TU_Hf(v3w z=2jN|$?0bU#5mByaf;Fx3;$w1y;H1u$pc#=?!v$H_@b4juS9&wa;@+$PHreLt&*`4 z`4;{a6<<76tVX2p5RV8qG!moqRR#>i7ejLw@tLc65u+_-*E>uPp?UO-v-q|Bga`CP z;xqXK)Ux8&j6f$}I2t21>}18S$w0UC zWtoYzf?9!-t&Vr;n;*YsAhx8ui3nL$)nu?2Eh4yR50s}nLM!=e0Wu-QS*>P>n{hB`XG%)zhV9ld$Uo3sH3hLf9jFm~oyfu+^U zk9cJ5B)^r`Vu#Z%i?NYQfZs$AY_XBi!O{d6LQJ8&jzu2{!mBH%kLQ>6)GEZQwbCJ5jjZq%KP2MV%u4| zw;?YwB=(S%jkz&ge1a&f?e?P1XgQGvsb=A6wR~rfYt$L&XqMAzfwoeHiwm;;`!LgI-(CZ;YA1( zeuh;82T6iYPKkixiy9L%bN@`76ylO<=472d@x?wyM!VV2B#Jjm4%V8zl5NnU7cojp zxdS!ugLw&`UH%T6)mDApNZchanYGD&#>w*hTOw-o2g0zZyNpfgT0vt#z(A5kYbBzS z<-Ix3(VSOCl@Fj5;HBw_qSVcjJ6^&QKL;ujBCiupu&LU9+p;nlQ_NLb)ip%%0z}n* z-&VFrE6d+m!>%zGka(kUn9b}~PF^&-+GkWPDQ&egQ}Co5e@%}c#+Fe;%rf>fdW3e8 zr05x2@&A~C9R9(I*C>uzOK54NrU8W9F+rRYoJXUKi80)xCNs5#dz9=t&<+9v$&NWImj>Q2bG-OM!t4%R zOpYn4N?`HdK>Rl&-qPRzSJ2Dc7M}0IvU(Z8681p3o2DRrZuKfD54TdnML@X^H<;Z_>+E5>t7xIUW`4r!oMPF93>6c9DJ_mzD$6I9u=WjL zP5lw0Ip@pBj5t%6*(;N_ApB=nbx**n%xD9*iM_jN9{R0(RY>Yu0RNA`W)n3@sK<)&*jWOySk@_Mo^rUBRpY{FtW^ z;Ey(7H;M9IvY)=Q{WiI}TR<2og9y}`6}8Y;CyB>dg@kM6H-zi7km4LkDqPHwnAlgG zh}g18#v1QvaeY8uU>Que9gLcaDrP^bxTTsi$Qb{Y2CWk~;*Ww>v`KQDubl}w*ehVeX$RlN+>e)nMRshTe_(~WkpYmI#3DviK_ z!m`2UuuK1vBZ;`@Y>gNZ&7+xYaTJ zYr7Qu1kGu=%ijEWCuv++Xiu)JA!C*71ca9Y%P=r-$sWTaOeEn^Ybo|*W93FvnRnCT zi!YP8*qPNd3TB47^evg!Li}^vrM$~ z{s3MVZbSBXZonHHlGNnxFuLlhb$*4R_P`c8fb=h zMhqf6#OPKvg2*0-GdgxBAEAZh$h;;fJeIXPYEjIt+@mAQa(73qLRUImbeqv-ll|RM zThaO5?6ODgLFYB?J`h*a?tr+)it8bC>rLHB{{I*vv3P3k%H89B4P7$2^{_iCgZ~Pp z6LTiI$4t9X{BJXLWBEVg5q}fWW!DnjN&Y_=Ch=v&g~Os-54)oV^Z!^EaUF)P`~gXA z6uNDu>sbE%@#1e0|Le_IHlwq0uoa!(E3R*$D>Gx+i*CvWiRA-y*{16Obn8XuN}WP6 zgN+_$3aNZwT3`b@9M(rDvt{A7Ey%QGA?ptbNF0`hJan=<%D;3^F2a;v=KX~Q7HatN z*S2>ZvC_;mr>!!374R^@838Mk(y-uz&92nM%^g&*+s|AkReoe%$ToFG%pQc4{l28f za18g3AFUj*z}HR>(D$qXp0SHin<6AFl4Rv_Ih@MSvj&=P7Bkf@CSPFL#(cXavAF5J z*K)gjvcM=Aud=&+NhS(HB^k2j*8<1OA9|1e`Wk{Q+KvSu+WS86!%rJgXQ!rd>B>`h z70L8Hk^D|P^j-F+#K0|k5-Z7iTw*DC&QA*QTl(pYLwwt8d60!}{?%9*_82+Nl&35M z%yL{U(u#j>g#-(_ina3B;=_II|<z?lhyaO9s!V{`VIKHT!h{cq0 z@iqxpC1tbN(wrU176ijPDq*P>M9676VsRrAE?uM;mR!Dfqqi;0`|FaXOn0R93E=oz?J$AUjkg{@l zpug~#hc~i@l(FB3d$8}J!jswg`Lba(uVnO5L~7mJ-7F;c3!}u2@j}~L+G0;`8~H0dS>u{dU$k^JugM8^6K!#2LCs*t zwW2$b->r1nDY0C*{i+7>}X=C8Y#;*y`b>|NPW zYxV9j9`7Ol8Jzc;^~SPqP0v3DMjtgrKvO8c3s;I^3YYUbR%DWF=xPK*T4aJ;RL{iovSgKj zxf1Pb(sn3AJ1Ikyl!3Y|JQj2B`nF8GG6psvp31$ZxrDu!B-0^VBpEW>F#gT{+bHdg z*K!L_RpvKkkHN#bEb(r!8B}nB==bh=Ew?B*0?o7Y~%5Im>NiK%R z3?}`-cp?2jRuBY}%$1w#1evEh%P7E;q@F-;k*pb~%;>}Jl{^L5#WOSKIBmjdBpcO_ zn7hyw_c`*M6yqf6wv#l^WHO_hMwsEjB(seB@{@ylmjeYgD|(d%W4e6I!Oc6&MRmas zP7*`#KEla&a6n98pg9uXV&&e9@f`6|agc!bo4MRu@u^jIXFON=-4`S>tQSO;UrFP# zhDsU3$}h!eW_3V8Xm^y<3h|0q%!uXw{;-O@(@X8r|OHrrU>U>)rY^!~2b&0Jmvei+xns2MKZFQ-wPPEl2wwh|IX||eWtC_Z%VyhXp z>bKQ)wwi3K>85J-o#gU4JSjnuya{EwMrFA(VJ~DhCSHi~mF3Qd1CZ@6%Y7KUP0Df?!4VkHlsrLlGt!50 z7?w&}kk*{E;3Q0GL0ZtRC24_{Mq02JGFz49u7z^QItM)*g8{9{1Du4x>F6P*4ROI% z@V6xmD20ch)L-jCQ=Rsov2wwMWuj*Q@WiGAOTtkan?$Y9xDlMMd_3_i;C#89LdfZ!TXtif3t#+lMB?Od~ zut8~c@(r!dNJC4!37Be=t}wKu%avAlp`q2yGqidu;458A-fw8hB}%Km-O%d04Xwe4 zFx}7^9)yc@Ev3lNQvRW|MvDxs(Rf2^9Hq3zJh9gJ8C~<0!VPd(*Zd#B9HsdWpk^9c zlO(7Mw-{Q}*>E$=0hdc_w#CqzJqK?ZTIv#)mU=ZLD6RQJy4L(9O>5E8P+CKHUsLJ@ zxIU8)>spg+5)#4EJ zRjOqVmrCmbu}Y=&F;uI~hC0XXQmxzSDqShnrlw1^4e09JT83(u?NaT}hpoEm5a&|o z`3;qEy{hrUq`u+r~mFjniQvJ8UT-dCu0bLAr!Sk9L z_@%A}9fiMiHP|rJ;AKh;8D*#od%{~v4Sf@S($uhTH8uP%rAD06)kxh?BcE4l)Ni^P zT?r=)HRd?{rm2fg!moxJ`vd&0t8tp4#+@|O_+Q`;T}?O%QM#IVzpf_T1BFUmtm|sB zf>tgyuP#$7_Zcfage2}nagxF>pM+d z(n434E>!B$CAymZy{6{;1I8*fw@6p>mcw49=D!PrmAY&oOjK&Y2)M$f7G4e$l*+#V z7Q0lzBA2>+o35@H;8Kh3P-^jQuvb%8#v1CX4Z2#g4h)yNdcIQE4A<2)R~qWtR}HoF zDW#Tef?{1Q-(aZ1G+hKJN80(f0&96AW^xo5#a&m%3%P zQn&hab?XqNZW{z28|wB0@QkMJcnX^6>dwY+)KGW5q^rAM)YUzunp(F(Q|lkl)V)g# zb>CI+fv)b4S8BsRLp>0qs|T}O>Y+h~diZgr9(l)58^;;y(VLZe>_S~VeyyRN*srT6 zf7I2cA9VH9N?koY*ig^x(bVP%x_WlJuC@#@)N{`mYU|T*LQ~IQuB#V5Gt`USlzQoH zL%p2nQmW$Cg2~EBEIDDe3w?2j!m3sRHC^pnPZ!7igJFriwz3;)Fx_VC;>b*Tm z?d#-H?{|b-HTA(QFiEKoN5aKQ?H>h`mHKEj3{~pDaPYX)$Aew!lL_#FPQcm80wW0}!w4Mjg0C>8^WVi>60yh4#80-3}hn^coLCv`dePg61yW zoeEDXJ@yIsRMTr7f@EFy)Q7sdUaKCAHuSiQpq@*QPlm=W-P;JR)%Dt|;GnK2L>YR* z2ZmnfeQ4p*6K~e_q+6h+ORt*-wGF*qB51mvT&eWr=DJ=#6+TjWgZJ6I>z45aU&~;xBY8krU16jJ>q$@1b^`?v9J56tP44UbBYC7b*^yURH(9m1t z>3WM8U2j_10}bDLq|-nl8OfENs>Fw$DMF zOFuUWUeNV+&qJ0=Z{HQ(G4u}a!Z<@eZ!D};dd3Pksp%bmg-T8D^cNH=z4LOo)zCZp z4L!52OV5nb^)4=G<2{d&zkMhvsUVQw-xY?rgwiEu2*`GIWE1&wT7O3 z4P0sHJr_eWL+_Oe#|*u91w5_meV&2=hTiuA7~s!5ddjD6TSl0(!0UHecg2&+l zT_5;9#4CMJ9PHQi!5>0*r4NaB=@+im^$Wc&eQ15yqv^w5huumaz6)M7^bs$?HeDaN zSJOwm3zz8n=vi<~*T=*e`j`uK{i5eI{i4B!KK5mppzGsqH1u)fb$$HRhCY6Xp-&hC zm+Sh()$oC)Px=r}X!^y!z^A%C`4Dtd`ji^*gRbX%4?pVq)Z_4zuIFB7=(%qj`n31p zGegh&6cSzf^g2+e>odB;c*D@6Avwc+vvVZ0GVTv5aoMO;z(Q59u;4sRGyuGiov6&3XZ95$k&cj-|zc0wOlR7`KU z(1>zBtVg-eH=<%Y!455|=F1Q=qCDl0qoQg}fgMIv+;(VTL~BX#jf&RFVWBHp&4U=| z4DE~>T0M9~uc1m|tgD9JAI@{tFk)b@Uc>b+?9*#Ry$6r$Fwbb0T(v&+cO>@V!QttS4%^iP^a(mlrZf|SluH8v<*G^aNge=XS&_=oI z^wivS+A4QqZ_S-}u5u^!(cDSxl)G+U&0V*>a@Xspx$AXM?&SWOJNZ22u79ECuAiaY z4Mu401|5~V;YiKhu#7 z7(F&>G<>VaMu*@#6fcc z9~rUnpTIXptoLj9Ma97O;V_2gm|`1P841DN8fX-tG)RZZ77(7>n}RS#Mj z9_=R0qi)tb`fZxWIG}l4pJ|?`dzB~pKIN&gQ+Z-4l*j$O^2DB0o|?ZYkEfCDsnt~X z#HF}Aap&ru`15p+H$(T-?x=eb3Up7MrMf4vME4}!$g<%k-BYhZ_ay(yGU8mr)1aH- zX?TUP_#QAk{^t!(lNSt6(_MzA*&f4_y4RqoyF4vwxjZc!xIAeM zU7l7=T%L0#xje0FxIF3eU7j|VxjbzbxIE`x>GHI@%H?T)jmy*FT9@a%>vT`Xx60Fz zOS?`X<>}nR@MJz^c)Fx>GH9l&mNr+f#YkC8?NGJ!b?~rJ%UB1G>9t&?km0Ho6$8Co zag3{R+DIc#jeuMgr%!>qjX2{jh}Pp=EQMTcjku`u;0qNO{W<)p#nn)*xEdq%xR|L> zV#K*u!SzO5>Ts24=t|2 zn^0-QHGB(-U2!Qz(8P#q)EuU{;u`0`Y(37mP>=I3(Bqmk)Z?0_=yA=as<_napo1RQ zyc-m#xE2H8UL&sMgV5TD*UmTMRVUc0;`OKDAr)^t2+4*#?BG>wQRpts%gpO#f885Z zQ}ag0YTg=d%^P!p=5@zt-q;$Nw`R2F^$gLxwOVW5xG2pVKUnj6=W5>C=V;!9L7KPD zM9rHxNAo6Ksd?+_nz!CS&70gx^VXlOc^eGSybTv?-joTNx6yT)xACQ#*H=&T`WI^6 zCXF<2(?y!MSu@R>dadSd-a_-XDAv3!YiZuJx|+9Dea(ALiso(IMDwOM)x2#|HE-MI zn)lq6nzvn==53#@c{{Y%yytb&yct=Vw_{Ju+o`wa?c7K6X7<&*UHWO>^ZRSwt{1W$ zGeYxr8>xA_kJ7w7Mr+>eF`BpMMVhzQSk2peoaXH_Ui0>yqTa^UgR|^UfTud1p=0yq7G{yq8{~d1qgvdFK>r-nrLn-g&h(@B9qSd)YM2 zyC6aHF07+@^XnP4wTFz_YNK9TALXiTJgV1rwQ<#sIl~CtCBf)$?z1rp+ zhCkSw`yE2;9hJjQL)W)ME{n8_p{DL~onpQ9x)Bw%4UXv1(RXPzqVI&=dJOBOnCQMP zcXS`9tzx6=sG8CJpeN(w4bYpdqnn@?{r*Piq2i<0K(_Kmm%?DZcJu(~qbEf7hD%*_ zqA!72uEgk>uu&yNKMfweZge8V>h+@Ipq8E-odlCz^`oc55u<+e=URj4!!S>87(EB> zS1Hjw^+wV67>%Rv1i#A{?SrX?KYAE+)|*6kf)}->(Ko;Zqgiw|^wU$L`@&|`Jo*{< zO0|go5^{`|(L-T|krq7@&M{g=r@$oRoanwVP;VW50SwX8qX)ryqfK;ASKH`rFwrEbA-W7E8|Ov$hl`Dj=zb6~Iz|t4b&4Jjml>U-7r=ZYGkPAh z*1Oc`0Y|j+V?F|p>guiwkEpEJ?eLoFR)kz7FQtKW41q{>s)E)~X^u7t>V4c=4`VM$d>mU7%HXz!qUl6^<7#Ka(H7I(9YcOwM z@W6SyUAe`u0s^oaZh~9kPFM%`!$a^WJPFUh7I*<(h1cLM*bhgc9FD>F@H3o*Q&0&; z`(3%wP!r;z4%CAN&&icod$37hxBC03X94I09cn2!4j> z^C%b8f%@QsbD%Sfgeh$6LM_?0dfiid-_QD77F?FVKVG7KG#ZUy- z!y32|Zid@o9XtY?;d$5&yWlO@4_`nz`~s)oFHoI!<<@|jP#b*E6k0+%$bum-3UXl~ zTm#GCIw*k~;SSgc&%$J0+V4DEQ9MH2sgsL z@DMx$+o240!<+CP9Du{{6&!;f;WyASX&+Dv5}_e9ftJt)&Vw${1Ny=s7!DV~B*=wX zFb@jgDp&?9pagD$+hH9%0FS~`uo+&2ZLlAXf!>8a2W{az$bufw4=#Wqa1l(0E1(1( zhPUB!I0@SM^keWsGPHzlFaSovY$$>aPzFcA=!y)$1C5|9w1*5hAG$$Lm z!DsLl`~jXU`WQ5ZHZTAt!3-#XBDf76hL_rF zTm{#|9k32Iz{BtuY=W)uI_!hPa18zeZ}(lfDR3_Ig@G^_hQdg=7;<4DTn>w28LWYO z;YD~A-hh4Z5qts1!RUb;Ar=y$31q?mxDYOai{TQu9G1gsxB+f~+u;Ft2sXm=@CxjM zLvR?rgrC8ay(_mh^ngJy1FnI)U?V&Zo8Vb^1>S&2K$3)~A2!Xxk~JONL`^Y9AnfZgymd;p)p_wXBd z2JFhM3w}5Uy1;Ol0`uS+D1_@E0IT3OxEnUY7T5tF!ME@i7#Gm@p*A#wc5ohKLU-s5 zgJ2@efh%AstcIK57PuYmg7vTkUV>e)AC5vf9E0QV6P$qGz%`I@9}=NH_@OzZLtAJM zU7#NfgV8VvX2WH0ITXPLcmejn`>-EAhC^@!zJX(K5^4;hEkaXh37ugO41@8I1DC=) zSOV)|2Ydu4q2XZGHqaYJ!8Di;*T6Ek4gzo+JPgmln{W`0z_;){`~t2a)F~uGD`*St z;5_IA=ROc}CLu=>&*)Rge z!UVV&rowcX1+(EYSPaWy4XlORVFPS}op1!chaaI5T*GN+kOCc`C-i~-Fd8O7F3g3i zVL22-0M@{rupSPzm}-$_~lkhqllGvY-d_hoLYE z#=*sK3Cx2l;7Yg}3Sl*@hYj!$JPpsmPS^!+!9n;2{(>5#7|S3Ik{}rxLsMu8?V&r2 zfH9B*vta>T1Gm8=@G^V=Cm?P#?F9zFFc=Fn;4-)pu7>5X8g7O=;9htX9*1Y)1=tCD z;4Rn(pTHOJ4^U&MJMchls0%631X{p3&=LB;1uzUo!z`E!3tvtTh?11sQWxC=JGW_ST!hfm-rd;{OYarhBVz;ECh$65e9P#YRT3up!HpfhB_ z02l&eU;<2mT*!l2un?|=Lbwisa3een&%mot25-XKuopgrgKz}Cgs&k4$KYr94P=kV z`S~3Us_4sYv*-`YA3r~sCs?5#iFi&}^t-W>pXgupn_5#Z=RwGi=L9vLCp3S4{-?_y zzgHVss{BjXetyfm*iy`YI|@^em+BtTdm_KoN3Z3Oc)7C}k_eAKgiO{z`$MLOclOpWXBJ6ua=(|Pu z>01?4>mQ-_MfgvN&^M0Iw~dIWLxf&Vp>v|@6rt}Jp>H3dPkX@et!aHC^yfzSk&}KM zU%$3;bei^OguZozpK~Jg-$eLn5n=ygguZ2j{`m;K9AWRIHVREXEaoMq7LFxq^9X%* zguX|FzPG&iWdHoA-6Ql^nv1huL}`sz1X1 z+z9>Ec7OgPqFe_f^yfw7Q~G;jJFMulBlPvrXTd7$#Vv|(qB{BcjROkAEI~xAD;j>H zZ)a(>&(S;WU+m@Q_=&gui2Wox&)aNwaoQfCHxG`m{qMm33)^is>Nn5~xA#zguoA72_o@0VVyFG*~yFO z9eIe}NmKMwBI?3*z1Ud4ulbgy^Aq`XwGAXydA_ZG4gD@V?Vbq4@juYfpgL_ztfocS zFOAU8kI-Kep?62WLp>0Y{|M_dw0_&h zng7=kZXtF~-;{Y=+!kUn7kg*^cIItou6E{WXO13f$NPq@I`i_ow%M73o%z?9Z};2o z&fMzEtInM2%%Ac$nTLF>v&-qskIvla%!|&P=*)-C{O8Pl&b%jMyZoH7-5J-jOBTSmTT>P9K+XMEspThB)JgGhR63!)N$k9#u6i z>|+3JPx(JZjX^z(8jE_wR(GSmg0P%%;6uz(ug;iPK!>P<|Am%nTxP1um}jcJ4C#0B z4S_|rDt%JSD{WQsE#|GZ`iiaoMVl4-leQ}TzZd4;P4#)h883c`a2Gi|ZHNEaw*S^v ze=x(*PfhiC!x>8|Z1-8#ULopQTMT)!EuyROthAY&9pg zvQpkCpMsi)IvMp+)S0&ZB-A;WBgY(qhkqAyw!mz-5{lqP*Z@z%EAS2+gm2+jh_1gU zw=SFmy)<(f6Ar^aK&9--O@`Lc6^6nLxC&Oo1F#J~f^Xmy)M>OQwl9%g@(NctQl*#qfYq@ka&0mLo2FwRGS>|n+ zXJLNKHcv@pk5&A?Xt`%6v5$p0`vuE9r7n94n8$9k%shVvol}V)_<#P#lJi#BL1Z=w_*Mh zWd4))$HmU@@5yZhV&}K*QZbJN37cWtO~H)zKl&9CrhG`58Lsqy5I(Z~?Iir*|0wnU z=RFruSNVyrndKjnlb<{Dv?jQhGG!;cW}Yyxv>|)Zn5WdX%>G8~NlTe+^O45v^R9F}&DamdJT~byv;9m-Wq%a&9@?+jewwpS)`W4wi4U^} zv)49fw`30u^B-P2Kdsoy#9VHhwbtybVScNI6~ETTYOmU+>h1OCC#%|PI{rl-1OCmb z$;7|3!9Z|e>piCKzhtBvW<8hj8UP^nC@%I47e2M!JyM1jwZ9IJGpNxm6 zkAJ2A3;CB3HuL{9`Olv{D?k75D?sFb8wa2{@|XE5%{FJZwfgg0r^)++ez^7k=E)YuW%#(b2%a_@peuxC|S?$HTlxgWsZU|DVv?kCaDpU620=rb5&9>)HU z-khm``50$g#ZrK>zAX0yN_=&_d z1xjH(l!1(KGTzGgIuBW02{Oh>8PDeC*caP=&t_hYn}ody)rni;6~F(?Ei%2xeB5q_ zbySJR`OT3zH*I15f?0ECr2FU3TiETwd2{p9{dsezRT*;U&CM-Xupn=4zUkV^-= zzd2hEHP?&&c?KX1BeVP&DMlP^b|UNC$1|NVKKkuz)V!hC2@~KNu_{x&@SCS zeRj@_g`%lyDF3?E%+0&PDvy~zJ0H>@>{8B~nvd+c9%0y!baQg0%;I5o-t_!A^Qe_H z1Yiy{rs;}V`7`}FW^4=cE~ka%`RC`zh(5O!<(k`O9(J>H=Fc~qTCUZMbMqETz1sc| zjFUQvl9U~pB%U{iMsH@MN+eFxG*#p?_rEHjw6KKI{c{WEOqHo=x}RhgwmMy8`33W5 z=lLbTWJ`KZh{^M&PnHmq=j2SwYh_jG83Hw9`=>&s-2c8n&FCV8YSxR?n^lW{C&+~| z|AxmOrxW#G0Qs$3I^huAS%8 zqGf(|T*(UB{^$ z%++f~qNa1prlGTfBPuccn|0<$^6%=+%zQ+hF~Ul6>5{EB?QOwVRh1dt8P#P*@;|C7 zGrk;K08VwuApaj$l_MjkxHNNHPN!8)wTkrn|Gipd#r5B*JtF!K>dtEOW|7X?=l;XG zlWt~4R;{c3&+E=!5LWMM|Bbq{rS#vZIctVoI6r6Z*($I@o5-G5ttVD@IW3F ze}q4~ugdgoxPiDtWYr`zirhTh3y6>4I?cY_u zmBasdq&<7}n~@<8djLOkq&1~!k8lwq>ECu%C&GU|>^jRM&6?2CrsYk~p+pgv*Wv0v z+pOpeOVVAqT#~h>tnbWv{kutW6qWAGBIG`tPdjOIabV?!c(_V;WD%^GFudKMHgA)mKY-PCfdA3^t@?l%vxN|=5sM9TQ^pd z`oGwF5Ae8(b8mdkYNb7rY)kS=R8l5PT#T%YY~`Lo^#4M=duvd&rA5$ zZ#~f3va5a@2LRc~H8t0tvHhHrcjT-pWFu+Qe<&wd^*1Zn{+=ZsN+EtKa;ep{_RH^;u*^7sNyO&-7M305Lx2i z+l>^Zo7nYsrNe>Y5sT(%BgVseA#XgN8~LLRB5e-*jf4NA78>WJ=nj{QfB)bh{;)#R zp8X?3#3N>km)6{j`5Q|0ZyfuJd^mI4Kd*E#viMio>Uu^w#FER&5-Ht(Udd`1%i+u0 z7I4le@u)3%9M56GRs#7)hMdTe!*bzh4PUZP`oE*h_{AqHXb+!vdp!no##0dls`V)8VI3t_UX6In8tPIZ9EVHqLV^%{X4!cjmz;o;N6Ly@jUGD*9`*vbd zU>E`X4Le3=XUOa{aaZ9K8D^M4rw)Gn3WnK#d4~YZj*6GMzda0Dvo-NId1Tg#4r>Kx zZa@DVtTE~}5N7R>)_ce14(_d(Zw`#7|I7TplLM!pvh}1BPS~_-)3)91bK2%^JNE zUw~&3AH)IL5{1Cp$uBx=+hN-dGJHa~?FhFW;kM6*75^Z?fAB0;icm}`V)qF6)&0;kloJ(;KZvmXa?*-t-qZO!aYC*eNFdu)U z2WBvWZ;@KCSS?th7A#c@6|-U?N@5`bUD%4hJX&d0i_{`0ph5cZsB0{ieYNWq25r+$SNF|+)CZWS4sDr%-lWJ!) z9gF0kgXFdJ!DKWQ9Y}}MvBW@kBH2&RU_*bPiW7^*m+6Q{9e2VMpPIvPKG;0p^w00k?6WKB5%>?Kv%TOnr$k@vOkd4fdDPW983129FzUT zl8IsDVk!~?g(^z9E7lVOcPbU@8HjeNFmR?j%{)mXgmfp0A7zT-OsB&r^)6G1a!sZR z8B%97o*4Gn#iVQ7P`D=uYDG2VOzZ1(NASsx!SYs>w{MH=OE= zjYNApQLCcxV`P1J03{LCjdH9p9JhW(RAiQlg!}rT4Dbnep^l zI#mP_(+|2vVC?TiTP#|eR+os@u2rKg6_e&hPeMoNJ4DmO1!7nz>LO9KpV~8Vj!q2@ z(CJYX$LQ0Di(B+!#KkT8GUDPEJsNNwCVDL5;uifDadC^@i@3N&=Kvi2K%`qmdQk>p zYA6Ya+MZ}?xHme$eCbZaA?n6c`@@5SW2tCc(WJ@RtPkl}IvzcY3bB;sMeTzaNhbPG zZ6YYMSTe#wSc88bACxX?Y!=g9f@cxyjKyQ=k*vKT9GNZF6-_|s4EClDbC9*lktx|= zj^xmzQ5=C)`UtI~4v85RNp$4kn!Y5eH~NB;pJJQe0K&(3!?aIcUgTo`yMW&?Cr-t9bzVjXIBky33q@v-*6A;^?4u+HHfqJ8< z7!pPDm=vJGp-Dop!c78ym~C^0EQlmy(tY-alYJ?Kdo(MQwwGB)n%hMZ0_lFPpgps(npHIau>}Qkl**35atE339y$B`UoGS)@}m`d|!|6C)GQ2N}sh z4)h}EujnY5pnDIO5gnR?ilFrjCc%yfz?2z?#+aX3%nsH(D?=FH95U#91|lQ6D!_TJ z5grdy)D1`A@i5Xqi~xr-Dl#&dj3t0;UH3HTTtP^pyJYkYqMLWtfHs~rm=WQ4N|r|& zz2VQTiieR**m2dRFvRRaQQ^U;G8s$t0yRo*t?24hT~Yiav3_!EU1t$ZsC|i))Ux!* zAo;q(nRwdk@FIz>=pYI=4VyteNl5H8inXlP;D@dgR4Y;Y#?E@bS#c4)|JShzt-bVjq4$v#@A*N zX(V>7>Pn$%b>W{uBSSjjql&6%7=N_26b2l_u`Y~uqCF#nqNG9UjiF2GiI1?Si1sH? zi_u(EbO8SdAIdQli=LMpM&LvR;_Ars?4W$SKTNizL4@bxx)G;P;URa@jFgFkC-@O! zj`Oi(+r4N<$N&*?$U>AZM!PXl5@@>~!jh#8iBj)#47!lV6Of;VU*eI)y}&cc#Gp5+ zR8eEhN=r-O^a5gx0u<9u2+MewvnYsNiIt3vi83B!A%fbDEK=R78?`D5HJRdYRCNQV zhDm`IjiTl@9wDTn{e7Icb;pvaG<)EIo>(e@RtM(^{LwflkuVPFPKNnJBtG4#nCi~N zX%s9drBkF8#ED7n2!Cx=(Ala8z zy_jtGj^K~FFrYAxi*-f#psvRTP>Co(M3I_-ngqy^D(D;Ja-?hYh)eV5f&UY~8VS zkO{J46hmdeI1)V?gg?TD!U2%cb6aC}A_R>N2aLwy&D8JwAJ4+Ag=5@V41xhAdF45_{_{@r+DND(xwyr6}X zIDmK$THT5rl7|wp2txthnHiwgvrb$=v-28KF{7tH5J8ZySZxqrHNs4=#6;4opO!S( zn;76SA=qpt^@T@J5(oye5+0)3iIPb5O1yhf+#o=;a{(AY!CDCvETKfZ*uwgRc}T@o ze3nAj!YAC-3k{KrhZB6Lpc!bj&1lRDA-4gunIQxz9}nxYLwe0EWo9iS9<9s6L}D^% zgea-y+T!7!2wUe^wybwzD}Ex@;DSvQf6O=sdZZr7ni~~}OudXmgQ*PQ?8Zt{mTvGU z)_)Nb6m$-Q?HO}OSVzVh3kIQBUSi0DkO|Oa^;c{07$&u5aadE#05#sN;<0|j7)l1} z0MUVHIO*v|>R=(*SY*fOBzz; zg5fb0;Qgw9mg*1puEBW2>UwO8Q3NVGYiB>oOB4!48aOZ-(TSE}90X)9EYj!`&2Usq zV^*GxD6|DYZfkD^bV^)}HJOPNN(XYWKZ-x1qNk7j(J0~;ji#fRbc~?0&%sfN#~E!4 zM%$!E$Tlh*v0##xieVSRnsW!<{V}x0{+OM?0z*1TfQE7bMpFuFeX^3R#1O?w;XoAo z1G$Mb3CGgMJMti{@Y3_e%d#U7Sr|6xBf0_uC&YHiX^h9|Xrxy!WRlFtdXXGQ&@meC zQEtR?{EDmo_z1EEl`GN3rJ?u41ss+KaMR zdVyC|jJ!<)?;i;dpl&Loi+If9M&9+0KsXPmfmsT27i$`LV3rJ35CSr+P^kNMm3tsM z%(e~la2gBQ7@|;GYEqvX=u7Z{5?2^*4J7p9J9I8$!#t)B#2T_UYRS%jL4~J@0V@=N zrUt|8=cJ+0XclKMl0$sat)m}+G+`$XQxd~lh4}~R-=v@bf)WAqsVK~c0nFN+eP<9HVzkVoOvqc4Cn@eyA2PLHv*qe*> zfhUd)2rTVzI05ki41+9Ad5NYH83+w-LuoS>Zu*2t%k6}gi3wIsh2$m%@sAGVj+bP4 zhx>qL0Em@?L=T5oWKYHz=VTuoCyAj!iXusY{6Q+HN}}|Jpe7uBeM0!hO;m)IGi)_x zJlgyw1 z2G!s!#Wg{Rd$x1Jx^`-005*C#S+G7b8~Iz9=c!r$fIw*oA*Lo|wWq4mM3u z9eP9oBlTD+odBmnx*%6zz<_D6cK{yuCa?u4eNfKWisbR*tiwq;1D+g94u}TfJCchw z0x^u5HyBSMmI?e3P1Fb01x(xY3NZx=exrU)Z{v=V(NsMuliCz@O2>N71CWAddDk4&{@;QlJg9t1jrcx?3OQpj2 zck#jWG=6-(26xv2B$ITQ_j|xHyT%|VN^=aUsEIaqXkgGR0`5I z2Atz%g(1_IU; zh6fZHr|$bjmC2)rnLHj+LnseCR8R-mC#EpU=I-9%l++PO*=D4MF#qDBh=AhPL}xdaAZ0j&Xd{}k zkv*)~l!iN1&WHueu~9X=MhznfQS>03M)rS@Ss2g^YZ+@+H`j6OO2u|5z*8jXk=(jL ztVXU&W!9;6>(q#1=axNf0&Eyfl&uxilp2ZQkIWv4NgLG~)=@eB>bI3@B)d*E60;-{< z8?aDVR7`Zj#7UDTm6VoE4weTif&x>t77SJbsR{TUgSQ7cd*bbY9pQdw19Q#*Cq^t$>P4GqUM&YU&7p`oFv`Pi1w zoVoK_+i;9^;iAP$mM&YqV&$sU9UbA$2w(wfxYodFS|T`Mf^&buEMkL>T9mmHctxNkaevxjRWdds_Sy)Axw{Ej>Cy8Au%+ z)G?|N95eBT?1^eN!r@Q5WLQnc$7Z9GcC2avPe{!H-&{2hKH{J^j&b9>GY&T6j5U6X zL0y9L$Het-8Qy8XLaoGC653(6+M~Ct4je}AggJsU5AE2T$380bUWF|e`K>W}9~SNV z#U0icFs)vzF#5$XE`zt;4=Z*I>(y~$K3;858`UPYS#42UVSj?!rnbZWM8kiQI$50p z^Qr1Ib-Fr3ovC)Hv%r70+NpMd{~UF$IuG`{)%jw+K)p*{2=hf^ZdVtpOVl2i_o_?P zWr)$`>I!uwVtJL?C-J*lU8Am*SnpTYsq57Z>PB^wm=CC%)h+7X>Q?aGrfyevs5_Ax zcd5J8d&Hi3b&tAN-KXwX52*Lz+a>Rp5_wSkeMnTBqq+LS>JhPfSkw=wgX&Skd(h|~ zRFA30fj?o)bp51yD#w)TAMp?2d0IW=aXhO&tUjVX3iHSCd>r^EjNK>Ir_`s_bLx=# z3{<-PtfWjc$MEInBNqt#;MSWGhgkQUQS!nI*YwGLj8}RKp z^-akcT^GJ3w%=CYK@NRa{hRt8%-@&V)2@D?ekis-Qa@I&2<=tR;TP``xvKLlsH_?7x~PA%6hZKC?k7}{&ku%NXo(_|BIaaT8>cwWp82bj8 zj>(}kIy2$JETPOss7-j9onuW5TcC#w_he^|^Msezw%t;vG@0vAp3HMvoi@kjD)n|} zzSt~qSPO6+!dV1tv9rYdSSCxIWzKSE1yZMfFR7I|G1TeTXKb~>GiquU{U z?Q*hpJnD2KgcnUKrEQPX3(9=S-x^>qshG0{A@n(M35WPgO5?QCG5x$L57t-xyUoO} zUG*CtOV_ch73!;M0D1y3W%>u5waAa8$DeZ2PMyj)L(Z_tr*+PVv)(z*Oa1ZA25@h5 zHW@dYoh^cGbxv@eLvC$zC`Y%0cA|3<)Z2`_JlQ$LIaPdNtWI-Icg}Fmg#8Y2-LB4Z z&USV>yPR{JbDi^$`!=_;I^FF?7}U>)s|&>Cm(;tQvA+wQu|J&)T76MmTgpWe%Eitl z&K_s4bE%1mw!O@`+_@r$awT}JyQ_r$yyW*jr(Rv{{7PNpTaYOzaoEsh6 zm)_(YaBhbEEqHpIcRRN_w>h^vcfj)VW*?Z$nNb04Vp8?JWs08H)bz0UiD!uIffsr5Fb7a`%Y`TU@8KLqt*;cr)u z0RMpT&BpJbXMWWAAnYG=9(SIA{v;m$o`U`%JWm^QyL!fRkqxWJdDi)`aD2r1sPi%B zY_MdS+3p<-%&pV$pCL2E;iypY4jI+Pb!x!3+ zZhx9H8#`@g&-4Z7%jyN^i_VKV+%ff~F{YT;4y_EJ{$(Q}zT$kVNR){Q9$`WVK13j(d$0bN=ESgCBX`gk8+oYd-c2`uA7R-x9m2 z4nET4Bb9zQKA%tfl?PqRR6lHKqv~HM&cDyO3#!9CNd~Nv=0n>ON=J7t6hx<5N z%K@3Vm1Y5RdZ)bH%;HLXQ>WEV&*82EUY}(yok5&0uC-ui6_!}s&`{b?Utio%Tv}Y* zP!GpYX)YzLp`rem`qIY6nGLgMW?eSS0-pdp2YW+zW&(y(45k_p-}U@;?`D#YoLv~cuA$96tQElNKrdNEv}#6(y{<%M3W$PA%Hm3 zUbHSmeOu&tQChlqNoeUZ8?e?f&uv*jca6EQ3g*>_5&&~xx3JR}5%!f~Ul;kJEiJmd ze2v|nyB@IgB37|AeJw4GV&53=M-&JHQNt(xBnD{`v|B<6g*3lmg8wZoO%=Yi60eq) zH8iiG7Si7N=8`ko64H@`AFISEA|4{I2Z@%X@snDzJC%kN51%p!v1!p&F9QQ(wJb$- z)!-_LqHr|Q?^UaiMIpLR3=I#Z8PE`7H`v%>qF!EGTe~h4T9$;vRiVLEjrfPK<(3F7 zODt;%ErWwW`eKsW(ijD5_!+bb5AIAjEz6Qa=@1F7aC0Q zh^bM>A0KJKO)c>Uk*lqpKYza8pMw9kXn?H>nf8-Jkf=XWQCqTYDghrNeUZp|_#trEfIA}>H)7?6rJ|Czlc+k?F+PDG9gHNUcVB`+MSRc~u*0?h9g1v!_umHOb&m@~kr?<&;2>HK(MUqHL?8H+VmmxkG zJdh&vfdIB7?2|NyLdVk+NVyhPmdN^$W!r$Xwxp%HBwJEwo(vq)3b6o?AB|(NPe&S( zfPfAHK_M^zs*?aC)s5QPnCg}S(&F26Ds!~SXr-m6G&O-;7X&>)tfh-UCqYirgM^@m zXl?^g2Z;GpKxye|;5+?{X012Vs<`+}=yboMIi%@lolV%;(XngSE+1YKb}r+6UPs4n z>gQkJd)I}&i!LVaE4+~ECFnOg2z%Jl-HY~06?8A!rc<&uRGtf$TB&{6g3A|NF8N>+ z6}cjEWrQ7c{gsjS;$r0a6<1tQTzpk=@iC3FBc;Wz+g@5)6WJ&JL)mWO>T9-NiyU#? z{gH?piR`b50Fj3U=SKF^NN~phDSp2=iClL*O$5VRLsm`EYOYZVfb9#?G^E=ZFdZ-B z1_od?G>Kx!Ilk5$XK2*?8cfo(h3j5)1Ni}B>t1xD2U!cv02Uzo5$l^+2MDb!SHNi) z#c-P0;s6B3CvXXsHjOnr`xexF{4_B<%{xS!g=iWvI4NFRAnKopTP#{~VTi zf$yYqeCIG$x()e!yG%alL`eqeRD?o~@8(-10g_6r6|>yXNN#Uxifq4QHQVW`Wq01y z1--FxbyF96&m344k*w6dL0vDIWQ@e`7D8=pW3FIne2)0aU{NTmDcRk{p>+`+)#v3p8eZak`6D5c+j2mjJ1{Rz72I5tU zJ;IAF_Uj~f2zL1YzMH+gB#szDsEIlYk-4boyT0D?1* z0X$~Ng1Wczab3CL-VSTv64jC;frJ?X!4lB8K{`kDuB)^0il#|S)7}m|I7rF?jxh<# zT4K6KG1XDzuNF5?q+23Sq*70!6M721_05N3%ELn1fbG^PJpf@K3#C=34jBsWzb#8#gMN2 zRvx3?19YZK%h3j+9D@=JnM^rd-+GwWOHT^bgX7S((x6>Jg^Tqj!~sK;K?f8ghC)YN zbO5oWWI|WWkt=D8a9*is*0+T>gw9cn%exSRi(8x zwN=H%HO2YUiYuKetmRbs9AAEZzLS^d%lG;HH8uX40&FDueU%Cu2iT3Ma%yov0UL}y zRT;$R$5lbFpt7K#GGFCaq7+nRb#1LbKfjiz4szt2;=mippfbleIPH69$P66;hApfc8Ciea@f*A|94G!waMH;dPT?Gk zFz$E+ZYXBY@)`yYGKH zc)*SpkEY{rNNxbY9|Am_LwjWR2M*>KcRxA~J~$4JCW$EW2^9E*yj+k83M4e3K!c23 zsMr}6gck%bz;w-&V1$VT97KXFD}k&pEdxxR%tKGQ;ZzuyVgQ|y0Qw<;Y6CR}WE2L) zioIzDrW>d;AoCA43Ho2JwX3d%{phr=d=U|PRz$L#qbLP&SXMk_NGr(m8 zyn_&cC9(wq3l}b0wAg~2>{?=ADPS33Ibp?$6|`KrYSpUM2H0PR0i6bHXWykEiWb}5 z-P6<4OTcNv*cuIe2JD%ie!u|k3t7;EmchZbYm)+Y?3ml!GZ`G>GO*47ju;B?m?7af z1IG(&*s#&SrcIkR6SfF!-Fkw7Z3bi#=_$bzPXd@Ge+t2C@~5A{M!w@L16*by?92hI zx$HW}z_}LA1E2w%p92>Nyi4H13ojZ27hjB{V1T^>mtK0=WtUxk`Q=w!aiu^oc$L7u zeOC)ybIrBaUMuBDg`(oREKpQje}e(L_;8bf0|st3a0}txS-ADK+wZvJP6!JFcaMel z++*Ng1NQ+$lso`{xUi9W-}~MV2nHW~@WF>30`cL89{~h|A0Qk&co5=1SSbb`dn_1y z{P8EAAmPa;pAz_xz|&7Z19=;{JaM=1%sb6@OcAYFz^Ba_Foiu@x?D0__BeoeB~=&)$o$Q%Lcw? z;OhpyL4ZHsH1I70-yQ?O;CFK1yJLW{3c4aJNVF}DIZJh>fk z2jETs#SBFZ2PPCP6f0Jy7?JW`&J`(5AWI-jFwOu_nix?+S@NisBac1yIN%AulK=`5 zijk)QT8>bXXj$@607ZxqA0j^}Iw&?MGAJ%6DkvT(5-0{J0@(c7^x5oR1hCn&$)mkX zgJ)xBQ)e@06KC^g(`K_~lV&q!^JQ~o6J_&clVo$uZHxb#ZIAwPRP(R)_pkQ%ulD!1 zwLd$*9eaO8dO7Lhur@s@IH{cYq)8Q8n>1+(kjhDus;Vckj~ov*f!e8tbDDMWFa4jB z1JnOG-g>^uVKKSkbkrLxSp2}khYVU~=PZ8AUx4i(eTii`j`zsKYt{1AtBKePE#4Z) za+z1Xy|VTQ)-vXhITc17ya{91KiG=D62>g!3D3c``>*qGjV!6mzlFD3=9=F;qw8BP z_JpFn?Xp%JdApk{V{fhKJ1ZwDeOG1dO%;7lMc-24 z9Tj~)WiIZg@Ma3{rd)!%DU3hwr(7<#Q?3&8KAe5$?`k}}qoT3>iuY8=fBg}DHz?j; zp?Z@#Fz$CV?z8a6J1ttLdaK-R(KfdU{bt;Bxfyp|ZkD?)cjLYbfA7Ivm$5&6^W}cr ze#zc{c~Cv1c)vy8YIzjrwfWQZyXEtsINv79QM}iZ9x) zGO^R4IMu znyc!a8Td6gf51H+{&<5&|7JO}akjb%_jmX^7QYsxHH3RR`Zw2^C%&}emJaXf@NUla zYJs!R{1!R9m!ogv{Mjp=Y{~P^&I)IxY5( z&2i%6Iw$wX`#1D_BTnq=-zLY_RnmDMXDjaF@V8CeZ+CbThxc!EUY+Xj_Km)OL&^@v z{?2mv)Aw+)`N|tPypyxrIbVFZ0QYS!bS^T!%~cmW`UZ`4!J9Pt_RN*eRru|b-_=g` zhRpT2C3C%VgXe>F$sBD{H{!+&f4nVoBY1Acof-aa@ovoAF1KdxH16+m^zUxmjiFEX z;D*dS&b_z;qy4?#Ir{Gb@Z{R^j?DXy@O#ksMIUWT7^^?zaXjqk-y@=bz&Qv#o5H#3 z(J`j+U-$Z;l$`l|Dc_(|56oR>}LufwGKh_AtxHngXY+1P7}R=;lSKZLt8 zN`1q`(uOw|cWW&7w~U=Nf6$n-^5WY<(dO^uNRIFrU%v}eE{q*tjyGj_y^S^5Tr)o8 zDMh1!JP(1j&j(AtQd|or6chvs+=7Ba*DWe4C@$8!a8xH4R5sdVtIf=vN=oe{ihFd} zbQ=#rODhk$WwKyw_Ta2WcY;?^hXTNAGFFspWN)sjwz^g$hB8&6DkMoEuxXY-^x7(} zI|J&pX4Lw+=`$=yD6T78byhjXb?ttg(XCn5skv6I!JTcKyNo5`DlryRE7jiq-mw-_ z7HMh$7MjE5?YX#6!BuVzbD_&}^jzppU!oyYt$hS-{uM za5@U#M{|K`J9i#Dz>5~zpjkGcIK?}kyNOUlBZ@V3c|dT*NIQ3daJ!&r;(TLXxQI*d zix)1I6?mXD$peBbCfbo33YmpS3n98omM&Sc%w4i<$r2YEmQ-MH^)99h-PkR2-K8c- zv%?7u#N{ivySWm-ENC2b*cv-HUA}S!R1k%cei3n3t;Wtk2Yy-5IOr~EVh8Tk9Z+B; zM4W7(4}fqdrjrr;jsOwQj;EbFg+1(AMwhlO-iB+S+qD>VAxBB-cDr4ey1PksVI=5{ z*>UsVm|LzXuDhnMkAHB+<7=>ou_nG|jVqWKK$X1>=m4nPG1s zf`sep-Cey0V)l5`uA6oR&!kfJ=!V(m6>Z({uq#_6&~tIa1Cqr?EJA*8yDs-rG#tm| zyRt28_ExyRqG6-UJr)l(t4&*k+jY6$f*lt=LgBuPhV77Xu8Zv#1KI)iVz6_JpEk?p zaaM5!g%#$l*it_AbSkIPoC9MC*>x?(J)RtJvEw7|xaX4v*A*N# zqVIIi=3Y=1TyNjnZeMHt-19_-J41JK&vNYE?Hcp>u54+WeI#rp0T>Ovr^J0Ff_stH ziExjJKzHQKzeHrSXq>Mrb&2FN`kaD-y|(AMw4i|I%e47&OZNFLh3hNmkA{4n13`Br zPXSkJffGQpeG{!GfFR~#-Q(p$D-;w1XM*jY3w2OeYARx80|QTyEc>84%mL{u^AH)V z@Cd+8(o=4j?7EjW7HWUN$vw3kxY~4^&|LQ#sN83>0QUXYY47)=)~_Qqt=}aKce}13zsLA-4|N?jBXY0Hy}vBnPxJkZIrjnyV^1WxF2@qEmi4~q(Ty|vk%S2Uh6Oq4UsDO ze^<6}yn3SR3+$0UI(IM#b6ve%&mH?I6*!#=s1jeGJd-nesj5;KfO$X`ZK&l7dn^F6 z<21`!&1T_MCsqYkknD38+XsEHZODCA;KN$e>PI}oN1nA7n(rg12ZgR_dRiB0fLlpA zQhQwP183o5F86~8pD^i^b0t~jQ=j~#w%|Uo2hX`K_lt8t_Ko$?64%xGXT_mCUSf`w z$eyx2TLRq`9Guu@c3SqMQ#N?T05OB52 zqY_m@CkA_&TG1XScBJKcZJ%NQ2K-HI*iI!5zmpcL4MdHRmX=joHJK4zaRfFE;IPeB zIt5VKHxSB2bzPi~peT2aIi|TeFV8_Q>?qOl7B5C$)7*?r7|CEqvB@j!#VRL&70c#k zoDD_ps=`7XX;hH2_`vigp3-k_E<&HqbE1le^Cu|9PFN{+F}RPwzv59*RaVCT4gvX*mB3P&~7#*N1xk7G;7@1)#}6(anMxZpcLL$hGR}jozO62 z21j4Ke;~jm2ES~w`u!70ndHay18w*Jt~&Yej5^!N7-03s{y zQ)eK+qb)}~-Xh0cN&=9NlNE$wF7TZ&fk2gaAf`G{qpu@+6hV07DKKd&)xb1)#cN$X z1z7|3sb>af3D4|c(BIT7s8;xHP(MUwD~t%UEo;>toUi-~V4l5jQ6SKc_l8281p>=# zJ6c|*F&uhdxk@`*9Sn8^!no*#+bDs+@~B)#3H$l^YMS-iMN@u!qq-WYS)S>x8^TAu zu^y`VGu=Id>(+$*QFZ4LxZ*>)yrcR{D3^_$zhRE_IGJ4=Z)9f9H9-1I)a#>A`L1 z2bqBvyerGB)P+H~UU$*O=U}E?=ikdDS6?a#zf4pr$4xp;a8YTnWv$7uyPRI4J7r!P zD3g-2ro(i+wFA*A^yqkJaG?AOxaV^v@T*KLdHrDD)smuX{5w5<1Sa^kma?Dbvf#ep zKIUx}g2C&M3p57;*YDHx8&<;89{pkAxotW+QUxR^ho(ih}kG8D5V(;0rkq-o79Qtfdj$d z7x0eQ7nJ(qi=dQSCaZtx%X#W6$bFH`U)A~g5-ca-V%p1a@U_5J7y^N>qb4GZY$(P9 zFXyz`R7EmsxEgen2tijwAY)1xW~t)`0uPG|nsZy&{^g(qs=ooUv6nW>3@~Qe2R>-c z-(0a3$vJ>wr^MBSO*ecBy<9TUk@gDrYLpzUV|zk~W< z!a%{HeH&>i&aI+TYE4qj#E?_|#?ou0mbpxIusN+%v6}-7$HI3las>T`fBW9|f3Oc0 zV@`l;#vd7e>px_QMazHuO5jx#vq1Gv%4zZMcb+C0FEkbqOqA_-XpM)`fe+be`BOa* zr9VF_xa{W-{o-eL{Oq#JlIW}t{1VR*qO1PnSHJqzuVKMCu>~gj=x`)oIKWpN++%KA zi1*52gn?_Ms$`-nEGjK4om`05IagE^PARKYRYg;(3k$1jDryVm{mm5>b@g=^7ARgU zRkNFBHCJF1P*^ypVs6E}*4j3_$aFzrlUulOk!mZfD870sIRo~^RiD6YVr*&0XVd2#7)fGKmsuOy&J=Rsxw@ghfDlD45Ft!kHbFRPuVKqKhR#+NSh0SVuMX0c% zP$dd0YJ1(LiqL|ExJ!bFPAM!?_`ImX%gt3W)_R9$j$k6!F|orfol;$jMS{|as;r~A zR>^74jhk?lq)k<9ZZF!hrMa*}6)sziPmY#tb&Hyobrh--wjm2=Y(H_^N$ZM-)yes% z6k?O&bfwPNcxG8}hbpQLwlA%3npAOCD7Zl_n|}7pofS>fyOwpuCWhT9)ozhnT~xRt z+`d+=#hhGWCn2YKm;y)fN(n;RWBEgae^E zfeOzXpo#{d128McU=+5TtdmM>%-8Xd3Bv{GiuaZP)Qd5j$BZ99Ht>-Njsu+6Gcxc3 zet=3*10y{sDIrmOE))jZg8+Uq;YWa9WJk(~3IlWm!`KN{OcSi|2!YY#VuB_sghN;K z3vV3P7=sfZKr3XwgFp5%bP7tD20VpG5f?7-f&qFjnizp0G$v0{qVfVd7kEMyf4H5% zm5hnV6okSoq4yxuHC!SX#*h&b)GS7UFAHY=iG7&>*4E8FiJcYw@9RZJ@iH5saTwNz z#vadh%CKgHk52IQln&k*orRiO$C;Wn{v8-joyjCyX4pLKjfwW#YI0wVch=q}kQT=Y z&2i>hj(LK#woz-h#PRz4@r1+73l<(m8beq##^fBkn6b>lSX;-D^Y2)Ja2&i%>IlHa zH^5;ws4rt7kS~>|sMzP5knfu)mXk_+d8NMmGBHdBZ9>pjUg7giu}<-s2%nE1ittUB zWsYgS2A}Vk#!}x*>a%=8pIzTH&DZSn9osSkueFtzGNK&YvM>--3lC z`xfy%JAfrisV?&^hl+6wl-;yl;~-wIH_-FzI8s|$a;k zUekx=P)*Ly*ZJr%oqUQxPqqv`->Dis&0_*`^65U!ampFKGsR+u&v(|@zI?df>D#rj z=N#nwx#x)uzF?u9zN^%C;YAv?>cu{u|KEGr-v8gUY-pGFUa@A)mE-HH?^o; zbZ0)<#BlLOLc;v3Tb#wAmbf|ctH$Zy0yga;HCXajHJdKrCNTi?uLn=u733+)1 z1rwnL3MP@c1aGn_o9qUGf=+WmfzXTCy|{UKg|r|{EGIn=^0J_+x)4kyFx3bxuNLpC zna*ydPMfFH2g+P}T3Iw>I!Ker+@S3$AQz|4(s)VL?8$Ckab8}dHe*?Grdv5>Cfqax z#qTb0*5r!p^Z))J7G=H)Fbm>4Q7sG3_)P*$)UZraML znxU@%x^mINRe2SQRxbjcH)l>kK}%lVL}XH1!K7d#V~S`4;Jv>CxgG`{K+FLppcRuB zXU770osqn}RV4Fd7UNZdGzJO^5a+Hy%c3d72niJK?4n6W%R4#e9$>_Oo5O2!H!3mgpu!0f3o;peB75cPx%*7&ds za9WdtcDNkl$8Zsu3Imqlpkw0(4;VO%gaHpdpe>yhaMVa08r_kF?&zDMYuezUhv1_X zKv0Pl=p1!%ONj#=cq;)ja`2BXwKqCQkQgvE@<|TB2Ht|qu^dwXOJ(0R!eKF>5c~{V zl4l$u6}l~x;fNr^7w{AW^3g-eN0JH)OBl`4!m`PQo+QW*mV;J7i~pBk%HJ8;!}4hS z@Q&XT!)ejn4@ey|V@BhQnKNc!P&T9a*cmg*js`79v+(F4Vspy$H>f;nS=j=tPQN{r zEnHM)zgPuMyy>Vj0=+9rXWdi;;Ac;-H9%(=u^h8S%gWXe?TcH2)%yo#@XJ@$I95-Y zw5M~TE@)|!0!+e8D-$LUJG~PesJv4m>Z63a^L{l5yg`d51##?8L@qMLtx_7n; z-%>jK?is#}X}+6;5Ak_lPRiatTdcO=yGbV?1b#Oudk1YX;$gp-G)=yl#F&l$oec`V zqjV1RbMc%f-%%ph1^6n{cy5~cbtUTh{@Nb37r4E-M*5X_uEN9HYP_|!A2`3Ov>5k^ zn&sO{{I1es{BD6eeqD**R%*tbvu4~mFe0vhw#Ouu@q~11||Qj*zqt~RL&zhTQmAISs1Mw(0 z&BR|a-&}I>#iehFjlQ$y%6FE&4-Vc^`w?vTeWgnkZ>P1(ca^S2J^Y#ax%l@B^-FwH zsaf%BO25JFf!~6vf6cg)V8d&cZzui1nExpHe}YecLy26x9Y+0sBo%)Kmit8|?GGlq z{Jx8K%gZ(2RkG<~9uU94#9)GB<8n2q6JaWFUQ&~wmpIL;6#6vz22(T4mx~*G*ul{` zr(N#Dcb>GL72?+v+}^5kt~UNNEZ(lH7CX(?j5{kf)WxWmwU~1!pzE7kx2bv@RUrLm zsv(E388^5X1D(#Vbz_1pS4^sdWugtLvuK)z=);&^WcuW13!PSW9M1uc@rA7C&>9nbt6? zaduN6;sLSYZ^-W>|0dd}S0YTlIAdPEIxYPF8qXEbR4OXg3fl?P;45LzgfQ)_Cb zX)dg4S&k`-7R$?t#3y`}FB{mh0$VkFJ@EBY8)11;_t;H*JGg!+7Xv+*yf#JqReU{gF zW?w|C`PPn*oB?s|`app1cwIW!7>|qPaAQkT^GN8p|bt>bQ?;fH_2NCN=sVDpKgSZqiwZ&usJ(nmC1okV}Pz_~bSTtR-u--O@P z2zQN*3<`jFE^1tH@`lhUp%9!PT1x567VE}Ds6#b&hB^X)Q`MGu%Ob_M;GWhrh}SG9 z@g0OA&`stJpMem*r~b>!e=98Z)7gS3`E-Lx}>7@ECAbAaJ&7T)SrNNN;FO z1{DIuoDKwb4i&elUD_L}EAR|AH?F`#-GHTtwdOE3E0&&9$h}UT4_0Sn!Ehd#b_?hE z7ceteJ}?fi#qj`=*J86@bVI+;_+#I_9NMf-ko1C%5ymCN$&V9b(DxV|MpPIfqYfgi zY?Df%o*7!RiI23^Xrs-TW?bjLh5p{U^0t*Lu}gD1@S7n% zjwMkiF%&}ft9f|AX63G;E7aYs?9LGTsG*A@C_Ld!>>57YBU27%ph!v_XYqX$vantwUY@RgNn<jEDBz>RqUm*4W(;q--K6imCIP{tK zUPt?^pPyZVtyZO;FVy{C>E}NG1qsS3YYhSkD?d|dUtk!zxGBmSSFnp)Qm%@5c}9)^1AJk5?VAiXCu|Pah>jx8dXzfxx#0FOwCdq>`4@c)(l^Kw%sAk ze4&2mV_7+gg8L#{skU1u@zY^+LYAT%CCjIs{HhzE}V%()$p*37Zqcw%6ZPwHDv?(4-O+#2A~l zDMfhu{7c${wkgGTKVS`G*kF)A#)Tx#$OxGypgpQ8nIR@4BCaw)=2(`Lj3?HjC(eQ? z{l+cvK?sb~)JdC98{85p@ww0R)9NQ4wlTg z^~h~mXp<%t>n+WqNu*7%=isrH#!rQ^5G_o^;)C8cR)L9FhJc+Mx~CKJD3>qqvI=#Q zVTT|8v=mMtdNqo!fawtrN#Z59uBOq#%$o5gu7 zl3uJOpqiOB1w9ix{$@G5CQl`KPNF;;5Z*afJ+iH0qLJGfsvA>QsyV}*Om1ol&yw* zxMAta@hipvd)8RtmE0`gWWtgsxDA z)~IzHW;X;`@m7=Q6f;z;>l&!StF5r_J6+hg_l`3_SwAW(RdA*@&hn_UiJ5JRrpn6Z zN}Ls{#AdMdva+((qHUF-cAkyLgqz^vW9S%W;u%z>K4^RK(7Rpgkffvo_*6`#{aDk& zkoqDR)o9(;KPh#^oAXweKK++JjIy$-(b3UMo_`(cyjDeRbQB-1XVW9_ILDtxN1ub{ zypGDJ@(zu@{`_?%>fLo}bTiD%q>@*ax~~ohqHzhr_9MX2(O2lzE8BiN`kUVadG435 zkZ|FqH~%`i8p!C&qocRI^+wSZzrO9@ZEw7>ar7^vCBMTXAtV3C0K6Upu-8im6p8{U z66&a=sHP~GiIXP=iBFtZuC<91D}YRyII$89@CZ;9sID=bwbsSabk=W%?_F+i6BbhTSgZ$e881RW zU)@2DF#Ya~0HZ%$qDN`b-9yy?mIC@T8aHw2Cp%#vVR#%zV<>AZpkudi3~-FbB>Rg= zo0clgipZ##P@>d!9iRN+|qxjX&1!T_3_LB9}R za=K(p1%qLa|78E(Q|aVV|62cLc*(FIOWXoi?JMzLUE)t(bFJUMze`n%zuOoMLY?S! zs(R;j*ZXg{(eEF*>44wQ+1jn8{*8Wr+ig=%xV_(h$Cb)|`JH$9Prds+_uNZw{ra0` z_uYRAJbA#6=@woVi2QuW@84PNf7oC82$((qyM7eULI0_EyBf|;!`ub8>m_1P`u$I+ zQ>$-LJN-{eJecsOK7_~twqXY6e;RMV*@#b$1N_^zan1-noqE6jS#_Yk`Vv2=e*cGQ z1s>x5{et`b9}!(lpx4tx`;VUb5cH3UiRO>{Kk>;=`9J;KAviVgna?Ia{_(wgpMU;y z>QkTp0xpY+zp%UyQ2^pgy%-{ z-h`&$Vswv>>ZtIHKKEhDHtCW^1Hj%=hiLixy0?CUZ3ft>S80Z%qx(QB!Ww;Z6mkr@ z^H=Dv=SkqdAARK~5KM2q^}GB2XLR(hpa1E7BYU4LfrR|sKAO*XeqXh3qrwr*-#v#I z{q?s$eGabxgCJA)RUZPMPrdfS%I{RYF#7xp(=JuNd*!d-`Tb8{nYKCaHQ>-YN-$DH zn7@2w!(O_3^R>}Eh|yo>?b*8tNtr;qz#b(0wwbTL_4sR}%Qw}l*D2yhnb^9wM)Qz1 zVo3l0{PHtUJ5=j)^`MN7zA?IT&&tu2M2YO7PQyNC5}c^f`(S#(QKPSvz>MdWiO?aO zoxP>7QId0`tJP@9s5816{3W0w%b*h5^A`Nr%eajGe)RW<{OEtGH&G%=y(+o7TK#wj z>~N26_2|LT(N{M8u%V^s!Lc9a01o?#l7&!TA=6R&NO4Zu#JA^*wU%VEWrI zf&*c)lB$CTfBoDjX38-f zVpI>Y8It7nf)&liC*k}zigBDYhajyXE zO&&qzHKUl6YRSV0GD~H3Axxg9b*r|v*})`6k~FMbwP^8t4#j59S`_ILHr8KMv_1ST z1OSyx^p@|u^n<6q{f)=VZhHU0HJQveK+He=T^Txws*dlzHToBnyxKbz^qYPmRRg8$ z!0n^Qf+RI`kJPJ7rlP~Eo~zYC-~^m_$FEM6T(M;Ks=<{dhw4E@Ed`*$>{05TU(Y<0 z-{e=B3ap92$8?4fQ>SK{@>K@HoZcW@U7c2YhOce=an|tUFJGyH4dx=cJ<-NGV3wgi zQcR;h*6BXU57W`=BCHMrPk#P?lfSxtVxl3kH!E^c_NbEviYa{c0l&OFp2ws7%^APv z^E?>Nl40bIl|XE=`ehhhN+QoC9Ts^*@FRoA0iEEm8pneIQ!wWDSJ%{n4HXytTV1_> zhINC{zeW9xGs!!p9TRNiL4|5(1p*+5p78v>F+@Z$mUkK`zaM)#<8x!_{u(E!i; zSzO=O@=UyzaX6HYBON|}9&`Vpx<=1SMTJPj+jGYPC$RMnM*}nMEE;p@CcZM)0In$j za8m)`O{sB6LM|#`DowhnTsg`1P^4e6&F6xgV9r?s5<9$-gU1$BDNZb)E#;%l;5Fw} z)it!$Ghs$^#>`obGiD!C-_(4J93=?NIYu?jMf+&L1L54-rc^u5jV)As_r6k`;ByA8 zR!JzUS9f%%aHopkZRHTNN_7hvr^b5u(sI=oKNgq2u@1CWC2`|0tuh5e!vzKFgi9`a ztBspf{$`lB;Mt1j1Uv<@ISpj{i3)EpS0|qWJO`4eDt+gwU_h0fiMMF%;EI#NTzc0z zYU;V$lsa#BnZm2}jhhQ)Sa8t*c5nBPbUL!J42^rQvA^`P%QaSi#U*OsN(hasa4=z? zvAtUB*JuqJokXq|Q@tEe_10W(AaQSplu(CAhzD+h#%4`u#mpBY^*nKkD9NY@b3sBW z$KI6=#`lnsFduqu6dA4d`edGPh!c=MtwzbC-J+cWCP8NGVP^m+e{05Dm}dC!6DXZt z&)FF>QmLz!l6s8#^bBZtRoV1<9YLp_MqIdExmk6z0`nga<&S|wl0|>4?a<*Mw)Zox zdtP~Ulo77$0GE38uP7Pyyn~s;wt7`h3fJ^>s86o$cZ}b zu|%@*j4E~hti8Xl1B#q&LXdkg5zPD3=r5T87&$Z7Sn2|(m~Rh;?`WFHM-d^Of@Nn5 z0lom}?ZC)CvxUHW5xL+N7T~&reIuZKNg%E~Ofp=&6@iNqJhXi@aA5Hdj!!WzW!~8F zXf4O1GgPp_26aqOO~y-lz%mPEYWnd!OvS*!U;&d4>&P`dSAD1P<&%$beEA)W?T$3Q z>aY$=vTn)uePCo;vcbmqHnsuV*p_Utv5k!Z za~~35FkrB`Z!kF_Hm$}4;xVb7J{7%2iUAQ zIpnqIxpN_c8bMeQvnshEP^5^V1s4bL35T^ig0LhP61l)?uowO^t-}C@^D~egek& z*m5O9W5ISyWnjyP0@pvWZ^B?ic=p+|MgOQLswuI*H%A1s+})a-F0X^he+c zYb8r^*Gkgq$Lk)KvF!0*dn{vrn>Bcw?aY3mW z=W=sq&6xXfe-o2o%;f8`~nb~9Q6|Dz=9Z$d7uc`HgPs&>K zX!cut9PWbiDC0$Z4AI_9gTvln7+ZGxG9wn|1;?--@Ot_M4rlMAlVFN-$GfAaWcI~= z0;?++BX|$2;9Ht2EJcNE3=7j*Dm}LG7V4?4nYa{Fqe)BkHVm#I< zrcanUZN@26nGYOBNOa6mSUl$X#QX(_#OI}o{^BLrs`i(0C*MCyp|@U@2-D)P#{NAY zP(RmSyN(~ydjC9s!$y_b#Qpru{wl>4iu2dvT-!G6!{b#y1bdP3j!R(t-8+4}@dvw0 zFN3o8@+28(H(y6-@`T@$@Ryw5i_QGAlq`Mv8_f6X`}5^Hp083n zZ@Ssvw;qBFx7_Oc`%Bbq*xz4!>sobS_?>e$*57qd`Bxsg+rI~|{5`;!eC+-Ma7-TR zBfgIlY>z+T`{z9A`#V$qVL$m4h_H|EZ$x#x-@p0;>VqHpFyq1+4Krw9qyMzJI#r@} z`p-x@n9+|si^KsoJPOK>D)q6oI5-CIH*Amv5#Q!^>w4VPSCP7M>m2BJeVio9FToGl z6x{dk5M4~L7w(h{D|DD&Z$f|eJS5-LakFpFMF*5?jXHkh zE$-Ws9DV~F>iSK%(sop~x?Ty5+hLI3t~w_gu}bh^my(-+lm!a53j zcC(@b1m6_$)Qe@8S)2QQoX+dy_%3N3YM&l^Fj%oV3>w*^&qMh59m9S-x7e_G2N#u& zFbvFAKy3Etv62K=@Ft9m#g#q|a&BwuKJ|77?C4t^mlDJt{T9%=we3OIwL4b4li8zp zk^J@m~ z%~STE1DQc#V61s6{TuGjYxU|0ej0VCe~hUN_g(ko2i=cnb_iyCBO5XR%vz5j8&drp zkB>Duf^Ihb+%l5o?bIOhZFb1{{TLq?oKg4d$hXz4FsVOT`BVP0f92smLtOAt7&EM= zEU#cXlHig_5DW_f9PbaRf?#-19dOlTgsKC5zag|?G^QDb4;agZ{^>G&c66pVb{ZKt zNa-zsZ1K`yS+IOX5UdQ&TD3Y@6PzmR`DAb{ti`n%>(-xp-i9E+HLgL>9c&J^EXGwk z0p#Cm13rVx_3~Z2L4RJ*eep6Z$zEdpUV2%ucUf@x6?l{sH~1<@zunLi^kx-CaN~B8 z-V`hkZoXvSzTlQyQ^EdJu;RAcgW!(2s#3z);@0C2Af6yNpemQ$c~@}o5K7?gdxC)S zZovbHJ9zM+;NkNY2f-sMxa85tf&k)fhZ$M$l!WuX_t!#yI0$5Xgzu+=U|D7GOz^-* z&UyBuAA{Rsd=3``+wqR*bI&ubx$t`~0{A3DSsZ*yZLhpfEel?dbSy)s`{~ahaeyr! z03{awaVBOl&B2x}Ul85qHVD2rIhb4drQk)l1rO3m1>Kt%j*OeoG3voiOwj*`Cej|+ z-Ut0FG#L0Q#M%H~7gG?t7(l`;_~UPV8$nq3&UaV5_~MN>e(!rngKxfq2M+#>;SerC zZVZM>vi`+AW(1p$F%aW0M%d+U`Tg^BN;iP`@aWApkd-X6T z7N{MdKc$)DO^0v!{G`alA%LUlP!{g>!&mn{e-w097Vi7|XL=hc)nR4fUO&>V)zLI$ z;b!)ME=v|}_KlcT;4M=#w*KVUY$FecarSlKok!C$#{Tr!^}Y0;k%`;43BHU>9LAx% zP$sS;{W`|lyma1EUp3<`r%MLwLxy{v>>24eaG&;=yaW?(eYQ zLYeK{F}RN5^{U=*{7uiPL%1i7BlOG|%n)FfarLz$zz}9;EatEaV4^VoNxq^STQxRi zpd+6>agdynPG1*}!|566Jj86|FrhoWVmTC`V2Xmi6368cbFWiQUi5 zD3lN6FPMg7l1!vsBaLaU2(ucF|0Ms-{`))cK5oBpbO^a~bTa(_;SUMFBZp2Y^t$;As9NBZ(4dR${B?<&zb;*7X&{O& z*dOMv|HboHe`meS@CKR3?)+aek2T}!K>2g@Wm#)%M~0F;|8G2hjoA5X}9N z#8`ucVKa@+jF}i0e%td`3~zTl+lK)!cibFo%>2Xrwf_kD-)?+7V__X9er6b4YRAWA zZhTyBr>n5H*h)irGXCTb^Vk2v`D?K38JWRh9{Z8t0sV)0>|ibRUFWZ-{9*q3zjFTi z563a?WyW9(wskQ74(G4jU&Y9aVc*SP?|3$M97c<-A8ah3k@~nM-fC!0^T$2|N;WogZv&cE0kE;O*5hsHZ%D?p!q{R7sdwQSu zGZ0*GgX;Za_k@IN1_pTS&jNNu%@PRYXn9SjffzMw@Wm=3qP|7M`7RMb?1xh7;m|9N zA_Z%b0|}F>VD~0|*P&fw(S?q{;QXenCW(>dI|Te*$nU!y4!1*Kwv%ujf=CalY?%p& z=nRz6kxWv!a73M;_?95!sNSG<=si(HLD@gFqp{WDEP9jRpRr5}xe){~T)B*_at21d@Bx}afws zWMlL8@Zs6CV>N&RADWS|M`y13-g;FEXfPRj;{!x1M%4FWw^bmOBV+%{i26R|8@Emk zI)KR8L%;jwz2;5 z^+vWH(Z5FFGL9D_GY?h0EuI3%$9FJE?^P~dP3%c2+H zxlunb;q+I3qxH?otiwT0ya%ss;Z;RDOUvDE>_2&f3Gxy~K*()C>J;8bkvE&~2GuWNaK*E}B=|%2B);r6~89ExOYXZabPho&upAp7ty}?R14B%{WDb z$tPZT(#(Zkg@{&b8r0nny02OAgX-0Kzj35`o4!3Irozzf4k-+M z0N40veJ7H1*TF-Fl)hW3dq^*E;k|l)p}r6J{SRn;V6A>os8M#t*-&Zyki_?}enjg> z^TCMzlAfM#C?%I*!0lV#Mwxs^sqfzQJ=V3-M_>69(evp#SC@4DW|DK>u6O#RT(@gar1-yyHNBY>W~=XfM=%r+@PI|ECA$e-Ia~ z4|WmJx>x`7XaA`G>F2)ynT3CL$S?IjzWUm~{OjxL|LTiS8UObG)XfL^ct`6K2s_RAZ!_`G`Jgf_3}q+2jbg?Z?C>4qSdzZ( zHM^IYpV`MeA*0T%Lf?6&j4yTEQ~V~!8MF1*(b@G?gw)YrZYZ7q8h9zO7q?i>~n5;tVngfWcE3q{tAZhmoVuG@BUEO zR)cI3&qE(S#^lNpX;EpEfka#O=bXDRl{V%Y{+zFC? z89RdC02`o&ABXH#hiq)_aMDY1tx56MfzdSYLlvB=`bg6AlhTH#@o}QCT8Cw zvY+JXLnt@N%Ml1X!3Wq$Hf6b2-v6PP4UqyP!%kp(j4z#$$ zA4T|uNidNz0-<6Upk&2LIxL-|qH{LX!yt)JzL29-j7MKmEVEss^md9rh9?*@f@u)T zCL2&`{XqN-p=A8YSnXJy?DdBX$sp?pc8Jf=m=N5V78l+SvCFY)){29AAg-2Z$MHkm zOicBPnu*9@VtEo}K>GRz0H4{>o54LRIOm8~{BB^Xt`B6_8PY!b=^x!-1!#!hMRnz|6bG=R&YLKdKCvC5?<34bXCOSi)kPu)Ob3=W6jK=0I+G#O#F&Vy>Ox2!gn{ zWu^k_&n+~?i?mL_E+=$jtk1GF-%+O{>$yhR3fmb_te01Q&T85%QtL2*Y>$dcartW?|L z=nSn~!|x4kfY?F=R-dsJG!u`(GR}izD4#4Zt~rEOxw*@<#*l=FtHgnEgzeYRyU4lg}f4`*u`UVs75Guo$vw0AQ#qF^} zLL67r4unLK&xFyw#5fL!MUpFZWTMfTnPE)FH9kuKzf9iW3gKj3s&&~gT`o493J(N4 ztD1RN6&H+P4FQV?oG0rhQa5Wk#zVA~FR^Hi>qM|*K#TEI0AV^am~_$RohiCvWzi5} z^u{nLPuRv~)HYWZgrhT<1l%1fv>3eQ5*~ARh_VZ&)h3*Z8l%@jLv`2LwqFHf1AaK$ z$O{ov3ww{&M!ElWq-umEo@oJKt+HYa^s)Gjqs4eC1aAc%XTpHqD+c>iY2RskvE#sg}u`q3K7ltF2)P;nv$KiV6 zkX%(s)38_Q)r)z|#2yM#M_j-_#cw2S9~XyrrA>+5;#E9UNC34-iz zvI`9cy&9%X44ytF7MkK&fms6Jm?%TtBaHbCg=sO7f=a{Dq2xQWs)nfT0Jk4n{3 zAv756WNKC|%9PRFaST7`mhG`~cjz36E3YUmtAt)vG92g3OUr6XO5|5tQo`8l5oM!9 zE89lcH($dKpOyXx)i)pwfYWN~-Q+49E*jg^3-n7)3259wS z!!rT|%!uB^{khTu^wm8nS@dX+`8><8@6A_7V7&*cF=i-G-$@@kE{v_6e)b)%>Q%TW z7qm_42zs%@Rc7zz<=S3_J8<#qMYq2RJpl$8?AfS#Xxy_=xZl>^iKO1_xf*f3bc-Ir z=?=S?UiKc61O$zh5-_y%*NbEv$9hAZEyUw8r8|MHtQRXA=%Ba)!DTMMYe^1Tg2JT_ z!(1<^PxPp$bYf4;Rd3c~cb2rO)809R5D1JJYdddBcvwgcdlU0T3(cU4`2yJ~nk&@% z5oNwjS*WlqML!ZT;3LX{0YjpM&K3=#d`rlUPXW&%);yTTnk8gK0u(1B4M_NcMm$-; z0Pf=PqAKx4_DO)hPaNpsfL`T2ez`4g6Y4qW}Lhq zF*M?>T{$9cEaafHbCX-oonc6w{E1;)-T66b4#j2*t3P{M39dBzzB_WJ*^q(+s2OU1D_>4FUJ#&Yibda{S zj50I}jfNdD>t|@KQ^LP7>+ZRp^znQ((Py{8J_UflaVIJkY-JdGb3eWGc4O3H7bATq z`VK%ImRQ-iQ>q>vDZSN0!xz@O2|9`t*Rg%|hfq6-s@|aY2s+9W$$A)2dB+daYl==d z6C_=zu;HpB-2htz{#u%j>NtK+>3w?yms04n?F#)sC6b3V=d80ix$KMh5Whnx_$j6`hiXJ*xq!&8Z$OZgPYKW1+_YyZPAzCl^9I9RT?U9DVhkLkn_HdMjFSZknn@cMzBL@t@AZqAm z5Vt|BK+e`R2xJ1XGY*q_%$RbLk|7)rO0H8*R2VA^INb%{{AJl^N)JSR{o4U*J@nac zcHMtIo%tNY95`>;I+|c;v=uC0TWE=;1=AO0*$j%B{DC!N^75d%{TzkPDhq6Awj;}O z=yYG4FP|7(dd=4ru78ubkBU`+)b}C0FozZq5-P4}LyMCkxx_i<*ONoXGgPoSK@3G^ z>~o28%=kEm%;!)6=L9hn+2HXHN{uebGQg&_prvBiC2(J}18IEEyg9=+J)jB7?$TwV z&2)$F)&#Q)CMSM7Q(-R!D)&|N3ozR^mYiHM=b2>n^T%Z=o%=nQ{5v(nSF66^y^rGa z8k(QZjv49BWZhsWoh;^e!2XT7aXdqj>)kbfe30^yyZj6&XyXw~tAPRG(847y?0gWU z3y|(%pyYk=ei=pZZITg{WYfuVI0g;mK~RW`;STkgAg0@S!Ve(D7|w!l?_3D zBwCQMD6}Zna>Evw6^=<^rV21!3|&#|nPRfGSSAA|d=NNFGhu_~I7`F&D|wGj=564@ zoq^I#l1Y%ReDZ`TWIo?bVD1^A`gPL2Sba4>6 z4d@fa#gg@}#jvd4ip5$(lWl3INiGi6HGE(i`Ue@3z6;`f^^eVXGHwH0wCWUhY1)IN zBP@aJ42Q{Z{PloYkYT%Bg&F#sxO2b2Fwmh8$IMuFEXV-DzF<&a@AdQPpUZxxLBn;H z@_nJd#>1hRhc5bcX~qz9?+*2I!($kUJb4JiTDxFFJxmF|WA4N{2>|0@=7(-}$o)p_ zHFBfT`m+y4iU~W9y3E?^VOp1C^O5V*?%9GmT`#T;P~A$7YrXvVSlXtrIgb=zw~LRE zLzT>eV*KvqtEaWhe(>F=AZWyM3+NZ@dX0NtgG&wA!NUr=v_7uaaE-<;(x_TSk3|M< z^3_3HsUCU*evSBL!0VLWVTJS$ig-%d@xYUb5z@4ejlUB=)up0rhNe6E4lu^tho9^N zO8#i#_9Cr&p_z7iTo86S>T42JFT$h~v)P4T|8K|gB8)c!IUj%vIzwPDzQdrKiCScto zmKV%s34s?BW?9(FT-`?lpZ%8%7!-sh`TEaQC)S;YM%fD+G97%+?$sVse;u%UEuDbD z4mW*Wu*uEaz{Cp?mHuG5n*Mh0*#zdlAFvY9Z*V;q4|4t|Yi7+QE55K|*)AMpb-7uj zEFPpso;3KKX#rw_6tQOqi!l8z-ML8?dnvyRzveK<*D+7lAJH(kG;nrk=mL5}9Z<6z z9~r*>kmzrW{N9_B{S*AI>6J3cR@h2VLRb=XCj`yju6-f5rj{j(O%7`Apo+&!X1#H+ zad+h5u*%e_xMOyz=Ru#^?s;-~MXj2!M+?X5YvU)*ME zj{R)#yp5Z(X}h|*yEb=i=^~tu-vwK@T^PD=53%=(?C?As%ky>{dfbEiZXP9KtDJLb zR~L@yzzZJ0#r1!<{4dvgPp(Cdxu+Lrd3sL*=KJ8)+T7j8Uk32bIGTcil2T(|Hq5%0 zR}_PF8cyb^c0_SqeJug)qqe!W7*>Fm`r*S{+lG%EHGKGJ5DupugtTHYwwc)ESZvDF z*raLGq0g8cJB9kp*rZco-#&HLq}Xi4Gba}7fYv#8-lWr@PdPm{Nn(dT(dRD^?Tm$@ z#m-zreQ|6FR5XO*6|=;Cu$K+PMbxt@YY<7Fi!#kKh>r-YkxtyUAL| zVqF&N-n_-xou5j@E`R}TWP2>OV|Hxk_KRY>V6pq6SnT3Gjx2V`rI!&eF5Y`FG@QFa zb*7{~dwOFx-gski@oF5n!qttj*#4A-+Z+<=x5IBFb%&S_q*8ar?uw;S2M;miyJ2~c zINU3$QSP&OjK%JMfK-47jaFO?iie1&9u``J2e>`<&?Biw9}}9#rDUEEn$&?<>?#t+ zo`ibuVOkn^O0@H1@1xEjsN4zsN^yAb{WivnQmGG!%?Cw|#Xc1K@Y6t_q4Bajc)=mH(deg(&)u6!ede>y>T{n* z-{wbHbOcd!MWcOr`0zinHb<-ut?w&nmtWnRxIKm>zQmBm#lH4+ z>M(zUdMx(xH>o~|3}gVeO2)n;M#lMFVAQ36Xv@<5UQ7yaKhUGEyz+`o_@AJ9gfw;F zPrrZfy|LJzkv?_{{QG|nhx<|oQmMa)rF`Ij`U68r^)K=Js{^UO7HTLFTK)|X>MRB7 zfCE4YKXfdb{mz{xT)r75grAYQ7g@KMoaQeojPpRYUD8NJF;}wO4h4IS5 zVrYd`fcWrub-Wl()$w>uRV|Sbb#$nzs&A+_l5f1gysD~gq=8XYO-&ePXc$*Dz6za2 zG&*_Y6l1PxY@AwEHEnuh{(Uu_#BvKi(R~Z zR(pJQM|?!Q6XwpExwW-$m^H6`_G!j_Zv0gE1l|rWMTMu+c24`8`L*I9Ubp~eB>vR+ zoHIaBHFE?qGjn#;JdiU}_+NPD@L5$=Gppvuq2a%(3U2XP^Q$@$W$hd>KsmKjk~F)p zaCm$XV~H2V#Bm&43QUp~AcmB$kVbm-v#G%;LsH`=tvBII|7jBHvVNPwVg6Y|WCMJ!DWnCCAq82aes;cTnG=NzA)KhCv zc?@DRDNsWwGZaM4oLb~?)=ZW(DB9=GZJ!gLjeN)BTN)eBZ$#6%06+BBh1+*5*ck_Y z(JnCLk==z0l)8A&dJv)|UQ*Z4i1u~q)W*ik3Y!eWZqFY;4HKl~+MSV93SQ{JyS1M9Av`lmW`~+PHibWeeggG87GRUpSnF7Xtx&LR=~X z@|8w0I_Jk?IH8R%kn%3#F)zTy!e+b=#KLUDieH-HAr=cjURbDLqDRjo3UOy@AQTtI ziF%+vQDBlVd`*Wqgt(y)gw-r6EG+WWd|ZA9TWK?mO)`r5#I1p zHZYVi9(qMlBbPA*K&d3fie)t*qbw`QHp-CGP*y8Kg{>4h>IFVgm*NB^1HzwsV9*Ku z_U*;ycco+!GyroefFd4>**iytU-N#E0b%A?^t*o~$8AVsz2aI~qjPT(gja<0yJ5pQ zJKemJ=S-o_Oge+xB#>Py+)aW;$j4~t?4)8Tj|C|xEUjh#WT}nvSX^@B4{LqZ5HPBR zBv!p@Xr%B}GfxN*T19PZqc&1-IVUjMpkvHI0g7UYP^z+0sm9ek(q^wZG4iOCO@;iG zQnL-w9ITpj&J}$8JX~rHX)APt1Y7`X5LLOzBIZ_ZXHdL?zyd;8j>|t*(rEpkB~IYF zsh=%|cT?CK*oNf$=;btTeBn$K*7RE{stE-jt*-EgnWbB-jyk|K6F}=R3(+V=SB^mN z;7h`Z_rhq4P>pFGJ8qa2Wn&DX9CPagttW=EZSaA@9X4jl)L~5!Z4(G(+hCeu?Pe&J zFp4+>C~Q~SVu{5*b86O-bQ+y9!2t7Uy|FU)%~;$BxGk|JYO<`WtVA$kL~WoFLRew2 z(v^l}qBb?cR9ipDuU*VrWoTF9!W!q_R{FGpxW6WP_7Yx|GfWRV=Ump2DS@>lU8mR2 zTz1|DAI^kQCkzODBS{HLZR(<VLy%Sm`S*pL$MKUU zn>9mz5d0!|7^zH69;b?|XgyDxa2_t?^khB>1cC4*z;Or}pT=YpA_C>#WI9q2LdBHf zhrq;wBavc{CzR0Z8^ofq(N|=Nn%PeQkQK_uk5lN7AVY6^sx|;mq)eXdGZqn`$Cd#H zQP4A3>91I#;}NSd(gjW)oKR-8n>KpfD5PepB$oxL>4X%CGib+7nlgUE1cjj+Fpil) zAczlNGK*Laa}yHI0d$6I?u9JwJw@}99qQnFs(BQ(Ej$W0I&#w%O7bYsTm+T@tW<>zyOD96?s zC+Fu+nL4;rj%`!ZG_lE)C<`*reo9gBmS%Vf+?g%PEJK8vP=$fHI#H95VYxvysCvUi zaDM8-lVMp5GB%GQY95Sp6i#m#Ynnfr`UJ7V5fbNSbiT97hgMx*#BQ441{P;;&ziU% zXeP%Sc6qaAH_YjPBA!&I(Ts}qS6pG1ZKL=)83vRkXUZ5K9`#u&7@jf-_?pQ|nB+MV zb3GDnE!((BLg~Wt7oINRikI2}o1N;SUAr-N+M_Ok=~DbI6T1G&-pjXc-Fn5|y?DmN zI9x5-H6hitAtuOm{f#tTFIF=VP6lp}yS3!DB6SPzEK;|EYCj2XyIttj*4wsjz2m^% zJNE+a+PnA8gM>p{?-u>w)_V+z;mHLeOES@-#H@a~1P~TVZ z775|&-vHo>p>Nq_K>PN0EdJe$ox{HSJz_@_P_Sh5$}4|@A6_Z>b7+6@gIE6Yul|~r zx$rl+7O(seHh=!g-~Q;>@gM&kE*JWH2Ko^<;B1KOKxRPgU zRat~u0l9=yoTnTXE5~;W=c1TA+Y_l%1tr{7ub2HpegM&;A_Rv(IDN#hfY})40DM-| z2yWL4$H6Eh2?Zt9a8QL%Tj&xu2Yrixm#WedM5n4_GP)S)G+lzosxbnWv=%c~vs2G5 zqq@0Sf>I^*1+>TTS6PYw%F2;cuww!%=4otYG&)WpfeHnJT#p}*9LG@#6NZ%oD~c8t zl}B;vbA+10h)1ZYdDGN%m4{ge9z>gguttv_JqEv1cvxd*BQ7wscZAJ5?ezBfc;jyY zpbTJ6l@%cnktZlrrO17=TG#}O`j&c@31^^mM}ZUpX;5bp=y?&5#dK?;1OkBNvjo4f z_~n%$IZJ`4;o{gVFuqnp|_X1-!(14h-kQ2k&lMa}FPK-EhuE z!X^t{-3~TyA)LQ);|0cPYxkBd+b-u*?hJzsITVZCTXVYvQ=_2`ET+`KP@TW;Ma zfBSE`ZQm`Z29zOM5F0T|QdjsvrS&BKZn%=7M?4SSmJY`^QEA(v+n{e3DoS_^V(7Ds;ul@RG_c!LrnMMw{qqEuxnBe zFzPJufpbYnG%Q|l83GFu3X8$y!~n`2xrLczwDKtGKvJl*Gfu)W885N{ElVKcOd|S% zH~50iNNHt!(xVt<2cPjF39?KjYbaPRA%H?*k5&MF}XN;1>Z12&-W{wZX#zFz1O-GLFpgv*SWIuLoj4TuTB=NWhwobTtTF<9pHZ z6fC)*?(ye&sXVL?VYx0p5;&DfR?Y&JK=}`_EQ{O0HDii%fGrPzMe?CX@~H|&jsJ9p zE3IiFDVD1U?8JZ~G09|7;g^hJ#~pux{4rTJHAo@@L53`tt8(pix#rSbxUkznk?@}w ze#8Y6R1Ao&fGZ#<1|zx4a0$Y{GK<)Mm*q=o5mdN5hIPY!kh>p`mA2n+NaQ4s)t3dy zESzZ46iSvFmX9q55mU&NiR1et$w(?<_F2k@go?pkDj8f=B$DMi+{I8m6qJ{Pq^8!< zIemmfoL*P&FwwK(AleXV?B^WGiLQwsKl>51Co3Dnd9Hlt_Kq%;m573KaSelz0k8(c zwXWh+Eqy?c3*%p+~p$w7?MTx?KL^NIy;YXKZuLu^W7%l~|{G@P27y{5bW2&S$ z8B_Tw_Q%EemF6cfPL`FG6eJP_=pezd;_$7C7fZ7o7K@`_<+^=&A$B4V9K5J}_%Tc0 z30VjoXIG`-zqs2^rH5ouvhGvees9I(SOhKJhl^|s`hEK@P zhjl%9t}=KSAv9&G!Cpv$#U2MOt`U#z6Kw^c(N3(4wK38T<1_{!VH7~XVTofP3k8ZDo|HXrAwv`?u&iVNgOmkW z0y9n~I>zCEejGTvA#_JZ9W9XT)^7}^B_kNu`5TEWE^A>z!qq;w*|i=<*4RY#sV~Yj2Wt+wzRx*cnS-cSpoUA@P^@j%$RYm4B2!6 zhFO7Xp0|ODl_P|wg-t4`t&O$D@R1s>jh`}wDNY$yG^)5bAuDiDW=xoY=*EvX_a8CZ z0G)AD18R1dry}uqetvT7sH(=)pr*cYM1IT22%k9wOqn{(CQEX}%b^Oe zs~4-RL}cYiQc+P;9YoA$%osOj%=GC+O--e~DrzgJEw3Cmu5Qdsh9T>JvcHBUz;`{a z?Ap(NSa%DIxdAXKgF>cX!ydU@P{a$E?aCkI*R$GX74OQ*GQW3}mvo2s7`#_+4O(-j z#gVrNf(y9-ypwBC7&WMEw&iH9(`LZj>Xk9)Vwo~yhcOUrIS+7WE4j)_+%tC#G{oXKp2E)*X%{k8P$702KJQl$xK%Y2PO`<*-X4p>|KXr_( z?b&rbunA)r)09(X(VSPyh*`DIqP4;dUcg+AFjsg7Yz=t}ri%3$-~wtEEzZvF8ODRC zOE529R8NR?>~`W>+rsaW*i>LOSz0rPfbV=dIfyyDpnHV8rfrZVF3( zAr8dzF6i2-wgJ1)SbLsfszRbN_!r<%1YnoD-Jm;+X4JBs_F%+@i?G>*^zNel`O1TT ztS&-DIqxyF5T-N8-m&U(QzXU=^$Mk~3=M*K>Vj+wn~u=RE=PuDeYH}VRY_Q*{;p*R zNWyibYE#$WKpo~D>KW+0F@s|)M1nKGrAeD_ST4ypAbit8omEc1;H+han};c`kpu7` zw9V2Kfh=?i$z&>7%;6089kIHH0m_LaD~55O)T{Q;eBsPtIyXfQE65pWu_tQsY?~6IC>?0I`5! z$ir&g7%w^&iO0OZnuVuoc$oo9842@Iz+-$4hMtFvvEQyiKACVP4|J1274-^Qm~(i+ zeS%nn7&9hMwzg1~K7#V{T73Axj322)pHom%UBF_(y{S?jD2fQ?_~dA!a0Y!e9}5!5 zAoI~81%YB(+bRXX-LrOxR)Cv6JHW|C!oFyK-RRuMJG_?u$Kd4+bK>p>fsK3n9wwU2g)qVPQ}2 zjSFvDcr%Rq@Vn*K{kItxsJDk$h_G5b?~a8BLYw{wUGKc>pm(Uh^^hjg-yOQ%bMJj2 zJ~-mt|G7uM1mU0|;I94xxYIxrNVv za)75S3-%%CSkPfc@Z)<>8f%#azzgk<%f18uco37eoK^CVlV?01h55ga75EH&X%_Bm z%P`UMG1a1q8w}x_(`v35;Ra6#Qjo45w%`N>H~zTC)Pkj+HrQ#%LAcO-xjL&w{BV%t zcJO%U6x%X?ldR55w5E!`X$ZkwF33$@3T^R)st(nO#Uz^NsnZnRgMqx&8OTk$JWsU< z?u)@a(S0F!jHNJ_K`>}Jc)*o-lWG;{SF1IU$7)ySC_G37_jPK$n9qZG1I!!6?5j$ZJY6sD^v%B;tiA(m6icdCRA1eg^>>ppe>bar;h!tjTd>tj{1#F7LG;nFw{(V zWr9Bv+B^#EO7$529*55-)RW@>Fx02i`z+P_ZI~Z`{y~KH5a?V>n5aG^R3BDPt7p_l z)U)cNFnAg zME?`@r|SFa&(xo*zfeDb&0ng&Qh%-f#?p}Thw5*$OvbNMeQ$((;rB1(wkhThBpByZACX{dFLYPCZx8)2HEgI)1->6JwgMZ&C|1`>-?g!koWj z>P)>zFV;(JiMVoKs+VQiEVm_0*A-%4CMCKOZR#wP#wxx7rq9-2fP40zybFdJTZi9z zJl(VbemCMbUTxA{x?6A7TVT3fov%NSzJaBc?c2v!d4a^XRaCkiSKDmq(sUv0*~jv4 zk@e3SC!HyKUu_q^JM>Olf1gK>m#LSF#B~?c-PZkL;CpNwEW`F9dYxK2xg}x3n#*A0b;PYy<51J=wJb`BY8~3UDM!321 zsaH2ylS`jT#duH{%&0dbl#F?w;J0MiWZWEftGF^8_h(!(xp9fEe$TSo_!iT{fJI|6}mAG%NM4t=*#z>O=Z&>vE627ubFJ zetou$#nenD9D_ZeACy1(dr0%eH$3=;=iZ*cV|7pBXY#*PdYgppb4(xgBUPghqlc>& zny2)S)%)<{-}^;>DlCBy=nv`-iQiiNVQor=VLYv$u_3ZIW1ssG{VaUZ#r1<9wHVDG z(;v5{Pw40HtlTH{r?A2q(=UWEx!U@4=<74q&4d@jy(EUFe>pIe?7!i7qi&*%yoPIi zH+7;+2W8*EP7K3MREh#%uAJG@2bL-}#uR0r%u<*==A9_7sjaCQUNZs&mDW#XT}@r0 z3Wl1R%6c1ogV7rs-JSz!n-htaW+;i))HUREW87#rgBWDe(R)>!q)htp`Hf(BR zOTiqIenK`(gn3dctr1IWV)7K(7K6;>wCNHB;$n8=Gfqj2vvDR8T-_fBmvIPECB!{+ zOSF|*T;iT4DH3#?#6s!jMB-FL2{I%31o0;XMl%5!Wfrj+W z1pb>5?X+gnlNe=>P?`M-i7Uq2JWk?a+7KC{YC{5< zMglWGt(j}x42MyRLjesYf2QDsnDMqTUqTOxY0^-vpJq!hrGxy_9Zo19hHAn^aXJ6A zb@4UNVp7DvL}XHj=nxju)7p%(LA*#N5-LU7+&p{EAkfh~+S+zXVYh>>ql5p5Zq6L~ znLTIr>}J8l0NaiZV5YEPs-Igsciw5IPoF-2X2LXuv8AO87T8wN%7hTG7OG*#)`4Y5 zQK?L8M|#nuTN887NF)}XX)6)7k{(1PnQCrpUSwf$7A(mE&`F(9W8LxRaJm85+zhmi zQPmEoF6C_serdLSYMH6{Y9^C_AkY8^38hCFU5w4Gs6oP)Cl+P8LfFoym@82`FJzETDz0+X6WM*=v~w}DKHpKfk>*QH;_Cs7M_xz z4uG92emb|og68^G$n%}mz6x(jx38{RbM~6EYZ9_q(=Y{)zivHf&f7p0u(Z9sx_x7! zRWg`pX3w44R9PeXvWkj|06#*x(TwU6mzZ3cn9NWr6J4Uwn~VfC)T?R)I2Hg%0H|b% zRFNVba!7+v-SM$trygE*Icl*n}JWHnYz2L5&LVJ zo3FJ%GYbrnSufPCVY)#j{RpyIy~7NW7??PO+QAsk=-}GXo0E!k30|BePB)l0SGU{l zO#iHHIN@2#j{q;HyHV2s}5#zb|y#+553Jdx`Cm&*@`UR#ICHl`R09O zyCxalYvP0n6DLl%85+PAQ$I!yd0rp|#ljM}uKAW*Pu+hTqU!Fx-L}_Vx9>uw>{_;d zI&6qubH@Q&0EyN+w|58K3%YmFzPo#U_g$jjeo(aT+YjEpXTgR;tn#~E6h>dqcr(A& z=JM`4?tzu`31if~Hd(fN1(VZ0%5~OGXFx6;r7jyQogKacDKHY*o*Ar%aA%-#&}?v9 zDyCYzjTYgc9g4lP z7?-GC%5R)>(8!YsFzovl>`5dxqnoi2rC_v;)sD)|V{EsI`1k?fN7gyh=sBL50EI<$ zCBhuqGA1I$Bi)OM2{xz_#~s4XutiKbctnKGIai|1BvIQzt zl1jyc6b@*r7P%}T6{J*v$DU#cG8*6sq(U6AsjO6$@#12?xVXd*{J8c?it%a+-ae|Y zZ)hlqLk6p|q(GIF_$4*Nt038)hs>3fmE}Q}7@PBv5pl1ofOk9ari-GYsw$k`fn0FT8moouOPzQ+Dc<BlbL{bitU!3w9nKP=XSaAvNc!ShE0vM}Qb z3u?JQ8;Ce$0YxD!ok&IaFjGW>I)9Y*$j6UTCNxtL1VAtNQGi&0CszbwMiUiXfIyLT zgMmSqA%$Wv5{5V$6D)9~oB&}8(bX^tnF19-d1Hn1uvwB_5G2C6v^q7S9v?5zMw*+b z5Sm48!Hy}#4PY8g3rNBl4h(Csic)d{X8j5%WNAcfW=f7g7v|_zYEI~9P#!A;9DpOp zJf4WSWs`FWNMeVM>!6^XLLnRgw^IQ;`(t!dzG83|9co7B@VWC!Pm`?4DcS{wKs=ox z_`=Z3nTrg1hH+5t#*8IPVXt{Z12xFRE;n@8mJI=SFIoIlGyPx9v%La{e2qn+oqbLQ z53|OMg(c}KAd3$1q6Oj>b*Q|3CW04jBRUGbfab!8#w9uNA~X|RVuC{!+ABr-!}gNA z!+{k-GzfR{q7p6@xNe}d0=+$so8w}E`ichA0$B4c`E0MPiXo^{o~djpW%;$?Czk`j zFp70DMrx}WqgAsx5?3PY9@0qAL?&RyZu11Mqv>NLe#L4Me1JPKizKvyk8y2M7URsq zNl7tT7oPlTYXk9Q)hwq4idgm~$fX)hZ|1=&P!<>2HaD%Js$N>CK_zU)}61Bu`Ot45wDtINB zxXUAI!+`RJEC=RHi#5qPdWb96aCCuPJ?$H)5E?~o!muGXjQl6_7nY}xILJN#+(-<$ zDF6ps2eW|)9|66ib1u|*mZ6|{7T~1(1;n?koFz#qtnXL?DX^8ah1`~dRjUoQ#<2ru z8}m6l2CpH`B^poN8T;_sBp4x6X)QM^h;&i3{sL>URfz<@HQ`o|47jZAfYr{7^+gWd z9P6a3Zc0a|O>S(E%SdI-|gja<86YJR$ws*fhmFCk@GVrtT&oc=K)DBb|yKtkZBj2XfKK-=(0MNaUuHWfOSCF;_}My z&KD~v7ntN4BN`K78-5cfT_`w|?QB3IGiXvmXF^u{ff!-5VCJb-rWS7Q!fQy=-gFI4 zPqf?p4*Cy~UDbf-^38K|!n( ze6_g1FmlaC@bT3Ox{$WCB`dN0U*Fi=s_D?uHgfW;1uJ+d>>5*F=0J2yTZIfa`4K-} zQkY1UMTZ4N#n@7ENx*5S6>HXR+_)LO8dmJwUgoXdRC5$Pudz`4|Zz0)uCvGX#c<7&byf z0A{%I6e`6-0i(oeFDV%*&L#mByqO%wrFmAmpWr)gRk}Eqtf*VDcJt19)(XIybJhY@B$INfO$8_+>I>Mw;vG2|$wMha--t@7fNl(`Vg<@K ztY(*xWGr5yLfegA1@chaCiNwCRaK4F1`O&Ym)6!n2Q*+Uucd_xx6%+uSX)T2`-8E=>mniaf4?sG@j8&vOFuAt6PbOP zN%@@oLIe|+hztfXSmL5qt-~-d=;VSqUu<4(LtuFM2zS47>Cq7;^KcIc!5q^hRzU?& zX|%jNtfvmI7K2>c7REOik|!MkTa0Nnyw0OPkSnRovI@G4p-WlBWoSgl<`>U-Gx_i7 zx>>#db`%e$9M0F@NvFS}=DdWb7xAo05_8VLhJ?2muWr9;&)aFfoSyy_Ty@7+XVjgV z_u3TocKX<=YbNed3X*a!R-NEGEJu$}?OAc%p4%qOnyx0w`>biad1>H=iPSTBdB$>x zHZS#ts@G_ar_If%bB%R{X&*&A8IB^0wFG>&xRCs=A~_96~+yV3zqp&mlWxN+ge z+Tt1x05C4tXPF)i{^)@LvU1um8|pg zP^1M?Sf)rF0o|pipoM%Fd4;MVRZxu8xky2YohiYslyqf9Qjex$O%VCTg$kGJho3s) zstSe&{9p?TNm89(RZ>$+b5i)W{Jg>peM%+sarw13qM}Y#m_b#V9|X8kTh-S$aD+;U z8CZRNBa9f~n*Ej*gx{Q5ct+5r#jUVwO9_c-4H&r@VFC7;1d<~yLKAoqBwPSIzJ=1D z*dH|-vq14T#@Ghn(&;fj-z&#GMfs8m<5bWJZefCkx5(J?@-TSZ>pgK&c}0n%ERF^S z^(N;_oF*N~Jlh2(aa{$$rUzN{i%|lums0tGU!Dq|vuD%=LGjd)mRtv9K^jb$u?RmM zlk#L~{@5zq$L1Gcz8Hor!x~E1_XATfI5esAY<>cNWJ__oEv96YM7FLA>?cV=EIxXg z*Dc^UBT;;}T-L(EK8~nr@caQbY<VuQ*z!rml?pogmPfGd?zE93nh@os= z=5IM4`UU>hZN7iucHhTE$bz8Irnw6Spn=tp2WP|0DgC0P}3ZL2QERH!r(DQl{28Z&|;CH%Cu zGLE9MvC%QG8;1)HVFzF*y$V*&ne&3P z9b0y)$VJ#&ibUq0yKBqti)p!hr`mG~x|d6VUlvh&^Dd8E5ygdyxKS~3Z8Ulv;)q-i zuQvce7JEcfx}o<*2F0*$!t+RxTVcN+Nx2*rk=qa!(uuJpa?{q^cY;tR|99s3=iU{K z9;A~YTp4A9*|KHJJw-U%2Vbl2gWKf{`F;s|(F2hOw>%WBeR$+V9(dZNEaTdx&(dd&19CjG8#Te~iToT!hhoeuykOLf8(HVH`#O>P?IQ5;M z@8`)tBsco;5~U#EEddx<;R+8PP>$?@yxAdR3J;58Y~=7LEm!5kTqsoBH--V1DG(HH zoWi0YE>1&FjzAc)cr!zjE`}A-A_--X5+!f3Qb-duPR2NnM40(QL#AkT*ra>R1TM-qgRVJpl~HO0te)UDM(_3kMrJ3Kffr!%(86cnlPlSw4@X% z#kC6d%@NY)mm>2x6OFnOMuE)+o4e8qBB%ra47qbymX8BFFCnjG0q=MagG5h}$cf+< zvQpwjMP)`SDjEi)yr`&xIUNX<`BlR$WwrA$l+Ls{(G&{r;B+J8Qt-lqTwkC$?$y=f zb}2$bV^dvoOI@7|tl0{rP%N}jAF0hUle2_A!Gr)+PsGteyO0EZJCWvt~nZRL1y}8Qzsy5<{cl z5?*BWnn>jA2o{muvbd6CElNMbqIh;I-heD~(amh%_mDvk>xTO-?+YR3e3Mrlr#Vlh^Cu#n^xNq=d8t>w1O2r;iTKs@ zu^*?8rca#sS$W2 z!&QBt^VBb1p8Xe6MV!a7d`dqya!ueJMoEMq}w;ur(Y+J$n`4ZDxI!7kpTL!E~GC#41vlNBf(yzB zD)O05rgfj7@RJ0R$JhkxIe~C`nXdG!=~t7me?6T>?Wpum=mDO8bTQmI0O@Db>0_II zSa&p;uKQsf1_^je*X?_I!kiUfPQQNqG?* zuZZguC=P37VeLgq8D=A_7U4R?Bo`l!(!4@=JRXq>Vd5kUc)kXg8rW?t*vZxXljcsE zcNz&!r(o>-1;FU@4AB?T;mk!;0dB@-Osgij{Ua08c}CNE!$w1Za16Go%UD=~?ywwC zKRHbq>=+t0H%UCKKG-&1(e5@uBfYs;gVrHS%7yZdfAl(ATi5Sd;)L52-G zaKf`@51Z2gozRKjTn|eU-h6N3f-^jCA#L&Cv#>3mhgY0E?<{YXw|W8g$Gmgbdh5Kr z^()RJM}02tr}8%N*=F#>OXv^K)$MIw?(t=kZFv`NPwl{K(0F;7ih-pbUSTF=zFMwM zAiRqy`sM9Gk}g?t>7|}`3ibj$Zz(N3Z}ncZ4qQ6td6!?|c^9X=D}`EC#OO>K!c~&5 ztG#PH?^@5hj%f#6zf0ZV^$_np#q(}Nx^Gh6lAD3=TXG90v&!2~I`7Kc5UT;0ZpZyw z*vY;V=w0~j@NoOn-Dg~L&%H3Lm-Odh0~<^b%&CVT@w`XXj^*^dz+0s9uH2;_^B$M< zEPq0&Cl5a*0l)A4i0uPPeegpcM!5mUg-xP+&x$(~c9Zb;(T{oF$3Nk1c@Fp|#LYYF z35NH)arb0D+L%E9DItOT3wfUg`Wa&+Jz=%?S!&B+{+zgY-V*fbjAx5C=ks6izWAjV zNnqg14*4VR3rF}kiu#&&E-K^e-%zVA_RdWy_3}4Ue{90}mbYN3_w7Yq-goHfyWa9E z55eJko_AE@g56RR51p4N)54e%1Fyg~SCjw27-RUK@9&@4kN``JZ%#|CvqxC!HViKeM~?!0V*R1A!lU{n+d*KInS#K^-STK4{-2jIA|H8~BxU zGUS6gz+o`6b&}&_$VtBNJA?B&b)dvpTgOrWPF{zjZ4Z8q-$BmF&-9QEiOcXj$$x=G zx&!n{=y@2hg*gJ(gh3qsUxWEg@;NhvY# z=5_ECZ-#tK2ly7t!wCP9HvCJTBo17XG#|1TZy-p+$AJHtlg-Pp0@CS2Y$Ys-BT4dv z_!2u%jWB|@IYI;k>6`HrJ_qU9kJ8kV2?o!C#ekmfAZNx885;N?=7I&1kIfC*ptQ-C z2|v_>O6!38Q2Y>C)j|0nhTd}m-cO|a7_)@Tvj|7h$51$u>@?Ufl+%xq7Wv4e9EMQ- zz+e0i=P$4}<+u`~gWCea`zkf~3+q;-6WUyEg*C2H#m$uW#9u@$f1$PEFHCTq(B@(x z=X8kUg1^wXbP2FPYY`RVGR+FDSL(C$ss&)6G+wq`tG#v0*Ml$C=YWh?C2hnPRp^fO zY{G3x%QP0e^#ywCw$z1ZGQ90n3@p(*b_y1CHrnip=v~6U@7A6A;>CORXpNEn5{>Jg z1Xf*&Z8(j^LVej@t#_sL<(Atw+A0^=6;gy(>Z`QATI*|=cEGhe)ph!M;y0Y4bq~_r ztMuXa1P*9Pk%k|3>O%lcsO#1xxfF zpQ*iX(bKo}vdiy+!*{g)uEYhqB_uQ@<6F(n4R2ZxM1t`{=koGq2n(2Wv$@EgEe zpqozrZ|5(5*SrN6IR3y_bfDq=H{dHy%0F<)qTi=B&~TFV2`nYN%lgExzyFcDV1c=J z_Ugm$|Nh6qGwV1>H`^S`?EZ&4ouXH)4EH}Qc9yXiSn$>c`B&H->A$#?AB7qFBSD<@ zF)FBvA_`#yL0J%hH3%w$fTBR%QP!BoHSy?c;yc@W^y)3a6utAm+pO%R-o%{&L^pPXAXr)v zJQFJmAotfXveDnV1o0;>N{{VS$^YOU} zq;Z!RZvH-IG8g=Cjw0gUzxD^Pj4~Jdp?v~eW6Uvs{xkE(UwCmozNHFQ()Hs570*1= z+xwHB{B-_{I4ybk-ziPH+E5zN#x@JUL3GVu%a}!f*!jsFn2S}MA|2ao|B~5Cx9Nt_6g$7N!UI?+&KyM z2~zJ7#GRF}Jp%Epgx2rzdjwEyu&N*WA(ntxKfjN;QnVGJzG$_K%QN>m2`#R%8hr#I z*%=9~Oyxa;`^5W(t&CH`o&l{lL^o1jg8bQl6Ip)Ty19 zuzdt{X=GhGH~9@*)HaEG1&4mO;OHBqRXb_di1~kva};T(O*X)9&Wq+p#WgQ>-~WQl zjFS|;vU8zqnbVXP5~QBfQ>?gaMZR#;<$|<~*n*A)!LIoHw1xAd>sC>%SO2ATUD|wn zDl6sf=~(m17Yj`H%$$PY(v^HjL>)Hq!iKN}(EcqAO>$<)RshV2GdKp}q?mK3Y6#g9W!} zkn+Kl5I9fHj`uts`zblc6Iu#;D$GS>ht8AolFLQIgl=mT-Qwc~?3NOCgA+b-e;TvI zeH3Kzxr-K^$H4qWxTSQF_~A?FOft&^Q_oz{drs(4NW{fGCtkWYjBZ6LE+%FrKE`rU z=?c+gzqsMFtZWtTNxAGYwrEb^eEg2pxY*;e$x$nnP+Tq+UCta;)$tgepVh1tPtj`D zuKP6EYu3t7V_nlk{BWqmK5^C3a@}oRW9jj6X2z5tjp51$EE3vd%%*zm^D z{oI!8nKW!zw}i!>f*& z4L98;{zqheCfl>6~pP}=(cU#mBg+U?2GOz$&S^F^uih3lq6pmT$BZtGmcxjbgAsInp?Am zeF>zJHa*j@ugJDNQN8%`+qyKo8y-8J*z&yQn)-PS^XSehEN^fl*t~i4{hfL9uA4V+ zBkpxYr*02|r}*U?Jfn-`wjjNWFTQxIbm3Kf?4n$Vmslx1a@~mLO{CzcT==S*>c#aY zT%?8JqTkPeZsoXb+v5`e#^KW-cuE+fkX`Is?)VX1IOAm(LbXYMop=Nke|O;Kw7$MO z@4V}-yYKGrhj$x38iK2{^WJ;!;|9pe-2aB_J~-h2SpqvdKleE@;od=?q3i6t|Nbp- zKk&fkKTqMrYbT5czaZKlk}xs`xre3ei_!%!R)yRn(Q7DriP5u9p?lsQ6AModDpRy* z%qQt^m;9pao=Uj5rx+LdrBK6Cz^BQ{wquz$@%x%|jYya1f#3hl^E)Q^`MB?x?Jr=4 zmFM}ClWj_mkE|K6ZHBp&1G%12%}lWq-T2lBZrUWfm?iqEJhNfXgxy7pjgm~-Ct=`e z^D*r+T~FqgY@W#=eB;Gr6O4`;o~v9Im`f}Un6^q7}@pgeGcLWl)#1VKcUNs^^1$yKIjK8 z@%D&eP_Ssx=my*Pv`_cxqKp`R32ToiCR-LnwMwpZ{)*GN`AmY#zHA7^wQUS18`B>W zA$3=Ds*GA<;jluGQ0V^RAFUJUPcqUoMCUwiK3Nu|<3R~{qC3Hsg)dN322aKZw8UVi zrsGXq2nTb~B7#0a{zP=;rc3`~V8HkXm`;y1;aC0>L+7P)^g-iv`l7MK;cRk}U2)7!<-E56okVVwW6xxts~n#Dj&Z7sn@D z(kscJBFoW`8dPI+zJv>?QT#I+1;Iq$^1@{z*l4xFfN8T8!nE5R4#LF?9W?g&R|XYH z7aVfdVf99@bb1MboE_TKq+rpIt5&gi*A=HPS*j)g{-n%KXS? zJn{a|%#%)H4-qYh&W^c@PdaVEg43BdJ+E@s0-2M#NqvFd@p1M!It`vf;qay*#D$Xo zDca5u;}Ek8FJdeg6kaTv>=)0o<6YV;khqQ(!++FY11|YRnQ^H|R+Bj%<1BdRrG1CDc8R6DCN;&ParCa3__WWsB0tKB;a5VA zu;&M&Ftc2=K&rF_Ta%)ldb8F=>K%tXnE^IG3F99MOOA3TnKF z;rt6?#f{m(C?>NK$E=$3pA-B+ylB$CJFqm9hB^&mAGQ`i6<6$g% zbJjLWayxy4_D<;{ApRONj`>GGgP?v;52zJX2dV^3fp(e3{I`II{BDe|txO3$?fFHg)-%b?Y1b8$%uVX=%Hb^S8J8yE-}oZ6RG-dq~#;v%N#NroAnI z$@bcg_O2kXrWSvo6OlVZy7d7H1FjvN6tFYY0WO_|Eb_AD2A)TE`tb3%mNxXwmL^?Q zsm|ZtL}`i~QzjaXA?B?kupxlV`vY8{I~eeX0!>nuz@RhK2#-RYm@VCg_O7-joQcWd zy4qSO$y5Q`+I5{&TP&SusvUt~YokA~3H61%QcZNUHMZ(lZG)2z_1)Fl*r7uz9f8iy zmi9JXpzYcg)aKZVG5=vu*2*z|0jLbr4B83WLniztU>*eB4Et^nYrW-F)P@CIp>9KK zO3L?2+-7sQ4UuE~Zm|091VnpW^Vs&LPhZdPMrzVa0Ae1)4=xRt#3AZ@1~ zbHn<-4`nHMA3Bb7_A0{eP`E=1cdf#$ERzoY{m2i|Zi(`nFqea5_YvSkvU?xwL^;=@ zFKrNs>=|)xvLBWFC=A(W;@o79juUA>Vz968+JMokiVJhJdbOuuy1H@ZDR8cSM%JM|EHsWA5!x69Y~PmcNfQqZn{AM-bW z!av9SJTc}URS@~fM7(yxUrFTe{FxZ;@ByqPe>~=&eF<{;N08lcPwp4}cs!NC ztwxld0Kbnz@p-2F>cCHphEYZ}+W6BkKhg73>LmNirZSw2|1C@4*#G?ZbF*Im(8 zL04M^6ylBmRHRM8mR2YrrEiY;iCW(p^Vfm|5C=LqgE?CAlf#g?19%gt5OnYlV%&KD zk7M5he*K^(kQ0;vI{16&3!orqF5czv=Ri})V;$&t-RXZE^AkB|G2ei)K;b`Oo&X&L z$^NoA3~UEz0O5K-GXA$Po4~IeGzh9i8ahxId7A|dOZiNdPAmL*P(CORbiD2(NRz1W zzsCGEpld-rpgTaH1(DywF!xIK!!R{(kNHEOb3j*sZUsF8qOkj5{ucB;Nc+y1e<{cU zBEK5RB)b}25C89gehNAW`ZLIJWXxX$Y5=LlA#5xB?f|_6I{Do(|5>2pb$<$RT%dKJ z4WMnHW1!JLL!Uj0cK-|dB}}KNny#kFU)R3=Iw<81U1zYd%~imCs!+$20v9Q>U0b(q z!LaLU3w6S)P#0|M2(>h}x@tPGR&{ed6?Ue2cSdbkg@m|`fi0a}MGpiIR0A3-828tL zW-b`__kvj1Pl;w8%$<^b$9W>QCtoxvoEnATFMv3Z4*bgyFB3F*F46?4#UU&NKLK=P z>9~Is)DJpdcP8QxuNmFAKYY%(e+bkJd*RvRejn_IVdkTZYc3r3cNoY0FFFv$Jnql1 zjQg8F2SBwZ#C4*+Kojn9zuSg71Wkj=?c@Hvh?gs%u0S&&;+0V}?mrvkt3aNs$Nhtd zd(Y+L{wz@0+HwD?5;5EbKJbRWaOJpv7U3ywZt=K(2e7Ft#{F8)xc^WM@=`VKzY*@z zvT^?|&=*!Ay~|K9$XoZCaldu-xPK|kKJYkzu+^30{t?jey8q}xS}5aA zRXXl}WyQGvhLz*~-6(Gl@)tloJpgJ({uUtZL6{RD%0E#bKkl#8kNfoo)GzWcSjYW) zQ0^Jxhd))uSjsKby+=4NN^3B^i?!RgCxc{{qFkV68 zykg&g9WU&U#!V}1#-Rx((Aa@BEro+?Lsx67xX6_N(IM-S*nEp_7S%TgTCo=^?%Qx{ z+PDguvxsBY`UHoxWyh`du3S~Zl~njj>#J9-E5$xta7#zawap=}g=?wcs!HoCD(hEx zSCy}=DwSN-YfDN>tE(lKcgq9fpTu1Dsjl%>)hPTBS_&n_D_^xnuF^Q9Uak}gtFEb9wPs~vOcAS3 zW)SD0Hb6ldE%OmAA62bakn+j4P{3OMO?NE-FjCHB#y;t18x3#@p+u{u6-G z+Evvxa@Q#Lu2XO*uc)}p3og;BSW{XnbFZwbs4T6jkuxSc) zW%f8OQFj~*5sQmox}rY5wCG}@yM9Hv+=>ZUJg;cjSf`7H1*RG{mUeZix2mM9o_cwO z+>xtGYwCTgR>=KacE*(|9*RpK3di%Wsb94wHb^K4b1S$-F$FsjPvlp9)oNw_WJtj^ z9#$}pdL{B+yJl5|Ja{Ru%&p)W#S|<>JdU3{F5`wybgU8<9W_xjVf;nWxY48tK%+IT zmq;TL-6lS3Y)r?OAqpgiiqAb`j!KZmoWz`JCDtz!!DN1{y`$nVE_7nojPr=)ptu4u zAtuO}lhuioA(C0~(uLe=l0?K~(uCZ}(jp;deMMASvXO~`)vT?OJ4RgOxPYs@H5f^h zODTUMP=o0#T7x90#i1@9VlA(1q}5#;Cr+}lxmTK#F_Cg?GG*&Pj{UaKa!{Vl$z*`M zYOKdZ9o$l1&(+sA1p-0I5tNdtX%1jX%950ils0s z_K=#EbL^ysBNk#HmS-H4iAOlg#RIZV7ND(b)A~S%u6={f-xv&a(Q%r1=F~~&NtBM1 zi{)Hf9POd2sYVRIeMuq~&&#dx5r;7~8hX?0aQCSnnd=$x}*`-F2(v*&WSPM`m7wat06wRluWrMCI#Eyg32Lf$6v1tPs z1=5ZVcV%+`IqpEH3p#a;@8=YpaIR-( zW#p3X&uGC-7_sv)@({;QeS2Fy;pm^7%IzE!Fm@M5`wfAPR*dQZhF$bXpWD>fEs8^0 ziogS#Z5VnR8oOGlO6I)M@Rq(bJTpyCV5mMR%>u-{WT$LOFYHYo{D*$Or9vJ8waD=*yWOOKiJ{!_CHZ{>b z0=i{EVy)AyZQIz^zPU{o>lR5^DFix9ZTy?4E*UP0JU4K%Dg$ zlk6l`3aiNe3FqIr2683-XC^g zs1{g!IJ#$e5STpvC>-4ld`N-y0?YqhVz?c^nt?ULq>JM22JHhz_x8}02igb9nSL*_ zi2#&;8(w*wo$);Ln*!97!tV(D_Nw?%IytD@tk)9L&Ii_@z^uUbD6n#1nXf0tZ2(rM zz(T-A6d1K>#v8HnQCdi22uCt6tO%D2 ztn$r7eg(jGDKICnqYA7NSo!Z0<2C^sQefS{jwrBxU}b+uj5`EuP=W0MHmkt)1M|%! zmiHjAoeFFg*bK1vI>obpT+v&J7@o@Gb^wd7KYEnzumURr=EMu~0SW65|d4>sMgAfE|j%sPFFuCd?-HeQM`P`1QdrK2L{%9aLapVElh2hRea6wq1ec z1DjG{R$zs1C&n!Y)~mo8fK4i}5U_%G665v(>rr5Xz$Spjx4{Uo{3Gv0LkspuqBgO)IcMVAlVR#mz?=MZo%jJpnt(;M+Cc?5u6+n!6TeXFl)E&Um3j%j9u0 z!e#ySy-1Z54zjwEWHs^F4nH6KKCj@hP3BRo{lIx@5b;l@__(O-JZL8{veQMT53~aq zUbDe2!f2lASHz`xst?$yER-0xSHiO5Fq)@&5iTCv4Xhhje7ZDGg%sf?fVBd{5M&pH zp9a+d%N8M)=cBOKD#B$!j+X&j9v4mrtO;0rx&p8UVCTh!D+3k;cBzCFz^ntd8yG#) z8rOy;*}95_*;!~*){wQIrwBic8B0kk6_V7eDZ+x1G|7BB31}&2-rXzRs?KGII*p2 zfaLl^k z)%2}Yessv5WA8=SGlS~sFVS3{Tz)6w(mXYUxPOA3>h2E8`|VVB+cGpap(~-rGErk0 zFBWSx&CjEnUO+Xy$ofekqD&)x<@@hNilz9HEV)h=10~wZ=Mmuria>3TrvWECG)~5<^3@H1^COdoys^0j0Z+C zhAzS;fz<#*bF+*3(P3a^!0sjl1x0o;eA+AUTdZvYMBl931OMm9AN8UpA2s)=^bMc( zGL=!`)mA2V80v#Tq?0p09JzC@bT+7@10j{nQS1|A;8_NqWfIR=AG|T44^kb?B5V`F zz9Nl*XjmQOe6+uoXw$7}aqePmGvXGKK+HscNXJdFr%^ z*o?0z0PVX_{1L<-L;Q+4;-l4*^azSi<6su?ClMd7B8ra9oU26fkqamX;m99Py0dYz z4zjZV)&k%Mf$Ip5mvg!+W8DT`Z2Tka1j5!xVQDVVHA~~aL|Ymi|1lfe!|6x78N^#J z^)IDNtWOe78uY6i$dc%c@72~NA!`%}q>U&i!mu1#7>+EWeB#o9a-eh*b{_#KC(FAg zAZ5N-OKl(^Ou053`9$h@wJ81nVf-YuLa~eH6Q^+y)B32|#aLR=bm zLx@|8xO$azH^wDPWjKJa4Jpb%yk_7Z{1CjTF7r--j`9)mOmS-vx920oC3!J`xV?z` zElGD!nTIPiK9x=h9Zh|uB#!mN;Cm=HOs|k;7wHLMI1U1n$3Nvg2OflVQK$qtr-|=! zKCuHzOIUP3s^4*vq7_Bxi~sxS3`I?xHjh^S%pVdl6RF z<46YVm9T3+AT74imc~hmHWV8)h*v~$!E^|`i^-lWORz>t5G7virHPWH2hn^IkH1Ph zRN9O`p0%xdJ9Z_D9Hd9-k0Jdfr-kVwWULGyK7IAIZ3<=-dJ7f%mI3=;qNIcLMdIEm-gmc)rAQT`!rCgM^Vm3<6qS-kALDvlG2 zJA}9yA0gdJBy|vR!>E%R=9r5h=aVYbtHq{5()?DUCHchXV(!ihM@~!4vr>aPPGaiQ zUa!g&JgE=&f$t&k{cqT*j#Sz{#TW{yu=QzEpvlFO($8Fs{f#rik$=V*rZLoq^rw)1 zqg4J6H-_30#*l!x6X0_Md{#+(wrQZNWIT`c7#U?+OdatC9Af=vo`ybp=0C6g`;h*2 zr2o&V|4iCIIqT!qe-T(zg3l80xnHV(sU1nyV3&@z?MYg&%{H&rFI#n>Q)ub)Ob9M8XoGSlg{Y zyxLn5gY<%T(HWQ*J{gYG&Ls~q@g-F>^tF{LCB+Ud3!PL{+W1SVmtrmDVGMbgMjjge zc6m_WEzn@UNF@)=$V1tg*o!(l90|j&oa0pMJ9*`bE&YTR@M$$gi3nJ?g7zS-%5%bz z|CG{7nk%r@PCP~MqW>ytv_yM@3Zw`mrk8&f%7*lQa~$b)Dw!9fhbg!NQXtTCk;V?B z$Lqq8@1$Or7HFWeB=xBht?HH#;73&&4n6SmsxajtZwbcHx#0+2NSI1~1U2f)L;7Dd zs%)9KQ53jXi`~$qE`{|3h+ja!$ymu%V8jYU4<>$Vy_B}zW%HVEb3glkcVI)_MTFY?*`4A6kU-A zpB6jgN#&*O0^G|7-4J}O7l$LxIryf}Q`@UZ%@|F_)trqvaJi(%V=n>KgI#9qI$%dZ z2mcWKi{Q`JT<|9ir9=y{2mh~^r-*)(^%~9wrw9A>W*ry7^HUpQx z6y-C7BgCIB>f=^m<-qg=ATqipidVz-%gDbL{tfV7F8M>mARn>)v~KtZ;qNAY#lAy( z;+imNKWz`%JhpgXmk~+hwbwuwoHCdy=0yT z{#M2LUX3JgO0<`YQbWvxfUva)yHt}h4-HK4D(b+iO>bw?R51xsCP=U82j6^qI6~+B zDe5+;*`ZpBbWV-2Pn-UEH5>_2dSNPuD;%+;Zj0VD&3^R+m#Q;Pe@h*wwrkDD-hmhA zbgAnth;vDmMoQnT&Q+|pG4RbP2}j1~s<&^bGS<96a8i3{aEhV=QyD-421N6UaAYKP zIVv?btE7j?pVg)!Jxu=Zq)Lza<}ReSyDS_**Ju4gnr|@M*TtqO$`@z?VTTZQuM{?Z z-2*X&t;Hk}$Mqs?=J{xwRpE#>b(tElAX00aP3mpKPT>?KEx~l4Ua^#ie&k{IrQyiW zQjhJRW|c}NP=Ny~e0_Alp45y8yj>M$=dL*yU=F%09QpUuc}P_cm#No7r%Ga8cAngW zwCYxeBO6nv6;$6h)-bJCQMu6Pzo3#0q z^CEQ6qKa_j$FQf6S-hz6D)>SMkxb}C`~!&p;9T+5CluTwl9Vqd&uQ+O0^gj`{c6uhrW zEn|AqP$(54qdthzPgQFG);Fnb4OS9~K5=3wVeU`L2W~{ok}{syj$SSC(G{W}gU^#vK9qbQQmu3Kwg*p|i$}qCpl;4JEU#f46!nDlIhKb>0tB;zPZdU5O#i(Ya`ftO zqzUd6CXa#&FcChw?z_k-^U_)gBn7eh6vPeUhRQ>tPz zk@amI7BGd^gd?MK@%5_kRo^0rj?HfH-2uK=r6fYxZyZFc6hmyE3Gf|k2uI{| zVU=;iH>$*^`wOXkb1uPtD&kY$O4Ys%D)D6*SBdzuh+mHL$Q1Dh(li)rNhN^HfiO<$ zkhm4?p-dGV2?mkGDAGI75sp-5rbur^_Cy-HnJpo0!=5}x=#tOO>l0-}C8BkM$0&H*CGk*cry`ncl5*|Us%=3qnRfs@kAmm*>iN=? zDI^@tiwVLD@vNX+Eb8-bjLm^6dE+%h$yuXuSc$kh5chkjRCb|w0I4_M(7 zW8BzH|D1C-O1~HB7v22NyLSO!Q{(m_{qKQ`!E2=QH=@JvtyJznE15?cP8aBr$5|iiD5cm$? z7mlQ*>MJXT1<*GC+3?W^B)LD z&QCp8H>B7vW^%a+@t5qxeeII$O4K2FI{8Qt!|c`^#hQZ3Hw->m4~8QP=8~;!-zBNy z(FKz#lg(#Tz6=Xw0Qk=JY>?)c>Kv#~`VhbO3m!EODb?UY#Qdf6be^OM8xHpi2NiXwZ>_dRR%6zU|Dy&Fa;FW4uCbpn>&QJ%wOTafM z@r~_U#gF5?s(1pDoim_sGk?w@$(4o zZ9eWiX)aaGl$wZJp=D<-JCT+TX^|RDR}N@c1shetCRMP*Dp*(r%W)*8OKp)aVJ}fe z)c10VG`m#ljk<4=*b(QkZt&cP@;y5T&-E%SS87#f950Q@q@>EkJ+^72l`|BM(EAZm zM~T~Mw_H;Q70#P-h=oPh~JbtUq$J;$Cs}H z@SOzTgI|uV0i$D-o_dOE6h1ADXZmn+-lK|hW>mbSS3{Fv%5-$y$|JlJ;lGtS&%J5s zEozzeY1dL^C`2$gQ{V0b-@#q6XST|K4FVegwn<7WQFaui8<0wZ^zdrgBO-D4kh1jy ztz{2`*Ph41kcFJbvH@%c>b zonjq?6;d_(CI3tu7?;BzDiqsW75yQgu(z5Ar~v*=@Gna67yGdfetq!cQuhfy#dDR- zDiz4ePkmw#eECa`MW0)ze2xGs1cv5h`NX7y{aZ1g6lVhdn9R5~Mc(Z%U&)s#-JR!u-*Uu`f&p=itpk={YWvB)1%r`NkU{W_Lj zQoqo!1Qi2F)M55hIn2i*fmC`CE63w%{o5zXP6b=E0@bI^3*F9oEP`!wb`d53+o{0H zfQ`gqBwOl$?FSa5nDJ{%o|OBjAYy%#;%+l;!p`aLgr}tRohm^OH>;}!Z(ebb+Ne2tmFU#OR zlEU8!|7Q5t6d#M!Yv53mKj4|_+@Ip_M*NWPSmd{<)=VYYmFW#?;)JRBDc^HJc_#{2 z9E+R*Q_LIQ_q3MY_C&ym>tD47W*)z#n#yJv$Y7#74R)dexC=o%sNnl)oC_u=ziu%c7jGgW1uO}A3+&U z;6ve{3qi%88qfw%2y`pxv!Ef+H$Y>cNze@Fub|A`s7p`*$O)SBpriw@8}>K0R^vlQcvmMk z!Gnh9sD~Kcl9#6O684U;TYHLwXk}_=b>2j{AX(u(y-aE)rgV z-P(#zzIL~S@HP7S`c3QW@ln`%ygioVzRlI+>!xk(9Jes7zNLLVv^1EV{?L|S0IQO; z`k-iCscBr_j(0;>Yfu?@b1BEI*KF9(+SS?2ao1}$bOaE3i)O=SR2OW!G@GPQPiZy< zHf_S|Yq{4oq4w7H&3I+^8?bfZUA7(EjOK<7!47<9bpyvO;3~IxJFcy-Z0zU^)X)o! zq0J^?-nOR80$Vn>ci>&q7r?g!=`^ly4b+!32mIK8tODl4o3QIk+S@{nc#AOJKpRDZ zTevG^7iw@7UP%otTSnFduqk(S%!T&~Un9G!<nlUz{{>Vu3d7kXj2OL-;OmO>;+}5i!3k68J5`y8ZR5=!Mo&zkN=^s>HY6 zO6Zt`R)^YysI?CE-dgS@39Uh25d*#~A*^poaZgUG+_Gv@5S^!9G{jNCoknKo$O^oOy}TW-Mdox8LMd?E1>{2N^=s&z&joOm<7MgfUUVhAj(oZ7X6<;1 z?5YaTTXhkemyu{&nh8NV$O22w8gs90>qM&sniyUx<18C%;X(`5uV8)t3dyxv>hD)d z?y7(Y1jxcI6~^vPx_Z*?m^EzK>8M_IUBhM?)1nz+*>dvw5ZXGjP&rpf#*pN})y8~CEQ-Oot79nM{2XZPlsv8@oP-@Z^=58k)K!TOcw>hp>XtigTNDw? zeLcA`I_g(-R(Gurv2oHNW9WoUkRuPky;l4j_S%wa11d;zao<$9OAC=yTbpGemz!{_a{YyXv zz4-pX2)-e3;`+Z;1K7wPz-He`{3rMV-o^Lv-{tr7KjDk@m+G(6cj)iYKcfG({#pIF zenS7M{;2*8!$k(Kq0O+x&~Mmj*kyRZ@N>g&4SzJeXE@Wi%xE?GjFrX?<4wi^=Ygoo)KOZ-V%-p3r#xHWu_}kEv7A|`%KT6 zUNHUA^rk6dy2xxcuQFd{ZZ|({-fiA%9ykBmJkOG2(OE9Glvp-dx-ET{`z=pdUa=gq z%vz3FK4EoP%dEB5fb~Y}W7ZMtsP!k--&q&h7TcED47M^`m#x<}V0+m1P1~<*ui4(U zY3zCSQhTMn!M@49&Hl9gTlR7L%l5hgB!q z<7EC!p69RToB3}3HvS?0hiH>S{9Amw{zAP;U#hRtH|syEe^~#t{(ESdzv|~1@(jxi z4#RrGCPS~`9>b%Cmkh5M4jbMzXpIJ=3$1dsvD5ek<6}mA3D@{*w8+VV4sB8*Y!q$~ z?i3yrz9#%icuhDe%rl*3DmJY)HJCP;wwazb?KSN;y<+-$&a+%oTj=T5A2Y^;YXW)*yRrwqMwOhc-Fc{z?0Vc8mQAd!s#M|BU@! z`&aGXwI8tm(*C-AzT;F!zC&<$9qS#N9KDWv9A9vJ&oSJ%5fLF zFLgJ#H@UaDpLXv>E4||WgL|<@hgNcVsy#P(`aC<)O3!#+^}I!G#N&*Oqy&F5e;&V< zZ{UOcP5hnwzwz(#oIXeYNqxTla($h?Rlh}ltNt$ipk8k*Gu~_Zndu?hW46=nEzX;e zx82SI&X=9D&Uc+>xt6+Cx@ug_t~*^{aXpLPbJ%q@dXCk79eU0-H&;Zv8CW;+m-F@L z4WHw`%J1V}Mzqb>Nn~i)IXu`G;|woH|#ci8{=})@E5~8<6`4E#+AZB z;V(j1aGM5AUo}04eB_%g=IhM2n(r`w*8He>*!*?#KJ&}w|A+Scv-v&qe2lWima{E| z7QMx3DYsm1sk7W{*=D)dGHCgd2g2q3u@NL$>eR-n1RFrQ5gK@3Vg$ZTOb`9ecUs2FF8=A31*Kn2+&fcDkLboE^>{ z=Y!5Coj-EE?M!#&xO}LGBQB@=8uu>u9`~#6Gd(??XFcyw-B;oa7sfgKgZxYU`~2ys z?LvK-ewY4h`akH?F$PSA%M8ti8w`64&lzS6e&bf-XN-3kzi52lxJ_`H`siT0LA;OV ztNfXUJB+WJxnA7c0{Ba|Cv2n0?;`tByVG6_xp1fb5&JjM|KK?wKD*MOzh3{i{wc`B zOv5J(RzscPdc$_3NqAJa%jI>yy8)yb*n?{%w6&Ki|-7++yrE z?lYb%6bfcxg-{8JctEH#y=qS;C#!jR4ZtFwVBi2)G zX4K}NZCUnS`#ttS`!Mo#)E=>GomQvIdAW0k^9koX*B@OMyMIm(Q;&-8KwiM#%>Rb} zhWDgF$!+oL0 z?0MMpDC(X&B%TjGrPmtvnw~ekZ~BzkYrfL<2}*00i7oCF{RaD2?BBQl%syjZ=ve9) zaCW=<+)pAz8dWjZ&(BBy>@z%K8aC}QJ!|rte_?(DJx*^awzOM%Enl}hYMpP}WIJek z!*-E|;6A^lhNFX>;` z*BNd$JZ|`LCdryVyU+_TZ7gu*0-(Mm~}3*wc9q^`fbCuZ`q!;yr3bWb$8}zRo~k+06DX`(v2r z_S-i)9(DZQ)#SbfJ>^aJ`{<)-+%))~%^Uaw{82t%?}SvjO8;}rDko!pzs|VL_+3G3 zsxw^!+5fWT50=-hXW5q8zJpS|W-GT3*mr_&j-$p==eXXH;XDUD@;>L6ony|+FeB>G zG7h)LUFxoISG%ur``y<<(q8Z0?7q?c8TW1OyWRJ>?{`1we#HG1NZ)U|zk_-5Iroe1 zA0v0KxPOiL@=f=j-0!&m+kMQP?pfeD*>kGrbkA9yrJjpCmv~Gbo5$lR@vOpZTJ5>g zbB(9T)8)C{^Le!Xk3BDYraW(Yj*{FMO~aly*sBj)P! z^h@+Q%!>t();yl!;0~p6nHeyx8P-h9A34@sYaV71oi*QDfSH6xtyry2YmwClt*+c! zX{~{7S7&XoHermlVw8of-PRs!uXVe%&)RPtuq9ftn5$GX?L4_e@u zb-(q1b;3Gnow6RZ9^b&a=%Y*Q zI(xpo0IkT|1-liqP?6ndFSD0JPpz@n+UuaLHrbo)t@a?aqi%Z-=7R0^K6^jL;0}z! zLHm$>mwh+ph7tQ7`(FD#$oDaf_yhI{`=ou!e$al%J`Ejr#y)F5g4qLiemXK7nT{+- z*jz`RV+nNMd`E$!5E`(68NrD;!RIJ*lshUhx@$4M8yroJW=E?d=m=<$Ef!@5&G3pp|>~|b+OgJW?ryX=0g06PhF#~<=h~uau z46QoDnd!`O<~VbmdCnzHoipEA;4F0VP61NH=`3>koMp~(XQi{oS?jEGHaMH0f44e= z&XBVkT0^gMyR*;P?;ODVx6?W39CGf0W;N^_aqe;Mb?$SHLJIANrZwT5geG{(4B(Yf+n1+GFD?-HQXJ24OXTxHN3E1{p&y6RjF zt|sVdt*)Re8*MMsWw8}wf|GQkfUBj*s*B;ki*FM*%Ys|IZb-*>@ znsiOM4!RDxrlH-9Cd|VoIAsv>CSTJxO3fkn8$SPe0PDn(9OFA=zmUkk=y4k zbC*D6?$RF-R*jk2F{pa%rs^h zbBwvhJZM2W=s^X>LL+Y!u&Q?&i?FgUGnQi=S!1j<))^a&O~z(pt1)N{8M~n?^%}Pu z`=Hql7tGUb?ZO?jpz*ptYI&R2*TUNBirPE(P|XDTz5n<`B;rdnu1 z4W=ejv#He-G=)svrXEwTX*<>y{iXra4%1GovxZE&OuM1yjzH7hYuaZTHH~2%eZVwf znuLCE&~(T&Z8~h4G0mEen2wslCeEB;&NOG4bIiHsJo6H)we!sd=0dEv1+&%cG#8nD z<}!1+xzb!?t~J-08_Z4SW^=1KXbzdX%{}H`^LA(({pJDl4y?@w%|qs0*fkk8kC^vh z?_{5O)I4V1Z$4n2Fi&EoanO9oJZ(N~o`GI+#C+5o#wtF;l4;4p$}iWFXIX+>mV8SA zR)D-kuvoDQEVB44WmpSVLVu~nda%LLg!O)_C1?p@C#DD5`*!Td^jiijJFtEkghsr} zvfDCj8L{ladT}521ja1;q47*uCM{FYmJdN+K5Uu6`tgY6s3mOSPUry%dH~01*f*^H zH@8!(wFuf%In$l$nC8^V^rjxBHT5%{X^?45!%Sb=$F!vbOjkO{G^JT+Njjzr`Je^W zLjP%H8qP2@m?3ByqtGr6Fx}!H(=29~UJ+(mMHbU3mN1Q?km(anrcH>tL><#4TA3ap zY7wFiLHfgpa}V?c(hx{D$YVM{Ih+3**xVmt^L`(j^9R{{KY|&ZW?GtM#W_}-VQF@y zU8Gj5K{afRRRo>868d%>)3$@qw1=QiAA;sQ3$2-h#+(CfSqDv-*9&ac8Ttp#Bt6l2 zWCxo?cCk5RPuvVL5jTI#L}!l-%p91*bsDx#9b$U|=^VWa_JqFlH`bRp-1|5GgucXm zEPZMC|A=0cTAMhbH-tXa{z2Y}J%JN@0v~fv;KV+_hu8^J02t0?HI*Q$00gr9l`TEFfwoo!Hwb> R9N0POOoFT@u77?F{C|wLp49*V literal 0 HcmV?d00001 diff --git a/lib/regex/Python26/__init__.py b/lib/regex/Python26/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/lib/regex/Python26/__init__.py @@ -0,0 +1 @@ + diff --git a/lib/regex/Python26/_regex.pyd b/lib/regex/Python26/_regex.pyd new file mode 100644 index 0000000000000000000000000000000000000000..0616ec7da825eba630315a471dc68ed7fff0a881 GIT binary patch literal 304128 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

Q>Aj=P1 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

szd6?gnAi5r=x{5B-{F5(1a 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

*=e=K<2XCsd1yL%7Eh>RupUzq=y;) zVZo|au3RZaVq86jYYJkN82(!D5%&B*49y%@&XpT&E>}DEx(m3uYi7dn zw91Spg)6b|6C>R~CK09Wi>)d#$4tDq^-~VT8x*9!IkGKV_(Y|I$3yY-hfh_KH7^5? z&}HD+gR`^Y!ZOOCae>eb4^v9PsN;4oZ0u_3 z4GnlPLk4F?INpz=EPpexrBVq>;UpVxYt=MT(diuy35G^241T5L%2Um_`=4NFjVQ*3 zxs(wG?CIN_;iu5qo;w{D%8g*V|e5S!%$9Z?7&8{1egzLQC&LpE^EG!=Jq%w%vlEL5sX zUzeq5v6x$EOG!<^ei)j3TV)sYJ{i(y%JDE3y*XPpuJl*goroemdVfvU>9IJ zpcfDV)B&mhhXBLY$)m~hnxIL z9;wnOcuJ!MO8CEvt&{6Wb}q_HwdP^f-gV^@%Lhg?(fWGDx4 z%9jki!0-1@hK>TX!rv~gAO-!moBq9s7oc`Qz4HJ9pan1h7zI#yeq1scIsw>-cv|p6 zim)%Gz-!U?N4R_AXk8CCl^5L{?Cfmsw`V@>)JbmT)4g6xUqX(i*aq^x((q@ z{Is^M=hn5it?TaW47P=hZS7%WE9~}8w+86UMMTIL}y!L$jDk7l#FQa?oeZ=5xH~*ySiH2+l;}s^{r^lvBi_2X+Y+Z$xs0x z0B8d20F020umi9U0k*j`JFW81mhTBw+>FM=a^|S~`6|Df_7Lb5uA2<~8S(xVaAIvD-2*EBYe1fa0G7o}$K5G21xFGPZUZSFEn6P`p@hjBUa7jp5c!L1S0z)}RtVZsW$*u8oc1buC=i zC0tvjtGPYY#Fih9JNV3GXxYCA)U?M=BcBmf+|%`|>(l^x`^HgMK$~on`<=iZIbB^` zdZJ1GfjHbdq5bccrb@04*$&xF_Br334AuT%GL(@5jIT|G4o_h2e19@j^Xg{4C;fk$}r{Mn?wwkuuKU*H^xTou{Y^x;GRtW*QGYFAsV@GQU z0?FfVPKF33em5B!1MC8{00IE+H&U1qhwR92v5o_F00Mycuy^au2fgD*K_4&-2mu0s ze83@%vc%`N7vU`cKVTf?JYD~W-%o}JhW`M43m^<=0@MHk03}?pbAgK-gM18oS|ePE z_fG5sptl#0@kjIt@)!U#0crucfZ1qHpbk3$+W~!m)AiROPl6qQQNSyJX~6FRe*;k1 zoIg#5i~w?1!M+J_7;qQh{{h|v%snoJ7rQmt5yC(8)?~;A z2mo#bd;#zjU_U@B4dLEE*zW=6KTn3b0owql>%Sjq9tAuD_#WUlfZ$)iV@^zl2LFnF zhn@d7@Lfq%T~4dNv3>1L5YpYou8zhwPa$`Ck&#IS9ujW5w{G2nY1iEr?m|$Jv7@mw z+}arO)O2AW zgj&N8(@93Y^+Qu3f(hePs6~c}%cnxS03iT{8D*Q?6q zfYbG#xJ06V81~VNr$U2(TDbEsnhFVUAA+5WI(n~~3azzGg}&)U9OqQ%IH1Ng6&eMU zJCN3g_5zF*PlXnVXhXmRK=e$7b|YPe9c=|T3?N#^OQu5ErO2ZiWxi%Av>j=0shJ8z zR-yj2Qz7SKDc<=@KpWu&Yosn8C< zJr&4r1=U2B7j2^jM}seqkzfkrnNW@)x+LLc^%{VbE3L zJd3bpi1$0r-h&D%1{WXqgJxkbVzrEyxA_`|GDdp8-7IlpKe`6d*c^TW$9s zE#ZFHEakULw#mN|_}R*!l$gKd;RpPu;TU}nF{i#L?lzhmha%#a!#Qh7x ze|e)6UN75e!Ku(IH=sZ3rb6|AOu)A5(YM`Gq3?vJLRSKYyQV@fZTQ~_hc{uo0rqUh zJnozdWdTZW#+k3Z{AHiNhrNR>y^`j*nSWxg4dE2$fW>UJ)p+ zR&pt+E?!YuE{By$IV@JZ<;B&-r8Q;MYJdIGB`dUWae0<1Y2$E#vc<)#D{AUhMNrUX zD+2YEi|engtPaS;m5^06#nm;cFvON)$>}PVu27mZ4pXl*ii}%TQ@wP>lEjn}u0EMS zT!5NRTqzf?Ub9AN&L!2wRpn*N%hYvTQe9RSxDIVmRaRUh=f0%6a&=X_yPn!V0Z~@F zbXAQqG%AYMs3=raR$g5UDzT(DC$Z>X)vVnIsg2`Bl_nI2AbwpGa@jb<5S|Q&1|Z z@n{v{SWqJE)hm`(DwCJW%KR#-F`SB|gpZ@A%*(i`6Pv4qi_MxCHevq7uyM0V6@g}J z+$fP}B!*3V(b$}huR{!x94o%`j5r!Wo^vvBYL%IBnTSlL$ND?Q4&!1c4$ZiLnG%## zf+x%{GUjD%A{U5wRy=nhzZNHv@H55y~eYFdKWrn2mnW2ffM_Kn8PEv?w>h7rm( zzw)-%xEU&PS+CTzh-0TYjD!@4l^=&`(lO5>=@6}pMQH2ZxHi~nY;QKMYwQSj(~+BW zF4aY6PLz*aibY&o%6;jq4Cij0VJ?WnHrnP(^?oH3ZsQ8cuL6qO#4< zz?i`SAp8=gwZSdzZB41DZEkP7EG&~kK_m?acWp}$eb{Mi4PVw}Y*Z8n4Sc zDtinOx#Q$K<>MsQOEe**b`3Vg%4uwEMoSp!JZWt(*k+WvKS(nsPDP|H!%Tx+i17w$Aq*e*VncV8JlETTJ#?l^ZJaP`HO7<79%3U(=0vL$Rnyy| zAxDl8Q8dnUJA)3U>)9b1`Q&>Xt+=c)b8toh(&VXcZ>uLf#wMq6?Smp>*COBcXx|j< z3}I#mo8pfCxs8oI5>I6MH_WS!5T;#oV|R#}MAM|Cg3iDU4oC%uELiLm*URZ=<>->l#!jd-TQSj^8(Tx&ok7<;JQH$FYiGE-F|@Kf2u@1@n7B}B z8W$3O4hJz-!^Xy@Cb~mlT-ZURjmFh&8`|18w;4OSg56E+7^I>0bvSMX`@#STx36mt z8PU1y&cVW_Mf3hanzfi?>}Xbwt1A8(@4IY)TseK()@m-TH#6=1Ss57v7%xWP=}vyr zf1ZrqOL2;`Gw;xqoIOX^Gw(UXDKo$8A`hw zFbW*q?IDu~7zN~vpNwuK1nR#HuRPAqc$S470;(xR*l~pI(+Hz{a?rL}&n4zvK=V_D za{#wjg{uHA^ZCTI4Zzi@aADv^R5j2C9=M`hUsTrF_%?Jxq|9#yjCb#3b!4& z@|P0R4gt4Ih1(0mksDOu@_?IG;fjEB{Aea^0rK$!w;j0u zfSY*mox0-etZnJKd*)?lK3klf@qDR)@#7Z6%lh%jXtf*CdM0Fw`DAU?*_oCPQ`rumd=}W`h~R(K@wVm6q120pQMIv81$pGA=6) zN9$A{;>F{31J?swe7>|!g;ntm0v7@fQ;->oKMkk@E?YveGM|9ERuwM`e7qdEMRDCEpRWL118|qb#VZG{1Gr@}t`K$|aJzwfm2fkCSek9DoR^&i1nbBW1JR~+s_G{* zZ9_5wty6?!&+#JFvU%AVrG_Rv>Ls<^D8gG1PO>B!qH_?q2H=!FBRbQ-)y+aD1H3zo zaC!ub4AIF0ZaZ+7F^q&O0&WPn!8n{BxctM3eN_WoE^zEnA8~sDEx?6=)1fSqOoj1$ zS9)=F&Yc;>*}2>1lxF+4&dbgP0LJ*_p-9Q7dfG z#wJIV^FM<8PauExwN?TAoESJ&$I3fsKWmdNR4UUHMd21*T8&mzI|lz{pkPYdGx?TPcb5V$(vl*d^qo(LS#jmK317f|7v zfODvDJ-`*IaNB`1s>V<*IOdfy<1;5g*E@MkBZcDO08ZMxFzoSV^tV7x}4Y7o8~;n&2%yD)Q~4H#~CHa2%@ojQy- znG^?x=+ZiM5V#u&QJT%`s@a4uQ~G5O!gD51M$e~km|VaZaJj%;MF{YSRz$9X^APYw zgik%+I&`}=8U$4jYm8z6G-;j6oH`k;qr6aWc^sjnXxTV^b{#y*fTDCwNLPe({c^ha z@rxqs*3HB0jvK|afg=973+Z~0j%XS^9F}p6 zC#&WS@rz}-t2R20R@ z2pF!xZ;7D^sN)FVgYf^PaI}jSFVx+qF*X8*t2Jgtv7st?z|a`1!{E;R<;m#Xv*pvQ zkq;PBGDT^;kAS8hG|wZNs9QD0JB^k7GQM2SYi4YIBw=h)+Z{*TI?#Aco*S{aM)3OB zI4(7$JJRC(C59HHUqWMKBdu00Yk4wO#_Bi8gZdypuBb=uc0F+qi@M| z(%cZWv$fV5~PEv2*Ml?frD=+`Hsznv|wK8?JJPcJVK^ux$&1bJ1Y&dbkMeN_cW z_d@CSBK;`RSI&|iy`CgXPcgu$5;{Y z6Tlk@AJ6}c*Uk(Z1QB1TMcn;}TO-G%HNw~;^Mz7FS&T2txS&79x`K4mNas?IOA;R!M7sL7hv+`5h~A{C!-6fJTOK;M8UGth{&UQeq}DDmP+K=3z45my9==g(YYOip`YFN#2p>XtIl}LPo64BDcJMk# z(kdp72F*dc#Dt)Lfq2mo&=~-om8t7dg#|&Q7HG>P`BQ2e5zKku_a~!|r{)Fz^jfX9 zDKiis>P7k!$7W>089s!?BF2ZX;KcPNjbTc=4{7uNpp_OvLo98np;48Vjen%|BQ4wK zU|2R`WuRpZA{3*Yi;Yqh!oBdT+Z@u;jJO#vl*TnQOIwAsHSZv8A+p+zw6#cU(#Us1 zT((q)eTdtTq7Fps5W+j&1}$pKjQNl=-a(lutsiN7-$7cM>%BhX`ZWH1*Anw(2T;el+FlZ(jfx5&Eq_PhpZXe<*avbr1VHvmnALPY$ z)iOscHH2r_BhvW+M?q%@v`b_$Dv{10g}k(TPH=A96~;(6zFagCU*DTKOmirFF4iaH-zeAr?aiUKggGQ2 z?I`FR2c4xdoozbEDjCmWKSox$0ZT``1&`GJ$B{1cZ|`0Ehp~Cs*AR$5#lMgx%!X3AM60dUqiRNQMIlI3|Ju&wg@GL9u=n8a9d)OKF}_@ z0PDi3lhNAQ_#qa)q=tsPwnU?*(AKipNmV7qUsAi27^n;*D8n?$(D2VIgSJ*c2Yr!7 z8Cp;V;X>%0{(dqVfm^-CX|^{s9|`SUOzQgtOu(S?Ct^T41Q2<(Kn*)D8Ll>@@Q0QWG!12vbo9N`=APM;?91kLM!MZ>HXt z7V03gB#o(3gQn^S=r3q=97f$Aj;5@6^R;C&+i7^uPM2z3;_c)<4N@; zbpg{W9RXd(*^#I?3*GcNTDpqVgwbW3|ASZqvm=rm4_yM92U=!m9iUM#BD?|NeuT3< z7s5$GDK&uYA^Zkt9EuR9A8{HGXC>UkPnbNvT9(sG3{Z42d7jmUN0hyY-;ek+=PMvQ zBmaZAEdRGi4w99QAkA*1Ss~{!BXgldar%<3I4O(L8KEQ`LpnvqN|i2NIx9!ITBMsm zy1V84lK7SmlOd6DL7S4yHE16(3|hJKBhjy>q=hOc(!$9;_$FWyX$O$DI(5I-=>DKN zo^;ET#}nrVO~DA7Ig#jB;FkIeyGW8dm!SOU*9x)%nC-Ai4a>+XQIMH#k2BIp|zM508W z42|&u;3|MK5dw)ZG*P`8rZ1!L0Kyv(zDN!Si$OVN^l429??AYh!c{uV_QXA5l0Iz+ zX~XXzE$LkjBW;gTZdJbV`ZTI{=EYcx5O*P!5k>^$1GfXX6NE^yPh(PoYVhHRi>0qa z`il2OqIad{>3#^yNvw?02ax41%K!WbKC>?6A1~KYAMRK6VX2{kFmc=JVgu2c2Au~?(tJ}Xcy8(Mu)lf*5SD4PL=o09>E{G(a3)aYds?@Mj;x-b$twr2?#Jxx-<(V}9 zkuhV~soj6~^9K#D%;(CyG@R1oI02nP)54{70%A?0T* zKs`PfiP}^5VP6{cL{cvz!;7>Dr~g(PUxWMxk>B)1k!X49cI&`-rdDp7wW&(&b_8@M zE{Q~+o2}iR&?KyTp3q7Cp~I1j1{!sscB{oiD!MEZ9Z6k}D&4Ib`9Wx4t*OcnLc^a@ zQ;-tsW|lVu5pO(>xJ`(=PmZgaS5Qf+<^$sO0g5g~-yoeK zb)6cpk<#j$joN*~PU%!NEyXgT-LO=K5tJcxWhDBF%o8-`Rfle=Mj_CEgBo-LbTFUP zjfmW@iDu`r!euyrD2hbCpSldG+Tm*LcIeW`teBlQ4byF%_02jaEvp(A z`+$cv@+x8azAOwRNnPKbyivgvz|?=K>CYXJuclP=mp&lTO|4><*v29F3uiG(^Rmc8zDGo)QoPBsk$6}3i3yg z*D>VPNqJ%M#1aP?$wV?}SEVcckKE5|ZbRBJK#{{z#6i!8`quQb9G0 zQN{q$6cwS2VkD-kRIMAjWI?JTsW*vE7<7g~=P|h)YC2dI66zYj<{@#M6f=G`3Obpd zNOVr>zVPclr`hJ(3>W1I0dlVbe+S)J_R74DQBbuL^Z?j~CJi;LCIL+}@}hp}M}Ga@ zNVExVO+G-AXO%`hFe+(GjwAhUq`z~v^jaDjnQyCV!T2N5&Buo35a>?KMi)~!X-q?g zVN0-z6VZY|bi<%qU@q1^OK2aM(w7($!#ozVoGu^4eCqt6bBPPX zyhOb+tdQ%PBT??Glic*9wpUSVe+vSJAeYntIe{hyha<=pfKdi+4LstR=7%v0LR~_E0Hhrbi$IrhS?P$)n0@8p1uKP+!~1l71lsnn!MdE<NV;ZfR;@O2l&=8qf^g z7Kz=@SCs`4MnYL2X#f$YwWqPZ6Eu22T(1h}N4|qHZWY`ba|M@K=o_D<-3 zs2nimfP=tQ0Jl-jE0Op3)6K|5#eM1t6UTno{)qP7`8ZhaxGNI<=xy+5$p(wF`*i6o zTIGiH^Juna$#vh+Ko>KrX|$F*ikirP+gN=`XW=v}(|?dBf@t8Yj*^6)lz5 z?Zo=?x?d($U-zo2{;c2fss4Vf4f9V)&$&WpjC~$+|!i@-r#dOY6xHOJ?fD9mvOFbs|6wjx&XfzkRFu|IGF0|F;5gu@O-WxarIGY80>X+A_UBYG@#5^UbJK%b zLUpl0i}6Bl_=rZONI61tei-@f%{?`nY(H{t`X-iN(zwvE43pU*=te-dA@5W)m`cWD z_4uOJ_zt9!bE!RRN-%FOJQc-}12cqc0d7Er>jiEo4oAFY5V(E7bx_Lqy)#djn`4ZK zjnRHY8AJRNh~GRmtb#APya@nboL0dii*;4TK(04o3ufKEUk zU=Z+GzzENco9b)pa>uWssSy4+W`*%_5j8J6M$*Jp8@*sqMm>vfETa~ zPzPuM^Z^C|!+@s%hX6+a+>069g#aE<4!8!;4Cnz20CobN0DKSdCV)d9F92K&5CDq- zO@K{+0RWjZefU4W4`1N|^a|NvX(wLzyRI>`3LiAWJ2<(cTp4{0RE_5Tp0*?yuD}a= z%h(rLxpQ>zFUQ-7L&0*qkTw*Aj8sgxs?PRx#nLN3Iqs*rrC0)5@om(tNjWV_uLw47 zNLm_f!acw)^_qzX@*h`mMEycx{}*RXD*9P7)vjlqo@@j6=Wm%4C!sC_fu!~H9` zy76w>PVT5~Q*%crzOUNMadWw#G_&yMi_J;$cV=Nx0&+rmKTnHn(@;z0nsU zw1j=Evc4Lf)!2m;PT)$BcjMYnu)ee#++8xJavl4gZxeRgG6uzA-}8NV#xED- zn}pfa7(y#`h4GExnwHLBBU0{D@T)M+WaP_)>seR7lwL(GkL4fBxN7MQw=(v18M`Xn z-ho!@WbdfuelBBcFn*+nzmYL)yvk|$w5lyjH+En^)k~H%Q#dE#+rst5U90G&we?}n zD`OVph3ggVc=a)NHDQon{R(=Ma|L`Acnx}eF$NS~G+wRvS5LUF`&G?aX zaX8$mjK^aMA<{_ygBsV#aetn{5qshyGk&GIx>!xBgB_jR+!_BW8tZQOR|RkGrcX9g z{a1zXX=$!39?Rk_VHk8?QxmsTcE=_uS0Q7lD_4@6s1P{}PWn`J8Ti+#7@kHP-rG!m zHvec4NfR+RgQH<2W1F?GU@xp-Txceg5xxt4X^PZ0uDiLr72l2o7u>)N#NmlAHiqQ@ z?!K82VvkaE?tvLB-t0^~O9~hwJTW~C>&@KfV!kSTz#EcY%&!dF;TT4$_haNo3t)~n zHi1vP0{?31)7Ps@SDDcmvXA?tDukLu9%S5~HNup1Cskp~+FRS8<4%v|Q!kYy519Ir z?$%I~v_d(^Pvc0M4g$wLl3pL{B#FvC!o(N1roDoe3i@z%Xlqo$U$+f*8r%Zv(C_t6ou7VKFblGD-4VF4DXk*x0pcU1wOLRtQ>W;Gfq9 z9b3R8+srnluc*J?YeVmVF9f{Ti^qlFS=?&8f(*@=$&Bf+6^A_`V z^G@@y`FZnynWxOZGoLhHXjy1+SOS(ROQ+=)%b?{mmd7kFT3)jpvAku`2^R}j34UR@ zutvB=7!Y;}j|xuv7jN zT+g{)bsce?>o&T1x5vH8z14k(`$6~T-TU0Xa36DX;@RRQ;xe&XY!SP~d&MWjZ;J=T z*Tp}H7kU8`kmGU3vyL|%Z#m{T7dQ)@)y^B7 z9q5z$oL_N%%lTdB51cDh;Jbq7wr`EI8bBAZA=TXlSo>x7udw%QrnO^FHp~hhBQk`y21M zJ|lX`<6Gss#W&#FiC%iz_lEDc)JME@{>AZU^Ox|e`3Am&zlFb>zn_1L=S(@K510x} zD@}E#kZFtQcGEqkT_%&I-10H&E7p_F=806)Zkm;WKg!byIi>BATcm8M%v z_nNLX*O_m^tbEw~n0cT1C+1(9|7uRRTq%qRKM^K{i>-au2ds};ziyp}eze${ZMWLC z**<1_1as?g%&za*zHj@f?T@y<*mU+R`#JUt?S+_U4tu$MxxLoD)qb1(9{W!FXY60J z@3nu+{*3))JHD1|KWhK0{qOcnN1o#YjzUM9<6g&8j$b%9r`~z1^C9O`m}h@=MxC2n z_hNp%=K8hk_pWkxr~4uF+0WcM@k62+{Z%Hmi9O=u;?Klf&n=$)=nb>C$2;JC()&Aa zmG6Gv3%);5n^#HC!j@t-JjuU_d2p5~&m@=zO`kUX(DZxLIp&MZc5@BJ|B(4{^C5Gk zrP;C(BmN%Co0fK=&>F_QK(0Z$)ABH{H+NZHwQ+s8#|iX(&QCb^IDhT@yYp;Up=*)r zI#)MJ{D|vO+`ZujrF%u6H+|Ri2h*QTX=a~!iTQ5xr_7%-f6@Fkw6W7tY`M-75UCFQE*YX?qkDxbxVg9|@Y!NMsEx!_0SZl3ot;eiAw(}hM4y(iM zxWjReCc_ll#KC3ep#&u;HtFE=SYPg99;_E~<8$zWP&dLP=+Xus0lY`@?BCHr?= zAECUCF;>NGHh<53j(DkP7i+{$@ow>iXVQ0!!f}d3!o&jpxT(!DX*p(@YtOak+ZWnj zvfl&_{T0V|9Ircm<6Hs0Tj2h%yUTsQdkpjVQjCa|Vy$>1cy>;Fu z?-uXf-Z{RdzDi${Z!>1)a)}e8~At=QH3>Z#aMBywJ7Kwam5IH3*(Gf$?04zG-l`y5DgB-F>d;7VE|J zVz0PMd=w-4N%1}pXG~*vG<?kNuS6Hx9dVh4VVhwAV4uIM++A9+cud zvBdLH&(|@kgyU*dMij z%|6GG;hg6@4|TM-rd+4cFRMZCG0#h$|MHyceck&@ufx~t>-T-i7x8gpXt5ona9`tYbZ>BPa^K?qocjs))9#|ggB@nm>K?-Fm7_ge2}@4eoKyicKBf9t*2ccstf zE5pcM=j-%s_1(_of`@&d_dN!F@|5ox--{UOKgRm=rXnXCOk?*mbo@Mi0c3@Xc^i5H zgJv>~8-~U48GI(6#pm$3d>)_A8~FmrcSVpX1m3}myq^yseg$8}*YLG`9oDcW$QmK6 zWMN1gy?h_v4_RM6ga} zI5VAD&Kzg1GtZgtG&&0)mlQd9r{HurMW^2xfZSN&ta8>kYn^q@24|DA#TkOs5_a}D zdm+2@I|rQGAyw{h?sV>Q4mpRNyRnjtIQKgDIY*si&T;2{=K<$I=Y;c+^RRQ$Iqf{+ zJnB5=JnlT#BpK z+T?0+g| zsSddgyCz-JkZ+H=j=7GzPPig2&Yj`TbZ5D9+_~;NcRu9a0(YUi2-2_McDO~i-yLw5 zW5idvYry5|z~`FWE$)!J!yR__xO*Xi^}7e$+ueii9qyg(UG5?GuzRD}cW@(z1)YoW^^N()v9CGcJLsG69r7LaP5P#NM|?*i z9~}3cpf!Zkad~t8oq3gDa+pMu-xM&Fn<`9IrW#W%*R>M`}2`mpW| zn6^U}-C^1ZX@AHxY}#$wV;V8-HSIHvn#N4ySQigqWt=b_G95Nenx;)hOh-+}OvkaK z#?xo!40EPA%ba7*#V#)2Y%~{`3(ZAl-Yl3MX3^|72h8Q>3Ud|Y+geEZ4dy0ui#cTO zFo(@O=3eag`ppB7{0GfDuqWRI33%AN+q}m-V&03Lz^Hl5JPs-7fcc<#0+R7z^Q3ti zJHw;qW9H-L6XuASvt(E@Em@WvORgo)l5a6u3M_?|A`5R3u%j0(e(dVYEfv^9)>vvS zb(RK8lcmKHvUFI&mL5y5rO(oD8L(`}o_~jBr)8IA$TDo%ZP{ZPvFycebJQ|s8Mo}W z9Iza;Ojr(C4nrE8hF0JxWRT;Q6PAdD6EcKMAxp>+a)mr0AN$e*p-?CictH>xf(X4q z0J2JjP$kp|wL%@FmL{P^2niiRSm+UYg+53~1HyJ;P}l*@!Y*M*7#4O5dxQ~Tudq)T zg|s&=>=zCQ2ZagYkZ>5gp=sfWa8x)Z9LIh)B5>9WYo;~Jnq$qi=2`Qhk0`JfT8pf_ zRj@j&qSbE=Sj(*y)+%caB=wtB;b8Z!w zYwxr7Ll?8%K4{;8J>o9=kbT&`+rGy>g1zEC`zZ7QCQpb=ny6s1L>-ePLQIa3qzFld*u^9WNq!h*(!)VW4wH}?I3^>IbU<=J1zY*I zvsHhHt@wM{YQLYY^oKoJY^9}DR$61F6_!?4Kh{#*Za3<<2$sDD$lM)}w|kkiJqSsA z4DvJw$vFp7vk?+A4-JPOt4|eHo(8NsWB-jS$*$NsvX`wQ<7^F?h+9F9#jPJ%ajQpR z+}aU{tsHe&HBf24j_rRZX&;c2!O=Tp&&XB(WVyauxTkDqCGONW{dZZ?h)8UC4z1Q6o2b6)|l!#Wqz+&IYOo z3nzgbj@z!++SY2QH){K~w6y_IaRW%eD;K#4UZVA~%c7zv21NGv`OKWNySbpW@B2Q_ z|9SpA57{|$X1=%i&Ud~u^PM@DT^+V%+H5ul{wESP+gkkcpI`j_`aeOu9z1H@VA~V@ zU;5Tsd(}(dnl|Ugde7W>H~(nf_kZg7;rDO4>1NgQgBv{a0ylYXyvb8`#Z=EvZ@&J9 zv4aK;@S32j%WbwQ`vBXXM;A}Euyxo5pEJ;&ahh#|-DYb6Wf?Zx%xt{n{|@BY9~sjeY&MUq#|o^Ef8uAg!&b?Mh{F~f#KcMd9dg+2Kl>!_nBC#9 z<@EB}wZUQAM8Zz;Z>)O50u}Gn2nvxP@|t8qR;sb(*NnaX`|9`c808=G{sa7O#&6m` zzpW-RcAhM_`Uu`tLol8A&BbrpKa}&2yB@$#_u>gjM+UbVcm9<@?9}puV0} z7w}I@*Z0igzo0EYGWG_ESI81FWn0?&crbWE-L_ZC;cQ_9!==VE+I3Z@T{8RPCV47;bA> zRoApbEi}$_Af?3}zJ2qD8<|ZJ^>AXFd@V8?;=0Qlz4BSRt-TNHP-yKAO4SxEMXt8V zbCAI-g^zwCfTl9{n?KbNzI}zzPx>nK=QJ1CA6+}|$=&eB5ZgZl1K_qq~ zD61uZ+QA$k$s%SVBSA)amhSLIr=q;pX+J%(b>r8T8-sFER)hs1RzF%7osG;X;Nk`X z9fll2ypj+PW+8hBv$Kekn;3SCtD90*^ zZCf`Admn!+EPvmz_%dnP@r>PeC6Jy=K$A^C&mmLNLO_y+tsBuk62=E%V;UNGTU&JC zl6MmQAmi+N>WLU4vc4(%N!il_oPmet$RjM5A;32K{{XOG1M^QQ zn14>eG->TvouaknsT8d>&v&KO2^lC|WZ-|1aQlEUd(BG#0_kLG@ANap5_u&>Zlz~$ z8o9Q8fSi==Aiy0Z;btkVJ0RPR{YkjN*Ckxa)`Z*fMhb3o&D&{kJN}stH;rBsuKzt2 z7HwAZz68=oduNm-hYwP4w*)^-gX`%`hpT|z#gblAEkJV3mr2kqNKzdn(%ZLmn9q>Y z?OQy@QSR+NkXpeudz-$cEt-ki5#(xb_uJX2b=Z^bn60eYL6N4Aw0uP*gkz5&nU2JN z!sJIFN%V%K#r{|d33PC(F$)%KZ(9_I_UrrF4mg+mlMM`dwm2S>g1S4S14$O@kC!kr zO6%R*Jbh$VpSE`>%j_CFn>_7J@l?|{h3*>a{MX=H)h~%Jf@C**wyduB{CMt(&(r_Z z@f8k8;;TWj8@?7Z%i^ztrDdC?@z*i18$PT5^{O8oP7@={#UNlz(~qF}EcIh>5?8u@ zC@EY?{pb~sZDEulbUd~Z@>$^V=*djYx6+WLja9w2PmMRp zPYaUis66MUq4J#98>&cd8Y-**^yJ5tm*mHfWIB?F`79gf!rqX0^3#xf6F;7BC;6#C zG96Wi`7BU%6!wNH_}w&Af*;uL!5A;Thw&oiMkuX%$0d)|(Nz13yCMmi&k_k9dTF1M zG$h}|PYViL<0g{n{P-`G&k_|LdZO}wFAden+vm8SNC?O78P^p_i}@^&w2bc!NlSSe zl5gZ^Vu~Lm)A{jCO5>*n4?X#@O-@5)wU5v@G>++qpmEAj3{K6K>G|RP2;D<%o2DyShNQ}{>x7Z z&sr2S@pK^BO>VX;(%Q$5hn{$X$UOyqwz0A)x9T2vJZ6^Qrv?u_@w6bf2Oi5FK(Piu zv9M$XRp?-SiOPSaL?tI0w{K}NpV@_){ZojiyZ>mL+6$gu?R5ktEtaN9JeHs8H=jjU z4dS6E9?$gdc)&!@{_`1%QG@%;kQkC|-o9nHnbnW)FT_LJ+n6u(OYb~2$W02(vIo85 z38N(8tTch9;rXkXCGfQ2p(maW*X{fr} z(NsU3d36#=5Xo+O9Wk?nzIm=8p6+%hh}t?8&SRnuG7EALEVZy`kAAuqxu<|<6Dv!8I!vHx zcGUJmiAV60gNL5{B8@kChPREZyV z#p5@h1)d-tdg8JDq!&Cr<#s)anMi_2c9UC+nI+`5mPLEWZ5wjC^3&^h7ez7prAG-7 zCCtuhsYabdE%5m9&=b#0!ev~xn zZ$Xl9Ex*ThlYD0TGzam}vwb`__kyQq`}_&TOe7H`yS0yPZW=!xJoMzpkKC?u1D!qb z%wc7zY(W!fx;-_sq#m$n4?XBW?n&{a##P(Th=+2qdyphQmJ?TFJ`1I8VYwcIkZoQX z5{|1?SmVY*B>35?Ki_s>;F7nw)(xk$1SJKY#*7*y`Ldt(_F}=}-5D*+;sT~v2E04l zQ_s?w1zVsx+dA;Du{OEJYmT8*CUgDVuO@k@2}mBe#!GjuX1;tD>)gRxS&6t(eW*wrm*=GLV0(7d)ddj!ve!>PI$l`ZBX!bmiMzd{Y8qJ=EP9h6yFXdqq zF7){k2_$VV#kPuBaxca6_s5cZDIF0&P4f%Wbj*~oXM-t=+wK0160W5WkxlX$tM8ap zwXyS)a$ABJykp%pC|Enj&#KnF`uOfzvvB5$FWnz<2jMUQ-fqW zKON??z|)cF4Nouw`}E(u|Fx~pDof97eOHMlq6IPKSi>xue0FJ1KNRhu5<%o9@ywWN zlzE-#E!lcoTWpZNdCB`?AM$WpJPS!E3sfQ^;V7;553I=o{7L$F0)W#Kd#I(t2l$0wUfa z%R~Ixpby)4ncy4G18hV1Dzji84FB_ud2HSxJ=$>fp-De;vMWIdA~Dq zS`v262*Ca{1>2J&VSh^4HD`#2%%#DhU_8@U+KAs;?6rSOSrgGq9ks^NWoFI@k&`7@ z1JfqYpPM{?7$&QGLyDk~kc!FKagdjx0$iW>Vml zIJC}*>bKg*J0?O2w9XsV(L!cVX5q2jG2ll0kY|DWNve>Q2|c3zh&DzvjJ~lgj(C-- zhW-T+#v-E49uH za39|SJnL+8ZMNpNoyVHDVT(Hck99zyq@Ewab7y|)`JQzQib_2b`@T&gkEgK-`$+l<&#TyBW#ZZrOW}Czx7e0?j$J$T)OEB+4@h&h$n;+4R zWj5qo+64a8A(!TQ@H6<*(fA?RVd_^>$I!|n*t|n8&4+|k<)3EpN;y(T-&(jlTd-+A)VZ zagsVf+mweetZMv<&$o-VDU{=WeV0$U;udTh*2?LX8FBS2g?WG<*jq?qd z_aBCPh40PzFOEJOa{ty?`#OjWx!?MRTJ_I^jE&)@BkCBVdX~1qQLwe0cAec-pc(Iy zPi}!m+feBHB=Ck|Fz67ZZZLwxqeUDAJ7id4yI0f zCgvKm?r<5aU&Mp`&ElVV<_|K|I~=|z!cQY-UcZ8f@K-YLdl!$z_eJp+c%aPZc#S2y%EM#kf{ur*W1!q{|-g00XG zX49yNY?tI^TySNYki06GxS6H2JLxNo0?}; z66F@lDx!M5sPh~OKUb@Lm0jQG8Adtl(fBiAQFdxt*$JX-wEp*a{Q&f?G*?@Yl~C>} z^D0W?JE$fpqH-8hbB&?K&2vN3rrVz3xL&Ibu-9sx*{TDnjNn4AVw1M37DKbL^gb5x zML|Z?B;A;r*S|aUz&Ua~>5FZ}*hD)vCreQI-+UA(ub3NhU0G`k&|lGBvDfOC2%LSj zt(mp@fO2&%vDNokFDdGDDB4cc6vkhG4C6gAIfSpL;>YGN#nQ3aWM0bTd#D4E3;BJ! z8)nE*X&i>Ku>tra;MLzFV8wrdzNK}zV#TO36_J_x#->QX6F)EbA_y(bJF+Pw;516J z;am2JzK+Vq$fo^j7L?=2CcCEY0U@t2t3?oIwY)!tnQNExQvuVk}%X%?~d@3w{Mc<7-2KGpn z2UK`3<@B~;ke(@~AljxJ^cx+)*(!jhXQI4Al%3xvHWTj%yE`ws+Z!#E#CQcheS(8| zxiU`>olcuE!GZW~45WK%!-6JAh2;K!yI?yK_RCe;6^$WW#b{DdNpZUbb{6it+-yiFbFzyv2-^0i*r16(v_V+>VR+hg;; zN+eR{*LN+ib!5kPrr!Re`&&=^AKHO@YV7jgNN~Ab!2P;=1$(^F0v8yQ)@Ia|AIUaN zm+AetgSVvs$xKTS%b9rz3NzD^!aQc4Yi0_62co%_nb~Hh2eeRLmCXDS)UvwONZ)4W z`^ZH9JH`3A=Xkfdv^hVI^}`Fun6}739&N-qoHL&#=gcF->{QL>a7Zg18}*?mZ!N0C zh8+~opo6PV9KAMSps2m{fNj1~duh}*&qwnj#?0DFKeIIqz3?blgIAQ%@V;DB2-jZv zsjdFC3lCcPFBe4O?}H{3x>;?TpM&2U)F<)xM)mLb`+fDlQQ$fFm|AB*T{-W`3p=cu zcjLvMtT`+O1HUmL-!F&?bM$%+BjV4D2^>bUj0qm{1B1WNYq|kqblHY7e!bjjT$c~u zrn=w=hF_&NT&kD-&Z%wA@m-hSP;5*nv>!669l}Sj24I3oU>L{nyTd5ARqEwXTy<2z zhkDeS)q$r(xlO;hD3xWDJM=tn0^?=Za^@Tq3{o?x>~$HE2%m_vhN0i1@Xzi|aY$CR9w8rcfzL|vAm6rEl7z8aZ_k71` zOL%1j_=WHi9i-_oVu*I5=|PkP&FdE9<=Q6vi4H=}Lqrw(zI?~J$9tpB96!uCrZLN# zZ@_m)!#3{%d&Q;s%JLVHU`q$_8&dsW8Ks4x!b3(ymXN7%fZO^0S9p(HCT~ZwV83x8 zJ@&W)+Kj85y5l#czS&s~^&!U_cx}t9aP`_RcR}s98T~5teo)b$6eM&k_sCf++r{Cf zWi|b7pjEv_sh7H9l%^XAIiJAmR$|WR0;6EZ+Aq*1(R`Tybnx)U^b*m(6Y-aUs~4F( z3EV;^tC0ZoxnC!bAj$}Ns6RiMENTo0p=_@M3?yelC`azNbPDKJBgt>O#qL;AA|{BF~P!-C2Ia zV!0-rww~<`eyxU1pGT>Ylk!^$7cCuT@BHS$szLPX1(?o^)!Pe>taL$nL8aT6;G(8u zyr|IHb9^5KK7x7Vqcv6}OUB@bLLV|;B6TN1aQQ;=cT@$p; zg~bcK?!fzmxyynmOUL7!7hvvh*n(>(4uI&@{)yqQqW5DnNfUE?&V{ps>*PzP;g{xo zn=l&O14!EI=nkm7m=6lJ_6nO4Z{a+mxX(6_rsfs*d6B<@u;ETJzftQiHW=?fI}Cy0 z&tvCUc^^cR=t#{CjZz*K?r&sI(zBsfbw;T({khsGby@FzM>3yldRCeEBWY>f^4auuBltvrVGbmoX5v|nR;PtH+f-o( z_M!F~_c@R&6khvFGm?I6wMC8Z8V`n9dcQi>ES&*eFLfAGvnbCpuPd?3nCe72u}gFh zNXG^1xX*a-K3Q*cvfc}5bz=qwgDkzu>x!yqLse2L}(#XjZ>ra>!rF}FWJSZ{zM;adzhZ}MiI5xqq2$b0ZRyw*@joCF|>%xKv ztsol!I%53lGr%;aWu&+(B}ZDs<(pkIzr$G0_g$N9IajY~gpfVnXyvLlx=s$=4|Wk_ zme-9nVbivNciI%ARN9sbZDVdR3X8RUnPv2|G-L{_pq0KP_-v`LE>5jIi$mb>+o5`v zEeb;>`ZCJNoX0?Tdd0$6g#JlNN1jScKV%ARd2(GNRO*aw!g!1J`9>Y2O#)*c)(M|t z9kCYUNiJHYMh3BHbt&aCyb8?#r8Sq^zJsljb8&9~eOIW1zxpz-E8^n63`-J`a|QQYYeK_SrZax#bnwiNWgmhU4=_ylk4_ zR6lC^Q2oogt0jP)qG;eRv5ST6f{!UU4yjl#RmGxkE{M#+Iwhs#z*J1M!^2Q6_Ql^r zI_qwbpqfprQ7DyB=4Cx0h-uJuj1Ak7y>5;ydaYUX8Cf)sFfkNx#t5GrnQ3*6>9$Gw zbQ>CVFy895pflElB4J}X=W;0Nl5OXTzm;0IwDMwWiT1}5?fVC$Tq=+UP91f~MiX~k z9#tC8Cjq<-gBrJ*7SUWHJ;$71VNgJknJtdS~<0H6uAbafYa^Fv?8ZI(QtBsOX#)Mp=-+g4lg&FGG#)NF~WV$iClf~z6M{)V8 zbf)=xz4<#={!WFlTNvGsHG5;K*U*A!vFPb=p5@jiNx4PfVQ?9kkEM@$Q9`EsI?%bUXPj z=Ii!69M7^PV%%8*9N}{rs$5`h+P~=hP^sKTt`O@R_c9hk>l}o52P?2f6SHIbRt!uj zo?Uj^Vd{|4rNRJsVewr__%M*b;q}#*EgoRi#8`_Ny-_Og+$Hf0P?c_YnvN`b`SP9x z2NC`nz=u!Sv~|(9CSs6t$j$$uR_I968)-{ZG*R?1xj&2mDp2DJ38Wzq@JaL^5DYd+ zK85A^0jlZ88nI7+7?HcNLn_whxqW)w$?FGF_0Klz2U!1}Q>_1;RQ-2eC;p-hsk&do z<4gPhEgpCDz;P0}EJ@MzfT+{B<6q)yT&n(TvwrV#m2;62uGTbHArxdS6{2a!qCUmd zWeYD(Z>o=Iv}98a6d*5|hG37y4EYc{1affVhLGVGy0r)W)f2iYA-2V&x-rXbARCq= zx_uo0!tCRjjz_c&&swJ=P^4kkr;mEB0fQ}rk*?d9NHjAf%_E<$!1E=uydwik#h#JG zjP;|=zUuQ@XCL)BLg=fm=Z`~OBjK&)Pe1i#{`6Pd;mez#ja)cy`f$NOfOVg*H1g`LisJe* zB{T`CE`4nep}zhknY5r*uxGvwsClTK3uq$&?J}jgAL;@_F6whn(Gni&-=D01!lLSR zK?gSi2n0Ll_rqYC@a|x;6M2QH*Iahy>j6sRcr!UrX__dLUd+NcKC(b|;9L0df~qJwZ@ld?QR5|9U4zL20EL0Q^+w76C1X%i9(G4c&G1ucBu0ZP+)nOBEAQUDJB zBr8zTE6rrK(!@2p*d6!-*q-QJQRy=k-t{v5AQ>=6fd@V=f9+iy*vFG6*l{(p-;-#T$(u z(X~0?0H-yAeBIdd2Fl5??bOGfb4>iNN&Gt`{uituz&LSZJX&|M@#rDE$9$m3_qBGB9jA_6-+1?^2cVh-o^)5voYUG>|`}#Qa)| z7gAp8q03mi(^z4CZR0Nzk)9M0W zsBlRr?+#J(bQ$wElrc4fQIQUjsQ7`bC_>$mctzcDp}Z?4RvGU%Oj%=M-HZMpD!(r) zGuF?lYp%!sFY}IwyOFhF#{0RH*2@_g1Rk!m$S`@ZhzL`0EZ$M`3>oV;%((oxte9g} zH0e)c-mEKmCsrBf=Tg>OenM8>kNz*1f3G|9sdc>nv5x9(P|u$cQ&;u0bjvB^`%1wP zYy}OBpN;+@VvA1KkLvsMXmljh>5|fm0td7scD@KeLfR&$n7zurnzQ2Sv0B_2{PGeR zYc19dmDc^(`k9M46LjxtFV;rhHKyeH2B^1SSE*lZ*ymiT-t7174IGKTV2sc8F{oCo zFaoCVL#H4{Ovge{wp@2a8Mx%dS@VA9+s@eR`$*>$@iP9yR653u2s1zChGJS}2BHj1 z@@!aiw}gD%=%x8>shnL0SQWCwAzJhf^J}}^5$T5!4EySqTon)Md?^A>MXgWLCgW< zHXtkxw(Dn|FJwKHVVfh3yfwz;+~U#dYY=x9X!PYRQD5@=wgrwx6wLOy)+mi!$}$W5kp(`*A4~2fY-cQKcsOI?G_yKie@=+~ z+a-hMpD%@7naj2PYqIr1uO1VvKLH@n`buLPG_W?jxy(DtwgP{wl^)W2O*Z<^!1zCz zrq1n4RnL;u10S%WJ-s5@=9+8)4wVPR{}@zJKvZu@RcE_UYd?r%{n*0ugoWpise&!C zp!z}VY6t~BX_A3u@(p}Bybvn<&)ChPOv(=LM%;O~G3fGtVGNpu(PyJM2E`FQemeH< zeQ|ZD(mD{+#?B~XUW7f2>3hc@%FwdHi2Sm}Z5O zb%h-kShbBAs5?|yBP;i@Dt{m=r-mTZ{lDRzBS~#|GI+=MJ2@ekUqt!K@wW@}XwNj> zQS)>S7rVYuKh&6fTvRN#Dw_1CF>lqCyo>QG4&LiA{!Tt2DrZ@h-|xmY5CX5 z^#4s;^`fVYGyAvnlzTquZJgFr->j$G|G%N9lPogKzGih&OV?x{?L|+ASQY;rJ>^_e zNbdh!Pk&5IU0o%#4P1teFn;i&;d$d+S%!M8_N7D3pNtr4&KvC8?7I{jNZnnmt$$D@Nd3D(5fLgq~P1!FhG-4UQ<6Fy$uQ>=Vv&# z7b=`5$_>>b87McfHd*ka(c89n%5pvFx`A{Rb)~Dp6I_rm3CoTT13&Uv5LXG}4oTv0 zzQd#s?Kf15g1-8J+JfVv>T4?SN&<1_&!i9KhG|jISMRLV7Mw5(erOVCjj4Gnu$J9C z%R9d;RYVoG-6*`S*FlxuY{U1`JnPv0&VdIYDQNNQ*bfd!)4gE~E5#S|!1pps@>c zA-CiW_1v1U{lk?tr6;;qe78Gu@LQ?zuNc^9g4VmC^{%2SuZM@sG7SYCKxu4d+dI`qZyO=zAt6RI5>Kns12QxeWO0N zV1F?t1RGN|mADJ>EHW4M`iZVHU+SYoZR%rvzOp8XAyt1^JO^iHQg0*-sO|g%R8@&z zwkOt4;cr*NO_|2UPk6-Od!}-Co1sy0EzeNQPO!}Cf`4dC<#9WTNNHR{q2S2fY#g~` z6p~!f%*2YKIB@rI{l)O0JXl)I39lH1g#a8n+h07(o1=~{*uk|7_r2;Uxt6h`XnUZ~ z1mDMjJ!4Qi1uOhFd;DEGyP=YGJcsvjeSrlMHkdG70$?5h_947;Qta((I>_q^`IaLqYehk^p6EgT(**5snWqaKT z06xPK?#W?8zVo*CDqr-~tG=nPhRwb@8GUtjm%iFiptR0R^z5v|<2m3l{T(|j2aEXV zZ4!jpUmHfFXI38X-eK8aMXu;<982b5T)+Tg;kU*RP_Sm^iJlao)1uF&-bgs;wDV%@ zv;quu3%tJ!JLNJKdUMbT-9?;}v#RTDn4N3<#9@3po{hDL zxN`4C4AVpXzD{)zE!5%qc)|W6G2n@X4vu$A(cMtnjf5R%l-(b}nZLQ8&A7EhOJJm#%?*u&LuvePwC5G-S=v)#l~!r;adQPT(#;uIK*b8K zJl}k)U&MKQWq;0o0ux-{=ZfY*!O(4X{m|$r*1Iqf4NXWWt=A=dxC&m)@s)U$WnTcv zgv-+M15xdmebGhY%fLm-@d?sF<6r5 zPKz^?w>(t1hARpr=0Q{n-R2-MTC|Vu@P;NF*S`YyS;g~@tD}4fQc;%Of_KFNMVbPNiHIanAak~N#uoFv9MfiTyN^+daFm2wi*+p=m=Ofr}%DnlK)f|-fXfX%Ml39;Yc^u51COEwS zgEiKhxkr@b)dOA&m1S;#)KJ`^)p_$B@pahgBd;sbDnM=);`uo|<+mNk&^Ba1yxw&V zD7(dZiQwFWy%fRs4eT*4o^HZS>H;wDRT?iP1m_4G*M~119rd2z{T0+Ji7)BNdv%KU zNfz%Kp;i;Q$$MrG-ZL!TYmLeiVE%O6Y4=V1=K(DF&mjL9@m7=n?I1qI|6k-&{`LbF z`>558eXQe|{EPUWPeWw^8+lg)Z1gpf@$=pljN>{2Fy72IH+4R68?Xs|NArzAbAy$+ zc%Rb!w6a%rEnC!fl$>`dE@W!K{#Lj0+mCiH-VRK{5QMNmHHPPykrA6CABtcB#Pdw^ zd3&dLoQTIX8^B2AYyi%Od6^3aRU^o`0*dA(EkfBHoUVbKJRTLcyKIS_HBunS&e6-PP*I5hn-WfmGz6CqQA5{yDI^#^Fsa6Dx*5Q8545Q9KPM;auz#VE*CK)RBH)6gHvE>%wg(9!0wZ z;9w72@it)(ve8F=!w#J+FrQBtu`$ajV(u7Jqq$n;}`gD(6l}_LjlB`X!LENJ=>@~Vp*ED9Ck|Djlz&~Z76S*#s5vH zF3myj642VDsi1@?1D6nh7Xs+h8~>vSuFmUn#5XV=f&BAJZ{$=8h~s%0|DG?l!A`qy z@f)1GZx+KD>^qRbO@NXngGqS&Vw*9o$r8bP9YO@#g$U}%Fj2u29|0U6v2C`lQp z4bXu#)5kD`(EuWS7DmI=w6% z2w|K|m~wV2i$04+NW^Y}Ezn;fKER1hNIq>(#4brb#4bV-IxGDK2BI?HqX-f!!JQ+= zh0maR{hRwTRw&DuT_UD0k5cMi!Xhxfax!A<87Fe5;C6@7)Q1)UqxojLUE{$C`r^iH z`XAZ)oA%B2xAYRP?}W1K3FvRA><(J4oX~8{&PN{#Ey!qxkA)Yu(YR9qTl=sNu2896 ze^Y54hT+knp6+vd6>R~EOrDVbBJctFfXlw4{kg3&T2T z{0!e7rSUUxV9dJbGo`gE`>RR57nG(9)PMu}&X_WIbtc)6Is9&Iv|63)Do`Jb;ZZvBd|{5sRgf_K@*Mc(Vk9=Ii}2_{|H(7%WLPAg#8_-h z;cX(hcu}`GgQIZ`9$k#1FW8T`A;58mVV-jq=V7)NqIoi^?l0snHQq$0h|p2Bq5@0Q z3-`iru3_0lukr~6t|vSU5jD3Fy8}77I;I6c9fAYOEcxispTkM!M^PV#1HCRFt&tSO z8}XdSOWrQE9GXJp)NQtLa^TW7Rf%3txh?e0!2yRDvTJ~K4z6KLD}cW4qOFQ=mG(!< zXAei?e@{Li^6a%KAI>$yzB+IA;$q)nCG=;=2s6gLMpa`zXviKN1#LOTwB^U~KUB0JvVlN~jg2CJy*M36b??5{-4td9-LB-XTi^Y)-##5W{%$PIx z#z|ibOP&wYHX=o)8p0d65c3OZ;ISL5oDpbr0Y4*#WOfKmbYWk zV3KyG39dVBsDiSRzEgppwukJitXe#PU}c;gRL_bnK3PcJ=X-i=#QhuaMEKJ@#;^9+ z(_>$N?Qt3TM#J3NCie{W`?Zrp?kS;?->BE&@-ZynIh=Y^{6@hxHf3a5TmwutY!ma;Qb zVPhu1KNbJ|iqb3*4?l}rs#dzOI>U6|XOMf7EYpzZGG_BrCsJD0v&XWq?JpLMJ z!h;?~pQNYlvX?sLn`gr~DrqzC#EJhE<$PNft&$q^kZEWASb9ZpLi0550EDc}Y%cQ- zG&FIQnqQpgF`l{|w$`|U?sksR51rJdtjFmlcs|Pd`Ta5ed2wv%!o=+wFIY<$TUZ)q zF;utIg`+&9@8V5t38RDAKedhiY{f3;11%idyNLj$En%~xe58t)R+Yl3>{b!ZwcksDw)1o4_6eyIH}(vBKj zt8nT=ka8h4O&?+bMZY#Cd9|ZZ%lG!PRa&^Njb2qX%KR8AG!$v{?5)t zPm8vN4biW5*(asJsSK?2ZD0I0rboXG>yun2g8wCYF$Ixl&h*XkKSB3l;De5`s$(~-bm1Zn4VC2e#3 zKI~}-oV=?BeWzL6zs9AlZumCGehg^nKCst3kK6}0!Qnn7UO6W2gmdGS$MEMiMSecm z%;l&^yMj7En>w3m=6}suoZ&b`B#!*Bs2pBT<-F0I@BsfO=Z&VA_5Y=FIcevOhKl;> z=Zz>Y-q$mdH{+Zp@9U9w+^Siza~=`CE@dSBF;1BBF%%UdvcC^P@)tT85bhSn2JQG~ z;jyL;i0wj4M_ZSJ=l02%R#@l8MD~Norop=$S2(Lr!q}-#Xo*bqFC0i7=RooZkF3mu zd!l|<>&#Lw#)%X4QmwPU3d`6>y$0JX>UmnCulg;m(+LkI#?zwk1F#K)2i~j{4qerW zDb@VVIL>etpS48)02(XCNYBt!NAa%VT`e&{eM?IW4EzNz3itxPPohtt1&?RrQSvR% zII7+<90}+Tk(Cvfn!G3DQvWV^r}oK{GrZC!`h#WQ9fJw{xw0#`*OUIT952N(+9pn* zaE|CNWbARyTKlRG@yDUw&!0Z(JxvLv`Atlt!`*?{1dx8bey+dL^bR0hp(PT5y}-&Z zhP&BMc+#-WTLuTe?6z-H-|M;(@^ljkv0&T@80E&)GT*L+yGgsgt=#vV68bM-@1<_g ztSe6}l^6e{Y~ky;uoIp%&c2KxV@PHyjUFVM5(~~u(GQ!IjiZsB=fi4YMP(-@&t|nv zpxLa(vzbV`0jxp-a|2j$3hta#Zj+gdLomNFlLOU$0#Ja*cU*WO&L#mKlCPwSe{3dk zW`;`*tb+4Bx5->rwmO?RpwVu=%uW1r8u7T<&{K2c2Y40MjUrSg*i%QF4bCJuo)xW}# zt=B+dFKu!V8jw2gB~Fp?yq7z6I7wHIq$@|#l>@rWb3-mjnrn6@5j=ziB3!5_)>Oek z<7MV++{w3;QXn5cm*ozMIWOww;3Y{l!R$ajz`TSXQ%-1rJ|-MsJeDdtTSEFhiV_Z5 zdx3nJgDO8YlW3?Pm`NONx)I6P6#PNY%+bW@ss=VV**ZfOL)(kv%^;#u(1@b0w4!X8 zY!*F+g8h&{!BHqE+63pUK7#;|<&;!WNQ|SF+%=XYaWoc~NzSQaZ}J`nbUMgB+3}+z zgu^U#-U+C&R+K8(5!(vT=&<5$;@DXLWA)zHrKAIHw{{R?I_@d)JH*8$P0z4vFQ_)} z8-|4tflfG8jlu7F)Xu_tt{;f=>bR0@!4;b;#@UTUS-1qdf;TBO@{UGY7LNToZyTt_ zV2KmpN5)?T6(@XOyVA&AqTr%&a3G#V3VPuPEAF;RncglkmGGq}aDn zB<-1y_mSRimsp|IC!?g0e@*jFxa{ue&1fFXLmJSy7@#s#Tq1{c$VznvZWM4whoFTq z&O$vl)nH`Y7=G4s@xyf}I}HIe_}0<>f+N7ILMO_+)jE8kJ-9yfIWDeGTO1V-Uiq6) zoM|S2XEzl*T!;1SXAkkWRltt_-ke|4m&&1Q#fu#J^X3#r-1-ZCxfQQg_6znjn?y=z$N}}>F87KCUfDl+u2mtODb(JPw2!*E1 zp7WiD>q0l3&_2op1-Y9!5+XZ?Iwok-583xF!1C6aHpBHRNF&Q|EEoNhBOYXmF$pak zm>k$0ax<6%hXEJV8;(&_HtRe`m!dN+2L*0)65eHR;k0wjFlTbphd=)%8k?65d-d_z zNaC{;F1k)q<|NpC?Zb7#Gr^fJQ7Og)s@UHjeF)V&y5o$?1cJbj%R!0@Yj8P&tN8DD zW-hns$j=YrNbs*kS=7-Tk6(5<&kuhZZ(=#S_@o1g0C&cjyr3bmQxF1XcS6aJ%dtWF zJF{qL#9WxpF_)uMM7bOppBGdb$D)CaMcK4B9FhT}P;PFO;LaIHGS9d?*JyA-1V#GJ z$)UX8QF=z3#{~ns(zu7iuDOv& z(V%uo$nikPbuZB6__ob|5ykVcXpBcs+dE?O+x|QrxLlfteMMftgvb2&urR*oOLAPl z!tOmBqMUg+$&-tH1b5&)fc7-)U+^9LdW}Nf^pflQw$juD>`3PWmIs>bj}OM$zOgXh z;VU^k;L;CI(vBqp2gl&fW3KuhqDW8*G!_}Ivw$UjAEx*pK9NWqsi61{q5v|UMuwDP z(>hoa$_$tMK+Zss1$1+Tzl=p%z0gY$M{mUvt|bK6KIBO`*1YSAqa<{0z}g!GzavEDP0@+pzeV zqb#i8^q_vg1%6`1>c2u@{v89vhw>f1K&nQ8E{nEqoLbQh*)mKj)mqO zXP}jPNZ<_pQ(tG`pomr}!TLDkQBkFeyv>5_9K(n5b+k+{%rv*UmK`up`>pLw#T@Vc)9|Af; zw;o3bRkpA2^ngeIGS%*|g3Xfw&T1Y?0Jw@W9i!rRg2+N+>BCr5DcGui8eM=RAhk;_ z&kNdON65k~v^cjQRJ1sT1hHL^=hubx%Y*m|qf1|dlkgRcIm&ut52KRoqpTO}uW>cL`QbwM zFGG+Sisa&ZVEFMMq_~U^*{@MR zd(!OJ-^G+d+f*lJkEmH0%KJme#SOk(->&)Fw2w2;a(Q~E#9pYsg)-3VL8Kqcaf{Bt zZg{nNF~%N56p7dw*E01Szi&(6h}p{-=-{{`RM$lH&8>enwg83zeg~}}lz{EFO7`wT zuwJ5V$Om$Fd^p;gaYb6(K`#=9ZYfJSM;RP0IK*dcpaX#WzNq7lGl(I6KYDfFzY481 z#h-~<$lShKW~N%9=@#}QHq0b^eZ^}uilzfeSx8cnNb(vW;POW=!A3+^Dc#8Zb9^BH z#OC?X>wiyZXeQBr3#Ht0^?*s9dddz&0@HY4qD5h- zQC|J(7`2e8YK%ot_Yf5&*A%CN_l~6RHP;Fb8~f(G4f~zJiP-66$0!K{+|chhol<^ z0i+Ko;{_m#!lWN~@8`k~q@8f1D@K>eXPU(lS`^NsL3Jb7pONSOVxN$734C1Fk}m$> zm|4ODaEE@JfGJ_@Yc9lGBJN?8exZAL>18U1l3c^_INTi%)`f*x6!s9?Li7e-hd1cF z*K`Km!WsOy^s)eV<#I(GrHO+{J0wRh5Whv}h&FgZ7crB!rP!VUvC;z(9 za4+)e2S)Gf;S+ixP56Y^l~R8?8DBV%J|SFoxAMynK$&h@KHRi&&~TA0FooxK-M39o z0HZ(+P0F3jYoHe11yPnz#?lweH+?}Vdy*}D!7^d1DnvDL*%SS|A_86bN0>ABq9-YB zYA})Ojz5%FAVl(T{P*D=Zfc5prEv zlH(73L<}kzCfs5KVoaneho5{o{9G$FB3~LlF=_ZYv#7iGu|LR9WKa|+Lq%jS%s1wl z!%txdjuf=Sfe9AGAkRSKN(Yh!bg|=vD>t7(c5-ya zxD|5T0Z91DiX3gW&3l12WMJ%vnepnM>zl*IX%IZF1Hc^~3_8m*tq0<+maEcsm}AT= zc(abXLWRqq47m+k;!DIjNsfI{xeOcb&$GjDTGj7_oWd0r0;~ERe9#9V2~V{3DLIy~ z(4uURRS3*(jw*%A;*Sf5fSx5CAR32r&^{I`7+mgtTo@Bm;tueM%v1l#%Mki$-lHk0E4&XHlRC%s6{K&B;UdQliQbEd~xJt*|b znO+{}D%LD7*Ek(L$31!%%#+ue)P04j?320ZlL6F~eG)y&inUQ1|H*D^9y`PMr(&k& z{xfh?hw_&B;`Kw~FUUEFV>tq?d~eKu+Q_7V4#XHHm4`he94Ank-Xw7Rx4}+$;@M$y zI%AY*zLF(@;eMH5^^}xyq$B=>}9%hMO+iYdR*! zsI6EQNt+@~{~|d>nh(hG!&a9gHDl_P)YWJUwx#q#(XVh#C_)kTM(2v>YsC3xxlY== z9kCJ*G;)Z!i(BW#cV*#k{n?>g>>($Z4vGRh(~JIW%q|e<&0hhP0=?rMONTJeNVrS z8};o$0_DHDffqz%d5zL~vobj@-kEaU+K(MHoikt;Jw>Hm9H!9En}TvME132MxkKS2d{-B3{L1 z_${qa0N7IH;(_HpR$ffdC}5MOVF@K{1^Ih zuOQkAOJ|YD4K_>GOsjB87r8}Pv%wObtN?cOTFIsX~2QDReuC2R{Bw#AE;e? zsb1*C(#HXG)Mv4Vh3)tKxVa`7@r*jqsVeGJ3et;E&BFMdQn%*H?<)4>2X`h5%9YmY zu|Sys0#m92&K~(OW}Z`t)a_ zIhE$u!FSI-Jr6zy8{>IO#p=^p?8K=)jjk;F^c<^C*RfA0`>^^i^*Za03jD2PpPSsJ&)tEiLfzpN3l8E| zn=-g3=z6cFcfI0LSg!O=On~?%68aTJ1*LU{>{Wm06s`WVWFxvoBkK9WFrCH*#KO!; zjqW|C(xvkCzEVQ=lw}B`|L`su(;m7R&;)rq^bLm1@Vk+8LVIT$>-be!#1z*sNC}o4 znKv3BYOWJfa2PYIac?EcLe|B`PY~Voyk7Ub!?-m|FZsndZDWqFP259ICLH=w!b*>6 zNl&wcaVNhFfWa;cad_9(hS!NNZ|#lNz-bZRhN?y>C%)>A?o!3Pasoz11~Q77v6&x+ znvUu!qr7tU+idOSbl%89v3|1yQ_!r~cy_pLF^2A7Z|0}6`)#=&c6hoIfYu`=Eb2dy zK!GY0AhY@^K^-B`V})IkV+mvjlJS{mrIF|4^tOT>n9^V=H=H?6erWg8z~^KyR5-iUnCq}Es~>c z;4IzYb9&W_jVuEn{2ZWP&90BY)EGkdjLIzgOMtMw?d?osu1kOG@WaT`Cpq;=S@EaY zVwxFQ1O{usO;Qh@GiGMtRK&TnqTpXE3O?6GU4%tiW&boq0RwTq@0vZ_V|>a6B6?`Zfa*TZGJ0MB#qJf^+0 zni6a;oy8vjscY6MumgtF+-7YuQtg@w<>SA0ji0lSsf9@Sk!;t5FDX(~1O98*sL(RS zPgBU${mIl5$<*t~)WKxxP%`ydGF1pVz*@p6uYo_;VG3^y)Y$j_S$g)-}t ztJ}*L5}7f+2u(f>FPbl8QHGLY-O<;k{PGjNUg(|42m~q^-p#~2H{Wf=GvqS5Su3Li z%2i!!0SP#PsF#+knB;FZ#v^~lq;bs#zYx*5HGn<%40RsnoVYa)l`-$!g~bpcCqOs4gL$ifowOhvaN1^pG#S}_M6 z!V)Y42PD|MB-j$9jPeD#xaGwdU#OS*p;c~uYT1$UK@P?m-&GEgV2SSnoAlwDw`-r+ zaiUrm=V2gbk3P8)KW=?;6}|*zq}^o z47Rr}Z(&Lumh!Tj zggpm#Vm|;e_@+-Cnu<+}TV9oBF1)dU&A3FfjRz@B`K)n1{y;8*{>*6T4V2xWi%x-d zYHR^5veg9XnIL@+Naq#X{8qC0?SW+|C1Ch5tOyyD6V7J6wAvEDRRmP-4mtf83Zwvx zfSaF^Sr3OECwRDdpBHx*QtVzIn^JiS>PK2eq9yUndEJ8uhYv3>}GI+ z9Z>O^n;mB7uY=aV0W%EF^%MFYqrBQE%P~Ve+!N>rd=WUH#|@ODbfn>kZ2%aKdo6RA4P5gWZvqXH<%R$74<2`BQNka^sATrHDWp|L(E z%}uSssPCxo{|2qLr{QFw==q2V>Ou+DaPi$QbSYFshhK1I@%a4tRdjPgW%xedq{5J+ zjbE&Q`y_oicn#v4m*!Wt-8dWI1!Y;rcn^N8FKb#K;l>#z>sxV7ff}PR&m|pn0%taG zx`6XL#EE?()tiPB-yg$UnAmJad5aHrYnz<-W;gJ~-$ff)aG$^wht}SCYH%sfUcjRL z$9u$i84K>LG`M1o%EP6siRxl~TeNT=v`PfwuRs$Z#Q6MLV^}Rep*+8;U@KOa@a<5& zt=4dr%FORJyA5}$=@oDXvf?sQP@mp+HlP=prY;@Vs;nf(axa6Iz}cCi-9Zz{m0 z(;*;iqp;OvG7ns0V`mX=D}(2cKoxzb;dl_4Ss}++_z|CWo#u5j+$|^YuCP$vOx2rH zj-7|Oiywo9Utq)iK5P$;)C}Vk=Px#kB$Ysj>(&(@JYDjz(Osn%Hf}1Ev@d!b-vz|- zI0(vtL3E>kkYI>H&@aB$iqVWj3Pyl)*8~d6*SUDNzB$I_0@Q)2@`%ajK$t{i{{-2P zY%ZOp*fnx&;WI}v>$}kF#fRmu6JrQlfqqXckSyz_du82`vtE2Oo*$0J${APIO&Dd;RogOPy$Eqgeh> zl9r!`h8W!36pRnTULKkO;R`F7JxewYzp;_n&9zSbBT7ryzbTAVa*HB}UEKpS&e#&O z%{h04%dGr@*Ael|I`HAMLW4p71Q{N2Ctet3PcynE`DtE^C;&Z2^w>Jl8XjQQKS5?L zX^+x%f!%vrGuMMna_}m+mhQ4Ga4ni-4knI=q6;v1L67&V*O5ko&~b_R@EY2T9^c!| zk>8@qu>gb4b_k3;M8u}X+C+OnPU7Q%QvWu_SHgh2D8f+V&zUxFC)6t6q(+@O`eh7k z4(0P+{5-slrW1)G0}=7PQHaR^eN~))%R)Z=7k;q8STHdVzWrkypzw7|ZiV zYe6l(q$<7vXEn-jH@&vrV`y7&RHbVSZ62I}mzt+}N3G3=Sfll?3Sr{&qfhb~F3ek) zAT#p26r*5ZetT&yvc)yq&81lH#y8-bOD}4BZ(yzd6RMqGFZCERDt$Am=9PvVL-h)T zfvBUgh+tGyM`y@Zy;`rRHfB`m?(ldWKZx_q6N5k7qM|Yz;Me)_C;lSFo{H-DtH`Iv zvUev)D@B-2UX^4^MK;ctDXkks z$C)_)YGwWEj?ADL1!ALi46?}*p9{#NIH znn)@^qY^{yg)9UJ5G5d$SZSp;Rip?vfXWidy^_P>Lad;+)mB^ETHAhH>VmkjC~<9Z zM{%j$yw|7&wF*|v@AaNJ=Pn_jpYQLJKXT8RGs`p2HqSis%#7QMP{HNz(Ve{!i%*7F zI_t=qM*k$Gy+5}p=es4k7gOiBI1BTfEAriobF~AQ>jv6)oiTr~0ioS<=y0!hv;^~{ z)4+%4Y^I@pFtVEB?jco^1M~jkg7-sOH?(gGK>z)nF?n74^D&E>or{Ht##(+odRsRU z{i3R4;Z7}gtn0oSJ8E0}JjkT?TNMMs`yYW_@7J4cj)rf{3ICmY)HT9)^wm%<-ZN#aJXE58kCzKhu%8LL>U&d18i-Njj2)XPO~hg9Zvh9~HNvd+qe zwSn;H(UqU#FPzNWXRTb9Xz`r*|Da!)(eW5A>*4C_>Jsj8IT}{X&3@I%?W}f=PWPpz zo*5)Q^5sSM$GmLD>~e;tDsJk#HPl+s{&?s@r@GACZICna>;*^JyAASB)ZGT$m5}3n z${OOyV2nX{s<{&2u~hx&!(^VpHqXiCxMi-xP`PC`?PzWz=w3nIJhY^&LDqd<^C)Zw9 zcqkVyyHj&3x6T{o&d%o$sq@)`{us8!V}X!Umy_y-+Twm{lOe~M7U-(Wk=9LRxUlot zzlmP$pXSYzQqI+wK%H>nkJuzALdY#0w|53VM)C-fIZqR}GV8=nhC8Mi7i>ZMgmK+4e+&V6>Fio-vQLn3El3{`ci<}(`Ep|u}xUf1)d+wBm=?uipB6XEGjeV{u+Stc&>J(=mm zN&GOopU!ONDhDQ4$1C6>wdhfYq=eRcQ*Fpta&mkHRn0dwkDXh5#+01a>)iT4$u#TYbrY9UR~*n;9QP3@!C*0jSVw$s}xlZj& z=e*|b2VvufQ|kt5r>XMgd44-{)y^QNwJ@!j{OPRKxV6*bZ`e3jHSu+4Tj?(2o+5~7 zDel|cSpM?##-=&vHFe)dW9w|67GXq%lAF@JrIF!Jte42g?^ngB4Mwv5#=Rqd3E@mz zf>*VvdwK1jo;5#c1_^u{k1jH1UQhAb8AH)`vHIM~KL?k6mP5ul0k0U`dj{uHRe{n6kPTKLpf`K$T_jncsUJCWC?n}tUs3L_z8l@T+{17At34s zX;{PF$c5NN&KvhLHOcz$*DLS>cQAw6Qd4}9q82WeC!!&qL%RlmNdlmj*z>01iyZl* z8rnx35{ym)2!!UMoXJP?b8*h(W7; z(28oCo!UHMrCdJJhXC1W$#X7-of3CrgLKMzr|;VaPbP^2_RBOLy z0%BNou)c2+qs##m@luOGs)b}3i0NV#L&Y-@1J(=U-PQ_{Ny_GDz!O@W{tPA;iJPhq05|=WI16!B@pb>zkS5lf{|l*b88KFf6|93 zdBZnwJdD1A{b%=skixe!IX|%mXuwZE_*usXx5Z})AwGqjqj`(xeL(NGsMmAF(lBa? zEYK@*s(v&h*#0lE%9xp3YU2AD79Al-r@+z9oIGcqh;agqd9-No+M1Koz9HA?-*!b| z_TkU9|7~~srt>`PXNvAx4q`&T75f?YZ{IYv&y2Hd#uD($g<8SL}OftmtQWJ=tQ*W69h}=Wf*+1z69Y=#1-Y^q`l}f}!fea*;7&V)?0prxyog1_c ziCn0fker`osNUtbk=p)gq3(@1-8oQ!P}yLqJ{b9(IG)?#TP!i2Xn#VhDyJLzF=;G> z_XEZV&XooJ+P@9q@IMD5BPD?I3TS8qNam-+T{4T)@eg*s=xpDTSNWfLyDL8lE_+?f z#mB1I#d8P5YO|d>h2g?Z;k;PQH_WI0b#pGfGAAoQwsN-)LYiI^NQ1l4nUll8hJ{XJ zZrc^?ml!Nq=gf(f&AzaG0>`hV>#sC1{b6>Bh-^`qX%yMF@bnu(Ud2O_ke%pDwHLe{ zT4qnqUD1asLsnNbp49f~K<<+{h^d}=Zr$Il&to$EZ#!eFLSPI(XP}VNil=y-oxaMgjQ>(O9uuFdkt_ff;Jd`ElXKi<5%TEt>=k-YF3>?Z z+k_H=n~0ytaW2huQ9PGI`~v4v{0&9UrFd_MrpR^c^NFc&>kFN60k^(b-A2B~6}t6h z&bR`%zMR97-1-Vx~+4_JWf=@ooup`=wB-#;eOEp)>^-sKkwI} zCi&Jv!3G!w@(f5%la&(XKxXy)+!w5@m$YxlNshUh${vN06+ceV#C;Ei-`4m3`i?>s zpIm@Mh&aUJLYbUvd|EEZHsqlFmg)45y-U&l z-Fw9i!jTn!`<)bS#(-Pl#`xHimK$7bAv8^=GZ;u{cm!lD?Vg=6#Oodv4`OLp-h6@a zWE-3`#V?^{wPx1PZQtL4DAZK>$&!A~C#u~YsEwk*_WSwJzWZyz=pD-OnEX9_P1A|# zHeCfKp<$>icz{Ev^)gt*#iqSz9l$%aB9S#tOoG;bi=Dj0C_Xaoh;NtG%lN4e7(Pr{ z#%Udk{~}>}6Fmn2;dko^`VVvwu$ZaEf2Hykv7I6q-65ry&cVIp{ZlM5 zgVIsdkVNTtnMN5JGDF@q3?VGWfa#X77)3e5%IO7E)V>>2b^w*cMq|omUy+-5f_CsT z)@CIRvW(R?PmO=u66w%CGy5^sTBx8Zji97!yoh<~C*`t8S*;%^# z*|%c(3%%L2b{xoPYnTbiMO!q1b@H8 z2|{sS!Q_Nb!ci$CUsN_zLt+y)(&!N&6=z(+>ST zMEJ`~d?M_?1#jrLB=MMjvJ?Mu zJ5a4VAgMn;8!qT3cbQk z%@Xyt2Ng0t?YBlA)wfglWlus;F!})O*Y@eC;PSh8faCFt+*)?)ENhW(X#Xom*-xWz zdB^CJgglf?Sks^K)ZC#QTf@%J4wS9lFEI|j;pY}nPsU$f_lu6E7tzDSeghJ3${0O4 z@n0Hr4pRCnddg0ipMeRvbId$7e3T`j)SuZRPj|j0&!d7c$eYJwhkeZDQT8UOMvdO_4HN0{f|AlB zJ+z71wH4rPi3Q9W0)-l2tWdn^KKjHw8tjIGksp(n^Lu9zVsKQR7G2qq;k?v67+ry#-PV#;|FaJZE@tys)d&tLD;j^2ks_xFJUx%Lr@y2K?~h7&$Dh; zD=K~SoPu6a$20r{KkAq>(qwOWxMM!%A+$QTt6FYcVtn)MPqFuq|2{joi&HXZ7!HZGfF z$m&eX=Z-Jy z$#%z=>t97rHX)rB8@CqOYZSVw7b+fy>G2F0pdot)NS;YhLd(b1gtIaoUjzvZI1IFl zGsR>vRV^d;&@h`IkSMeLfx-o4=Vjp(hoAp-S=a^nED2FA55x!VFErn5C8T1 z%#bFX3!LMNQHpe3;s0^RTyztRykczs8RR=2nN*gUZeW+6>jE#=pU5?)>WUe2U#E(A zb~Cjp3^IHOWlVwid(%yh=DGi76O;zf1UR4<3NUSO-f%YS4m+ppr`2PsmNW$0CqW>0 zYNK1W{^QzjWU~i@iIgP@?;OWBm+wxQp;GrV!=H;EaUrAqHw3HH1X5{ZYD4k=+=Y69 zq*jK*wMoSi#!>nroHUK5b$*Xi@qof>>WNH~zN&dB*ETrK*&@~QR~Vv(9&JOhG+QM= zQ{t4Q?DuT#trimR$?BkkZgr9R{5SQvXZU;cd0Kao_E!ZvHj-9PRSj_Shy&WYa;q*b z3bx-(s#`q`$Qx=EIfL^tbpow*J9=6ew?erf9kK>#cfAOh-y|boLN+=l)P0S!jaw#! z?CJ*iOyGbswxOY32ho4XC%lVc%O1vT3&Rq^b?d)kwR!OidFy`7t<6(Y5}8_Yik?jT z74=R_{Eti`9$ePOcg1g-4C1Q`+LoTgd5B9OS68)`26`M%<_t}Okso29xs!7d`&;Sq z$D4{;2e$p=5y!r^{VNb2Z-V@!;J(=}#G2@A))|fgUqU@&chmaue1e7F{VR1FhrbfpU2tH7bHKMQ)kn2jIlXJ zrE;7te5ZA0tj%#uDo43;`1?r`TEhp&%}J(9tibwVd;|AA@%#&twVA$KR3{FU%`~RO z<&5+ev+2-_m3iJh*}Ybw=%|>(d!#qfe{?aw*!^Z316t3^F#P_0%+0p=@eoj%AZC_( zl?pl_`DKM0X@7J=-@WxT#XvppmR6oP?+4UzF&-k>i#+7qb{iHoH6tib8--+YTWwH+GAgk}Ib+)QJYVpM;OK7H?CM zF+p7%VenLJY#>I|OrV%%r-3Y@0V-nS3u05bFs9HZYd%i$QG^6IbtS|XICW)`uDWt9 z0s7}sPR*f)bAeYL@Llmnp46uKO#8`oOLyH4FvJ0v0vjYOVHJYM9PLgE6q8Wlp4aG3 z%2gOTfs#5q$gRL7n@yNpe`gVs&Tw{~6Yifkx_v`IReo{nTg*3d!9)&c`#`aihI3XV zky_5?PB*u>|D-%OzqtRDW^}h!e(Tx;Tsb$dc){O22nb$@8i0Vtk5=$u6<(hQzerRb zCQq*0rkqj{w~5p(0r|E5B-S{Oy;Z?Tn^IXwwHxiUr|ui>dAYRjj%!qR_R$X_id+8* zopar9bAU>?(sbf4-2*%8+Ba8JE-0RVg7bDYje*~XpUfOD5dUH(u)JfM{*XuJK1b3OXzct>eM{)v19QG-iF<_e z>c)5Sz9|!lbB*cfH)Vpvsxfi?z#IB*LGa4micXk+jIdWSeRKOeIUM9LKf#_JXYk(9ClO=#I1}T}q)4Wt+dA6RJQj60F0)|9@=QBTox5HU`Fze+}9 z`@{C!Mzv@*DDShb!>*vkdx%92xf4f%e4R#b)|;JIhEA-P(y2_$*JfwpcZTvN`e>+o zmhIg-%i;ILUYVmatZp#a$i$J4*Tr+mc?;6HPk5$ZO0KWb4Q$6fU~(rml)eHy{hUPh zE4?8Z6``cg1MutbMJpeU1ICfB@XPbn!fOc~DDKzSCoPV{3{1?Wwp9Q7%(uFpeB(?$ zo$XZ@!T`zV7$$zSG;MauIon`J5(*%=P+mZS4laNqivC}5_OK2HFx~V*q4*RcA`?x( zw_@Bd_v{iXv2@#OC5CQ0;t#>6iNZa~3F>W0PGck#m3PEXUrO#DlN);Ya2ND~yLV9w z?dV}07y&v2PSE~$vHEZ8NvC4E1Rb-8JYTnYriN(5$Gqjl0*@053?~*CddA1Yzln*E zDnm9aiS?@{5t&$i8NVFdewxYS(I$A+MqZtGVm&`@Mq8OYCY=zUba_utO4uUT*b4s% z{ru|Y+qL1M@H)Qm046rewYh|61reUFfaZ)eGSH5B-{6lqHbelP+P>kT^J_LFqN)dz z%A?{-KQ?@ue4pFv{b=*%HATCUgN?asF417? z^}pW)^q9;C8we9C_~?(-4YCM0%kJ{P$78-x)cSQ?6XWOS6RgZmZfAcE*Dz6)-A7*t z?~l>Ay=@r0@AmV)PqN?J{rywe&+*$kO`lj8X?@$Bs$YZf0PXjTpb2JOdAhj!(i zBqr~r|GVXX%_+qX2k@%H=g0iyM;)X@cNV)wB-0?$i3HK30sW5bMDw0Clq74= zz8?{&CV1lp<3}`P8$n5>&XN=zW*UK*vJ;d#N2%F+)|#8F^&fCwuih6XKX&oawDMz9 zF+!}JjJl8xM{YgAf?Gfz0rEwJ8i#4Js@KcoT0=;vygYsJ;&Fizo!PPNd-dzg@EA^zbB9Ttsc3WR{y2J zP7wV^)ZNCLV0auKlYv2pV)`)rSooYFeBMbm1JEKdjCmRCict>Qf&^oJQ45=Z%O)8_IP^g41RSv~j@+Jx1M(8WnY zzrm0_d;@*|`G&-EJon0&lgxOJK8`7NCzZHHo^ZwJRM%B^vhGxMF{sde?y<$$*>NN< zpZUW(pS)^Msl`u(k*w1Ru;025#gCm&T$Mrvc8#g3rsPSKbQ{eK`6ahdx)UE(#Dwn6JZFIdz1xT#%Z#R98pjSK{tpHGw3((2Q>e5cf{} zyADL~_Qe(hcOLG0osQe|U0?!+3_eWng2JHmp5chI}($`-F9`09Z_Z%pMEO9Q&Bwf#MvRg_mrb=*5dWtE>S zIz=6*x&rC?Cqq5p<;$w}<*1MDY{B=wqjZd6ygzmAbx|sHKhH7jvhGpsFv{=9v(oNb=obNnY`VL^?=epYG51jo4jLmeN z@H&b)yCzjtQ-$u?!0(?4aUP?F=3DvkVHU0~;CjwDlMR#lIQC(JRR|X_+zK?}Rbbfy7x}!pOfAfM__GY`rC|Bh_Y95%OPz9_V_<1FEKBcMgJ0D~ZD3}} z`4%f%sR?l@eWx#B(b|vXC0u85vE)Q%4|#6I`gB}KPB^(d@gl~D6iH$~T4tT?0W;~f zcF5l`uc-^~d?8X;Wc^?x@l|MJ{xkUhg3E6P zM{c$&4?7cj_iWs^I)#RdeS?vxzL8b?bG84Z=~`T$9A+aX3E=Mw&o>bIo0d2iE34jy zC`4{j9$497pb`se<3!X|eO^!eC3+5GR92?=a@M{_4(56a{mia+a2*CCr}Not#`c?G zu506Wdxp%k%kA=_zXqU%PCg4@A)APsGJG%1yMuOV{TpfRd6uN*Mxdpa9&=bY95PM0 zwX_%hKD+Br?;OK-dtiaSHtDOjJz6fPAzqIT4QVFX+W{ZubX(3pLVyvU|1uELYqWLv zzKPxUa7&ivv1kmt`j*%Id?#`22PW|pzEn`V{puZgPon`W3f7X7p>PFCWWc^DfW@(4BdIJ>TVRJ9rRCH13{OLT?+ zh??n+E+OU*QjV}O`BMHf;`dH4NUvz$pnF7{gSWFt6yI+xRS||H4%%pWu{pkDjY%w5 zViRqeW9rK3RWk^j+CqHL30a)SN_P6e6-70r&(c^6JL<_(R;t^A6dR>DZo$>0Uq&LL zZ0sH8oCX(Mbv6}~#NswtipY_rDAlass$2Na5vXAptPv@g25o7DIyHtgx}!plkrmxy z;SF^)2BL7kQqFx@GMwch2~;!3?sF;AjlwtE#j8|-V^;V|%()YsM@Kf7Y^HQ;zwEB; z%?8FmK{lfoYy#x8%qU#3L}%kRFn$#UqqD_*z-G}9IYDUn++-Ta{=t@DWFjd{lel$P z=ZTJDf2%t>*9~+CETL51Nb-+ZI!rP~Roeg4+?~@|Yf=wy8+kP7{RL<+wjZ-9uhQTVjOv1x==Rp*A0h0k zCvk+n(n9vc7PG?>5R24(Vo}Tl1`4!qEI}U(h<_c;ZnnR7{F5r&GbuK!eWOl0G6Iw5 z)~rUUOQ~wnBZpoz(>cFm_+;K&?^hrP=_F#>__1&wp5@TK0_GIU3g&hGGQ8p3Qe*1s#?!d69%pk*J7$QE=Tef z*rc-l*b)7ki}P!BlSk_lCf-8a6XJ;V{MeG7;O%6{?t;BS9*F+~2#kRv;K~qpM2uK6 zkpIM>m`&0B-TE3I1$pi$M6Q!YImXJKg-y=#rPb&K34KL3cS(#fNxG{d$0(DLV&MX+ zu)f>R*I5=`sN3j{%WB;^LHU<#Wx>|=0mS6lh&d8Q#!tn2OyRr~Wn|y5*umMWlfYT0 zdqs;ozNU0HgspeyHI#lKtb%`oRqr>%YgXb$D2%Uk6OigMzT>jOCzQ@>>0WO9*JVcj zgO;a6dn5lnnqSS&%AVI^E;y0Tv?n2l7w4*qU(9xAqe~kqud$+}ZJ$6+3}5TO^+ueI zBO^GdL1ws_`lFBGlTF~S<3O9`=F&R^Vev}T#u+-y55Cq~jV zjN*ttk7Lu>1y`1Fwi^j-=meYY{1z!%V+NMVdH;Onrr>IVB1D{$($~pfLI!#GP2^wY ztFRRp%mgDQk6IgGS!;xvO|cdy!2}~SARM{Nm!3*Jh1~<8f%JI!(&L>9{78UN0(@oh zF&;N98Sm_3&a!=?GA-F|m`PnLivOq9@K2HWr@7Dy`iE^zVWzvuyjZ) ze3Z`kF>s4}64g-2*}O+`8Ofc_W}_eBDQCAq&=cXD((kl%Un!pXPD=uxv3Nme)R+0H zRwro+ei^gvLKhZ=uT8h%D6zaTQn?PL2a=wVmP0&5g-Me=gjNMkix1(VD#;T)mM5;` zM`!^84TxpoV@vBiF3`>d%fQd;$*}1YJZ1YC9^}P~T`5u+jplmy0Wt=%5E)TufnimZt~(K^}vrnzx_|Kw-nS7oVzdWyRr)O%xm=5N8?7_6%Bet^-v z%-z4<*`K!n2E(s)8o@|&xNeW`f5$p{JbvVv%yoLY9cb^Z`E#VOJH6?X%|MwK9>Z36 zXx<@93|4z*>E*GJM}pRl-z(wIl?g)D-*-^!LvF#qFMR_h44|fI#T+%&?w=QP<=@Gl z6Aqc`7XHvwb-wdv^ofO+s1}s5>X_5Jj)f#7>u|cemq9`8IycsynQHi7f!}$*`+i~s z8ScTE-n+YR)O+_&=DS;+lpi&}n~6ql>Oa%Wu8SQM68B{0i8Y7Egr_L+)9MnK{56IM&g@NmT;P z8J+8#n@6-YXK^@+ZaqRdyGG>*wwn!qWVL%M=sFG(l%8GCy`7~Thmar5sm{{kUS9WI z{@D!-D&?fe3h&UJ;8oS-!R2@G02p&(vp8FFUPY|zeYZA8l?};)9QN3tE6L+d;P`;> z<)Cy>r+W@TpLf+&w&u+LVJu(A4rleBlFunFG+w&VJ-Boe2Smqz%D}`3^PJC>-^GuU z47|`BRk|zHO!#P3Fus@yCKuTnrkNVT534=G;C$*Q&#!E#5<90pq_h0iB#-MX!BBEa zYtXA2hTl3X{_e@fO~SBO@AM}*JuV>`PnZ^~fS@tBU4+Ue1n$Z8-~T#D+7|zf zsU^H#x3_X;x&8Ww^~JQndx!mcgUbfZiR$1~b+9fszJS46C=Op~Fy0`HKjz^p7?}-% z6jAnFc-f4t95*)PGfmdJ*fuwg9S%~^Q`;w7Z%97UhB_W<}HcvG?>2~V2 zCG}b1{Po|mKz%q|T?j_{Q*Ql4oA#!crj;hdATW#Gfw|v(EqN}c*~u?MUTfY4=sN(~ zkEh-9L^;n35R95p-kc&(b(<8lH^5e5M zOs+Q={?rkzP58ME^>TgPg@?FpImpp3s>e?Kb8!#w4UOR>QGH zfi8EUl*cO=6in9r4713fV?AyD&8%HdMv+XZYAj#Si11g$n$Ko$e?_eD4fhZ}6uQ#` z+_O7G+m&A_-C6p98_MPKp2YELrzhKa{9JDGai`Hlap@~=V-eT!*$e?P_~)tSGRNXp z5tG;RePLiX8s&lpDPuE0nKTKkkUR6Z-)K8WP9wx}wJ%XVTjqs^2RdL%xOl8Prrf-D z8b&6i(&ZG{kHN)uo%`t2+?eZpSh=8l{;{!nx(KF>lP!0}52EKNinmg3pTSHjI3<3h z7o+9+gh)?@9)vFypqQ7L*xU`_gH78j#gCpa4`|m#-i(#xPjl&p!^T$0lgrwnH z9%N0M$m!7_A^z`7svhjKHgIu&MZIzAX_6C2oJp1oJMXU_o0dipr_w^>($WsKX%z#1 zEr*~j+s~%`Aj>Dik6g+f$*tf9p9QVy6AjhI;j~p{3(~RJ@>LqhG0R@kXt3K$en8q%+}kIR$_s* z5^3hLpLF_yIxMA$xs*hj*b0N2sfTT1y4)tqwLaec9QLyn{MLt3f_;~7kINzC=p9Rq~Nh~O>+B^@*V~Ct6f7Z6F2n?B5%4avqTe;>#3_+Ra9CUWLn(eYbNfT>m~JBs&|vAl*Kk zBF`ah_aKP0)g%yKVscG=H_UvHqJ@P@T5#$(95xq(mq-lTNS(B2688%lA8mLk7|GmI0? za>niyXAqOai&+;6*?0&|jzjI6@|o)wdOWkp>by-}F{ATZJebXC-J07L#s{#53z8-Z zYa~ct#0T%}i;wb?e3b9=(e+6_%C~%k%lNY8`{bklJ3Z*f-fyisO2b`vund?XG74p@ z9nfyV@CD1M#vXhLnj;D_yG%yegR%x+?$MWneQWRxe14puxbecybr7sV{RpTH9_9RBw3H>j5Zy(j*+p^W0DMxBFe_0B9VBWRVv}y6T zlxE!AciN<87;r><3$sFu=WpGdcl2-UNL^1qfF+RSC-{5R;oA}6W)2VQ84wG}hA5;W zNkxHF0l&H*kXuO_xGID=7^=?&P{mr-TzcJquOH}|o29nMwH&Jl>nt5!waf@gbkw2e?{*+H7 zk%|&Yq@oN-?)FI1Zif_+N6jl{BeyDUM>Cq=_Y}`}UER+M9XoYM-G5{<_*{CZAe(^65|x9X8WWiRw=fQf22XjolA}Q%en#B?IqUJbAhD z-FK-Plquw>v7@1QHkZ_>>W=2(OWYFo9<2uAP@U$Ur%MsEIDH9zn*-<|gc|A2*AaNl zX#M6DV@?`*XfX2IU{==1n(#61jV5-WxwxV2A?s~E1sGY9Li~qc*y$w(qch0wPH4fM z8(nv>+4Vm=D^*rS)K3n{c$^=Vc7bBW&lK1Uh$D=EmB-&&Ze1p8&J|yWi)RB>jdJ3d zMiCzo3$(dwKcXv~JK7a8GpnvpuBlGFxJsc5D69i*_ag5Ls9Hr9%+3l%Y6gP>^EQIF zqxr_n(yT;lxMhq3dn}yJYgu7#=i(mKqpIfBFFr9nzUazFg=Zr%omKN1mJISf1|xs1 zV&gOs&B5pkgJ`vX+qzD2X0>`b&NgZoZ+GV?oG6-VC2>3T#ybX-+Tyz9g0x^ zww2nlo`iJuG~S%?Go6(d9uK-dv%`WIG3HgldnXac9b1E33unRDYj9m1lr^*J7Zs-* zhXNIxO4Cuch~9tBYF>Y!oKS=jtVzz9U@m)S%-+c41d7eQihq1o>!?}5l`SaRVDt#` z_=F2a0=ZdP6QN!(X8e7B(#oU`vl>ZW8%ljLPte@l1zX`x4!PB4%ZYG|3a!w5b7%Z4 z7~R=YRb8_vMd-pa0Fk?IgR8X+N^DmgRfMW8cl&Y7g>2re3)`2LWd%Eqf#F=@IZZrd zMQn}vC@sz7HnK@WyCI|K@WN1q?sh462gH9lL(K{w)t5rL2W_pv=uqB-ozoaiy<>@L z7C@~eV%(LsV%_8$+v?#*hnfYWN0QNCWYw>DvY1Lt;gjNE_JnEult|CYU`F?dvA3= z1>rN`&a9izVT;&HGU`^$vaS0_uWm1VLL+E}^BB57k!eYW4IfGSVy{()LF0+(pOU=n zR8T4G@dOhO%lGT)cQ3v-^Vq&{G?adPDep8kz(NW?67R$t&htC>pY+Z}2mQ!!O=Q}1 zSgyD3_#m+p!S9qd3LHq2Y>L275G5<14+iuL`4+y2aEyx#Dn9Q%$VAs3G{p#1B#&R` zli2(|uBaQ>`Xbl3{ad1)C=pugj4LfYq}|+An9Db#7jDJ2tBZcT^d+57^)YP&g3CMy zTr+@JKU%fVhj930obKinj#WDWUF2B3!Iqjrsm?yjEC~5!e(jf8Y0Dg&S;prZ+8OgL zmC4is{Z3Ph?A@4XOaGlv)C@S&%HPhyYwz+;pX!wtj_K#GYV}~=rvKaXUg=e(X%0E(=21e6>-KQuGrMj#<)4w-I z_@#zZ%HVOKEi{NiX?RTU)9HKmslxBm8MgFac3C-{EH>RI+*h(Mvp0rzRCqmD-3=7< zppEMMu%_HElgkU}$zJ6023y^5s7C)9!M60TD7`oSnKXFM@;9C0mH#u{067=f@;-jF4Pl>p>k^>f3w{>a8V^!` zj9i{U-mi+E-x^q@L!QwdCE=&c*0+%bh0Ya|hOvzW%v$C(9Bp`)yIK@wqXocK+x?Os z00MnmPDyanyR0U4UfCE+dA<3k<75v*f3UUaK7!jYUxb)d+TqoU28j=C zU)}NbzB}RrB=mKoL4=$02Y6V0iHzXpVj8ACcYH&7{%4Jr%Y=F5a1S3h*pkC3xra`% zO18nbe-cLXsokfw^^yX6TG@GpHqfeBY0H z?HGI=RjW_l7@Y6pb8lntt>B~=9zA=~xr0uErCMsVyxdOSK6u%0tKiGpI&1H3)!4RP z`Ot6c=zX`9_hoHe4<7f@FU3jGuS=3`T}j@)`ZZZ`w-vG^zAC@(PL8ToaD%1!4{dW_ zd|>T?V5AWHylNi1yB;79fc%3m*a_1s=hZAZ0osY_dkysAU?of+d$NH}k!|T~jPg#N zt@zgz@9eA0cB6o9q)eSD)BU9EkzmAZ9jdOW+_LyUw|bU_%0~pOHqi{R5S?vctyB3` zvw8L>YSBtwET0YINwDrzji2%|)SCs>2Ukv;3J)hIYl*3Rb^9k4@Y7jY+Y*e<;XBOV z=&Z4muV{!tggcPT?}f}kk9Th{Uz}Ilt~lwu`2*K6S?EbTi1#pfZ?*QdK6~;Sb8$`&LuHvMc;fdvhLshO!Na_UVHKESK?Aj!_;neO-&W{4x41D(l%gb>0tr*q@*PYaj-SyxA#ePUN71hpcyG%3APci)~YiESN-S&{~LC*>+xb~8) z)+w;XdCI;9w+%^5jH0j3Vm`Nxxi}Z4-BVfHu=xJ=hcrXuCg*=#WcXUX>qhR!u`lu_ z1f74-NqDz}TI_XIBP(v5#X8^@S;18+8Vww|e1p4IEwD=Ob4s8yVYnrO+{rc04i1)I z*}!b9Qrr7}hKqyxwh4FhYAQ9=)%~g@J*IM1cL*jfI)#Z68~6wB`DrhLf46M}-z zP={mywT!ycfpX6-&fer)lL^#p;3(bdcwnvko&{?o#JljP*H*G~nQa+cGuhVPCfK&>Gum3)o$PGi zZ5<|U-ln#Ckv56NWAT_tGbu6|l&_*jblTz;q1Y{7&-^$m{?J_OBRy{-l)Y*twz;z~ z;1qO)j7h!X+Hp|4qcP8!ma9W7xMS(sN69nySeL7xR&CJZp@ijD{`^5b9_TL2t9-5h4Cu?u;*U-`qj3J&&;Iqx)N^L zD{Zei4|M{X@j;g{(FF&A%Bdw>G=&v` zi<+ji7)4VGSnVGl)o2=v-eW&=PVNhQ=BiPcZG$qxUh(+19x{|!yV)DUt{tD171Rwl=N@R!uC*;{%Xd#SzX{pU4wi#9f2=U${}B%go~I zbNDH9>T|Vln1d@%aJZM2xbt(I4?769o14ciKO5ifhnH|<|0UDfmgdO29X?PC!~=Sw zLXa~$;IcJrnhpqzzQ!2lW_#}8#J8Dw^abI0K7=#pSP09$0))Ec;1xk{mg6h zD1b}sl17SZA;q22VjOS8Z8hd`CXSag7+I^PbO?InDKdLa(L`1sP2KOQ@!!2owW+3b zXnI0-sv>i}+u|S&zp3bmWK%P~w5f?+Q)gy2HAYQ+jne3tJ=)@2k7Qdz(FC?zAECYW z-L1dDMZ(~7|H|mrc821_y_BXcuosWNG~VXBjePYSua6(mYtOc{BGuAfXtmI5sU@?e zOVv_?v@GJ76{{ied_rR^u#s?8grehQeQC^(6~2n3KMrZMCE+f3CDz)a8-G_tNi&Qn zr@wEO-tZkU6Yjnv@o{CqdA`*+<`A#cq&FvKD>rN+M_ZD^E}UokJ%(~g&wiwoHxC{G zvHA-7oW5A*E%C@Y6w4-7%FdIt)C5;9uSZ?^fS!rx_Ty@C;8^TBk5p2veQ@CEKeC{l z@J}kU(k$z%oVpVSsx-D>ZHqg_xPPq9rF~vFnSF%fnV*vnUU*7+%VxK{u;fcyn&q|BoY~U%)l!Jkmgfe0?VM)Yxsonr zv~y^xoxPwe;I;G7-!ppj`A*u|hBYgm<62%WjnFt_hO`g7apn~oX8?%ascarS8#&P> zht3f{gsdt++68xWsjU}$~J`GTe1vh~x%>KdGWc#&28r_X><0`s|iRCmj* zHA9nS3}>J-x4@lK=FH{xDlVzZ6-FD&oM|P&+rM4J^}$nGQbW!AJ1}3gov}QA%UOJ()3n+TlyXH$ z?7S8(bC^$81;YP)!voNdGp*;|vnlGJ23c(U+)jn@7eWn>I* zNf?%{@BmKNW&M36*7ZJY@`Ty2R35)*i?>|)lfN<@kGPCYdvJ#CoJ$tSe#Bq@H3iP? ztHAduU`5}pu_US@Gb*N5s7Y5bM^b#>%ya-UA|+{QdlcMgBT=#V2{XJVz5fsVy*B=MnJ zGvo0aKKY`@F?FmU$gg9q>P59xIJPYdfpq2rf?{GYdWr^4Px~e{&Y8>-J@IHC#Z1P` zZEHggVPI?Jax=@6-{VUL%fuO6_D#l@yh-sEI*>-jzc8&!+(v2i!X9=PCsuh`gVBvO zKFcin(zY)0+B#QlrF75*YU@nf)&$Mn*Fji1Mp$z^e$gG4&Av_#KxTIjXNRC6qDa17=^|7=Z8R zLoirh_MjZ+*d;0Vy*i(An;2~N%_Vny-y-Oy?a9u9ujua*ASlw;ShyTa+Oe?KCqr|p zmA#CGWE1tI0jzFssn|Gwo4s&4Yw^E zmKBUNe={p<5;CAkX>AraabgNb_G6572RKpnHnB^CNpE}MGUhFY7Jo|8Vk`MPitmLM z4_{y@J~K7x5ykIgdY1Sxr7!IC#`JdBD056-uatQj)4RVb`#gONdvI*p0G@Om?tK8? z?n&n5luHfZ&AcTC@ZhSD8nmW^d%Q6nmaK3WUHe(OlH_EU%C2CP=|qoLavbX-k3;gF z2`$`vV~pbSn%66S)o|JF^DUP>i^lQn&BAs&oH%m|bh3D3t~C|F6hHfpfg<_?=5_0^YkCs3FQaEY zp1L00?aoWL6Ax61u@m>?silx#Mxo*4uV54|pXq6P6lRL2Mr%r9If50FRj*i{V)mM5 zdG|MiOT*$eH~%`O&1GqWu=opt2BY7lGhRKTeGaQ_>HfXfwHGmh-08)dMuDJd?(`8n zRxlch6=4nM-Aa06V^9rJBgIeamp^#piQyl+=a%4YzKM5as|s&iF!mE(Dz_}H*+cR# z!k){75mgs(uo>{~Ia_GPuba8G0N}iDHdeA@uY$fBpZ-*MgFS-K3O|!ErcLZ0~YM@Hm+vhN8^)Pk6FvUGm zNi3CN(i$vn4?2Uuk_SXuFThYHeo&CB0t7=MH>*}2LwybIXLRod!R~c$@xiux33$`% z-q_6U)qCBGZdiJ|l*MfxfM+4ZnOyp3rA#joanXKaqc*kFTOqH2EJh(;S;W_L^*A=2 zmA`^|d=PGvPS~GvDOOIP=aa0wv~6GWo44Nr`&M;V<*J4qok8ak>F2vzeH8EuP{ijp(w+ z83aib_Q?1LC8lN6orP(VT6qpV4`w5(o0ksVqxYx#d^vn5s$hGXU{&2+yp@`RtL9sd zHPXI$$&u8qba&+%HC(yUC=SknqkIMle+YkCMk=K7EPA9MWB^r6e?G6Oh1WbDO}~gh zMv7z?s41^UuI~aL@@-4u;TaTuUKI5-(dMQ5N4GEOk0$aE;P+tl?k^b9JjE<@tlmjN zx=z{_TzMy>Ql;1BmACNXbtXBGC2oJC7jL&h~=por+XDp8*wtJs-N<)rfJ2%KuD z+{-+nuf3_~lX=gaH>I$GE-!;QGwFP2F!rl&S-m$&iY;O=EH${OG>IiP)g4vuk#HO| zRHe{RPy{2(icCJ)E!HLQ0s6tCAw1s$xJepvSQ)SXI~tyKj-}z%RGX60Tcq?Y4FzmS zuzNjQX}j=5aP`qN?^|zX?|9PTvgS^2&h*KjH8)G7T%ak^eZ+JsC7tOyX}z-d)=9BY zUplE1P5D0)QcUYhRz2i zUQIq`G*tc0oiL+vLQ63660w-p_wwT3k~$sIX2tCAgJMZa*Jh70e|m;G?Puxq2budN zu2bo~>GaF_xCj1@q*LhhszZ|Qy{E9Tjfe5&BMq@rEH;z8NvwVaP5;oj7OP*QTnejC z3XPU&st#GYB2BjU5aYOJZLKwxtu4V=P7+0TF?xB!-d<32(^T7V=hGP|`U%w~!WvRr zTTle6_B+kT`uSg4q|a@2*Z&9!qIrdP>;(lXBX>Di=FDF^W&Nru1ijO~S$q z)SVlUgMDG1@2m%&=p3YL_{WuVbAro@2#gBeKBp+VwIwAQuP~kU81OkpB15FH>Vxs4 z{EPF-TP0gzCn~H0gvg;3fY3ilPwy7;o&{S%H?Jvy6 z61P#>tP5n$f~JF3W4^8)=2NdN)s7k8_f#sgy>=Q!la%l82Wn?@-|f7C(O}ximt-0i zEcnuP26*jE%WS9TCE9rvAEMu%VC-d#l&acU!N{L^u)6VnGVB{&zlF6RMaOlIXHe!Q zReyy_oAt;{d|m3}Yv4(KKN?dF?FC=rVKww#WLkHV_B<<=c*dCkQ`aD^XKSf+q z)2SS?OK+6RgHd>uJE1vN_!F*DMjq@0KDhuWxjB2bm75=H5T0Bz+97o1A^F!l&Z@kE z(3U1OP+#JX&8d7cxNHGxVpK3Phac)J6O-Z3(3)YOay$VoM<_Q=-A09~7zc$3Rax^> z)4R0_Xa7_#j1x-G;CSP*g3&@Ad&ZX}$}~>*HqZ}ZhG2N&0hWd=PXx&45p6HH{Gid| z@=0r4XuOd)b-w^Ew=k-~6MKkmVVXRhC@p0~_j+>gn?bJf+M2&5gF%+6t#iG$^+Fotk5A)+~>2U!ewDx0~x@6F+&(kOm~KIv8DJRQa<>=AOrp_XxOMgE$-4TMBNUR8jm*uF#tne( zdHQ*KRByQYj-ZP+_H@@~6P&k`ADi%Y^6B;D)APxvCz4N(B%kg{KK(xVbaV3Qy5v)g zC-%>dFJk{}6T!(uvbfbb^<0@6%YU}*ioC4w5O-c~EIj}7Snf{u(j1QN2~2b@&4~p< zx=}!JVs+En77{1cKb%VxR!&dMsGR;zKOLGgI?s)oHM&l@!^b)1M*+TrG~%{pkq8?` zdKgC>lQHoTk1qH1R*a41-s!eB$8uKzfJ2blygcX9GIw6Sb7{GIAU+-`0(X4C!C7m< z1EmyR+DhqVezlMD=2iQUK42QquK@9m&5Ayloa>MF!Jk!iF0}CRYlc1T(OqMJT`>{8Hx_4twPxy4^uNB!JI&a`{G|HP3 zdS1b_7UIbK=QUQ0SCE&rxdjKK3UGb3-bt}0m;mAu7s<`Yxr&bLn~ZfDp^{`A!JCKg zZ|K7*=471m_@d>s^fAYf#pCaB(Y!EgeCt{U@f99d3qK@fr;CE!NjYe*Db3m3#SuT| zD&2C7a$|wF^`E-lSlRXh&%H0E!*eTd9y~Yd!~YN79;6V+6mt^mI21GDKHMz zhp5cc(&$#x4aLirMqe<`kDBLgde*4G5$m#d;T-o*EA=o@cO#U!gW-V?(X)d{GW*+f z~Ap7URG@~Go!AS5xQ)PwmaYwRw>#56euTk5h9rNS1D?~SB#v$|Q zjw#4)m)YFY{#UiF*MIP^qAstaUCZ;F|0%P3VQ%FEf_v`aRgF1w^A!qvjruqD0IiZ& zEzBeA*W}NpPod!LbvYc8&MI1qC&9^J;HPqv!N7@sGn8bYAXK7Z(L=-30K%Z7rx&_s zA^;(`E(dMeM%RN6PtCk3B05L_My$2vlXUhU@a(%F+i+_gvGx14>=> z4kJbfIUFy1A(6VQYVF33mBn&7%k89^+du8MWN6|~NMJqM+q4zAH)#Fn=KHRG!PRT{ z%vUw<1d7dKa;%BFA-2UIDVEq>w%Ka-K@Zc@@i{0K8FeC`7nz{$$Ct9!Aw!{*k#sK{ z|0ttIN&@fY&Expr>%%@2>GXW(+vO?Exk%ZQnsaulo(uFLogFi1VOTO`=+Kl-hq^(A zmF&Sc!H4SxLyML4j>lXcErli?1QS>awTovw3gHopEn1fE9#(oy8il@9`al|mF0-Tz zRb2svHgU+}ryXkym85hZ5%OUX_T=O+ffn(yV~yEq^gAl?Anb-N6d-AY4X(b0bf~oU zB}q^Cb&qI+kGHx~=S0-Ec6oH~sLSn%Sjer+Af2(AEA!pFYzw&+oh&OksMU~jUJGiq ziIX+V=w-PUd^`>qRNBE0Z%^}+I8d|4bi8M(feNmb<~(J0qN4knK&ud5Mq$;FiSQt) zoi;Uv`>6+kjy-T6Yg*3nQl)Mh-VZLlCW&{>+4Q6$GIGDHth=&3q-P?xDDe#Pqq$Tc z_`Qoy;P+H+)=b0icZ^U3JK}uZJAPv|K({yCR#@DIeB3Sq&30Wb6S2Gr8Q^5A(0mJ1 zK}65^7Z_0ko{xcZxQ@PfuR=HJFVH4A?2Y2h6S~v%7>~cXl<$3ynE4q+2c(Mr7oTU} zhQ{LN>`&2lW$xu=4m&mG>d^lRYi)$!CM*s{>g+G1jm@@zrc7mrm?&nF(qs;xiF}enMl|myZ_0pi zJ{ih$>~3ph%qngHk29SQyN7U_RRzll8Z4~U!69xlII)2{lXe47OMLuFiBw=*13YW_$M-!7OXPp$OjH^jy?)Y4X z9jUR1)WlD6`9Iz!MU$=j+4XZ0_%AI++|fnt1ad7|Y|{r`y*3 z`Q4+fV*O?+R#X#$_n%_AcL3!(>B9Yg`RZM`hk_||{FXNlm>YQXM)zaY)`Xc%9Fki- zejFgFww^05BQ0e-vN4s-oFk_NBW-*cc`o~b`R&gwACyWweNVDuefTWwrk{?ZY{#A$ zN_9z(S!9ShR{ki<8xKz%%z64{j9!U*KLu!w_fP%pi_CqxKP7=pK#~727}&kKuhBLt zOsr|08uy$C+ZZQdzD&Saa$!f8Md~0RjV7p%UQs%9(QZh&V3Y;)0_sV5;U75xuv05J z%LedjqXrTe;;l7)I5`lG1p&PlG?2>VO6L}&NbUP&&#-0F;jabX9{dKG|6BNfh2;w* z9aA&lAHkakKd}{NCD8+a`5PdKv8gVnv|R>psU5n{DG1)a)fyb7X4nqiKBl0wm&x01 z^hxGiwl&Y^x9|YRWMIic#N2g?cU>` zUR6V#7QXPG$R0E4?AZ7LejA(KO!^}tRKoeVr{~V>#2X)x5w&eLKj)78R`9CXmT%2gMdKHd-1^o(`oo1H#aqzU`Q z(zo_e^K2%4zEda>q*~*PZb>k*=3w_HR0D*fl?kg{_h5Bcdll&>MJZ;rWkd1d>4CM z#i;N9oyzxQ)JK&3RU;k{9@%C3OPmGE;y+!r4v<(6P29mRnk=2s_YCVu2kd+gus_I_ zwt%Jc{%j>DdHe*xv^>7>j`Z|XSQoYFGf3z3!uGgf^TO`3avHc@PiG-%Tex zi_ki$%D&7=CBLVyql1xac=K$64j%WI!{KI%)m*i=c}7j~LVOn@JCh4(c^JEmA9^Z0 zC#F0|TgG?xrC<%r0PC|&Nw9YE7<_o*V6JVf2u7>Wj)^m+KA#;rp+0eUH@egA#k2R( zKJ`a(-@AeHKAt`m|E&z@(Zy`3%ibjOVzGQBWf~+(H)7Avge!Fn;;QM#ApCSSxN0*a zWo%+k>;|hum;#B*U`|t&tdduT)A;73Z4f=b)Oc+>9F4e3PwLMa-0=z@Y|ZH|?wrU~ zB1h{OKRCMsJ!B40JOLP6|5^EAFgk@YKDp(!lx43y(nlR)jNs@DG3pOwZG6R!%u=X@ z>By&mweOD9edy}9u>CnH*`K;Jy6m{Z>(A=n`~7){B7OBIdXVkUIqJ_}uz@XIwA{{;6()1Y z_!MKG!B55k!SLHXjpa^xmdh;yw-xImIGd%{9J6=pDLiXRsLqUQ_))3Fw&KPF-Nm4&HxPna6&Q}pfylkk&4 z^_mV&ysP$2;RE%d0r#O~&ti}!Y2oC}f`CdjHfmmHO4Cbkt zs|IFD%@3$ZQnMZ!SgF}rWVFBm-N#?pnJzc$7J8jM=T;*(Zv>-J3iZ{g34^WNoGH1v z4y*8gs|N-rJNh-6h)vv=9%wi^vqvXVLOqI8hwafC#1jRLUQ6#!e1X@W<-hgyz&#Y{ zt3QherRjk#Mmo)w5jHDw{;0C$Fkcy8LOoxdIz1`s$@*^=GwlDgEqiek$Cz;@Ru=xLh0T_CuM8`nu*ceoVe`;^4oE~*Oa%9 z>|Iy{#^{;IN?6DR(&$?Bw7w?)ft&#L5>Ccp?R6K&F}Musm$tBXqY#uwz*c zgp&VoOFG$`7fGWi`bHEP4H5>AL$F(p>js+OFk@i(qLU{ zPaYsNwXS!*NNjw^&L?%z_1F=z1L-|jj(i(gVm}a7!R=YGm6q%A_R>}hcOpOUa+`{o zasgG~dMgVvv&mmwd4BPNx6IYYEj|u+fWsX|->?2IUIFH%+ayF`s+eVLofbH+0uC(i zK2@_YOB4I}dL!yL_IZ2uKMHh*erAu!AG!%Gr$-UXK{0QN}UZ-NG&I7SE;QkmmHAhsYIG}5*q5-oHM`nV!XV{L zucbr%mU>Okt)$JcE!~y4+RjtemNtfk@P3(2`~%+Y)d|ABjh#EA^|ii$A7rcCKwmfdG98fmv8f*6Tudd+}q8Cb|3V8?3jg2siue!5@H zr^o+)?7azi6xG_OTdS%P(xFM35FkLH8we0IAjlv?fB*p^pfbuVV;D37LZYCkU=pEi z0#R{BK?THVi;9Sd3WDIcMVwGj5!u>paEpqFqUO9`4V`9i@BRPJf9`Y6y| z2sb!sKY_bbgn4P9OEaw^Txz{?da1l}O2&CLv?Rj)IgaA&zh$hO`EE`G_eUcj*H-3N z+L=!Xjx>W-oFbK&DDAgcxA2CsEzO^pV?>(QMa3Y& z*h^EN5^4EQ4DRDrk!mDfW%~6oj&bLRq_XRumnBu7=~Ygjpm{y4?Eb zN%o^?7euVKO3*@{HtP#@tY1{;M{qiKG3Xsr@4ABiyJarPoQYk{<$DzLkB%s`l`A zF3>`C|6TTulfCua|L3rxs#AVwyt0Y!+?@R*$8O!@h~9pBcFet2+dZ|`-KrRp$+xwc z$ijUlkpa7&yYxCQxpc>Sn0o~jjW&A7LrckIw5>P5^lu^^xsQkEVj}In=gdey;EJFs z(p_S5D>AYf(`n6&>^iMca@~MWO2sDNmuC`A%k^9$IeR`iOLLUjRdJ4#m&U#?`Oa;f zr0A)8&y1w?nK^Ou(La+Ym>MPMBedPq)BkB*Y?1zPis@rarx#Fqr_+$Fw?tSW@|B{> zI!=04I=8)eW;!8>xmSWb!Ya4ehOuy!2`Y;#dKpr0s!a#9A3}}%`nT9D4LK!CxtPu_ zt|6IprIE!u+E526OyJM(NK9;|4nB8grjD=utJq@2*8MCYw-S<8e)^;QZ(MG5A8taQ z_r5j0J8ge~byIEeANGx%lQL>KLL8JCsgN3Vk{YKp zlKwl+EUbqtSM^3aM?e2==jiiOb2O6#ozt5+|BP89(ug`attq%!h<4J1Dv4X2^yFFk zQ;A$EMmy=%nEqX?{VyX#OfS{X()C*t&#A5A)Q;GQkJ-k?vGwgU#q;gM|2mF~KRY#! z_FK-3V;yl+jSqL9V!GuN(*jJVmHgB!Um;KS#uWSJH_lA%0*Ug>KDDol-KVP8s_Ij@ zEVN=IRCP+yVRm4hwrD>9@hY>!Uq5CdeRe}5`wrXc6(nzGQJz76l!bAmMCO+02ze(~ zr* zWv{8d%aHYjF#kW@qf|ut`~EtMH|YV6*Sz2V2l-gZ$J^U#KUezhJ zPY+Lj38Ou+TW|Gqb$jNK7ZLe#W!@=ku+dfyB@THZvvf6GGA5dV63yI<$bDElQ@3QN z?cT^&GWeER;ds}zbmj}O;euC*vD7-ZywCKQIlrn;9^%5qSshe-&X=2=J8_)|cxplc z$e2dr3UxSmKf6dpKB*#8y=?f>&Cuj=UmYW0JS%Pj4N6TScJgo$sBL(N63J664--G#dw5yxA^O za0&JHIcvhml|;~X8;z+w#}>VT6HRRZO>H%Lnp&1sx13EVPSM!DkH%KVPA8g!Cs_mA z>HJdGa96EdUzkdKv(ZFwUWnu?@g}_`_R5^`fQDr-=!Rc)MWDQZpG^WXV1^$sO z33-I2o|DF7vW;YiisaMLW73FxDASRhevEZhXZVndsThaITKwArczF4#E+JfEeO?#! zIUk?y{jKEEtgsuyMC^Ij&b}F!TzWH=V@I8bgRSc>L2Ehd?#TBvX^w%bkPDVlc8<#i zOlR*gtIU2Zx9kb4J5*G2Is?rnl{%^{i+&W&dV-B@IeBHq45nr{3$a{lA@+EEYfvw_ zmx$f{-Q<#MF(EtYXB_ylwvta!*aLoq`vbA%J)>IgTX~9mWWSLd(RUxLla%zgdGF#YU{H5$v zmoK6&pPlCN8ZKP5?ZO)66%_WJhDCZEJ~e^|@D@|qXB7T{``n}#oR+{8Ldse%dQ`b1 zPxge$CRno@Z!5a-4dPvsk7%*>17d$at?kx3H4_mJX1l!APD}KAd-5VtYZrzkyIqMS zns(MiujbZ?o#;$-cBIcNJ*CW%dx;bo-FKRGG1f7niOfCCJQ=ec;Y30b!Dw38m?VjZ$;;NqYusoFEY-Ai=u(q=IDLu<-b(hfAV?~*{ z`c!ioW?M9M$bYQQKUZ0z{Q=p)0IRlLI@;lX0~ z4tR0K^Hs09vD6|gt;vf*JGbtp$=Z`w}6;T?Lir~dX9){}6 z#pN&iBH!(CBYipOW^E%nS;p{y-?G)rII>owVE5p3&V~ zj{fr3XVz(jm`>=O5l*T;3zLS3ijtX>deS(TWN;T?b!#MsG3QE?MC-s+FOn! zZx8`SCVput%jh(ip4v~2nOs88-c6oZYL=$cRJM5C0+^&~9Z_3y0Fk~R_QBn4xBc`O zfwH7T>BZZ>(w(D@KTg7PUpa5E zksH2>F&v3-%F|E*RB(x=*d!zA`i_UVrIjUO_)y;|en;z9&7S#=l`s*LH%ZchbMs-ddI_w_>+EN29v0qq+m4v*flHoh&$my)z?|-*dxkjrx2>bXMusi_R+h15wu% zQQa+3-9ph>A+Ce~M)PPi@G5l9u}OB0 zmx+_rrb?o^Yoof^=;&87q88($y5UjX0MS`l>lwAXAgXH>b!{58tA|dq8?=V{Nc*j{ z+8;x*QC0D`Kb<1|yvQwF1v;*2hmW{)Xz`H+>>srWe#C}VZbpXnDIoh|Xbu6nI?7o1 zf_z3#liJA`_7efiTU;(YmAK05cy>8po()Pl;v5DQyzrp zOJNOfI>bN$?g7#YYuq6+qRfZ;_yLJ_*f9Cwwce^fN;J2DN?T^s{OX;(6y^2IjL@QEf0ZV=Ozql#!klm0ZnKWOB8ePU1the4@!L+> zpY~#Ik1Yb+z3`x8yL;hbN4IOC^%1V!3uT^@-_+d;<#UrXgmS64(!E7BiZ{!JKMx9Y zk=b6F!r)XEc9ti3u1MPN``6Qyb2GB7hrZ?Gp2;O0_|Ho&DPrx$4e$P1a;a`>FT^no z#}{aB@*YJR+iLB9S}R!$4Vuz<(DdYzU+tFIN!BsnFy>j3xN1u0&y!2K5s7`C_+5|F z^hw<66ZYq^vWSifPM2`2CH8`hPP8{3t3k%O839o%TC)e!Cp9=cffqBke`(0UBD;TD zQ;BmiUek(SOCz}e4LYl9|Ma9FY}lWB|`6f)$pzmFCiZt_M^*Wuo)H*G&;5Lx)C zhW3?HF$v%l9PSPFNv*iglFj#z{VCI9wj_>4cJa;y)~7RNze;5H6z)=MAsXqd>7m7z z+$q3aA_VENH%V>f1#c1uL@DyCVE9|O#p?3OCAT4x;N^M2(E}szV{gZs70R*1@EeZA z-igCC8m8{xQNe5&j}44MB1JBC`6~uU6M=h7uR`a z=WEU6(p%B@EPgdjPSgIR=nG;!O)OG!Rg_{i(HE@b=qk&l(NcH8Ia7j{Ti@6Vhu1sh z%9IBcdRdk8BHp-H?oS*N41xvg&78Mta{+?{q4u^R7AHSPhXg!>pom_Dmr~ zU2|&1O(Bi4!i*`djOkWVYouazq1|#o9fMuZk)lwP+|VT>L)Qf4V5#OJe`#&KI8po+ z%e{bS=+7(Xi+-j1=d}ve>wNNt7QKSQhb`m?hUAi4i8DBSWbg|FQ@q{Fp~*LYC1Oh} z-9P{BUKJ5}&O9SHDla%=V5Hk`vVS-%V{F&*)zrs=+Hw=-nUgf(%`%u1+gc1UePoza zUa+4WxIZX3LXO|J+Q=&WTH;PFX+;j5HrE7gWEyF69?ln$D=~4cc%c@V@hjP}+I*y; zKteE3sMeBPq9MB5jw)CQyKg`@{>eq$39I&XK5?m z#iarl`k*y!2ZB4wa=bKHIpxC|hRWpd+E(_g0R-*Wghsm&4M}xf!cNGs4Ki2UvW#lrvjJrEQCtve7B7e#3MKkEf zl@+N{hhpxAIn-?rqe*48;ECd$0mic(l~&fGnfeFOh6c>G)8zg^ICl~;?=Gz@e2n}A zizO>g4wFmv;h8KZmwbuF$&)Lc!gwT8lv{4cnVv%T0&{B94v}>=x)rq?;lNH7;-T3K*aZANqF@S@y zeBn|%osH$8>xR8dT$PdCRJ)9|At_2|=xp&d-trZxgL~V`NDq{9yEw`&P9zH}OY)K0 z=p1=|M=ou53e<+HP{J}^R+bkZk*OyT-awP;8YcoTG>dnp?+E$&2Yo#0RQPn{YAKHZMR8~at`g0);%Px?Y4?9D2tn3&R>K}eefVdI};a zJ+#Dxu*uRo=y;yjJ#IMjP~=iY_ME3BSSaX{L*cp8PLPzOuA@l~Fs zzHRr;;%;S+I$Ll*b#}bsF{>X@V`k(>s*mqIA4zwu0^u*P>KZ387FHAKOI%Jpo~=F( z;BI~C%#5sc+Co)axBqoqXRD(Fr`6G-BU`1-K9R8p#cD&rl8n{pQP!ZanXw*4e%L&L zw#-%-$pUD_5p6nJ@h;;VS}OwX<)B?@+xn#XS2kH!fSU031vDMLvTHk8&*q3$n$i+` z!BBFTVT&@`QH5`tMLq2(KEZq{6Xg~<%#FB7is7rpZI|U%DJvX1d*R(!OH-2XWs|16 z@Jo}DV73?exfwjUY~|X^ieZIS8fGMRYsn>zR^Dvj2CY?wZ_9XnI^4-??|0=AtymzG z732aj-HjqYXF*(9Tcdu7$6BC#hXdQUW%yC`_7)$~<@M@p^11!wQt- zrCa#7M`JsQuzdf|T2&7v?c|bsaS!zgP{z`C(K@l?@D9$DMPerJPl#eyL-?(+A}Z-| zKKw}eLe8vK`*-Qhb@~VEQ2dg)xQgt)wc}kXB}*=;A@Q@p`UO>CT?0x+V!V~h+*R_tBqOb&TtrF63&+?c zF3BMg-dF#nB89#Y%w6RT{?xfBkbJYuHDz-Z#lIUJkz1S3PWg$-Is_*#e0+j5j-p+m zYI(tGB9G_rO?U1T(({74SiCL~NrgZ4ptWW{TPBHCB+%8CNAe0=5|LKYNB=Sh);VC5 zHZOb?nXqc3bPgdZ7M9D?lx(nbL!EILFYP1OSTZ6ms}`49$wgXA{JhbTZKc!C3}*9% z*tAGDOYT+j{fQNNgwcq+^pZQL;^!R8kBrTWj!2{CRFVxSwB99Bhy2_jKGbLScAwsCJ4v73DB9RQJw>|bN-HVZdHzG%lbuAkUV+_Pd*bCk z>8<#&FPEud%5~u9S8miu_LPt5(mrhaAwC zio^%6p4)A{kb-BDW)?=yNkEq&!9%UAZi9(7Ao58rt3z!)GB=PuGhRNyt5NXzUfzRZ@69MR%HIfOLj&J)C%9Fp)ztHpnNWxlhGJP&ruID`V08RWg^w=LO@X6YVE{ zt0pdgKxW0@(M3C@)w$QaPP3Exvlr20GYZL$ER5t5Ad}Eqq?{HkaoXaks+kD(!S}e? z;RxpY5h9q#A*@eJsl1X3qTR`e;EKMmUDuWNI9u{2)(m3vq(&lbtp38KJ#UUlxvYK| zh;WI^nCAFWkwlD=r@of(=~vt>#hqhLG7HnJvkmP!jYj(kt0*_?MR{Bg6;@@uqm^-~ z(Vax=)~G!o+qGJlEranoNmMGPA)Pw1LHvGV&5+XK!$&Wb;#X{@8nV6kd7HpOuTgsl=Au#dKO-n)DV_Yk|Ofm1M{#GXuWm zlENBwcpgP+-d!1dO10#L8!-^E5-kt|vN~;5ki2PFMh`?J*5P*CFrlwhm&Is&+x--inL;Ee;+#>`(kEA>aA*gmvN6N@Gspp%e~@ru3I{+q{=#TSGIHn z%_cM_p=@Sl@gJO+mM6ykUXEatep&n{b1rG}e5O3)CE_mrQ%^2gV);tNmn^u7|KzlX zBFicbE0J&UpK-~hlf-IBI?uw0a3e!8N*`hLKzs?bc@dv=1t4N{q-=i8v=Ny__c)7R z$4_*iKPG;ApWQE&Cbbsz8`lZHb#1@0Yo5WNxvg;GmK5wax8^T=%dJRP))WJ+J|`1Z z7GiQ1L4{46A+@Mxv;(Ev!$ErS&Wtga?Le;XeC;|^yj9L+&_TOzd3ix0_*(FNT61=p zy|fIz9?m{sKSVZ*L6`P(5K-Zwlhu(k2@!r|3iZF+YQZKCnz^kzOWZ=@X1DwWlvKV) zv;sf8Bie~?s-Tm{6Pt()J3`6JHFOJKDi_fd)d(JKd7^Wl!sO+3u%%xFh>#^vbp~P4 z(pYX}m|&^pEWo?6t6ynYx0$R>6#n|lt@k|n8=#PNKq97lSiMH{*jc@X*xL}L^c<|L zDwhjDI+#fhkOmVp&37xaU9Veb+k)LGLE55zM~}LXH=Q|E8+;ZF=I8ckePv$Q@)a5mHrJZaXR7oHsYt4isue*XfQRi08BZd7Dry^+Y-LjUOu{m3DI_PgZoM;I>SJ_r z8kIB>dBeBuUUn`^j-eBq_fdmCSXbTI;oC29Yc?eL-fGn=TM#G0PjmSlty_aG!y4;y z_K|CZjJ%+MAWIHPL?^W$f^-u$n$avs&6)oRVlI@f%foN-pGC345}T zVaZy65id8&B40S;=?J-wpvy+DJ&xnRy!4*+`fGN0IdzG5YyZg+FBd!_*$7v8vJ{j1 zm)YTI;%`^vXRbbipSn%#mfOhBw&Y-cd`9|_`*K?O04=$sGZya2$Ya^k`GF2#O_^_1G$Ws&*F9p9re=|!nTCRRzWzlivDM;@^3VhfQag>WwXN0TVN$A)qO zIl<_qtbA~`{g5mGARnh`sV%hJ~!@RwIevn`L&> zB3JFhJIfInno!OD!J5)<-;%-&HiO<%8qRarmOG7GPcDroKI_RT7B??*q_PYQ%WBch zE4fQ^>eQlSYSALAWxGDl4EZ87W8@ue|0VxC!9u}V(>)X9n!;NDM4L2nYkOQqd6Lv3 zwXJ&%%!H9&Bp5Pfo@96qevZ+Q88Y|*I-a}#*l}lisZ?&am1vQC@=>+j@hf?) zx=1@ACTGcIk5w;TC|xGfl>9h@dL&2kX736Wd29iT&|^AC>0U?6G+s+a?);+Bq@gPMk#jhc!o=T2A)wGW)FoC}zLXb;n|mkq)x!KzK1 z!hX_F!k3Sh3z&IbBqSD+f)`a%NRWau07;9I5s&toZHbRV8p4N;u|n86mbJ6ob`bS{ zx(rAE<1(ycC*@z2LB^1?m7&r9_A+?697c)>x&O8v4vqZRWsvT3wla+7A?yFW^^o}= zm!Z+WDFa0~YZ>nR@$@p-_nfkMu3-?v_AqzSxsat768%{yz(Y{2IO~yUbc&SXaTT4s{y;$so^1YRP~f6MANJ-Ni%yI{$ky&*Kb4WrO6Im2*F zD|$3|f^}kA_-a-dthDJ@Y4-hhCe^}W$;;$guk)+PH!VRe8^%hzPy4deJ-lwomEPb} zm(@ipqD$(EAlI_)c${Wmf;Mtl+ki~Xn3IItD!#L@ZwzLvpdoVS8?la z;+A4N71&M&PSH8LXcDsrgK}kf(oHN*hh=2a9y7v?Uqb-)61gygSMX)?pxm`+%Ak}H z?v58W^kj=d<|lWE#d8O&qUMUd(fLUug^HC^%bj+xJ8oXux`I7J*A(oITZ(SMV9{+v zmxFkA$8AQJQID<`_c}VCW%q%&T6X(HS6^HYpxb8Y(i#xoMG{LEx~%GJ(RD(%6L!Z9 zoa&@t&v;X!sA$wux)XI){T#a#9>>=16sS|0;|^-AWZ2gzMq*1 zP@~&Ej=iZhw$dDAUFmEkO_|r%6Py{NvUWhGM>&ivb>sOe)a@8s5|tlY8#qne8D<0_ zW#_y06LRCqz1aHE&JkA#+UWttoi)I-P7%mXW$i*|RxXUDGVQE^W?RL~aEi&-indMV z`&p@_O%AOs==|v%qinRw>Gl<|W$8DCxWX*F9t*=6 z$F8#EXtlSnK1`Na|}WR_|t*2)b@(~Tiy-h{YA-9&_yAG@~@O6N=0b~laXkpStj zk;&Kwvkx;145XE{R}(sDSaI^9p^&+VB9!vrguGfK#~WllD3T&K9`_!1CPQQb zW$oMf^TH=WxzADP!k-++qHn8)rI_al-ih}22%WsD_eXl1V$#IqBx~pFVJGpW+!PQ= zi=0y(IgcTeeHZzckK8XX-QF1ZW$C1nTu3WyZlFR<`^77%qe-s}{ zV?ZuGVHBDS?{z}Mebyd=EZX`ckZ^cCTMyO--W#uaCYq?Y1{|NZzB_LND91zOo{3sNq1GQt=Ks`^(yD=OjrPJgkTq49vdl z+OCl86gCs3h&ZvD4hOLcFXfN8tVgW|^3=&k+@PvnmVb=d{tbD)f_M_-8Gy1ruRGy_ z7wrto%P+-8yu7`5(N6ZcaS!!5P<$e%u(0@qSvad~_+dn99LWhQLD=Z-b4qcMgK@6cjheax(J~0u5l^xX0B>M^kcTKWBk+Msk zDSNtGp>Cor ztt_e@>abCC#|yiaFFGlfb2q)LX=@6~u0Kd$Q%6HSqgHVE!53sK4gMBhP1?mf5^S$? zK64W-57pQ#(Y#Sq>&2~T%0t|REczQU&?FyWWn?{rrjw`Q9bP+da&dp8vRTqHdYhr@ zp{GU5qq2(*$!(b8-+YCAi+>9g&M*Egp)hTCpTk&MXCNVl5|RkN!6g&pZKq#$FT|xV zW6`^^d)@NgMLY^e{@Y&=EIM3~MV%)N%rX*5y zuDy9P{BU>+QCFmgd@bKx^sVLj$Kde8mI!DH;gz^j3`@A2ZL_!&$wsb6Fr-B$$i=Cd zctMum5^%Ca`J$}mXE5GQ4zE{l&OJb17t6R(Vc^@*o)k7X`nyR)|CkRy_eSZx^p zR{w1{Vb9uv;**tyP1xh}verz!Uu*^x9VhyPch(k!_x5IoLHh6x?k?%f^*Y1+_G79k2wKv#XBx}VfGy0$hB~L-tdkfP-dgpyb)hl|HhY~t} z!Xf9c+H30{+$1i-`w%zZp}d4(e`_R`d-blDbHq!S@*Xj+*YMS&o|OsF{{(wcoUGhn_s0V`lhL))a(4%lWgC)1zt^2CdHum?J|TvMVM4txc>?Nlm5T? zpYlKBf7ZXzzsdi+f2;ph{|^67|1SS-|J(k({`dVK`9Jm_@_*$&?El*TjsHjgPyS>6 z-JWI;o#DPMRmdoOxL-Q7!n)el5tFg$`YH$ZA=_XT4TBx*S9ydvz3O^~$#~TyAazm>* zO=&eN4J{?8w3IbUt5s-dwT2p6>g_ODX|=C0wAxoIt>8LrW`D zTD|RtR?lN-^*@BEhSp#|jL^085<^S>r_vhEGqi@I4Xsg}(i(Bcq|vjw<}Zg^;R{_0 zd<<7AEwB%@lc6=P4Rzp7Lu*n1cfgfknp#utA~$^=-ZHd|1*Vp9J)|hD*(18vY^$a< zZ(%5{0lcp%wFU0gm3|N04Xbr!+y@Wo%Df*Y>MCvmd}XNk1el>zwdcU6tAu2@Qz_3% zr4sLh`(cx&s<+jZ_fbvNh&NTzbDB!t2+d68Yig*PFB&T4GhNksTvMr!!Ba}r{!CMK z(sWg~j;_*%8>(JiQ`K)|ss=aeDt*7M8h&7?M$Jv-ze87n7N%-k(@;$`T{Uf?tBk4e zu~N-GQ>ys^=%ZAN9;V9d42eo*<{GNyMnj$BG1a-Pb(N)*YE|7-t%JHcuZE%82yRPHfD_4x^wDb@FKrTT4xnXpk; zd7TY);R~AT|CO!=9ELx2HPA5Bz(q=3G|W&J_k_2Vy5ueRNmGNq)zsiWl^SwVS3`9} z4ShkWVZZ8XcqJS+)TKw^S51vL0lye(!&s%}41sG* zHTP;5qg3IAFyB-~^GtR1HeFqlXR3MkDmDLZ*rTay6Ag9U8eJ_|1%|1vpRLplgLQSo zwT8O!6+ z(N*XiT`g?}Ep=5k9lGdhStngB?+kC~s{B?%-MRwG;bNt38w3w%>h}BL8BML&00T^Q z$7mRAsyhpmy34PtyDn1d?g8+Lq3+oS&uZ%4r=hW~?rQ{x4YhKsuI_(PR}YkHYSkJ| ztzN6C2NxLXq3hrST|Jzv)SCW=TAQG&b=jtRWPqX8KdIECe>c=)qYU-<9ZEfMv96xH z(NKT;NLNq&sH+V>=<4Yux_V}yp`LwRQya(V>bcRn+H{ejo`2R*o1cN>ntI`CU2XZ? zP%m~&WO!Ip zyB~rSQ@vgjN|kzpr&QlKq^mc-guiL(tta7AUA_GYyr|SWTcFfXe}6}*cmEE1mD=+j z{GqG&l%d{xU8%htP4#{UxJy$X+zI29`fw;*rqoBnV7yWv4~I*X+BX=yrut-{sXiS8 zzZq)(?{Lyk2mXLwrmii9SxQ$on^caj>uVud*Ns|mr_#*_V3VfDZHBhG9^VEY)%0rX zA>Pyz;-HzSdotiDr6>LkKGXE-2Ov$?z4f4uuGgpw!wo%Y1k^S4b{0>qpsIn z3j1|ECC<=OJ}~rJ??ZD_PrXCeYu^biOubGf)HL+Esi5h4TBXv{n(2DI4ER{-^*@3> zN^g)09;K((fLudw*c&z)dZXtcsO$a^)G+jb7qWG|aaUNR>rLjtcbeYx2sG98j4UWL z^=3uT-_V=q>w5D9U2jnho>Y3~HW;SsEf<=4%exJ|rN`9IX$q}%{oGcdl%AzQbyIJZ z2%B}i_4ANq>gUylExO+31;{q_wq4=xhJOCLFv`%|jf53SZ@(B$XnKcVpi&0mIb0>M+32vkOc;dx@@hTMU2K^zQG#ElTfk zrK$J0(a>{lfNKrC=X_{t=)E%Fh@tncfM;|)_i4y8^gb6to~ie}5MD9#elJ6*uIF6? zYYhFuC*cEK@Bcm|D}6u`e5C6GKZNc|zbM(%FJ7VR7yC^8l6vsErVn}pb}N1GE_l(< zhirvyx;}J|rVo1;F4y(pGvJ7>Uz%j-mtL&vBc9jv5d#f<3H&~(!bCYhw z`3)n!85~wdwFeC&VIBOW49^d+NH-D-;U3MXzFs$~AJYx5X&Bz0b)!bSVbnOT8%bY7 z7sE*I2wyA1_a%%rOwu;BCCXHrsN{vpH1grFGR-gHLBot&2ZszZ{v#;Y&1(HjGaeW;^j5Mq1{h*y$%}9VfdNuQ1*sE8Idk>z}6SQ)8)JRaP;B%Fr zzX4yU1mgoZNX#F?Q(8jYgK(8fh!4U{Bca-xT0*tmMnb|S7;h$c@?o-(kT@8A)Do&! zKr17`+a8|K5^Ah~4SGV-+wg>ukh}r@rYHE`gvX48nty{OMnXyvJf$bpdJ7&m5>lUn zqbi~HaR?d-b*_fChDT$muAPs1xxq-KdDINl3k;7wPxI(aP_NTH#*LcCSdKcx^swFT zF-M`+Ri3ySnkTNl^2FECJn`wuQ>~unspeN6_I*7GO_j&fSo3%?lqa!?=1FX(Jk>Ka zPxa=?<87vSye*WcMhneTBU5>jGBr<9OXW$<(mcuMD37nL=JB1YJT*INo|;+8laj4@ zQd%ibt)7~vR%_)+?X7uI&r_b-xtgbT8|A6fNAuKat2}l4YM#31D^FTK&6CzndFoxP zdFr)Sp87*HPyG(c(_pCPY0y!5(uZlD^b3@y;czZjIw?=1OEpiU&dTE-p?UmWlqXQ4 zc>-OPr*TO0G)_~VCaIdINj>FhT3hopZJ<0EX__aaq4G4VuX&m^Ql91wG*9z@^0a8A zd0I49o=m^y$$U-ov}^<0V29>8=X`h>c50q;+rcaFspiS*0AIr=ny1wT@FwinJgqyy zF?dY(oYz_NoL7$eh~a6|Mf0>-g}O}hwCxHjpiJ|e-wl?+a?R7OJ3Im}DNp+zny39* z)UC?XAxHCcSdBVf_jK%~c{)x)ZK6CE1T@bDyEIRyRW|~t0%@s;5(IA?FdZK6B8ywKb7ct6Mi%j6TgRVjl}AM%tY@cFu_c$ zQQt^Rss|q%iOHYBH%6lGYxr3u);tD{jOz5y>e^~@u@nM&b-g}JFsmD5;TKii{08b9 z)#K_yOT(+(u6flRnpeMD^BVg!ulc#=jeAge;~!GqYCDuSp+b2*-z#t83FWQ+tMYmq z>fRbnbZ=6+=}kIM_a?W~y}tIkw`K?3n^L5EYc15hsb#vi_H8U1Zr8naD|Bz#FDxU@ zGraY?8Quoh7~b@I3~$4G4R51|4X=N#;SIcCcpGmqyiIl)-lne`-i$p4P2Kc1uVH#y z)Hl7E4NPy##-{h2ai;g&YNj`9w&`tkmFaCg$Ml|et?6xZo#}0RgXum0M$_BwX5HKV zTjlM*rCrB}@?Oxx@OFCI@OIAPG~7;R4Q-}ggORd^dR5iXSHXIthOr8s&}*3G(B7;O zmjJ!YB*xVwZK#o?hQMT%q)&kRjU;0w#Op~WOChthkrdYs4ymO0FX0a@shTpAstwhX z5+*^Jk>ptlw-`x@i=m5=RJ|jt)RMd_ps$`(qZf?TlaelhanMswO3r~RRg!NCoYazP zegwa1Nhxo`K_jWw7x1~Bl==@XDb=TvYA=D8^`ttR;6{~HHx&w1Qrc!CDQ&fuRPQ$U zT}!I}7E~HZ4c>-QGbz0U8XHLso52(_snJ9z(3AXg^`yWYJ*ja6J*i2$p44=bO3Jty z&exNgb%P?6)I1L!G?H4ZgL92!t&5SYI>Kg^tUm*fsAOXuq#5$if{%B+e7dRmn0bBd zll$VTYrgnI%~#E%`4TSFe4Yf&msm~nRgc$v-itI}jdL|$Qk>>X9;o?zGc{k$b2MMd z0L@oxtmaF-QuEcmR`c;1o3Czv&6n0v^VKWReD(7*UxWFYFMW*WYk0HfYjlO?^VijU zfw`KmaYN15WS-`0+Envp+^G4QHP?L2OEq7M8k#S&j^=AwPxGCVuKCVwtogE;=eCM~-eC;}FzV_LguR~AG*Ri+eyC7Hdb?T$}I``FlUHWOh zt{1Z%Geq-s8>;!b57T@-hHJi@OEq855t^^pNX^%Kl;+DFt@-+l(|mm=YQBDxG+*9i z&39qG=IcLI^9`7$`36qcd>75od>3D?`7W8I`34ngzQNaNz99=W-_XUHZ&;G%8{SIu zU3!V;8*!QD8#!C^jVjW7qZeqtF^e?c*d>~ePeuAJYpwal57K-S#%sQbS82XUS8Kk> z*K58hH)+27pyr$E(|ps;(|pqhYrYv1G~eZOG~X51Xug6QG~boQns4SUnr~K3%{RNf z=DTW&=9`nE`R3Nre1&z5n%W~qP4$>wQy*s5G#=M$nyt*5aYwb9@vY68)y_9-CbThY zdfJ*b6MxWZRzJ_I>Ak|JS>rOjX3}UQMLVpesG(+xzFSK%E-+HeA!bV42s0)AQZuF6 za5E)gflBdQqf!#*sg&y1s}%1IDy7DCDkW*YN=d#}rTD5FDK*bEQ&O_blv)oNDc1WO zr|-}G&feT_5Ml2q3_A>6-wu;mq+JHpb<;e_dg~1%E^Zqf)Z^n!pPF zKBgx=7iy}+_*$xZd|&9v_;@SyX6xv7=taN34SJ~L_~nqJeDUQlP_G%E2f2Dmd~dkI ztQCJb%rH~qr^92acKkEo)$7EkLZV(bJ_%~*Y4NpTyjd@PDjYQG#eb>QkN*N@=?&tq zgojmnd{4b$`~ya#`1>GW`s4jD$q2*`f(!J<@g3nstx5c?Fve&ap96jMjQBpVQ8kNy z7XG1{$A1MAjTZ5jz%(N>emb0Ew2V)OamG3EeW1U7Zv2ICk)9Pl09G5V;(MB{d%xE9q7a~T7`2J?c_|b5caY6hXm~C{5 zp9SaYovZbLgIbq_kHM?Ddg{QVDm!sIyr#NU-wCtz?%pflD!oUIIq;I6le7-H8alQIfcX?^4Gg>_oL_;0klc#nQz{Bomz{3LTg{4{eQ zZ%FX6#-MctrLY)+unca8yWl=p1rNg`@HjjL&%!3y0TId3b+gIgVnGO9)-u@X?PKK!3XdO9DsxH6-3|| z#1ExhPz&mTAI^abU?@z0%i&765$=Ph;AMCfUV}H`JvabI;8!q*(MF&H^neRt5?lwR za3`#SHSj2GfK9Ly-hn;v0ek|V!6694aqtYMO+rgJAG$yf=n1*d4+g?;7!4C(2F!;N zxCNHOZEy$N1FPUs*a$DccGv}P!$)uk!tgVkgg-%Dx~`xaREL`2hbGVh+CVm31jAr5 z%!M0Z5!?)Aa2wnUkHK@W9o~X{@ELp!74QSZjaXNZ3R%z^+CoR@0vEw}m;sC6W(dJ; z@E|+_&%$=t3A^Dfcn|i$7w``_0zbm9ppB$`Kn+NR2GAHa3;fUyIzm_I4n1K2 zjD_pq7PuEy!5UZ(PrwG)3~#_*_yUf=pWwS}T|qjW2YsMF41`NyC|m}UVJ=(^^I;Jz zhX>(Bcm>{sz3?#{f}>!JM~;vPsn8fYK^|NTBj7T)9Il3&U>V#Bcfvie79N4e;01UY z_QC=90=|M{;GM9p;9Ted17I5504w1!coH_ibMP{}2_HikeuMaljD?U1UEm@Z1Y=3oJ1W%b!Y&sp*!@3fiM!T zfSE8CZh&G~0?XkJcnF?{UGP493J2kPI05mKi63f08Z?IHa2~XWj?fvhAqNJ-7|4f( zupDlOyI~bP53j;U@GblXHKwd9NP)WGhbGVhT0>Xp0sUYg41!TG2a4e~xC>Up!>}Hn zfTv&+yZ|r3>+lX7fImRxQ#MG0hR_T;K^_c%%U~9i!fmh;9)w3>D{O~dupfSaKfp7U zz6OmU6FNd?=mvdZ01SdrFbSr?Y?upI!va_WE8szR5;nlIunD%ncGv}P!TWFs{s}+B z?@)ajd4M!%46Pss#=vBl0W)Df+z3nIR=5)$gmv&JJPv<@XW#{R8D53m@D6+cpTqa? zD|n}`E2skjI0rhzV3+{2;07p$n;{5G;cmDe9)nHrDtrvz!k=KwpzlLXXbNqh9dv^3 z&>IH8Shy0dfrYRPZihSJ9#{#hVH0eHUGNbchA51~$MBI0)avk5CEbRkSlmhx4H)!5F1!byKn0wHN{F9BKZaDO4=tb_1((6)Fbl4MYvFn*hGnoC*1#k13_K4zU>Cd%`{5h-6RH(5mO&EKhBRmdO`rv| zh3+r}E`^Cu0CV65xEmgYm*4|94oO9{7s!J_FcPN0Rd6j_4>!RwxC8Em2jOve5}t!C zumfI)w_z`Q3WwmIpsuFwzza2@4x~e4Xb$H<2grpBVGs<5888#(!aTShN+1Zg!kw@R zo`Nl~19rm)5P@S*?Hc+91Rx8tVJM7*(J&sSK>-xOb+81UfR7;zN8u;<6^wbr2eqLd zG=etJ8z#UEm=8C=Vz>iV!W!5JTi^}&6b{2T@GTsLAK^Is3g&#)0^o(3&;Xi4OK1ZZ zKsMyTMQ|yMfeA1f@?i$dg&Uz5ZiW!t2J7Kjcm;OCTksC-fe&Fn9E7jnYly%RI0nB$ z?0#b)#vuBzV;21v^2aX#@~*!84#qt1EBf8GwPpWGz&41zyqPIKo)gq~p3wRQ_@63& z{9b8jtMV`Y`vz?Dd|R>pohU3lUZT$#caG7g#poBu=s)05?qeWqn8KI-Jcx! z=KicR6CH!d3Q=1>#8BzV4iQ*Cad;Y??L*U6#pqv;(cciGKldEhx2BDYvCoXL?-8T# z7UQQ+RZy*8jNTvPKRrg@C`R8pCZ6+S^zCBw9b@zzV)Sie^qFg`63&g$pBLjtPPcY_ z{nFCaY1$t#`g3Fa$O(_GuWw@fG>@@=F-G4aM*l*LUOwC4#v|_@7s7mAMr!U_qBe`s z=fvoH#OQm=3rx;0fZ9DqKOsin8U0vzf^-9@%?Kyzr69k0yf726bhdrR82une??(;9 z*q;}pzuxK3pT?AHe~i9eOg^Q*H*&&?J|{+B4}CT)#a`Uv2q&tWpILbMm~+aTllUG5Q3@uPCo#f5>s$jrt8V#r{21-e|Yt ze-o9H=PdmRN0qRTp%*vNZ$RDS=&Ol^^IL=6PWTK~gPW&c(Yt=!dJwb3e4r82kD$_Fu=?dp@cPTc65vz154c z|M0^q`+YI`!!ddz#{ZWw_J?Bh+hg>rV`TDsQB3@tJmThIYm7eAwM5+)lm8g&GqeH6 z#-0CH5NdOer9S1(dEcNP+c|~-HTKJ!9tHxE9s*G8d+RKoB zC*RGO=cv*r#k|B(CEsG+?5Hn0>Yub(u|MIc(*Jv5{>@TfFx>It=NNa9!!u6!V~+i| zj{1WYj(%#XFBtAvQsKCNgG%|0uPs#>Us?V%?T}^eWw>LE*o!~gUKyWZmhyk$`2XDT z?~XmUIQjVqdnwPSj{3gif3Ky!V981H?~Y9}j){MFY;wn?)5j!t406XDcZ_kz7k6xN z#}9YxaK{aI%y7pGcYN6Aj0f(xFg1=7Ovqn8>I~E=sB&>J*|MLZO|sMiZ6>Ppfh!$# zVq#^bycs?LH6L|6>J_Nd9s6;pS7MGGa|j;&UCkK*C2$+8gvVejya^w{*YFeQojFDk z8bNF51*2gml)@@_5nh9jp#mx)t;_m?cF+d~!wk3{f^aW939rB&*bm>rACTI0eL)Lo z2fbkgOoMA61P{aW@Gg7>zd(HU`ht4U271F#mkH0>9xxPU zz>RP_tcIsy7kmsy;15XZzP_L-WW!*%9BzbVunL}n-S9Dd2XQ@+1GI)7FbLcVaK~>k zPr`nM>+pY(+I!ZOvu70KPYKM)pO!x_Fl*A~`IFso`YOtlyKybAeeofuWrV^73MwL9QWqzcVPB9=7TNR`@o#{itQd~$sPmdg-_b% z3FmN626Jw@Z9a(k3Cv3#b==QoF9LJ6j`?-W z?tJ1{|E01Y|MDP-_?NmqjJa_R?GC-yv1@_3r(+jz?D8;Q0}{5qV^@M1?SJX_2w}Ez z43Grc_}>U0+djV`{J{TG>i=hWE}^~_*0tZUzG!0M^3&fn^rjNN3W}jnT*oD1S%)i&P^E)A%y+X`k$DGrh zd&ZdCc=Jt; zdnarvdP#UF>cMQ=-vr0*Uu7t^{Xc~Nv5Ei6_y3u0Lnlw1IWvDwOslWT=hKuahw;!I z-(W>=hvLU&BFXuKZ>GYVVjAI`ZCdn!Gpv3wgV;a@Eu2|NDPY{%vy^Pxf;ZjT2#K z%&*gb-2C>#JOQ)oektaSFI1T)V4mHl%Kz1vr^omYV)k{b^6%!`RRcr%1kP{Wu63J0 z?^(0w&zUi8dSM`Qa?3#5&Ydr4b$**R=LaUu4-CzpJSV>}FmU3exq+U&0&ZAQv)ivJ z7&d})7~pl-xRf&w#&A9YYz?g`D8c${E=ez~tIC?2@!)%DvpB{cJaZP}7SPeTt#xNOgWqiF0 zSv>?Yu1eX?=H}Wz>G(aHS&nvs;B<@VnV7n{%6{BL*CbX7_J^xu^- zUuVuOoHJwQw5-7FS#!HxJZoltRv>@olq$pISu-aW&6$%wv(R#F8EDn2d%&9MFR|95 zfmw3`60CJ%fSlK%g+h-?v@DJ0}G^MAAfWky?2R$yk)m6K%JpBf;U zxh+p`QiVmc3-SXJV7%SB+z{huO&u>G#$P#cN`6bb$)C~Stl0i#qoZB?=MBz^E~e30 z?N-{g-OB%}p-KCi`9Ivi{$DM^(;DJjSsO;@H@6vFIdPulAfwk=C%1zC#on8M$5mWu z!*yFN^_65>lC?{=B@5Y>P}`Q|eOIg1l3JG3axao)@QMwX&Bitu!eX-;Fq`4@n`x?1VV-;_#+nlY8sFU3+x+MnrBsr{2=*FWkA~ zEQ)v$i@Ue(*(cI$YrTYJqG}^^>dtevqZ{)=KaQ-nQgX-kRoz?9+KU0en`DcPRy}iy zEs%YsbT`M5t>|@{cf;cyTd|lTPJ>>@WTObd!G0ej zs?4F-_{`d?=ca$B@;APX&mBXSp~)NP#klg%$Op-#w_pCJVT`o9=_JwGg7x#}&D*Gl zr*=Gn(vfa}orH{X_h!YOBOqk7j8Y+M#UE)-Oo!w=3Nb1}RE%R$Bhk#z^w6(t-E-P` z932ED=48j<>%6n}WieTSgCOi+i<}Zn{q~*PF+|zNriPepJ8$2P`hB}R-z4xAY!YyR zu(#ql8~*QPr)C4+EA=8PWSv~;UXVDQt^0PIUB8f7 zr*VaoRgm@dZ>=fqThE!O0Ndwgw!EyCm~C}zqokMhORQP8Dbm!OE_x}3 z|BbjEU-aT3<0K8YX)bz!xoyqIG~Z(-?eU6V$M9`S+KG!_JVSmM0e-BcmE1HEE<=(Y zx3O9e-&pM0;gQlETGRF&r*1`xGL~<=;-9Ejv|@?P1=DekH95YMay?!rnM9%6UIelC z;%S1G!GVqq{J|=a?fp1_-FeDR44x?O(}kk@5^=G8=PCOpNCL@Oo%vRHddj|?yUy9V z=R)aK$Ho1et!HD9IdL~1tUq(dg*&!OwDmH8$5>ByX8f9wLW%16ThBU=-8KfZ^{4GT zf5$oF(V?5+d z?M(c}4I1rORQ$5d;<)2cR6izZZ~YsObi^~%mE(%b%yhF(y@|*a|K4b%D&5rHH!2+t zOeZXw@&{L}uiVH;A=4@D?W@$1OC@i_smg5dZ#%lZayqO?&n~8KO>@DPCGL zGv+On>RX(9hmImD97$Py{te_Y9G8PDO<8y0ZJDD}84c^uC% z!d3$LpA31CBgf>z@fyBlpY*@SS#c1bte`!1-tYAo%#q{BYHxtHcj8qGZ&3JFWHlq~ z$?2@fnO;C=o2eLYvm%IpZzQ-)7r%YSKCF?M^?lP5cL@#akgSlH44;O*Yu$&{pSow) z+3AcnJ7e=?Wpa*YnS&ilvl=6D*uN74-)%ci*>&~~y~mjzTM&~1!wBRp?1-A3PqUNC zU9+7s%rS#r9sKwe6tlnhCIOfoLoao2Jq%ehHt{!kWY(&VX$9x(xL_aFIQ1F~vv#8O z=Iq>2YPb3J#(26lpS5$_X{VgBdGF@!``hQX&D(y~S!(lUoO8rjVaJ}$r|!YXd-Kk7 zPTi%1@r=1`?V6|W{LOL06~@SM?~c82w;lEISeG`a3H7;c^V@Oxq)oNWZ-X|!Z84N~ zJPYtF#IpzwX-n`d#j{M2uT>tc7}aX6#tym$aKp1!cz{sE^EP;dFxvURKiDo{mwd zgJ1A!0hr)siCO^8WjJWL5YFKDLU7~J3e+~Wuw5-&fIrd$GZ?|QSS?(l7A{o_m#IaH zS+NKuu?T@KYQc>Ac z)C)D-8ySd(g<#Rd=s;(zA1>e_m1Hs!hYpXR4)r2Ts-2N!G@OABk=N3P;*msTFd0fl zV}sqX_y9eF9lVId>1v=e+LMZS z>bAijlN%n(_-wK+5~(5MAF!eR$N(}31ZYv_SbPBG7#|=OkBuM~6X7T*R8h)Z(Vi%{ z6NzZgV5CchfHU1m=1CGEBs)?3C{q+?G8satcbQ6*X);yFkUAs%u@R45OuDuWhkD{6 zR*B(ABFU%?Cz7gDb+)U{5dQs9Q3g>PfDEKW8PF=zNZLR~5<5dE|9)imAgq$1wN#xZZtPaOyi4P{f&wjyzpwP_!c(PV$*7%Ie4nisVXVk910i)s@_nMLDa7D6BXYx$sb zQDf7X?h-tUXlJxPnjB5r8^XkF(XL1gLT9Kqag2ksRfbGS2Q!gFk4A9>R_PHNoK%W|V6Z_6Lu@AqAJ(7xs+aH727Ii2TM-S8+Nkow-lCx5P3Wp{M!3sAq z{9(4u8L}W8k4pDB5Q?u&Al&0wp|risIv!7Ev09$qP=B}f+w+>nbUcbRBTgsMe7R%-_uDDa_oA%!TE{=U#qh@ur;VVoiv zR)di+e96kL*kA(8=+I%Uv93r6Ic`neT5MWlFD$K)v$O%!7K&DD9_kN;BfV_q5~%hy z9^qik<4L4C`(hC15)$Nk4@y*e2eL?~X!M~dDknxJpbs&ULmcRZ(O=O~JVy5(E+aZL z2Ng!^8H$4)5r8Q*7>P1J)0iEsc~*unzB#1O`3#0fbya}#Od~uVp{N@P!{ZU8e*^)J zq*QoxC?1Ug*ShX$(7A#TM|a8S8$>tnv;l2AZ7?Ik@su==Gct#zG6G@m^OqeJBD4yF2&UWXTsbw!3y zxJlRy@rgrXCsEX0sEz0|p${V-PzFOi>{in#t8kV{k6OCG6NMAoe$yCB+atq}(Xukh z%qu+-?LxJ|I1a921JS{l(UQ@ARI#pD3jMVne`;J0@ie|J6-y$q>r__)RjUjC6dD=Q z2_IENMMC(attBwv7>Raav=iwW9TFu8Qg0MpQcwRVdy2?F47C`|MMVbj5A&fML$T<2 z$uR^@R3NSEe#?(6W5J6feH_~lVqe!96Z5~5Hp--lWq5+9U%im$RP_+ zx)|+7MTw#9dI(FFHY7^D&oJmh9#24i8h(jK8utQE#bZO>q*6tUF)b}Eh0_a&F$z#j zJ0UFlL!3oH>`JU;Y)q8#APW)Hc4U$2R^6yo5vcJ5hoh<+I5kWPv}hDHv+)Qa5gAy^ ziCcFxo=CC>9_)!GVrX@69>X7vgAxhjknVVhPgvs9ortRLRDZv&Ks}*u)q|+^tDZ3a zoeEMig7G<9Q%?*M#h5cg?}@|)B1u-4-p~*V1m?IXJ)Er3M1(n-f!iGIK}h|f9#LW# z1)=GAYOF_-Cy8+Vvx!vGca z(8zW%vRo{pYX?liDi+$4R3CfAsOm}eA&IH@Kx!>&9*`97`}MY~-UX@`GZ%Kr@SfSK zJJoa_O-yIChZ#`Pmd@mG54hUb;oRmiqbKYCxuQJeRLW% zl?-C|SX!r{=?;VPNb^{;$Xbx1q>HDi!5H)i{+OjviHsP{bkT@22qxZWO)#wIqeWpa z7G}^@4Wl-tFib$_7V80yaA}bmN60dw&h|#*klq;l^&$`AYm=%MlkMJ7{81MM73Oi# zt}q|e_2?if5haKyQZrDK02xvRodX7E=-y+4m@%+HaG@yLB~K?2%*oJ|p~>s95GYBK zIlK`)KF)psoEVtEuYnMPLyML16&f9Uw@v7nA(s&B^e}_1JGve+K~{{Ss0;i%YT5aVcIs9oTf0Uzg%f+N8iAC4xXf?)v) zBPg9=DmoNmd(m2CkVA508vn>|Ep!mmBw{GFkqY=jVgk|$1pP4;nThxHs6McwV+(6F zgmo~~ccGZUnd$a00D~Yg2C1KYN!2&3)`sx!#uG(~pkd_&Eu6$b#CyoUSz;<26xTW2;~ z+B>loKM`wi!6t$~W}JgPQjcWKjS57jUPhw9R0eQ%W2GrgH+Tf=zlaG6I)lOXj2R@X zBV&yPgHS9lG2|i01ZcAQtF`_pCbed9SX0aZwZB{SM+XpNC@H9eL4G4QPe1A6lx4HjP-C59*bk}fU!kHL>Q=8zR)U{E7F)v z1eQwE61N}AWc?Tk_s8L9QuQMU)Td!9`hkKtoJ^ZXv9i$*1>&NA6vJaGzz5X8Y&8(- z?ZbG(>UwO8Q3NVGYv%yUOB4!48aOZ-)rpp290X)9ERyIG&2UsqSu4**6xsqHx3#wd zIw7vIO=cp6(t%tYh~ST?=;`A?B!aj_BFP9Q9i!;%GjLSmaYoyM(KhK3vW*HyESRJv zqS%G7=FEZjKoqTUAZll@z>p3SprKrV(UibipR8mnF+{LZI2ghHKxQIM!m;%6raVY1 zy!3qWvTOn(3&RFIp(`+OLTs0uvOG>k!o7MSlVnELi{vcs1G!!>AINONQHrCo7&zOYN)h-OnC|bYg1*<9QDh8XZy(oL77kEX*$lEmVfzi+) z>ZUTfh{rT;*xm{P1wo96vuF#QU!5FN)q@FD9juNQ~0k%4{ju$*7Rrl4C1ZlWTzjA5%W>tUuCOy$+MU8UAR z>7+3hwvq{#E+Ea4m0WU~_9BelLbk%d3OTD{!}z1gg+@ikOfrQ67*a#C71snM?&;16 z>)MIYLD=XGnNe(duD7O4IE=0RyI?-a&ZW8^ac$^g$V8E0V{LvyLTY40tjuIUpK>??^7%2*faI-cWxWv5eu5 zXrex_E@0ZGC(qeLJC4BWR5D|@J_JwW_(w8nSdWC*0F~=h=~++)idAOhK^zmzA;cmD zoD1bzHOuAeLZPsN5{1%@2ZP9U(z4g36qk$iB7=vCRa}|jtcpi^BrP)IkktuNID<~~ zMr9W*j?ra2(#P3mJc4R~B_fm)#tC{{C90JzVo1g~hSJs=PY<{<7;Hvmkh}p`ypN$l z{=`wvag1@|v0fC$DEeeXCWSpfDk4(S@;Q!OgD@;0rV=VKTO~sHck#jWG=bqTrc00s zz`($fSR#}nmWpHf5z{f104a>Woh+KEO#*(vg9s*+iAWDOp3{}xF0pWLAL~$N*amyB z+V%28kHR_#G8`fFV#dWd^x_MM$Y5fqS)AJRNA%hr@Lm!y@B#l?1!)TzgTbDtTE2Sd zFw%r|b0l{F3^Dw>lU*_=0Lm0WNnoXvJHZLWNm`z$8PUt=3~0rUA*+*x??YI9MMkT{ zI{cAm>r$wg3R7QJ6httEoWt&|D0%`%qh9$(bILT>DF&Mv9zE1ROf5>ED0D={P(%Ao z0WULiE*5&TPDCg*L~)lM;DKO5;G~-)DDit74ZA^j2T}$rJvnyln8}eTGBfCLF0h-` z3pUoQ(8gOz+R%zMQwpas=u^hlmp2+$i4jyv&R-Lw_@f0-!Bh&;HVT~QQJ`Vm2?ZOG%AZ$$q1c5>7j;dLj@`7&&+`&SBR3` zj6_dAlwM>O6^y2!A@C@ARkR@J2oFO+FrU6uu zLxw{Hn6@W6&em}9-~n<==AjTD993~oP-#3Cr!#CRk2iZc8pmKSrBaxgiNdi?3R@AP z$g*cjR;yB2t}q8zlrkHm_5?xtP=TJ6$pZbG^B^c0u3GQB6)+I6rZ6(7&^UG9FRDx) zJ`KLUDZmpX=#kv|A*@EOPo&nX_3PEB zV&|4VZ31irO_Z$_)Px$1;*ZQ8jY=EU8rD%c{u;2AYBar0H5#=ub+}DoDToSs!VPM} zY_)-h-Zr2?L1l-tpNOo5q0TVoNj(uPmqa@HIy%<&4-CeJ)?w#8nHnBhKN^X^`J2Ip2^dZ~ z*%CK4G;G?uW$U(6aNqH?(|20(IQ@(>$H7_0KtsdX=j__u&~Waaz5C8PfByv+zN7!5 zi!ZtKK)=Aj{>v`EqW{YNt6;hs&!KCsy-wReJ?vo~qQk$w{{};`@wqX>e3Qq0^O0LT zTqBWN-+9~Z{de@=dDq?dyzAZXxi{1LzWe+8-}}DzKk#7xLl1x8=p!He(4&v_TmMCW zJj(>b6Ad5E^Z+3h@Tm z$?}_`ibO9~C2FcF#oIQ^RRt)O#=c5bgIoVQsH!Z>DNcC#Xhn%)%Se zC#yLKhd=F-VKo^an~hG|iK+!WK{XeA^VEF!h=blZ#*OpNIM|Fc*7z*}bt%pt6W71x z_@=>1wF+O!XouYzkKV32a2UB0<}l7Yv}1D~`>4=+6}DXD*Jt##ShODycUWJ*w0fPw z=oiDd6ux>eqS!HPP$!A`WVKOkQk&HlwN-6{{VDhs!VcJmVXpP|lFXQ{K* zIck^M4gPc09<>+z`_y^reAw?-7l`>n^$v9r%omHfU0tFsRR>@`s4i2NBSu%KE7etq z<<;tt#P1q)t-4NPeOO(uZcsO>o7Bx>KB8_>x2kul+rW3bxW}B{iAwSet%N`uKq*)r}{tY|EfQ$|5E?0 z{-XY>UQ>TluPb~Gz;T?Y@;Nz<-^q3IoPgsx`A&gTh~Fe{w%t;vG@0j6p3HYzoi@kjD)n|}f!Hi`SPO6+ z!dVP#iL=!FSSHJy<<1IcB~qtqs;JY45Y{^V5)SbfmBwkOWBLVC9;~nWce{ySyBaV&mab!0 zE7X_OAoLhw%JdI8>yRIDk3ZogojR3rhMf_UPwSmgXM=N+m->^Pjo{woY&LGTI9mnV z=A7a@gWTHgP>${Z?NsM9sJ9z=dAhUHIYWG5tj=`Ka?WOyh(W%Ujx`*)F({nNRi)fdFIrCcnbT;g2n9B>XgmzkJo z+smCRoGUXZSAo~MyISbaNq!%4>eV&QZ`8HUbCMg&=N8!C zil@hUr*oTgyK{$gCrpp1yPOwLE0|gviq;pXyQNLtBW<TB?k2;S*e;f~gPeA`Lo+pjDT|MQwNQYJ6Jnei$I6mrp%=x(U3Gh&!wyRG% zp91|Ul=r8hf5v&ndDghs_Mde=2RoZz&pDqrCL2E;iypY4jI+Nlz!%z(Zhx9H9XoAi z&-6v-E9!aYOU?@!+)?%AEK}5LhgJqq|B8_iUv<9bya@d3V*ZA>)O;_hZyJBB`9)QW zlKz&HufC1a`Hu5l=X=g8D68)~|Kj|>`JwY8WAkI@C$Rsi^OEzj^E1%?6{fVCLi7oA zlWp^J@cqL1rSmK2*Wms)n118@*7=?D3QWI;=?~EV=)5YwKOu+y-T4paKb`;M{9otK z&VM;yR{xDh=ht5(C2LIjblhv4sPk9n1pLVJ8tkIRUh}bM(7(Td{<_#rbMTQaAF1@i z@%en(uN>%Frutz^8%>Woxdzi_tL7Q%H>4*Dh>tcj>aOQ1-`H7~l-4$UOJmr!{MirC zUYqqeLE|roJM9{M9{erzrGMGu+wrET%9c)(@Fksz0n>ON=J7t6hx<5N%K(|U6{i7n zdZ(<+%;JiC)27$X$l$I6UY}+zo=Kc97Peq#6_!}o&`{h^UticzSX@}xP!GpYX)Y$M zp`reS`r^jMSq-yirCm162A=>t2YW+zW&7e z;N0SQ!C>?J!q!%VYoLv~cuA$97_nopNKrdNEv#SA(y|a{M3W$PL4Y{ZUbHSkeOv5# zQCz%aX>i$c8?e?f&uv*rca52_8s;^K5&&~xH^0*t7WP#kUl;izEiJmde2v|nyB@Ig zB39A9wJj};V&B+5fG7|KBZg1>i4D;tXt#tC3~GME1pixFn#z6aBwj5oeKhw`3u^Ct z^T-)#3F=6~kJaK75f75rgIG)4_(?6^ok+rphff)V*tF=Xmx6(@TArY~dT6yoQ8*gu z_v+Qiq9EPJhDU~z3}_g!8)|GZQ7@~ltz91sE|0_E>fq4oM*M@=a*G9*$CkGQm&3sj zeKARGX^a3h{0!QJ2X`i%mgVu`WRMOBomxXW#Xf1`L28`w7(npC(kR=4fYKg@XfM7xw zwOGS4!s-(XE(6Niu}arR+(d#!m}aGzq}jN)$72o3k|0Ju&GfepB!$% zO)c>Uk*lp;uwa4TpMd|iXn?H_n)VY%kf=XWQCre&Dh40IYs29U@b%C6Zw@x@uUxyoIUTEa{=LCCCVdC3kcIZMD3juj$#AX+CAU3D>vdR9&3f%pj2YgvORt zQZQ%-0;`P<1~xSoU7Scui!bHtjF^0v@|OyW=$+)tfh-UCqYirg9M=mX>J2h2Z;F$ zKymSz;5+N=X012Vs<7}J=yboUIjHHo&n4{X=-9h=uMe-;I*;)_zoTP6^$RZaz2hR^ z#g`EG*C|;SEX#z;tkk}I;S~$7kbJO-3SSw%D$EYL z{;F_$VIlJT$}6udEWEm~@Px)W;o?HqZ7(ja2_F*wq3p15&9ytOLyoxa;c(auhY#0; zfyl#xbHj&eB)C~Xir+6z!q?wG6T$G-kX2K(nrV~*VEckJ4eE9VOvlT(fdNx;kp;!NPd9Wx)ug-F&sBw@X`Qd z6ZAvj@Kp^*TIz$Srki~rE)E74OS?jH7MYHAIjXJHOX_@l`}U#y_p!|Le5dX6?PIKT z8}j+~ntafSk_^(R2nHSBEw@SnB$ZezX1Sq}+|kq&-f`y|w$s(i@4CASdSm07rY`oL z8L&DmS*d-4xVB_gxcE1Ou^FlE+aI8L5`&Wk%jM;>XxDb5oG$L22pS_!WgXG z%{tpm27nzqvJE2tgm&V48qO5g;1@zGT?T_qC&0IE{5bg8n2b~KB3j{lVb|EG{TGQL z3A2(*YQB$y6JL+WKSq%Kh3;%bt^}7fMj%um4DVyk`+SR}zktA@S71ahf{_Qqk%3p- z$Xy@DZ~fto!C-ewcLY673uUYaL#K=T#*Hlr-|6>@d*nKYLh_Ig=}5%yOCtW-6@tTP zr?K(92Ht0Y@gNK9ns8zuiZYZ=?)_rP`hzYE!z2MSE^gM|jw|j)zY*}7xA9(%10T2q zym=2kWa|GV4_xAV$HTsPKHocUy6F<%2i%)GQGy7=xS_UsaEY03AYR4TBfR($zfN*j z1{csKhL?U;2g{DGzpTbRENy$RBW$8$>LgO(n-_dUSGl0n_8mK}EpiIOD)KTM=ulA)2xzieLvgn(N4arqYloCD zVGK$)^q7@}ZCTtkerN_=qg!Goh^%7kCNJ$-HHZVYBsYs+dQX;u0L*7FcG1|3?15$vuG7wD>G87QflRb$;owcIQnXIrFMJz4xZF16C zy%q;72s^svpjm1&nhQqE7{LdJ0H}1J6QFB}PZu0|0^mSu8FW{2F{mrQmB*;}0G;X5 zab#iiixjw(Yrp8~BhmAzPuTo*-0J{-YPAv{7V1v=8D)C*uYL!=- zSDBYrnX7UuQ3|TEy0+Gzo12%HTbY|zoaguF<<;ia*5;~Wc$4c_dF;mXD*eiJRc&=) zZLLzZm9@F9n_F2}s7iAu<>r=^tAc_8Ra%+r_xTYKl~d!Z!SYT`jhZxRQgLbNwCQEj zCQm7zR5@*WWn~5Szmed|NrnD$KcW)|dbu0bu)Tt#UxmA^Ar4 zm>g($6K_v=6A=0F28wrnLzV=OIl;jr9Ca9L;S>iz4sv9i;=mippfbleIPH6LNDWT_BNo<=j&3;V%K_tksBFOsU62R1{JoKa+PPu^!1L%wd&<_bz8>lfLqcA8|>`gZ?!$6$@ znSZch7?AcMif)j$$;~n_d-fawJ&M9S2W!*>F8R%!J8#~61AP0P0WKrp9fSZZku4Nh zv}p0-B^Kml*HQz^0LuX@2rE~vq~)sBt5>fv!2UV}=rmwE`z{R;wAk+Mo}Qjw0!|x7 z`!uXIV9)#v00wbi$bufU3=OSY7Z^DLYX zKm)iS11=PJhrmS_U7Q7%T!N!ufP(^;U3U59mtS$k6<1z)l|X6f)dGhOT_bSqwbxyD zos=ULii+#gKv8kSjRx%E!_5Yc7`Vm2t%P@`;kMiFxbx1tAS?{rlMU~Bw}JNf_aPwtX#Vkld_X?lOmJilA@Awk|L6#k&=;eks@(6fC5q0 ze6S{=Wua_TD2yP3F1Zw7 z<fgHNd${#CtD03)oC~7EXtcbY{z~RXqfI9(q0VrlD zVmL6NXrWlKGR26L_j0aCX#!aSVS;f6fYQW>63UWCv>f@+haLqy26!AmK|(R|BtXj% zN)jzgJ_eu&G2%ny2So?P21N$N1w{qL14RPG07U?sKbt}=|6 z=4|3@-fY@z)@;&j#%#W9u56-go@|nAj+t%o@7ea~FGn^1Y=8f3fB$TMZ>{~=`EB<7 z73t-qi^JOVl+r0>#HUOt*V>dR6+kMdOsT4#!aj05)C6j$8P4g}#Xt3bOb*QW$9U`c zDu>17hSPCxuwd~63m-CQnUk^jv0x##gY+eq6*%4_6R*`P)~q37FSK}TAS+~E^~TD& z39MzzA#*B>I(QStu7TM3=bPx;IOofT-d?!^gF7&1oQZ`GEP90GCX43UAHs!}&_$t( zVY~znRzEJ&Hc&4Qg*b-5C?a%~A?o=I#uCOX;|b5fb%(F_aE+|E;l`V84jl>Ia_c)+ zthjB(?U~kh+!+eVHI~qO?!E7R-dtH3%F2@mvrI5N)cbIz2f)dZN&7(P=p&gdnSFC6 z&O0i62s!4q3U93VC;aIp*8q6kte?HrV(*(2swv}sMdQr0x3^w+_eI})sld&b3dLJ5 zH8{;bE#tNeas8VqI`6yi*J!A-aPx(CU*^cKNj2lg`z^fPGSB?x8(rUWu_qMmZI>l- z&n11kWsSMd!rLtRE(>q6^eKIN<&AExWZzoRcUDeS`mRd$O%;7lMc-249Tj~)WghOQ z@Ma3{rd*1q+ot4kx z-pc3jJf}X7-xnk&bm@Ol>EH9Be+j3=_3z8LwW9B>eAV1t`8sZ{eBE=YZ?Ak?TElll z<(-x9o7V9!(h7cnn=6I5wZhuZyDNq2CxYXAvD{!OR4=QaNek18zQOWK7=DFt*phxN z7XKzUSFpo_-|sT`-yD5KSbh)R=p*3|qNbHU;*Lw^&)U4I{^X_AwiD|AE;nJc%J}?e z*6;sFExHM}WccGvnOo$p%wKR{<}cFHwf}$h{N^2+*Sz2B9+swAYz%Jxipe|Y@A|Hd zANOtSjhg^&-K6i`Omb{Jo(%p1+`wVDuc!d%q-Z#TTR9fTEj+j{7GJbqC1R&T#~mL7 zHa1foohzkI_OHyC%bg1ORboqS{I3db({hlveC)4Q!kp%$rR;QPhEr$4ny2cWnfNt0 zf5JT;{&<5&|7JULaJIS$_jmX^5x*9sHHdpV`Zv#+FTS+mmJaXf@NUixYN4~p{1!XB zm!ogv{KYGsbjkD1&Pr#MdR4Crdv2t4LyqA+r$uvdb z)|&f-Z>{*&@3^R!KajE*a0Z>&I6sCQ)^FQ)t&_W0al~}8!@D>7=8e5`bCUSD-pTy& z{tZ3fgcJMvx7o3Em2}?6*@n9~{B0NaI~?A`;r$z(S7$i9eWUN+kh06MzugXh`W{X? zUwI>kcXIYS7l;oR;=avA&c(*JdFm2J-=MKBc#}rop1I1o8oxvGyT(c1khuZ3WNvV7 z^n9=`nWJs$Cfu0ekGExR0?#eDGsEAl-i?_%r@|< z(*2OAO7Tw3-T8{V(cM&7bfa=+%&9`9#7 z%s7GejG;Y?8qC`^ykqkP=ZlWM5%VPzdXI2H>Se$yxaIg|)bl?`EBzI0eqn4iA0@s1 zeFd(+Dn9&5ea(4F{3Pp(&eu)oufnAJh;P7_HngXY>DX(ER=;WNKa9IGN`1@3(uOw= zcWW&7cZ{7if6$oI^5VNf(dO@ENRCjJuiu9$6SBvb<4tK^Z(~h1*NhK2O3`Q_$3tN4 z^TE=u6xV_Yd3k|6H!m;Wbqfme3Jdiv9Mwq%m5nypYBO`EqGCIV;vO9~-Nr+yrInSs zC9+^__Ta2WcY;?^hXTNAGFFspWN)sjwz^g$hB8f}DkMoEu<4dT^x7(}I|J&pX4Lw+ z88awGMTyYt(iS-{uMa5@U#M{|K` zJ9j=jz>5~zpjkGcIK{hwyNOUlBZ@V3c|dT*NIQ3-aJ!&r;sRq{w3tipOBOAW6?mXD z$peBbCfbo33YmpS3n98omn~ho++DhS=~5RPmQ-MH^)99h-PkR6-DM_7v%?7u#1$*K zySWO#G-w=j*cv-HU9oB)omVa>e_xE8Bqp!cO&lOAzpvv9`bO2QDaab6%$Uw|Z<0Rq(AOmu z(Xh$o9*YNC)aI?i?Yi7=!Hx?bp>W?t!w$$e*TwdW0quZ$G1xiAPn%`)IIXyX!V2?N zY$=~{7L_w-&H%a;<5?148eMGVWWYJb?79}?9#00i*zpl}-1A9;>k1AV(f7FLaxW+i zuD5S(x39H+-ua@#ouRv#XF2xoca8Z1SGKgxJ`%Q)0E~v-Q{ui7!M#}PM7YO9pgVHr zUMjL#G|tzRx>WKReNJB9LEH0OmX}BK<=T9OCHs7r!S$8&M?)^pfuK8*Cy%SOzzLw) zzKPb8KoE1G?(uS=U=(>*d&PV&}y4;KN;6`HFfkl+M z=_c~tM62A~Vd6L3ppQ^JCDf5ojF_NX?NUqyX)S`t>N+D-enuM*6$XE zdtBF$-(~!GH+3C0Bk~@Xdw*%TkLLRrbM6HavQH$rF2@qEmi zsje&Kc~u(co?;qYm-~wr$i=-z4G*V{z;x&Ay4-^#;7Ef3vbm3#WV_s#%z!e%T^DB_ zJb082j7jTIwcK=F?qv!*PA&saJocCzkI>4Kq(Ty|w-3$6Uh6Oq50fhSe|NfYyn3SR z3+$0UI(IM#b6ve%&mH@Ua-2>DREaN8p2`@#R8=Vqz&s#}Hq`QkJr;o3ahheVX0!0B z6RQF%Ncy>(?SnqpHsn4n@DZ(P^`oBQqfc84&G%8%gM8OCJ*|s0z^x=5sRJ(efz$AD zm;1qlPnvYfxstT<=}&!1TX3J)gJ)cq`^6a``^NfciR)_pbK=k*FEPhTWKY?iErIR| z4o++{yU%m8ISpTW-hE#7oVo7|_%aoH-bCxJJ#?avp17{;Mce&od-eq0V{iIf-*#Qu zq5kH#%vltzf%Y2w+eguEau@kF# zgr8Vopn#udz)RK){bdh+W-xNQ?!RWh&#f8yFEW69Vub$7Z1~kLe??o;wf^gD_&3Ux z-@xj(9{f%ijZqt1_m$sk=d53XvF@4*c!0f(zyb7Hmr^li4^h&0(V^)+Og+t4Zhjg3 zF^#E=J{n(%NC?tQw1>i&FP)2VLAvovqg7S90Y6n;{ghysm^}3q0RH91g#9%K| zE8644j#6y?qdCp0(bjI+g#@QvT(5g;M3^ z_*YaY{v8KW6N0e{?y;~;n%Xh_!x2-Z7LMTcmmM9dgP)n$wr%UyRjU;K z>(}!|)^g5C;i#tCwCUuNag0gfXr{urTAg|-4w@<)l*0SUaLh@mQyON@qW`WxG8}He%y{ZZ`S2Ci3s`Z1Dz24?iA)S46_< zLfqWO)$L1<$2AfCz(Jv2Hj$mBUB2v!D=j{e&KVHv7w#arc=8Ka`S7OBK!8VECOqCE z$6bm7kdIRpgkmP}oiKqwm3JVfI#8ppBYG4;c;hKBWg6AMba};VT|EU^1NNzBmChEP zIi;okre;C4!gquEAu?NGM3`-9tM<|b%D)iiIg1tt0_}KjD8yMHu-vwz6(t(Oq4!m* zwX-#)r5%9~E_&fMN+7TzBG*wuety21X8m^2gdg9iu10EBq`K>d@lkKAhid**chAuJ zzL0;Kk^>hT0=#yj60|Q{0e-wibjyylp~qk)>@rc_eQtD>e~*p7QoHx6ecC*t)Or3r=kE_N^GarvZoimAMWu4ml#>J(l?GeZnhd)u=q0*S=B0rWDLHF8M#oz_ z5UqTVj&}wJ%C3ZaK34(1+QgFA4-Q=;DZ19b$Kyv}f?sDThiNV;Jyd##d7FmP((926 zGzS7V9Mbd~SHaUB|DMcz!@O6#y1DeGBcNY&NZkT+$E{LZ0_~-TB)pr^v-{sEw8QBz zZYwRl{SF-;xPjlLtCU(92pm34FQMK^jd&nXcGuk{_Z$h7++D&g{`cTzmhvvk_fLBO zF*LQ0K3uOJJoBuFram0N>sC#^qCnpqKB$9PYuxCfvIVB?pq6~-QHif9>pVslcH)xtZeE{ z%nt`j0s;S1#&pANPs3Bh(ZYFf^FRO%A`Kroq5|o`ZQ!FHLo)}LW;mj11-ZHOLgn96 zT3Y*YmSX!p)Cyg;CAz)ODZTyyTVLRyW0m^YC&c_o9sf%{wT^zy!6}K)d<^AER)s0{FNN_Rph?N=CA2|eG!&Za53%caPW=5HW&hdZ=xn5jC3f*125;a*;GX` zYPbe;ln6mrL?Bru471enBY}s+17ecBlztEO!GwW=L;E(; zRGeEyr_`FHnu#H!{Eem8N-cAV>R@wPrJ}b47>A;6a8JAZNc<#BY@M}CcGg6OJ$`^|5D^IKSOPHcgRK0Zw33kUd$gL}+v^YLCej4*JG zR25BD`31!##Z&X~I_L88{ECuFRaH|a zQ&;Qq(lz;R@!axORo~^R$stuRw{>+%e*U!XHRU~BssmoYrP}0Mlq4=nB3tOS5y~ck)U|8D(PshRdU*M(`H;H zX;bA}+6%UBZO-pd`ODYflcOcu+=8a%9r@~%?a0EJJ5Jqx+WNu~b$ag3d~8yjrPSG* z&M7I~r3$J`+n3chO)1|UEZwM<&p3D1p7N#{UCXLtY7h6h>1T;c)>R(;XtTPqQdhAsG!i{e^L0FA!f*k);=LsR^+L?%G2;i24SZyR;{fONj10VhAD~jyz(@~@ zibxcn^M!%-Ab_7t_z~b2*^x4$!T=q?Fm{3!(gZ6!LSXc`n4rlD;m{TR!W+jm#^A&U z(DK>u;E%lwoq}Sf0Z%?s#DxpIV1V9>CPrWgjmeXgsGNY#1)fmFA8sdcC1Wx&1)(rY z=sn1E4VMUpF=T`UHH%T;OM{tzVqYeJwRN*kVrNBvf4$&1UZx{74#WCT_VH||1Zzh4 z=mcL+>ENBwX{f1noM~y}+rV(@OeWbf!{%vkOtjxnllyACv-Spov^Y+1t~1Ya%on7! zjas`Uj@K8ACmds5xab&C7GZIg$vJTeW0{6*TgQ>}?^uCw9K20x0^s5s;20a!muv{+ zO64gi^!X;``X-CzlpxqZhSs`L1MbE)#qz#*ZPSIW{TOja1qJA#eB~WVCgcd z%Y7@L;xiMuYdUE5h47Zm$@toY7<^bU18^5z-+0z6+D_E9zO{(Pbl`ZIfzKE7tcDD> zE^d&7=t-zJsc&e$^*-O|2BiBW-^n0t+=RCTZn1X0t=mrVa3Hz4_%;Pz(}(3yP0r2L z`RFm7zSE$mTLz!+42_=YF#$RKET87sdA9EyvDoGF?LOC+3-^0`dpGs$L%yGPzS!Uk z7TW1MihUPdtWm38;^X=MgO?xt|4mDWc17=%eSKGrudlwVZQQh;>)W15$ngww1v})K zHPU^J&v$Jm?K+?DFnu`5=ewTt8+=avb^g#qIC6{Dq2ikxr{Cb2fZ(#V?=Fw9 z*2Bglci*F%lc%CX#S6Uw(!=HC;N3Dg-23Kftekuzd3hL8LE2Bs$;r!`3^kB9h0H~G zlTFD~w-hMoH0R|By@1_|o0F4I3&P|w(sLj$^Qx-z!BhlOjnHyx@xGcF>{jZuxuQN$ z;?mQ~f|)Zwno8ydZC4JtIAgZPi>l^Kb#n@HavHT6%aXI)%8FTV(-4r4yf99Iyvg(P z3J_f+CI|o4(nh4IEN?24CaIfZJkM{-tEr4(gyfr3V$k|?2HaJ+n~^t} z1)fvn=EyB(EYFVv@iqs05O}?kvBJm#M*{&cdn!!$`DrCYJt2cNKI{UV*5sfaF30#W zTtueAfF(HS*to$11`Z=(z(WscOJ{i;HByI0cVwYE`ljfbHhAbE_-F+XRAL1>M_t@f z;y?%9O2CX9{G&_ljSdnd22727k^``Tw;*#Y#}vR)*>{a_SPaMqKf{*f8HY%PZp&nt z5M=lQp1eRVdPw<5Qht6Bqgk9^GBw|m1i7VUpq10&|0Sq+n~^;xkH!!0_&qV47R~&C z)Cn_ZHqM+ib0!95Gn-GGIkV(=&~iKrj~*m8w?uz~%A=N)EX3;c8$-#W#U=KORp7*% zjyl88yCQVfO+^5H_Viit#@eoL_Wz~D@N`N|rz^@K@#G9&7OriQZ_ z!KW!B>$5G6$$xAR_|U3(*A2U?*j%=E*kqOmv%Q_BZ>Ck^W*R2)-pw?Ag=s3d>hRR# zan(%o4JLgHjW^JE|BUz0^c}SM__`8JZFm=c`py||oh`xlmEP>$*=l@C>Daqx_%f#X zZW2Dk=Y2UTegABU+KTTcoq`bf-K6v#v?Yj#{bJH|`DPMhHvV@mDEyAnKIrG+IbXh` zM6L_*Ri^RWH1q39)b;(f1L`1fdvlHStMFWnhqu*uYwa*_ephJ;?h`f3x0U!^r6u^? z3U~av62Gm~j5}w|xO2v@E76X(&9Hgx{VMUDC3`~rUW46dzPfZjzPt25*1fYOa^pgNlC}+S;Y0TNWNFNnHZ?xZot_&ud1_<{p*{W~P?tcm*9L9u4yFPd*Ix%lGJ zcf>~DS##w(OFsk$Z>jwRHvGQQWs0}c+U2`S*PtH$Lj6+w`<41NzNyr#_%)^9;r77q zLDj!z+)1$EHOse?{$$MmF8Y6fPk%#+T)Z7d{l6s@e*u>HMJ4SICcFH;i+9V*HQ!aT z>0%xbztF^Bl4Ij?4XBf0%5z>+Q=k_)&8issbomBTGt5_r8+_Qo(K)AG9>RB?w4deT zR|RfwRXNuf{}~oI`eq%o#P6)z#u>rZUSKW;f1hYHVyqREj9< z0p7bqfmF|(H%HB{Xst)o@TOMlsC{OG_P=Ps3|e_WhK0dJVmYm*X1eCWs+Q%bSiD4D zP9#3zt9ox=ee8=mup~n7xu^ee^X=)w~o^+CQW9v2t0?glKLo2sf`;o29(TG;bZ*vVJ8?aC^u0=FPB4yA{sGN#jcLGyW$0rbf7HY-CUX#B*`u z%F{OncLsxSf@mqFGh3`1W5Ev9*ct2y1kO-f`&$+(z6JNprXjp$Igalj41;bmcNpbz zhEjN)fxIkNJ6|vLBHEY=2E7`x3m-}pXoSar-GRWls&QT4y3yWXUkVih#heTT_6!%c zslD18sw?q~G&ioqL*0O-h_&W0HY=Cy%jaIF&IhYAvS2u$O#6lNf(w}$EFTz0*5P;n z$?LG$FS?;$Wc;!3UJhwYyZXgP8<4iD5{XTMi;r)Fab)po4zyWlG^?=b-O4o+H!Qo+Lv_*KyB3 z4}J`#+fd`>^h*a4iLJW={&tX}g3{(2ifXxbUo@xiO3^+1s;jiQXpZPt7ap2-b>THd z^9r%rU3d*~ywU3L^>}-p!YekFx&_zyZ>7Jtt-5{HD(uqS0sIz-j}uAMNel*&{c1j5 zuvxjc;7WB*>$?hPzk8;7&zyV7bKh*;j1@*`8g4Ngh!@t53Z1fkoghdQg??tW{fJ+$i`;`M)zSw#qs8?sw^v0ub^$1;}>`2BT z#Oe>C+&*Mvv&837?m!T>G&Vj43)|Ba71hkBu73Q9YFJfQe^^+w@?_&vPjyO!P~`-~ zfZEh22ws-HOW|b88B#`lja$%GgO3^qQs0QPCGS$VZXsVIn|lYg;Tjt$AD$N8l^>Bb zjrK;?@n#Alh&J3A{OHFZZ&vcB^N}{4!H?6O^c~tQ5|ak{ulVy{_@V@5m30Pzgq5GEw9hjPUECC9jVswjFda6E+ejrd?4U}VNNUC*RET}- zFL~W|Q4uW~o70hM+_YYINsX#0wL;-DK&ED?4)!DpLu-aFKHKh)X1-8A`0=!yM8SQD ztyJ5s7kMLv`$8b_w0NXcxPLy4Y1Gw>y5i%X%niJ4KMr3s;>q+ zmYE8twoAXgosA!$hZuM3R%i`Z(`XH1)jI!c1+9g5KRBfb1(9XbR#AYr&%dZWXsal^ z=YDI*VuL{f85fc`BO_#9_8dIc()g)R7NUj8SbWgi#wsuw%Mh@WL-%w-9_8}oT~?t^GVJio1wzZq$!gabF(;)MG`EL(lc4J1DX4| z@QzWQ1bPm(Yw-sH!z3)f=j6f~Mmi)?P#{ssmow>DI3y!IBnu*?rc7e|KqWhtF2$0; zgD`1QK>>-*b>1fJu_%d?ZP4 zQ|Gfd6(RuN=;st>3moSn2yjVaCL#TkCNWa7RLcBB{<^ZBgtFC;3pXrXIex_$V9y#W zypo%F+|1`uedtv4@b3Ox;3y-;%9Jw83!Y+A8&sB`Y;nULl}ciXTXqN*zZ}@Y9%*11 z!V*zK?oOKI2AI2&JFtL>3StX|Rgz^PiDGUtRm?^>V4M&bQi$w80(j_-)fkIplO|1} z|0qu+jTEE+JSbRJ6qSp7K{+9NB-21bKC|BG+R5|r<9CU&%?SC802^f7y*&>2k3$DJ z*TL&Tu>XrC2Pf?TrFRl!|aA2E8c1f zonnTHbzK8hc(oPweP;+8_ug>^DD6jOr7E4Jjk7)K9AajhqN%d7xe{lEDzO=Cy{xQk zwP;&qu$^b)G2te-_!v5dnRtd&u@BloJoIj_dR9`>0el*!(tfOIVMu*3jB2cI+kYu_ zikwkZEOr5u4mID@HoeRjg376&3P4-Pvty2_Ud!j z7pZsFsj)3EGn0y5R_fk5Ac)4L2-}YU$HrcwS1)b<>Dcf72;`YxzeK`Cn_v6e*cu>X zUmqL0{q;W=T>0DEkKX?0KW`fQ>sZkr@JPtW|15ylSpa*zbU>jffFhxeN{VWVf|)#Z zaw+l2lgqR=d2%_Bipi5J(Eulasz7y(;jFbTj;FJJGkouIgCidoH4FR>7a(v3OvB8E z6Y3gg)zz7Lm)2%`=p15APBRaSdnYSEns2;-W1O&%vd3aQh|75q0{WT`a)ju2XBZg$ z=@LCci|!t(2Cx*cR-^qUE(2sI48{zP<7fukriY0B|y%OXhxk=tL(BFK(DU-&EkG%i5MNU9occDt=s{GhEb#cd+%y8`xyA z!arCY8}hG<;}eR094GUS_}8mZzkfp!!_;t+if9F-of5lyQ`_H)NUGIJmz4hyFn%#TfPIz*^AJZ+o zED-tmpx?iz+W(Nh_+c=80Coc?o}>OV@OCwvorbv!ZZ}B8pbYpQQ)g7)s`mIFmv}JY zPkb1W18m0(&i^FdfU^mo90&NfZ|9s5d^+`h|I_M7ef6b&Q2qXo&j7Zc5&@PG1CpZ0&|nP=hDz-K=f|HLN_9(?Y(&#O;=;fuH|D*nRq z3dCOXFs>F}9~%oG0RPz70ZNOp=f-kW-H=lC!tm0{j_;2_WDuSi%Xtl&f{U>OKB{BF zGxp3!DBGk<8Vdk>T|G<7Ki0keGi)=!PQ6SsBpuxcS`pURYh#dO(4D_Qe>Fz}|Kr$8 zKZ9U;{q;ZG``=?@fBVAE?;Sn(co8Jz9}dxc_H&1-eVY`HX#U|D#OQCo|M@d`1sDXG zy0`jS@cGm$&#(Gk)$?P|JwN?2^@o@K2A)6u{H5tza$W%ry`u;tMTGh5mo^@xyVqVB zJAfGdb^d{an~{`Bvg$ibGPYuKy?T`*evFB&dwnbiX(NX8|M#yy3$;VF zK2s0M*w~-PRvlP1wu&f`1Jr3a#7u${HFhsd&pT@Dr6QQ|yfhg)gtK$77&c0BZfuPj zD;jgg)_}hVRAd=cVh3J_9|swiu|JOe5s@GJ5A_;KM5&i0SJ$YY?t&fe(XAOfIyUyw z<{#I6y=biN$H-kDoQ>6?FIqkH>9PNKISdmM#X>rOm|cK$lVj|F;yb??$jh*OJ!f?t zXfMBvz{l1g*$3zgB8t(>*nwAX0u`JGQILQOksfwhu=?bmnc~-6Rx4%;l0?7#=)abZ zjjdF8wK&2-Uq&i=ys?=wZLVbx$$L%BG#h=HhAhZelN^_*j z8(YC|0k8j*g8;caE#UzUZj1-(%+o#hA2kQteNXM ztC^QZ=eL5rt*G5nau?ths8Wk^@orme$Qr=1`Z$mZsMHEO1J~B*rs~*F;ecIF@2b_& zx{kh;VSWdwFIF=YKIZs|I6}=7`31v4)(-OmhE(bi!M@Yn);M_L+;zX|h^L-DdbAnD zzubBiT8IWzC{!e7B=e^pk5bnmQivaiXa{}{{`pvX8XNOHeDrAYyD)+SVX~5{qep-H z%oya+7=Btsy;LuC{2055V{(vRw>|ZFjA#!Qw?B)v$AO+{*9W$h|8PyskgJ}lhhJDt zr0)+OWyHsBJ33ULj&it(s*JY5DCj^%ilU-E`x4t85sdr5Wel1r!|*Jl`Yf9vS^kW) zB4sZXjU7OY|EAQRIX3+V*Kd7H24~aWsD9_<;G`O=xWFVirX=M6xo&H?KEaLnVx}as zf>M=JmQ$XSQ&B0z36-f;9+_TOax&R{-`VkDzjzQA|p; zn|$W0e%+(fJ!EM%lBUV z(G%bO)}tjizyD}oD)lW8bI*E5icTV`j(Gc027P%;U)JX${6u$a^Urr9s<5B)*jNfy49t>y6FmlIA zAU0Y3GK?-Jk>`?*iM%2Bk-_7DPH7OH&x7qJMk*{$!ke20!fMgK-xI&u=e*b(ws;wWhVI2{wiBW z5WWnK#xC&2Cn8HJ5#P?3KoUBU!ujcOAXn%UIm)2XJ*r(MxLA2K!1I0<*Y~wN6R%|) z3&rC|$IhR#?mtx5=y|EA5Q%tuZZ>cNTkmi*Fw4%OF^6vAD{~FtngRef6#(9p8iyq0 zq5`JUq?^i>k!%k|`W4%JCddiqj5Q#!!z(#>Y(W*{!~)t;+?p>rNTL8*z58=Ind_r6k`;ByA8 zIwY3P&aN&sYqmNIx0R!tRcfwSLuzauFD+LK7LLN$3?Q|IBt;R>}fbp8dQ(1k)J zhrQLh^(xp6a}RzS@Y{%ANH(W|Y~G@9gSonR8}KYRZ@bcGu0o4d(JtJgaVb}v6z0-b z>`^sWZc=LRRYeL{>l;7U30rXeV(i}b(&`cvV-Y^?lySf5=36wD+;^i|d@DMQ+aQ>* z-?-kc^*gkNjZPwWizz7rs{WemL0YD|q=verhxp(<(D+#s#$)CSPCX!AktE@YFc%~w z$a|MN;P25#!rXTxje=GwSLO+QoPeC{M9t&7#divbq0i{$U;rpRReuW83>SX_iQ!4k z&RCF2-8P-Jjp}Rl&~R1R@T5+llcW&`ZfAC@uJORUi=g~#UY``vzgBnYc#ztsnAYB7 z$J0!3T^Fd-@pn-(>Qx6bhfPV9qz%{fbgVCScAYwu#KrP@e1z})ju%5_@|Ei9{rkF; zhf|>BaEv3jp`s0a7Q&Jowp!0sfHb^`iSf#ZnpxatO* z7r5to&UoAu%DIkn9Kd*$LO3b;lfxN@N?qv{F~M zq~53lijp0HC{vgS22Q4b#sUE6%u-{m3!q`19t_=3n)Hv-h4>1Voh{_?0-)1@>Ho|Y z0?$QcLpVQ#;|}&lKzm6bjy%K+6;DOrpag}shXMx<|3Ur~d@0Mu@}t${N9$EdgN>@O zL>1$b9+0%4PR%$Tz*Gzbj22KlU?A7_+3I`omoI*T{N)e8+YQEFlJ)x!@RwbRR-7Jk+mEyhFnImi4G(|_#MoZgT#9Hc z#t-=zI6s%nks%z$5iD34tO^EkB^3F(EErB4bL(Ioe%Rq?tl%kU)mlEnCn_JQu!{lb zF%^D02#&=lhaMw{$p!`zpVl-OY-;3!@NX(fYkbN6{CR~xe=cg8JF0%!hq~8r{@nKb zbI%vtbL;cR3bq|+N#@si+NZkn3~7|?+hoq%ioOvzV6b^J;%dO$Ic{go{@gizZ0U~@ zGIvg>uH3ouJXJ7Yu8c|f^Xh@;6MC+kGfzg6e%t=%e@^?U|8H(TubK}6Z<9%Mug{| zKVS5Z*)@{fF)S&8W!6c&)JAyt%#iCODbOE*C#;n$%v~!h>s!Kn{IH}8}wt# zZeM!D!o1)Z_5=oy)Pv7dtK3vXoYjrCj0Ktv57STfX_2Kgh7 zb&^}ohrpuSb&Pa+XJ4HAGo3P;f;%UFj^NMG>lxC%*uZkzkiJ~03WGs)dWR1MD@1g4gYv4b%tj-*W@sE1;F$#5Zdf zUNM@x?9F&w&l3@rI!v(8cgnR9W(U8ijhPsWb&9FuCQq4m#$@ILhY@0(9SV!bT%VXT z7m;|pRMA_o5L?yWV(#R7=PC5o%VU08ycO8L=L6~&daG9RLt5iqE;T?O5Ocl9+Sz1CacUAN(S zN|VRD-k7&=Qwp2;=P6nG^w#R{*YoDccRWWWcHDf6w{Hyu8E(DJ^Y$03+p)jD>b6zt zK-FCx>ymdLRNhsG?(y!$D}N6%CJ(#+034Ht`iSS@1l!|Jc-{q1dftwNci4+R1tRR@ zd+SggAM&nwT7CGLk1#H*(J+G=)_KpWYZAq3hxeSMgBktk^GFRbz|0GV;$;uO*VSd4T z@l&7nKJ(en!K;DKe_`PZFI;`~7r%H&efmpZ#&*7h3&#yey{2JWhXU!p2HC&ID#B1} zt=W6`Sc||uE!GQEA3{oxQ{8>sv*)HN?2dDJ1}g;Yc4Xha(@UTWg-P$*0|7MRJ3zN} z>eTVWzeb1o^+xn(FGBK79oPHzTy#LW)~Mr0-sZkN>ES8>I#>N%@7o8CA49zFz5#b} z?h2?7<7#F92>N%9+x>bFq|=3FpT01;9_uLV+4YJJ5PVa}Qwqy2GdA@7BpvAD_%3N3 zYM&l^Fj%oV3>w*^405#-){Ud_P0dCDGiA~Prqj5SZCf6M)ON4;^1pGF<( zA7d)Rea}7lLHFaC9fBU;$c796z1E}2hE#vY<6}*ZpqoiQw~Sag3olw53gH^pP^c%gA+&J;uG$Gf{;f8|XK=Y*zH=AoFADWsx)@8c zml?m8UlH1~ICSM+JW7fid=;eMZtM-EvI-+~(>9Xc99j~(<+6SILbu+Q2<=aVmfn6x zD0Js6RUzSQwCnK)5Kky{KvgWh>+aCOLnwiJ?hS<~?-qIxafcpyIP`&w7KB2NsL*AP zJ{Af=-0d(U3q2*_eDFiH&_56g$@mE0&xS&aD?-nO9{lJ9&wuRWa9e=SVRL93-VuG_ zMaDG?elJ7-pJFHrLZ4RKD(+W{L!Xg!EJmmM+0P+yfQ?Us5)1!06SIKk(8i5l65ZrB z6#DYS(5#BDgkFMM=pj0(P|tdXBjYA?jC!yW6ZEgqMA{?U`k=o|gN9ci)&}^xm_nhK zLXdC^{qeWHjUWts=etW^dg-Q{zW2SOp>Mv92M+#>;SerEZZw8UGXBMUfiVuDr2`ll z_v>-?sR43w=)z|7Wy#3BZCG^lt$Lh=a8f_{xL4Wjy>S>53)BwKpV7?mrqeTgeq3bY z5Wvy2FAMkP;cHSa9tE9|h5P>g>Fzp8br@N=H;=SC>S!9WaMSxhmn91~^CrwH@Rq3_ zTYq|Nrk01pIQu5>uA^xgV}Ew+h7|p0Wa9R%hc7J?hjA$2%fxl2-^5rONC%#JMUS_f zE@`X_B}gGTKqjEBxT~_eS(5E4kREhy}%9w z52P4>96qrJlg6}+doCQCdu7*UuyI$V9N9c^;Wb_Nx7cr?%y#Y=T*vTID&>#A>5e*t zd+Ins&y2wg0cIIjPaFY;Ff(H@hg|>@h4D}F73SFLU{eM<^4S{&$raxY=bYiW@V{exw$s-$Fm%ea4|+!@l)5g? zM`!7ItK(=nbV{Mu&6!Kp0H=f+U0~*~3+?=M(PBdbQFOunFn|4Tp1*oKk}|^^WFEWY zf5|*nkE;Xa&(W7$O7{H!?}H#JKQZJ%7dU zcIWeb81Qn(&B4aZKg?hIkC6Z0jgRNdtK-B^4}*)$__)}Pk4wyS74`;OrYTRypZsC| z`rkNz4K037W^kCtel+x;^M`rtU@i4M=dWk{VgCBRa{l@c$1(0@#$XJ#buj-9=davf z#mI|c-_Bp}d_H#^MvG1kHWu@&*MH0WHTx5j^Y2*);O$8A9(uM&T6S;)aL#{u*1kVL zghWfO$qR^Z8{p4cPU3ex+BFtk z=m-qXCuKEBj4ajcHO1aWs< zmtahCQ;|}XEYx=zh&`@d9i<6IYwf*Mv?*QjAhdN4xdYTUY8p51L3E!fXSx}bKAc!p zUBPtK)Fvw`>l-St0j^X_YXwdmR;Z?GbO=ZTgGm?BD=&SU#Tfm=_1j7wVXY=JXudB8J6m>(a2gIeUD!Qu{7SQPw`y z3mf&X)lwJI6rMtYep6ZdcoNt7O2TsG?3o+N*t3oGm#^2d^@#oih08czh|D}x^^SN7 zK|a2dNqWC>@oIdRO4j3g0`WdT20qkZ20l+c^=kh$QqGO~fexp?`dh7UR%9Ixvf@2> zZ40j|nps-zc4Pm^8%&Uw&;mks1JX(0eH7_jaJI&QfQnO#GeMju+5I)sG_$l3K8`18 z9UKjk8~n%nwvID_ckv52lW=V+cjT}k2Mf8DV&d$HXPr&gIege;?m58dcb@3y(qaAr zssNk>=JnRgwQ0pf2)10vV>ddkwOVtWb?Y?&!qHg&LeDbs8_Qf@!w(7FmJUY7#)0MH z@QPbGidUl)l7<>gL7lAlfv*iugqR9^yE~;YoCCPV$8qjLlI}iu=#X;m zQR-gO3tW7kv%kQ(ANT_gI?jPr&O<_tveV9*%5ff+_&(q~;y8~wk8N?B$LaD!LOpr- zDdfZX;D?;2KfJp3nU5&v+2`(Y@XF!GMU=+*q=fL$3y4(%%r8358r-Mx8K9rV?{m)Q zoiBXxOP~AlS72Dp^!K_ieHHg!FwRvkzv4Krs?R~d30G7)YnA&@Lj95RbxBX}Ha( z4Tkq48leA;=wgET$3g=8WA1UFKhZ{sAG8-cf9w48@BY3Q=6?_u$2r(d#Boy2&wl=o z&OiO)mmo9n&ldTW^N(+w_?LfuQ~e+35>&>&{asu#R{aT0f@6PJmowwII z?)T~G9jEu9FTmkl$2oFZCJz0ADKKISPI zb#4>-u5)F4spFpFH#yGet-sE$?pF{}XMee&blwT@T9g?QNtRjM*Tj%T_=WRh2O^f~ zQ@=d?Ysw5gebXxS;;Ufjf39VQa288pf3rsY{K(ss8TzSH7S$@JC;5s`<;W|0YZMW4nOR# zaaYZOToLy_H{u8V7|iJ}}^?V3D~KB>ft81it|`Kvf-w z>{h32Zh~Ok&)?>rXx@oBR^6-r2NV}YPo(4HPjW9bjZ-*ozdJ&>`-p_6kG_#k|EO1X zQd4XL$aXK%%T!=8h{EB#P~Xtf8$FdyF}?b(5E9_`HYlL?o;*%3ou{~q%dEi)dsQ@*PEY$~`UtL}K_$O6j&&gNNhi}sJNV|w-D_yS>x^PRpYbo5!p}j^dXd+DN&K4u-J&Q$t` zU0mM=Pb{UQ_g9f#@-n^nz}C-z3@|6euZln&Ll{yv>U4K{VOtu(osv6K&^nNg064@W z>0|P(rtxX0lRrV>pkUAeJXB9~>7x)oKM6WgMj%uS z1C*>-Nr$1cRCLaUBn*-Wj&az2qoiB z#%jyzWUoJDNCsI)FhhKXMu%X}wAk>5h+U3VvsNr5f!JE29mfxK3o(@vH4~A>#PT%C zfb{hb06w#$*MoajaMls6_`N_^T_4D<*Q9;)(?7bw3Q!ZjhicPd$#Tv9ftmM=&xT-h zepDIIOBxw78ld6iu!O}nVR+x6&eh^e%z@nWh}rcQ#B4jm5d?9u%S`#kpIvB*7CKH0 zb~&MIV=~KDe@9)Gu*-Ln-V7%B7I{IY0qp_JiwHk&)T8!o!;sGrmf|I8yqWa*nz0_B zz3=kXw`7{~uu}{_c!Lb=EP2D`02rivGc!%z7(KujS5 zOJ=ME&BUXzjPu|a$|uWhr@0Zly+@M1qLS^`JHV@*kxIK1Ah~kRcfe?%HnK0TH zYsUexNOGl)bTm$8W*Bjz4n9i&zf9iW3gKj@#BoZ8Ib~wQsqjF+v#ObQRdK-x))26W zzj`0v};Y%!zgX=`FWI&6tQ~-WDGnjPI`kg7dVr5YiVf4l@DNoo&Wz^PJ z7Wktxm;~G%E3_EAzmIk^1 zb%bhwC7x*kV6C!zH1sj}wb5cM6@t4Ik27IFPl>^NTnTkMyP~vSz{N+H?j28e_EA4U zH-N@$HKI^T^Np7QWp}w9*66NeR5SPO~YKFmlXSY z?b^`L*no3e4LFh3-~$?SV`E#}*s5M+Pj-DoiA)i7;h@bodh zKo`$a%n|^{L>cNHVa#tROpA#WR2q&BCEuAeF|Q(UjFaqHUskR4Pe@P_MPqsadrsQ$~Bo zG5nxgHpkBGp>rgzth}VO0(xa}70#KLl-3j%%dfV$n6W1jWrIX3+eX+ol6xwpA4ZUr z+L65@CW+lKd*cGW9XMekttL&5V=D>wdrRNS&K@v&`kA8Z&82qq=yIRU%np1ion0#4 z0W;2zC>*{tbaDoh_&LU63a*K&nvZR&F8mf4%Z1b%7a7w4Eh#oUBS656=p^pXl^&q4 z?n%j_OMA@cS%!Tl-x!Yd9<0Xbp+J2neeAd}wr2X-cepa8a8E918`Tl?VuvgB-py;Z zDTO<5@k^oGUyq&ugADd;R1zBZY!vRdHFqMZlfBmpTw=*m)9*+2)y6$mbK0Zzm@XbB3JJ`8gyQlIKoVd=!4n59l8 zu{%pz)n)D+LI?!LjJ2JU5*`*({oX`>(Lyt*qQ5|PiuwxmengpXQx+-=OVN)+4ETt$ zV8D4B~6w4nR1tQjZoNA!(&Ygdj)YYRCjZQbP7 zb88qhTu+h-KPu@b4AiTqO1Ta3Msyy5P8AQb9=29GxGsJvKRRg!!^++%k7W#@j z!!?8LmA!T~Q)<0K#nCBhm}T3qnr&|&(vMBf1jV2PEDJE4;3Na-yJ z4PRJlJ#-W)u48-UM^L+ns#GX-1Rdq6coGIw-toiqnxGTT1W6YvY`E%7*TWWppGebD z9mnsfz;WouRkyjn4V*TeP<1KwqV5UVO9GHu=_IeFL0S%86(Mv<@7pW5ltQ0rSLg>S zkUXq8XPwQ-WnaXH_#HyQ_v5;r?q!S`4EaXCkMV7C5Zw>kDKL0;10l#KajnO)>3UWP zHk}JS8PG%4fJCBB`hQfY9dfYxjbT40EC?e<#7jl6VvGABHAwyVglO`d1oDkb(R~Ml zq@Z(+T)^w1h8P)qinwkG;iTXlRJ-xpEe(eerSQ|flY_6<(tQZfqZ5W9b3<}wKoSh) zn*{;XR1oG&1;HS7G(_mIwuLK9S3fdzQOG2ErvkAC7X~0pV1Z9KX9HhM7s$QS)!1|I zf?)18B&zA%6k2zk#;MXCj?(bOcD#18X=P>PfF>A3_5BRuHi#9-*}4XSOh9JFp;M0; zQ%+Jcgabm!b;^kfV}%B*+W@S;Ec;C9fvB&4J3y`bKKsqC`_HE{pQE1x>n&SH6ZDOy zg5_)TEwQwq`=TtHK~bGQux3nN0IJ>3QRu9)z=UQxvMh%#`^9(+vnieZ<)ea%j!@qP2=3}5$vIw-SCmx(sh9llo+%r2Om_{~g(y%ebI zSJ5xPY~NUNvc(+G$?E5i%TiA6_n`A{)eK*)`l?co;`17spU#dM>CR+bV z%6CoKX!NvGsibkTV|vCNchI27>1<10liG0yrtIR)!F4OqK893T{+UKN0K=nn{a`>i zlGyA56AHi7P-N0I=C-E+;rNB`4_{KBS)u9DHythO(GNqS7jDJ{$EbNw(9xRZ=F<&^ zB}x|yzT1F4QCtjJ|626R3a(hJ)il|b zW}0N#Kik+LLx0;Nqw*ahIk&NILuy$j-2z49i~+m<4IJ+g6yS z&xt$t3-kjW3bD+LamRuT!0!tN_4R%~pZ>Y*XBsqIYboCs`fEHKntAA=Uzes05&P~? zKQ}yv5evve7{=NL>+60>_#Ja6)=B_q2R%QuvqSDTVy}@KjmDpOFj7p|d2~vRy)(>l z%CPy!^=bQTL7kHn*LtXSCC9d2etax#UD%vQ3b5P7N64W{WKCi*02JGNr1zlPn*K4>&V-{&tEu+UG12_5VAg+{zUXNb`ei?APq<2^< z{evQ&P-Z-EWnzRh?PKHb!cTRpFq@(7j=lqoG56so`+$-^nz+44>l8HIPLB)1E=T>5 zM3q9AbYeEU@$3KX7+!?&W+3MSut8@CPKRX$l{MqgKCD}I1ZYx{9iccw)7jC=j`v!J zn{5|X*W|Dtyx;T5EMjy^o$Jra71&^X9m@eW?X*i;hdv-I+??>UX@wN-rx_qEubLZ* zZ_W)LVaZji*TzzWwS!k3g*pTVqdviX-1-HCJz1~c6Bb;Bk%ZvzuAL{$2N?rQqm zy>Ank|9-$qM8CoHTs+A6pRDOMm#p~wieccz696Qqb;Gg$cP zx9QGJve--cW%xCVS-y^WGX9AAxut=#LroW=H`D<&!|{>f>kqO1#^CS0Io?0P@0ngH zlWc{p1SNzeL3=__@9mlwa%*Z?ve@LHW)G^kykypGgN?l-4~JDIPsSaylU*13-L&kA?t>HXq1TYcv z$1pDtgI1P7yHKN^v0k;>AZsFP5IiHmo5hg}*Bk3dq}yOU8#Y?IO^HNgGYn`W+ai(e zGb1~;T@u*|i(QvQBA4#AWRc4*zk+yC(Vk18;oKFfGa>can~L0Y(@jN1D{$ZnS2so? z`x6Fkw}`Lb0l&e-onk(aNZb{e55_#Z3QUM;)T2T=w z9wwgnfY2g5z#Wl?A4xp=n9w{fCG&*PBo0I(SCcsMB-Hy3(^A7zqHT(NkUE2)au@Kc z#NnY2nHVogB%T(V4~rU!JQMlIvp}Dt@rpeIR@u{mk@j74h0;m;ObxF?bL+~=*;7ruzT%?q;V2)G;>D${wlO;st25_rnA~;n?qcxSaM26SV zp|UbrpVX3XyuiG&vUP-pk(G^&7-nc_s~lU2P9q$iIAW4ES2i?EuB@CgwV`2Jva%A_ zv^O-=HH^^VwN7UeqBtK~**{LFM$}$jtPam9s(4OyPgtxm7bN zE2me^i9*AFWhLCAGv-uwABjPw4;hYJ7(cy4gu#hRA zUek^kXG9}aLRcQHnS}rKx`LKdUZInxoUF4>OS*>JC&2iwX@WPUmlF$ZPA zOjYW_S%jb};Lcy!VvL#v1vnJD0+qFrHCAxG99a*qo*Tw*IiP4Re3VAY3l^=pC>kw~ z7DUQnu_n5f)W8Z#p(8MsPyv(z&E&&|Euo;If@%SpPsQAtS~Lte)W8h7qJni1I&{=V z%9)<^XkyZcSk?v6LTb^%?#jv@L<5LK&pfjRmB%19kODP?GDAVsbkrh;Gp4hoLD4>E zR(nTuCh{GPZft1S)PSb589(&a1>3gI-4O+T$xblj!CeJ&mAZ8I8W5r-URGD%fcACy z0 z$^hkgT~xk`(z#I<8HxtEFQ{VSML+IaDHYDWZvz?eLSDB)8@gi*a@N`u5tOUx^^QQKmc zS>P3r66qCPdxJ?f3nWRHQXqF`-vGs@ocugUE8=M_+2w#oQ(F0v2=Bm%L^xps6CBXl z_fRSUJTt-wB=yJ$%ML_LIwtakEQ5l=LcHOnOkgNuJoJj9MlK@=fKo|{70YTsMp;&p zZImIWp{!Pf3R@|1)C+u~F2xB-282I%!JrfR?c0mZ?@GxeXaHtc07X0$vv-aPzv2BN z1H#O)=y(4}j@yvNq~cmxgLQ8dgja<0yJ5pRTV21BXHCA&Oj?88B#>Py+)aW;$j4~t zY^7o;j|C|xEUjh#WT}nvSX^@B4{LqZ5HPBRBvw+@H&FPhi6;aIEuyxzQX3(-oD&$O z(b4*#07bDxC{-D$RPAaXX){-yXn9o1rb7NoshOIn1FI%ovjiVI8<(0x+6vtu0T;k( zL{-c;h`yEE8WgV}Fn|!2;PQ`UG#dZsi4(YP>gS8$y%hEarXhJAdO3$TzHlZAYx*q_ zRfmF))+zUf>7`q&j#|Jq6F`%gg*YfhTaG~R;7iPk_rhq3P>pUH(>BbAvM~lC!r7f&u!` zdTpien=!Z+a9e0h)MQy#8Hr%Th}u9U_^?!CCCfC)ct_U=Q*Hbpzh*ISxu#u#3u~-@ zQ|VLkqu$E!`3ref&M;@#1sAf8bP22?>1t=q^u-sg_25h>vBH4B*O8Q<)cS5ZYUrU> zf`unbibZjy#9)ezezfC;F1iucX^qe4W|9wljZ5uh#SD7D&CK64Z zsFAid1(Vpq+r-IJrtqI%@I)nqRK`MqK8G6%GwE}n|W#UASv4{XYwhTCkf}X)jf5j3Vi&(XhE^u<;gfgSulu>OX zk($YpTo$B5C!|Q6K|5x`q_N}1DGc3!Hf9EaAU=G_EMkX2GAB?*kJf>XA5CC(>4)os z82YgcDg$XAMWG4#TKnCpIx&N&rc?A6=Q7vyB=Th1g&Gq(-r6JL$n_bL_l-4>lJ)vN zq3JzCZiL`4UfIf}8$Bl1Cdb^Cm&XO799v_Yn3p$c^59N6wvCNb#3oasEXaWQl)~UG z_3#q1XSOJ_3=wKVB?ji|SWQfZ<$6`GlA4R){M3dg!?GA;Y#vEeKNx2ztX@AxH-9ws zabkxfB-Tyqd}oypt=hhb-88`tEY{wfHL*R=bdERd@@CAe@92ago>Z6Cw2JjtTw#`N zqxd=*29$;8${6n-^;skso-zsXHIrp9$#W+9dL-Ohwr;(I(v9UWJYB*SFSQ*uJJcmR zcVX_dTU`dz<@jA8bp4e*S8my|W$&Inc*aCKTqD}GKGk(TCdl>ujWpdLR?`tq25ywQ zwdA%Ubt~^IQn!I>KM8KXL+I6(+qZ1F^T3|F_5kkQv*)gZghN~I5&htndo`81&*=C2 z>u(22p1M2I0VA!BZdXc#xMuqv!YsXJ1HCoqmU%z7gxhU6+msKOH?29Ed*Yo zN{SJks*cF$qNUTEVnkMr5xBUeh_ULOdUhGrO-&M%Do*Cp9>ZTn1^z24Mo__y39Oi> zF%{u(n?eE=3Iw?xI~F;Pq7=prD+5*-E+{Mua4CWfl&Z1q?JL6JNVqA# zEF52Xz5%?%dI1aLGb-8~jIY$R-2w{Ej`+S0ReS~28nCq@zbHk0R zZ{RB~H?9$lC=55;xCZ@@hFkXeaO-XR*^EM8o0*mm#nqp|BWCP7I*zkz1Ha zMk|-14kU$2JMAPKllCGT(6R&~&LpBQc!MwKjFeW|Cq0T$cJLV=k|4`evW9~75&|d` zR*oQGFBBBcpsX!DyY_Sem_3Gt93e~e;X>RPU6g;S$sPUi9aHTa(B*k(Sft?soBqkn@EBxYN?6~7EB!5hn zNez<7K#(B=`l?)WU9P?~7cT5}P$c{(h97ak1Qi3K%jXIRia|^6GF*c2ugoI$-(~qy zS_Bm?k73=gALQ=GW2No)8)7-hWA$Z0JPRip*M*X$`sHKFLBtd?Wn%gMU_6)z>V1~7 zA)$P5mkI_~84PB*R@oS;hk~*)kkr&#I;#)2h}G+o785-y4x;tJhJMb$oah?)@v|R6 zdor>yoaf4SZtmzpS&1k(7uPTdX#i_5OfFlLs^DG;He*j!8`ZMTaRW?^revVGRQE?0L{IaqI3u#=W?G~3U5#xfgvZZBZ zAP2I{kVAuMXkbLv^*kWUC1$Zb&!W~HVT+Z`xv#H45c-m1alha~!m8DPHJCKa(z6B| zno`{*J@DF4QqryMHXz*_vxqYB3AV(KM@m zS|rVKSR{&mmFxCp1=xu|aPXq?;72cg$7DsA(S@VMAT1~=PUHn4kO_hahYuCYV}DC> zq)hh+pe{!kB?t-01SQ;KvBF}aG)Gk#k{m;a4>KA(+f^Ywlt2Lo+Rf3e(Xg(n?57tTYT&3_ZTxd#Fy}6JCi#-;aTbksrwP8e4 zGryp`ynOufV&no51k{0GdH_@uHb3ys!5gX(*q7RaC)x@?qn%i3Yi*<*#%T;d!YF`% z!xG0p777$IJSlVDLWU?(U|C561}Ouu1g4#Ibd19S{aCPeL+F-_I$9vvt=}4SOGYrZ z^VbqtT-L&bgsXjUGiyDJtf7(W>7fm!Gdj=~zzg>t8eb?>SJ&8BU*Fp5IFZP-Y134G zZAn>0RRRl`Spj*q@P^@j^yoHQhHSb3&8$Gx&)Y!7$`QhIgiXq?t&Oxq@R4e+jh`}w zDb5&HII^fHCM$4Irj471=*EuK_a8CZ5IW<=derPNR|TWdyuA3BiN&Kvjh|3jURjN) zK~1t@cwX~}AfGt|Oqx8!BujF{%c1hIs~4%LKxAb|Qek0Z9YoBhO=}xHdg|1|#>Ns) z6}INrmQ}R1)s3FcFl7Bt_Sdik_@2j=ZTtBT>vn-LHvlGOP{{Oa*dvzd~cXNgJEdJ<{ant zW3b{p7K`BHppPG;CQzRUGwdggojh9B_RP8-*o4uHY0{apXwIu;#H`w9&{|;zFQ6|+ zm?gXewuaoflg0WRZ~-;*7i4Gm9PL5Wg_xs{mH;6G$43b`1Bfp>FK$P7y({PYI3E~f zA+33}QfsEDi&n3dU6=K1F=F>vH-)7?9|z*Po4dEDt-vnU)~>6WDxatn{slM`0odhk z)97}sX|;5RIT*3_5^Odhy*p{YNxATk)kUZ%=iQnX!gLzhGe%vhi$t5D?p5k4-yn#q zHfLLybof?gInp;f*C>@)m4r3w?>dHnBwSCbR&~RT)M4(Wo`KX&860CF5}W}pO`3ee za$&{+;p-M^t#bMWYb`U}0H(NF4#0)bHcL|kvd}5S?(U`N4eUC^_E0SQJ6gC?cGqy}qT@;_cP;!~q>Z$L9` zL+~>iG>l{HIFD?W8q3lcufln5k9mJJ3s2SXG6R+}66T?RM|&I$ zT^AW+zg>fTGT}@f=q7+F?B+K!=kS921hED&dUQaxwosNHf^q}R9(-WNk5r=1$*-x- zXEEX4R4ES>MG$j*ax`H$gFc*x1qo!3`Dm7cKrt{n3C<0(pmPD)@wp)2VnDFuiO3w$ z3WqcRSO}3t4p|J5rlyBK7bGZE8S6<$;HrtxQv(kmY?clYgh+)OU^N&@1}yo76%zmr zVKOU>8)TAZNt9$+lBCdVm>)2OT)r6;{Q0pFQATSoC`fSDT~vV9&U|OVuq>SDu$<}n z@13#iH%!rhGLi~}cu=NzjO>ls6~?$;-+-Mf*0$`(VRp;O?L>DHWcBS!8v2n5jxw%0 z*L7u!$d{&HdH$0B2wd=fJY8ssR=Mu#H7@s=y7d+lc9^#Bp!ofNrgq8B9GLeT0~5UK zQrF#$frxKtTz$<3eF!=hbeKW>_#Tvlwak3r1?Im0OJ`X&`BA81d7_ zwW|vh9;AZ%YPCkp7s0$1=5=EB)OyvedSKq5Hi8TDz(bMG8xKB@yT04G>#KH3s==Ls zF}n;qzgLKPkGc}2uoqj^9#}E#nSh;g)OBEQm~2hU!Bm z%%`D$7@<83I@=P)t7nAjBkEc8ocgGGUVRMakE28x=ScMl)UQ%CGUsFd^pL$unqF%+x-mBEt)i=~@ z62dptAFFSvZ;P+*sPC%psiXMm{J$>xpQt}o-&cR8{#^Y){SY>Pq5e|+mHKN#L&_hi zzsWLbzgGRRxEw<+j^p=}0e^q%+k98BpF;gR_4n!@)X%U-{g3edPwE#?f2sZ%>aWxr zP*33ZFX~?v9=%cjrv5KX`tL2=^Y&}_|93IJ4fP%T-c_fJdm6fOEcI1bgUZxO2BSN_ zUaMMq>MrlVhi=<4-(B?7F%`m%FZ^Sj@I-As?#Q+w@{a6?|Mz2+!E>=f_=!1jhiBV) zi*^KO*&{f{4p~Sa=M9As+)-E!RsYq9UMuR4)o|$Arp~xqx@>CVHeV4Z*^jc`m>PuQ zMb!ws2`SV0Z-%MG_v@)vXRI3Gux|C=YBdtBc;Cy=jB(lo`-mFLx1ZEFhb?_P>?Sx9 zotxAoNB4(#^2?bjWyW}>IiFQ$IMbc&ieHxgJJV@*l4^!C)9FA-+xRj%{dFRaE@zfA z+c^urv+?_{H!-F;&dqAB!#?aBXI{?VF?Fsp-&x=+G$mroeUY;`%VvowVY)6A`%)>< zWoT39p){8B6)@*~=Sy(U{*!mXP-Cm{TZ5;Y*23>P{Kl&FPPfzJY;ZQhbcfpHd=Y&E zODo&Ahp%$8#I{9Lx*bcKGF7wToJ6FJck5j6y6rVcoy}+-+?`q%f8sA4IF6Nv4si&@Wu5*?; z*Mmlz@#-0TUW4{Q^8^P^pc((#eX?^C+-&(I)y>9a)2CB078DxO>MaN*W8NqDtywl1 zH;dgSt_;WiX_riHEaly5Kk9yxy50GhPfI^{HIH}-X>=H9NkC#Sk*X((Zf{>%~Q@#)Cck7--kqh$}fSZoew+Dh~HZ0 zBaSW^hViWPoC%S=8T;IiI?uxwU2H%2F@w?kapx1p^hxIhJS+Dp=hIl>j5we1W3sjN zS>M;^jGGQGf_q6cP5*LWDA|8ic%yE-jJ%p_eJ^#qOb2D(!AuPOO;m~kV6L3m(g&6( z(#8a3pY&3gIp!TJtEsK2sj3+cf(qlOqOPVcRtZB*O-0fKU$6Cs2D|4#+NM~nxd}?F zr6m??r44{PR2qwM^T=Ams>R|XMmC95lnI;Km=Z9@q#u_J<6)lALTkj*5}PZ%4o$1Mk7_NG1a8~Pm0AR=EIWyTbf#1V)$=Dv{RZ$PhylkLTS?UDpms2&?9Ql zoA9wL26~$z1Sw$RC9W86Q=7!Yv>`G?)rtf%jRa397KTU>SN(cF;JDgBJ3{{7V;EVYh>>vy=abuA_r~W_HY+*(8`4VB6UVOcypx$yv3tW}kKT z)Twi($8=K|Q&KW_u4xr5Ob7vMp$_cWIf`wTCI;k^itULZJPB#FXn}(Lrs@mezrMz{)FUq!0EY=lY&14b~1R4M# zrks&l7h_WkYLL*;(Y|ESQd>Tto7!GGwM3mu-zA6wn$YPYK!rC=wOK`OJ6OIZ95KR7 zTT?EbO)L-jOvN6=TJJ=W+MdA{F3q+)tJ@`CQv9$+6S3sFM!0v+X!SedP0QN#$D8TZ z+O3Q?LvM?rcTsIpU@+AbDggJS9OL06Sa!bZ&(O&B+$X^PShe9B)duuc%yk z{>t-fVzOCNKM9bxdJSkUT1yqMsJ*?qeO;_YG8k)O&z)FbQ6u`|^78T!euOfuY1Jk! zHnAc$k)c$?x<#Wm83}5rSJnt{EC7%IP{9(ZBw-8$v5LxySVcuSJXIoA$b8n|OfG%k zr)fBvXmZ%V-u{UzJR4m!tsrI~J=&1i0JKL6l7%GYD=xq!T^R-GwGrvKYmgej7^g%W zLmDMstc}oui+gww#rKe|04~$!THX;uaY(*?@WiW;jjPkkwlX@Kz>JGUT5XV^JVjnUN zmUb=>WKdeD*p(=>?QQLgw$lXbR{0pwN5aU4)dGQ80_8=kcf?l4Rx+0M_UY}__!2H@ zYLbjtWvd`k@Y<@WsTeY|k}y#(-7WTLc|ARs_4MqzyyprE+|yDN>SDYS$llRct-1Va z>)x~H%AQ@T*IgQp#^*!8rJ&6-Mg(_y0@kT0fPn}v?yvI8_-1*w}_ zb$5J2leI-}!(Osg(xZbHCyCPz=1tY@rhAh>I4HHpN+d#b6l4wLM@RAOsHPjW{IO97 zGg&(wB!-7n(@l0@XlgPd%Qv$tYihb>AK9)6n)ez%Zru3s<8FZlFvZl5kwc#6Nwo^|mwj-;StydhRgob>|&BQ7JnYubB!PqSxMez!X5N<*sc#p`N)tJ89q3v!>^6 z(eF4YTF)H^@7O(e?IBkAJvIuhuVK8IUrSS2&z<+eO8SJ+>OPY!)4hVpX&-4jYpXLL zn~oBjjb+vjUx5@DiA>K7)E`Ku+wZ26As={ z4}PF%ZAH-FT{#?zJu$fJo=O7N5h5xnRp_RFxK=vN2mJoOMa;VD9?S;aE9icW9fWie z(9zILP#ZV(^x&Ue4IFic1Dj2>!-)aWh|-n%0RTZ zva%>z=@eB)ixL!pg6MUaB8NCs0wLLal_*XmqM-y1XsTwpEFlp}s1P1|iXg~v2u~mt z;D}8{g{p`a6?sKP#a_sZI&N_hUQNNl8|DK&4N@+j8@D zEi5OJa*+Julvm4~QB6dOigCw7Bw}x^ir}_~|JmS|i$z3W3U~b5g#o#L1Es`WVz}Wc zM!v-;&oIini&fQFA;x=)jx$`m_ER7uR_`=8jurcA#zQx)6!x-mU88_QfNPBJi;pte zHyOu`x7HIZV)Tg)MER!XSoSwg6Jy-L!ta?tdFIJ+I-Rarw8x=~ESQ~z13e4Bvwf>M zJ|@WAbBuZ3x$_OSK=g&il+hMxbaBQe3)7ykpq2}?frvvEP!z(@iByCKGetD0^G9iq zJp3qSLNg^n0Q7<%1&9TBaz!AbHBr$82oxGO7#M^eQYZ!^VThwP!2(Ch2@s|bT@9m< zDNqrV*H$t5d_1_;`Uf(A-Fc&?IUzc1$U50MjU1KoU-KU|54yl#&zB z>sLS_OCw@4lX3*QFh@61b3#9j@>o9L031Q)@kGQeo19BP5<7HU2L<&E3gG~_oeJRD zAFb>16@#_tRMWbuX3Z`+OR^@XXy3+|>Hi9z?G-@eD-8x|G0P?6pz~%zgf*Lrg{Be%#O_=|oFlPwlsmva6Ce<8&{<-dr(SYjgZ%iSVu{N`&k zR_tTUCn4Pp8Gzpjf5E<0qL$dT2^Mil1+N4XcX>o@7*O7jWkH{5F(x@j4{_xhjxMlE z(!QPwp+VF}3>$L8$bT|_VR#COgX{yqj>M3g0&uXkFcXOI5zsrkWVB98Pu9MtcWYcT)}fnbihZB$|$g-+^ee@ zPe{KuG)~eF`3g0}?hF?>Ov2Pmy1q$!x`2#!#8t)F`?KSmk@8X*Csmy)P+PpHnO=1OQvreuyqA?M+;x~T6#ezfG#s(xZ zgE}R2CS|3peJC9(XU)nH!muwN7SW!i05i*qxo%O2dzJ)-4x{e z1_u|1<7(^b8=G6{URllATO>{o&kw z{n8z~UH#=z;vDIb!_^{wuH%4f#%Jq@@=9|a)IbyXUA0t3SVDKz-hQM$U!#ZdPKo3{0LZ!GUV3auRB_$)oStp>JH1Wz|I}-6|TdzvLi;!SPEEq!79Mgcw8>E zDF-D)eF1A(ydx$ec_?M*>rg4>(6vF8FGczK)oc?Ik3@@=Z@bPdM;>ZhrM{%DDyz}j zfI+?N^4dD+fO@RuH8*qNRvH2cYwPMNtII2+#lxb-p-4EQID(-#aPFwQl8serf+H#r zmLfX%{-Evfx`+?`->=Jkybfga(hoG>L}p)RQXVJ25W&PHB7;E$mbj?Zar`ha=;VSv zU#wqlLtuFM2zS47>CqC#1Goo-ppR)1E2jde&{`mX_0+0rG03HDetd%=0qGFfVsxwF zbsqhJTuDWiRj6AVx|Km}hK6@;c}R(EFL#3c1j`q=Vo$M04Ol5#Iqp5i+!M~_hL zU3&fQ+sDnAs>aLvtZBS?so}=))H8W`&Txn(FG)?6(wgOIb2DmOGa4%kwVO3frp@mh zG6@<2LpzcsSnW(+NZ6nus0Ucf&5r|Yvn`6npqZy(*$%llQ$jo3g{O5>#yCPJW~5B? z!dRYo#Zs}hFUILlXT|WhEdMUf)g_?*pR^TPzy}vMpl0b zMXw08k#6ibLru+G#DQ*CI^apveefAKF5DPfT*E=&RUCjBGer|ly|c^UM#B)IEGOr? z*!%L#P>%Dq8qSp!E1zus93Qm^j;gSdoxA{wG+zo!7pWznyYv*aknbW;pz;&>MOd8+ z<`Yrs`Dy~YienZ3*VL(D9F$! zR6GxtU%SK0>tux)R3&+#5U$i#$z(l8sDzk-C6f&>VuWk*nwt@RQ)b~AL6;P@z^*kR zB)T=E- z(4-SE`3ZR=nv2>^F~!3qGIgDAK1mW{@zHg7-2#p?62*7RWi2f1-QLEPQd6dX0FJUlrZ=4``UkTxnDo}$7HQ>Rs*QQV}0g~7tUn}m1+m#IY z0SSBlgTaS3J{+$7z_K>=2;Q*38F%&QV<>;-62+_@$2*eY@Du8B7Rn{z@RJA}b{Mk7 z817_T64_0M!%xAG0~}b<8My4k&D#?=^_`dJ1!N$S8~u2RQYge*0x+<`6&_rm9N9zi zW`~R^JS>i}k;9|3T$KlNflzVZ7zSLXKv1}G3X6icI1N2H0%6GFO%F{@5v-6FNhpJq zD0z#OLYk;?GRAQ%FBk=`w*XLD2!zf-?xo=#_aK8q3RD3lW9bW#!rj5G47lJ40}td| z5(#}}5Tru@AYp<5NTySQyCou+! z$y!1mr$d11jK|SJvycR%tR+G3>>|Z1hCTZ%VDx*o=yT{W_Z+GQ&~q-(=t7egBO2m3 zi8Z6uPU)~ zw*B?9mT@){XHICJK4T^XM`esp=;2-IB{4J#F5v}NtPBRv4`QJyxH`B-T@(zig(Q}R zb@&D`!uMFo7}<9QcU^kPZiI8$geeb8qmz`-8!Y9(XVqeCT2Ifk%phJ;C6kj|I0pz9jg>lPb9X z@KeEEyo`Xs2A>h{A9;2s^yh*>oTUEP$5Ec22nP371wR=qdI3Z)!fgqvXIpR=&Q9ZY zZkXr5?^;P1lqJE>sa;hMtG&U`OFH&0P`JDsi34o?C@81)@yFLN^WiiqGO7PV``g-siuYD6< z4E*u8R=)DezJ1^R_IH9`|L*sWzWyf?9vt^0^_qs2l!0^r3p9DkOL|zJ;UZ1?RV>cb zEyX-fh>p$Z`e8c#wzwQg2i^gKS9d|{%EFG&q>p@_@9xUjkj?{k3V{ILs5|wO^kKfq ztB%tgQ0ct!h$sC{x=vo|b>4-3A|MgJkv{g5^wIRGQ@=Wl<)nAN{?o&&QZF8bpI_~# zdFQM9E8TT{Sa5v1nbfBxx_YDXPSD|NWC4|J~jQ(`$}OAB)3`-?2jISa5Sv3Amt)pdz2?c-rX`6n^4B0*p z{hR4DYDcAiN)Pb-<4fVz2}nPmP9IzUqq?KGTYB`r6=Av)yc#-jPteh zaMUJ~hf-y=LOn*}W1D`Q{sn?cANkoaT3omOop&V(2K zZ>>weosRzsKQeIrfE{}_AdW#H<4FWg>^dbL*B%rGgu%tlexO6ZJYT?uH^85@0B0ao zZ_UtYwsum7DRI=QpjnC@pUJNc0IZaRy{wgrEMFP)H2eiP2abBD;V&u%vq*3@1!L#T1xBCeh(3=F=gy}JuroGoT0X(< zAL*Db(wgI}U8e~Uj>gt^YYRirKC#NZc9Ye$BCW(vH2h+w2-54$ucN4B$!mLVR zZFn@jG*MP(cHa$$G6t&=BGZc}$gp7tPI$)5VI7^&30?TjaI-o{mAjVDHiIW#NPmFt9(ThMmoJlS z4P3k}u^q2LDg_)4~YPmXr@Ghn3m%AHDx@_U)m%Hv6*b8*sMYMF?6?@P+ zaOs@uUb)wGFHN{t3AL<<(U~-at0iC8xYxSwb*_6o(+;>{r@GPYC7wFNb#FqtZ&vQY zTY&Fdcq=Ef%H2;o_o~|ws|J|v!2Mg;$-WEd-S};Har@If=UjX5eK4$%^arqk4JHWY z#0MU6-AC2-CG@LtsJuIxu^6X-uJByj&s;IlwKr;Vg1tZ+Y1 zZ3)a@5Es{7h(4Y1Y;-%m_$BwtUwMfH8op|gueo13!pBk6AGsHzGQR!|wfs`|!h}+< zeKYaLI-GC0a~HYap6>>}Lr>pzmt1uS4&QU#qY@YF7U_8Cyin;D#*}Dy9kv;F7kL)2 z&W1{BWCRTKLcjim<&`v#bSixtC@{jL^Xf2KVW2qz{Ac)atcEQHm|o~hgb$KoEN%Ip zHxFM!{s&`>=6}Awe|kUu=glMS@I3KfEdk()QcQ=Ihqm`?C5hKCXUC9V0FfFurFk~AN(7jGd* z&BuWM>B#0~SOMwuA+{2h#F038LVSsxs74sU+Z-VRg7hu;37>=X>_=%jk_iUSg2jNI z?j&c%4;dQxAm)Mvl84O=+Mu+_mkB@Ai%RQ+`%wH4S=B-LAco$13f@np`xvu?%(Dnb z(#KFZlI%3tFO<_ykQVvKq#TA&{=i@S59cqiHf6aIt%KVF!uu*6@E69d(1|(vax1KH zl_+keyf6MDZ1@Yu(foxDt_#{MEaaRGaa`~h4lZ2+%yk?Q72-0@QpZ{5oaZc`3kJ%; z%a*GgclDAr;ESCLK*p<**5QjPu*Z7Vzf&CZssiHpx=c-yFGSmW!eGP?NHY{HxR$^49Dq3x>L$oa1-#G7l_E5a{ga?UjrCdQSE=TNw=XJ z(oh2gjJkyu0)%?^`|IvkvT4(jHffSVD1jtRwoT|JS&|K;B}jk(1qwtcQlLuI#8d25vx=!TIiPj|IXZdH@kQ5Mhg1y{U4K@otZN;XTHyzIdkva zTN#C(+v4&C{I^50q_Y(`?*g=DY|gm*o+Z8a4#KmVm0u%1A_sroXCBPR*vhr8pxL`P zV=1TUSv$k1w|AoUc!kZj7lP!mk=-=j_ZX)BL_>dLki^m)*r1KB??UanFmGScr$yF^PQX5{vp#B_AN0OCGv$NsH`G_`$ z@H+ZISDZ=@VQ97aS}jBaZGl!xk3O;Qr*j`i3|T+JKH;RlfHW{n32_l=TP)I3!*j*Q zhViL$@gWGUwnDpHyP{I7#Ya!8YqYgm2e(SAy%dLevbii%tF62I($!aJwK)IQY8$kT z+NNcY1+>AnT%mSd>)JLthrD_{60FuXgs|^y?~oFAhPBr$*UA?~b7$hD*{4%?L(ZlPwcE81e0dcPOc1sV-P5dH$39_7dHIl*-aBDBfMwc^+`2RG=ay@~ z$;z=DCnw+9g~Gu!LD!(glKj|ra4{r|wy9}1v!&W=wcj;peP=$deF9<)2WVWI9kA(Z!Snpdk9Rs~EBP4?91(9c!`b846a5r1O)cvlDFKlFm(@ zrUm_tM`I_%Gm~jOfj3Ls`^M(VdV+*=5=l=GKPO3}Cx9Hr^aKg#Bur0`a83d}L3$lQ z!dVH^5r}6cw0}?35kRoPu72n#Yyq)(P-F}Yg5aMSgG0!KE$L}YR6X_CYpDpVWL_NYkzK@W8weu1bkj^Ej z{Mod9&*+C6x&#oR4;$Gb22P)q*b>f4uys#&PI4nX{yho8&_F5AOMuj?otH2@0){k- zE}fhF3O?$aWL?4JZ)YESjihRUv_>raeVn66nl{-2y%`Oyj|wwu`nmtv*;%J3LS^q9 z*)gLnZzM=Or?*(~)QW8I(B(xyL^cJ6-W4`AcH^=<&D<4m_ek!Uq#V;5{`r zG4N#EbMsCnwiNd?*z?E@nJ2B0>qXOq9%~f+;_C(MkrMWR6Fzc(26H5Q6y)@C=FK~o zAs5WUBc=1i4_`uNl1V1n2Ih-Db3(5|A}yXd@zb+m^e9qE2@xv|Fp~4i7K=9f#RI41 z+|EllLr#VXw=kCaqGU5=t>|CG%9*B;x4&tag=nidMU7^%dlo%tq!}I89Y> zFEO3WRq-UcX&pm7pz{>-;n+9L{@N*^b z`Z;=R8&4%MvzUF+eF?d-dyy`j!9z*1!Q`SMu#$1y{Q2|cfaTnZ73@nORiyOHfL@WQ zJ<+`Q^4sbR+zk(nCsdwSUDYtFaTYyUh3yR<1e-OBzP~eT*449St;e&j7}T9%&=kLX zgLib1-3H`$@x>Q!lnk!wV}?p08nIFOe+zwvuDknz2R6X}na@1_&aAa-cJ}a5eNe0O2CgdKCo1wT7ljqK*XWmA{%F~O=lq{a|D|EO^VR3R_O)}h9 z85R1aSUaSMJITw`u`HPAeO)r6k`V*&`@ea8#{#d#bH_}-fE89==hH5>X#?J~WWdx6 zGYJQBJENJIU?=+Vtr0x5Np7)7^i_H0g3g3JMGHkqHt9(i@(eAOeJ1P4)KcxU84BMx z`dEhM7<^2VnS@*< z=O_6@9BvLX0_fMoZV@B5f!*gIen1IS==l>e0`@O%=K5zpxWwBl#zDp6Rig)N6Z1YZ zppO$`_)oI_h~s3(?6_3Pm1!5B$!Qq}mqXbUO6c2ZJh_%vo2oe^u zzxYS{1p1S#%q-D6i_?;0b|zkwKp=(_TsimxH5Kqwd_YT#c3LKG;zB&w^X3uiBNR?R zCO=d97b63We;_mIwI=+^e`4%{OpZQioJn6amMDCjyyTYr*e&bzdU_1{9Gt2sDk#Tc z)G%OSpLae!%8H9&E&_pKgyV&IEK$tJu@}jO5N*6zsA@Pq$w*g{K}435AvcJ|7<@?v zSd;i?GMUX5`j!`rh0rFu9TsedqZqc+>2eWXG#H@MpMPa2pJd>Xiw>thZZhc-1i3h* z)TC(fm`j(kbmXT3FJl3jbTeJ1bQuZB(qs@Lt5Wkp$G=AkJ$5dVb_}zzcx=fN=nAN8bX_CV*BvbQ9MIg~hYL`H_$w)p!g*+M(mn z6XBuR*fzi*pdWBE;ERao|5YsZH~>kRhKP9MDL;+H&PJwZ!9Mf~6fv-W4f{8M9{{2~ zvDkstvDh9!5#qDXnBW;A!8M&QR)LBjjeZ?Y{Nfwa@lSoS6A&r`j&oR1 zutgAGX85NCt6I5or5K5EO|fbm-4&CV_gR-Nh*M(t%fLt2`vY+_b6hlAYP8v0-R#TH z;%2X&4#(Rn)1EZ0B`B@ezQr1*49q zdtqZ&OE)y&Vumcvh;ZDGBQJl`vBgrE<-&(EdR!PK!r zT#iwBMZMQ64=218%{8s@dYhY#EW8D$f!Hi3>4-uIY42dc_)aF7uw>wzZYu7YxXI#h zSSVMQzAj7A;xRYSmXex+{V+87HcBq&eX_*Ql;dSAx;g6>%5s3dL3@W}2$5*UO~av4 zz&5~UKp!9ks0UO54giKN!=W1ipOb8IzgO6zNK5{I1>N^ro_|+5xlX&J`pP!tM`5=~ zFacW)7OYNW!#hX|JgAd;+(@Fveh783X9ATM=f1C+!l#Wwre<4 z4mbJbJkq6+@svgl3HK1_9|Fd{<95ot=VKN;xJ6&2C zua<^za`^v*-O=G}ZR&0acXft?U6Bn9*EWTEf}}2lk`H0)f{})%P^h7~sXIuzL$1X? z9LfWn@TNi^@Oyp3p~C>R@OO(_kcR%dP5(i}3sAeD-UR?NpcSwQum?cp`9;Za=op|K z@zmhCG+|#(gIA;R&v17o(7FO{DlfV@*wxk9#Wi#V*9ChUnmfCKT%@y8-`>;Qs$bL8 zygt%}pSF&5Tytkfb5B=Sup^@H=#1#wV0U)uS9Ep+vDmKb>g)*v*V5J;>_+15h<;6w z;(%&bH%07@bb(5DF-yE~k&)*yoZfvpuB`)Ov#mv6U8ZmDY@s|wifJ>Arx4556@m#xt z;ZRd^upRA%vQkTQbu@+athGT&kM`~fHFfEcOINVFyREZBAM9AyhSnTgJRCX%$X+rW zS^x+DS^!%Bqhup&AM68wjc^YGSnn;Wramm{rk|r0~y_?=eN(tfu60<|+Jz3cr%}5a<;(4~PDac>fMKwkDbGK81g#Jcku= z`xX91g+HM1D{1E-yccyP*djq*3+6aL_D=#&Ap5t&O%PoRzAXW{k0kiXeJH_C?gI&a za>wV1G$AqB*YvE#Y~w^r-`1^Pv8tj%_F}=&cLdipMcS?n>bu)E2IT;9>)YG9+nXZI ztz7rHTt}sIZD**3Ek7K0_^IL0+J6%$X&*d^eD*2go~&P4r#{e|7)M3LQ;Lmu9e(mU;O-VDDugG|(q;EG?UgB&i~%6KyVUtue0EB!O&p^SU7{>qL@G98r=kh_8qncBl` zAqXVTzdjryIP&M=&_Td%zyP2TQ20kNOpZf#0q|3Q!kP|f1SE#NU$-6f@&HqZheKn4 zO@Ky#9dJ~oEQ$H;NB97s9x#b=o~-}&H-;h~DYy+IEzZZEDi~+TLpK2e$A&{Y z-a@|v>~EtTL{W7)t^WGXHCIDOcj>#sO&#tc?t)@HlM37<-1cnTxB=6yrz6shpkjTv zsVmaf6mr*gVejhU`YN4F6z}HN2RC$cYdgD;G>*j%CBjwq(fqA+b~iV5bU;w4?1QM$ z9S*fcAf}Uy{O~76LIg+jBcTBaj$AMj+6~wQpfEwQ$vsʊl61nj?PB-8>pcHu~9 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 literal 0 HcmV?d00001 diff --git a/lib/regex/__init__.py b/lib/regex/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/lib/regex/__init__.py @@ -0,0 +1 @@ + diff --git a/lib/regex/_regex.c b/lib/regex/_regex.c new file mode 100644 index 00000000..a40d2091 --- /dev/null +++ b/lib/regex/_regex.c @@ -0,0 +1,22557 @@ +/* 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 +#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 node. */ +typedef unsigned short 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 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) + +/* 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_SUB 1 +#define RE_FUZZY_VAL_MAX_INS 2 +#define RE_FUZZY_VAL_MAX_DEL 3 +#define RE_FUZZY_VAL_MAX_ERR 4 +#define RE_FUZZY_VAL_SUB_COST 5 +#define RE_FUZZY_VAL_INS_COST 6 +#define RE_FUZZY_VAL_DEL_COST 7 +#define RE_FUZZY_VAL_MAX_COST 8 + +#define RE_FUZZY_VAL_MAX_BASE 1 +#define RE_FUZZY_VAL_COST_BASE 5 + +/* The various values in an END_FUZZY node. */ +#define RE_FUZZY_VAL_MIN_SUB 1 +#define RE_FUZZY_VAL_MIN_INS 2 +#define RE_FUZZY_VAL_MIN_DEL 3 +#define RE_FUZZY_VAL_MIN_ERR 4 + +/* 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; + +/* Handlers for ASCII, locale and Unicode. */ +typedef struct RE_EncodingTable { + BOOL (*has_property)(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)(Py_UCS4 ch); + int (*all_cases)(Py_UCS4 ch, Py_UCS4* codepoints); + Py_UCS4 (*simple_case_fold)(Py_UCS4 ch); + int (*full_case_fold)(Py_UCS4 ch, Py_UCS4* folded); + int (*all_turkic_i)(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 { + size_t capture_change; + BOOL too_few_errors; + } 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 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 in a context. */ +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; + /* 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; + 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. */ + 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. */ + 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 total_cost; /* The total cost of a fuzzy match. */ + size_t max_cost; /* The maximum permitted fuzzy cost. */ + /* 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'). */ +} 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_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; + +/* 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. */ +} 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; + +/* 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_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(Py_UCS4 ch) { + return FALSE; +} + +/* Gets all the cases of a character. */ +static int ascii_all_cases(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(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(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(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 a property. */ +Py_LOCAL_INLINE(BOOL) locale_has_property(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 = isalnum((int)ch) != 0; + break; + case RE_PROP_ALPHA >> 16: + v = isalpha((int)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 = isalpha((int)ch) ? value : 0xFFFF; + break; + case RE_PROP_CNTRL: + v = iscntrl((int)ch) ? value : 0xFFFF; + break; + case RE_PROP_DIGIT: + v = isdigit((int)ch) ? value : 0xFFFF; + break; + case RE_PROP_GC_CN: + v = ch > RE_LOCALE_MAX; + break; + case RE_PROP_GC_LL: + v = islower((int)ch) ? value : 0xFFFF; + break; + case RE_PROP_GC_LU: + v = isupper((int)ch) ? value : 0xFFFF; + break; + case RE_PROP_GC_P: + v = ispunct((int)ch) ? value : 0xFFFF; + break; + default: + v = 0xFFFF; + break; + } + break; + case RE_PROP_GRAPH >> 16: + v = isgraph((int)ch) != 0; + break; + case RE_PROP_LOWER >> 16: + v = islower((int)ch) != 0; + break; + case RE_PROP_PRINT >> 16: + v = isprint((int)ch) != 0; + break; + case RE_PROP_SPACE >> 16: + v = isspace((int)ch) != 0; + break; + case RE_PROP_UPPER >> 16: + v = isupper((int)ch) != 0; + break; + case RE_PROP_WORD >> 16: + v = ch == '_' || isalnum((int)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_CODE property, Py_UCS4 ch) { + return locale_has_property(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(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(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(Py_UCS4 ch) { + return toupper((int)ch) == 'I' || tolower((int)ch) == 'i'; +} + +/* Gets all the cases of a character. */ +static int locale_all_cases(Py_UCS4 ch, Py_UCS4* codepoints) { + int count; + Py_UCS4 other; + + count = 0; + + codepoints[count++] = ch; + + other = (Py_UCS4)toupper((int)ch); + if (other != ch) + codepoints[count++] = other; + + other = (Py_UCS4)tolower((int)ch); + if (other != ch) + codepoints[count++] = other; + + return count; +} + +/* Returns a character with its case folded. */ +static Py_UCS4 locale_simple_case_fold(Py_UCS4 ch) { + if (ch <= RE_LOCALE_MAX) + return (Py_UCS4)tolower((int)ch); + + return ch; +} + +/* Returns a character with its case folded. */ +static int locale_full_case_fold(Py_UCS4 ch, Py_UCS4* folded) { + if (ch <= RE_LOCALE_MAX) + folded[0] = (Py_UCS4)tolower((int)ch); + else + folded[0] = ch; + + return 1; +} + +/* Gets all the case variants of Turkic 'I'. The given character will be listed + * first. + */ +static int locale_all_turkic_i(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 = (Py_UCS4)toupper('i'); + if (other != ch && other != 'I') + cases[count++] = other; + + /* Lowercase 'I' will be either dotless (Turkic) or dotted (non-Turkic). */ + other = (Py_UCS4)tolower('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_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. */ + if (text_pos <= 0) + return TRUE; + + 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. */ + if (prop_m1 == RE_BREAK_CR && prop == RE_BREAK_LF) + return FALSE; + + /* Otherwise 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) + return TRUE; + + /* Get the property of the previous character. */ + 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. */ + 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. */ + 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. */ + 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. */ + 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). */ + 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. */ + 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; + 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; + if (prop_m1 == RE_BREAK_HEBREWLETTER && prop_p0 == RE_BREAK_SINGLEQUOTE) + return FALSE; + if (prop_m1 == RE_BREAK_HEBREWLETTER && prop_p0 == RE_BREAK_DOUBLEQUOTE && + prop_p1 == RE_BREAK_HEBREWLETTER) + return FALSE; + 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"). + */ + if (prop_m1 == RE_BREAK_NUMERIC && prop_p0 == RE_BREAK_NUMERIC) + return FALSE; + if ((prop_m1 == RE_BREAK_ALETTER || prop_m1 == RE_BREAK_HEBREWLETTER) && + prop_p0 == RE_BREAK_NUMERIC) + return FALSE; + 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". */ + 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; + 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. */ + if (prop_m1 == RE_BREAK_KATAKANA && prop_p0 == RE_BREAK_KATAKANA) + return FALSE; + + /* Don't break from extenders. */ + 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; + 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. */ + if (prop_m1 == RE_BREAK_REGIONALINDICATOR && prop_p0 == + RE_BREAK_REGIONALINDICATOR) + return FALSE; + + /* Otherwise, break everywhere (including around ideographs). */ + 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_UCS4 char_p1; + Py_ssize_t pos_p1; + int prop_p1; + Py_ssize_t pos_m2; + Py_UCS4 char_m2; + int prop_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. */ + if (text_pos <= 0) + return TRUE; + + 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. */ + if (prop_m1 == RE_GBREAK_CR && prop == RE_GBREAK_LF) + return FALSE; + + /* Otherwise break before and after controls (including CR and LF). */ + 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. */ + if (prop_m1 == RE_GBREAK_L && (prop == RE_GBREAK_L || prop == RE_GBREAK_V + || prop == RE_GBREAK_LV || prop == RE_GBREAK_LVT)) + return FALSE; + if ((prop_m1 == RE_GBREAK_LV || prop_m1 == RE_GBREAK_V) && (prop == + RE_GBREAK_V || prop == RE_GBREAK_T)) + return FALSE; + if ((prop_m1 == RE_GBREAK_LVT || prop_m1 == RE_GBREAK_T) && (prop == + RE_GBREAK_T)) + return FALSE; + + /* Don't break between regional indicator symbols. */ + if (prop_m1 == RE_GBREAK_REGIONALINDICATOR && prop == + RE_GBREAK_REGIONALINDICATOR) + return FALSE; + + /* Don't break just before Extend characters. */ + if (prop == RE_GBREAK_EXTEND) + return FALSE; + + /* Don't break before SpacingMarks, or after Prepend characters. */ + if (prop == RE_GBREAK_SPACINGMARK) + return FALSE; + + if (prop_m1 == RE_GBREAK_PREPEND) + return FALSE; + + /* Otherwise, break everywhere. */ + 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(Py_UCS4 ch) { + return ch == 'I' || ch == 'i' || ch == 0x0130 || ch == 0x0131; +} + +/* Gets all the cases of a character. */ +static int unicode_all_cases(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(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(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(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(("<>\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, %.200s found", 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(RE_EncodingTable* encoding, 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, Py_UCS4 lower, + Py_UCS4 upper, Py_UCS4 ch) { + Py_UCS4 cases[RE_MAX_CASES]; + int count; + int i; + + count = encoding->all_cases(ch, cases); + + for (i = 0; i < count; i++) { + if (in_range(encoding, lower, upper, cases[i])) + return TRUE; + } + + return FALSE; +} + +/* Checks whether 2 characters are the same. */ +Py_LOCAL_INLINE(BOOL) same_char(RE_EncodingTable* encoding, 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, Py_UCS4 ch1, Py_UCS4 + ch2) { + return same_char(encoding, ch1, ch2); +} + +/* Checks whether 2 characters are the same, ignoring case. */ +Py_LOCAL_INLINE(BOOL) same_char_ign(RE_EncodingTable* encoding, Py_UCS4 ch1, + Py_UCS4 ch2) { + Py_UCS4 cases[RE_MAX_CASES]; + int count; + int i; + + if (ch1 == ch2) + return TRUE; + + count = encoding->all_cases(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, Py_UCS4 ch1, + Py_UCS4 ch2) { + return same_char_ign(encoding, 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_Node* + node, Py_UCS4 ch) { + return same_char(encoding, node->values[0], ch); +} + +/* Checks whether 2 characters are the same, ignoring case. */ +Py_LOCAL_INLINE(BOOL) matches_CHARACTER_IGN(RE_EncodingTable* encoding, + RE_Node* node, Py_UCS4 ch) { + return same_char_ign(encoding, node->values[0], ch); +} + +/* Checks whether a character has a property. */ +Py_LOCAL_INLINE(BOOL) matches_PROPERTY(RE_EncodingTable* encoding, RE_Node* + node, Py_UCS4 ch) { + return encoding->has_property(node->values[0], ch); +} + +/* Checks whether a character has a property, ignoring case. */ +Py_LOCAL_INLINE(BOOL) matches_PROPERTY_IGN(RE_EncodingTable* encoding, 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 ch <= RE_LOCALE_MAX && (isupper((int)ch) || + islower((int)ch)) != 0; + else if (prop == RE_PROP_UPPERCASE || prop == RE_PROP_LOWERCASE) + return ch <= RE_LOCALE_MAX && (isupper((int)ch) || + islower((int)ch)) != 0; + + /* The property is case-insensitive. */ + return locale_has_property(property, ch); + } +} + +/* Checks whether a character is in a range. */ +Py_LOCAL_INLINE(BOOL) matches_RANGE(RE_EncodingTable* encoding, RE_Node* node, + Py_UCS4 ch) { + return in_range(encoding, 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_Node* + node, Py_UCS4 ch) { + return in_range_ign(encoding, node->values[0], node->values[1], ch); +} + +Py_LOCAL_INLINE(BOOL) in_set_diff(RE_EncodingTable* encoding, RE_Node* node, + Py_UCS4 ch); +Py_LOCAL_INLINE(BOOL) in_set_inter(RE_EncodingTable* encoding, RE_Node* node, + Py_UCS4 ch); +Py_LOCAL_INLINE(BOOL) in_set_sym_diff(RE_EncodingTable* encoding, RE_Node* + node, Py_UCS4 ch); +Py_LOCAL_INLINE(BOOL) in_set_union(RE_EncodingTable* encoding, RE_Node* node, + Py_UCS4 ch); + +/* Checks whether a character matches a set member. */ +Py_LOCAL_INLINE(BOOL) matches_member(RE_EncodingTable* encoding, 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(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(encoding, 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, member, ch); + case RE_OP_SET_INTER: + TRACE(("%s\n", re_op_text[member->op])) + return in_set_inter(encoding, member, ch); + case RE_OP_SET_SYM_DIFF: + TRACE(("%s\n", re_op_text[member->op])) + return in_set_sym_diff(encoding, member, ch); + case RE_OP_SET_UNION: + TRACE(("%s\n", re_op_text[member->op])) + return in_set_union(encoding, 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_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(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(encoding, 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, member, cases[i])) + return TRUE; + break; + case RE_OP_SET_INTER: + TRACE(("%s\n", re_op_text[member->op])) + if (in_set_inter(encoding, 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, member, cases[i])) + return TRUE; + break; + case RE_OP_SET_UNION: + TRACE(("%s\n", re_op_text[member->op])) + if (in_set_union(encoding, 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_Node* node, + Py_UCS4 ch) { + RE_Node* member; + + member = node->nonstring.next_2.node; + + if (matches_member(encoding, member, ch) != member->match) + return FALSE; + + member = member->next_1.node; + + while (member) { + if (matches_member(encoding, 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_Node* + node, int case_count, Py_UCS4* cases) { + RE_Node* member; + + member = node->nonstring.next_2.node; + + if (matches_member_ign(encoding, member, case_count, cases) != + member->match) + return FALSE; + + member = member->next_1.node; + + while (member) { + if (matches_member_ign(encoding, 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_Node* node, + Py_UCS4 ch) { + RE_Node* member; + + member = node->nonstring.next_2.node; + + while (member) { + if (matches_member(encoding, 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_Node* + node, int case_count, Py_UCS4* cases) { + RE_Node* member; + + member = node->nonstring.next_2.node; + + while (member) { + if (matches_member_ign(encoding, 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_Node* + node, Py_UCS4 ch) { + RE_Node* member; + BOOL result; + + member = node->nonstring.next_2.node; + + result = FALSE; + + while (member) { + if (matches_member(encoding, 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_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, 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_Node* node, + Py_UCS4 ch) { + RE_Node* member; + + member = node->nonstring.next_2.node; + + while (member) { + if (matches_member(encoding, 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_Node* + node, int case_count, Py_UCS4* cases) { + RE_Node* member; + + member = node->nonstring.next_2.node; + + while (member) { + if (matches_member_ign(encoding, 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_Node* node, + Py_UCS4 ch) { + switch (node->op) { + case RE_OP_SET_DIFF: + case RE_OP_SET_DIFF_REV: + return in_set_diff(encoding, node, ch); + case RE_OP_SET_INTER: + case RE_OP_SET_INTER_REV: + return in_set_inter(encoding, node, ch); + case RE_OP_SET_SYM_DIFF: + case RE_OP_SET_SYM_DIFF_REV: + return in_set_sym_diff(encoding, node, ch); + case RE_OP_SET_UNION: + case RE_OP_SET_UNION_REV: + return in_set_union(encoding, 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_Node* + node, Py_UCS4 ch) { + Py_UCS4 cases[RE_MAX_CASES]; + int case_count; + + case_count = encoding->all_cases(ch, cases); + + switch (node->op) { + case RE_OP_SET_DIFF_IGN: + case RE_OP_SET_DIFF_IGN_REV: + return in_set_diff_ign(encoding, node, case_count, cases); + case RE_OP_SET_INTER_IGN: + case RE_OP_SET_INTER_IGN_REV: + return in_set_inter_ign(encoding, 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, node, case_count, cases); + case RE_OP_SET_UNION_IGN: + case RE_OP_SET_UNION_IGN_REV: + return in_set_union_ign(encoding, 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; +} + +/* Initialises the state for a match. */ +Py_LOCAL_INLINE(void) init_match(RE_State* state) { + 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 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); + } + + 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; + } + + /* 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. */ + memset(state->fuzzy_info.counts, 0, sizeof(state->fuzzy_info.counts)); + state->fuzzy_info.total_cost = 0; + memset(state->total_fuzzy_counts, 0, sizeof(state->total_fuzzy_counts)); + state->total_errors = 0; + state->total_cost = 0; + state->too_few_errors = 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 = ¤t->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 = ¤t->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; +} + +/* 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->next_1.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(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(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; + + text = state->text; + match = node->match == match; + 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_PROPERTY(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_PROPERTY(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_PROPERTY(encoding, 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; + + text = state->text; + match = node->match == match; + 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_PROPERTY_IGN(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_PROPERTY_IGN(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_PROPERTY_IGN(encoding, 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; + + text = state->text; + match = node->match == match; + 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_PROPERTY_IGN(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_PROPERTY_IGN(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_PROPERTY_IGN(encoding, 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; + + text = state->text; + match = node->match == match; + 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_PROPERTY(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_PROPERTY(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_PROPERTY(encoding, 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; + + text = state->text; + match = node->match == match; + 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_RANGE(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_RANGE(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_RANGE(encoding, 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; + + text = state->text; + match = node->match == match; + 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_RANGE_IGN(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_RANGE_IGN(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_RANGE_IGN(encoding, 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; + + text = state->text; + match = node->match == match; + 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_RANGE_IGN(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_RANGE_IGN(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_RANGE_IGN(encoding, 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; + + text = state->text; + match = node->match == match; + 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_RANGE(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_RANGE(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_RANGE(encoding, 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; + + text = state->text; + match = node->match == match; + 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_SET(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_SET(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_SET(encoding, 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; + + text = state->text; + match = node->match == match; + 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_SET_IGN(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_SET_IGN(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_SET_IGN(encoding, 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; + + text = state->text; + match = node->match == match; + 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_SET_IGN(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_SET_IGN(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_SET_IGN(encoding, 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; + + text = state->text; + match = node->match == match; + 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_SET(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_SET(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_SET(encoding, 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; + RE_EncodingTable* encoding; + Py_UCS4 check_char; + + length = (Py_ssize_t)node->value_count; + values = node->values; + encoding = state->encoding; + 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(encoding, 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(encoding, 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(encoding, 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; + Py_UCS4 cases[RE_MAX_CASES]; + int case_count; + + length = (Py_ssize_t)node->value_count; + values = node->values; + encoding = state->encoding; + case_count = encoding->all_cases(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, 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, 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, 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; + Py_UCS4 cases[RE_MAX_CASES]; + int case_count; + + length = (Py_ssize_t)node->value_count; + values = node->values; + encoding = state->encoding; + case_count = encoding->all_cases(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, 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, 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, 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; + RE_EncodingTable* encoding; + Py_UCS4 check_char; + + length = (Py_ssize_t)node->value_count; + values = node->values; + encoding = state->encoding; + 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(encoding, 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(encoding, 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(encoding, 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) { + RE_EncodingTable* encoding; + 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; + + encoding = state->encoding; + 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(encoding, + 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(encoding, + 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(encoding, + 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; + 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; + 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(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, + 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, + 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, + 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; + 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; + 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(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, + 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, + 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, + 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) { + RE_EncodingTable* encoding; + 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; + + encoding = state->encoding; + 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(encoding, + 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(encoding, + 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(encoding, + 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_EncodingTable* encoding, 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, 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 = encoding->all_cases(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(encoding, 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(encoding, 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_EncodingTable* encoding, + 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, 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 = encoding->all_cases(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(encoding, 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(encoding, 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->encoding, 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; + int (*full_case_fold)(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; + 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(char_at(text, text_pos), folded); + f_pos = 0; + } + + if (same_char_ign(encoding, 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; + int (*full_case_fold)(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; + 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(char_at(text, text_pos - 1), folded); + f_pos = 0; + } + + if (same_char_ign(encoding, 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->encoding, 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->encoding, 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->encoding, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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_EncodingTable* encoding; + RE_CODE* values; + Py_ssize_t s_pos; + + length = (Py_ssize_t)node->value_count; + char_at = state->char_at; + encoding = state->encoding; + 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(encoding, 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; + int (*full_case_fold)(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; + 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(char_at(state->text, text_pos), + folded); + f_pos = 0; + } + + if (!same_char_ign(encoding, 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; + int (*full_case_fold)(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; + 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(char_at(state->text, text_pos - 1), + folded); + f_pos = 0; + } + + if (!same_char_ign(encoding, 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_CODE* values; + Py_ssize_t s_pos; + + length = (Py_ssize_t)node->value_count; + char_at = state->char_at; + encoding = state->encoding; + 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, 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_CODE* values; + Py_ssize_t s_pos; + + length = (Py_ssize_t)node->value_count; + char_at = state->char_at; + encoding = state->encoding; + 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, 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_EncodingTable* encoding; + RE_CODE* values; + Py_ssize_t s_pos; + + length = (Py_ssize_t)node->value_count; + char_at = state->char_at; + encoding = state->encoding; + 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(encoding, 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 text_pos; + RE_Node* test; + RE_Node* node; + Py_ssize_t start_pos; + RE_SearchPosition* info; + + state = safe_state->re_state; + + start_pos = state->text_pos; + TRACE(("<> 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: + break; + 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; + + memset(new_block, 0, sizeof(RE_SavedRepeats)); + + 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, ¤t->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], ¤t->repeats[r]); + + state->current_saved_repeats = current->previous; +} + +/* Saves state info before a recusive call by 'basic_match'. */ +Py_LOCAL_INLINE(void) save_info(RE_State* state, RE_Info* info) { + info->backtrack_count = state->current_backtrack_block->count; + info->current_backtrack_block = state->current_backtrack_block; + info->current_saved_groups = state->current_saved_groups; + info->must_advance = state->must_advance; + info->current_group_call_frame = state->current_group_call_frame; +} + +/* Restores state info after a recusive call by 'basic_match'. */ +Py_LOCAL_INLINE(void) restore_info(RE_State* state, RE_Info* info) { + state->current_group_call_frame = info->current_group_call_frame; + state->must_advance = info->must_advance; + state->current_saved_groups = info->current_saved_groups; + state->current_backtrack_block = info->current_backtrack_block; + state->current_backtrack_block->count = info->backtrack_count; +} + +/* 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? */ + 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_text_pos = text_pos; + guard_list->last_low = low; + + 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); +} + +/* 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); +} + +/* Resets the guards inside atomic subpatterns and lookarounds. */ +Py_LOCAL_INLINE(void) reset_guards(RE_State* state, RE_CODE* values) { + PatternObject* pattern; + size_t repeat_count; + + pattern = state->pattern; + repeat_count = pattern->repeat_count; + + if (values) { + size_t i; + + for (i = 1; i <= values[0]; i++) { + size_t index; + + index = values[i]; + + if (index < repeat_count) { + reset_guard_list(&state->repeats[index].body_guard_list); + reset_guard_list(&state->repeats[index].tail_guard_list); + } else { + index -= repeat_count; + + reset_guard_list(&state->fuzzy_guards[index].body_guard_list); + reset_guard_list(&state->fuzzy_guards[index].tail_guard_list); + } + } + } else { + size_t index; + size_t fuzzy_count; + + for (index = 0; index < repeat_count; index++) { + reset_guard_list(&state->repeats[index].body_guard_list); + reset_guard_list(&state->repeats[index].tail_guard_list); + } + + fuzzy_count = pattern->fuzzy_count; + + for (index = 0; index < fuzzy_count; index++) { + reset_guard_list(&state->fuzzy_guards[index].body_guard_list); + reset_guard_list(&state->fuzzy_guards[index].tail_guard_list); + } + } +} + +/* 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; + BOOL (*possible_turkic)(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; + possible_turkic = encoding->possible_turkic; + + /* Look for a possible Turkic 'I'. */ + while (index < len && !possible_turkic(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(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)(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]; + PyObject* string_set; + Py_ssize_t first; + Py_ssize_t last; + + 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(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)(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(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_cost <= state->max_cost; +} + +/* 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_cost + + values[RE_FUZZY_VAL_COST_BASE + fuzzy_type] <= state->max_cost; +} + +/* 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; + state->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + *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_FuzzyData data; + RE_FuzzyInfo* fuzzy_info; + RE_CODE* values; + RE_BacktrackData* bt_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; + state->total_cost -= values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + } + + /* 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; + state->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + *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_BacktrackData* bt_data; + Py_ssize_t new_text_pos; + RE_Node* new_node; + int step; + Py_ssize_t limit; + RE_Node* fuzzy_node; + RE_CODE* values; + + 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->total_cost -= values[RE_FUZZY_VAL_INS_COST] * 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; + state->total_cost += values[RE_FUZZY_VAL_INS_COST]; + + /* 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; + state->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + *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_FuzzyData data; + RE_FuzzyInfo* fuzzy_info; + RE_CODE* values; + RE_BacktrackData* bt_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; + state->total_cost -= values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + /* 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; + state->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + *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; + RE_FuzzyData data; + RE_FuzzyInfo* fuzzy_info; + RE_CODE* values; + Py_ssize_t new_text_pos; + 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; + state->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + *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_FuzzyData data; + RE_FuzzyInfo* fuzzy_info; + RE_CODE* values; + RE_BacktrackData* bt_data; + Py_ssize_t new_text_pos; + RE_Node* new_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_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; + state->total_cost -= values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + /* 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; + state->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + *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; + RE_FuzzyData data; + RE_FuzzyInfo* fuzzy_info; + RE_CODE* values; + Py_ssize_t new_text_pos; + Py_ssize_t new_group_pos; + 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; + state->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + *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_FuzzyData data; + RE_FuzzyInfo* fuzzy_info; + RE_CODE* values; + RE_BacktrackData* bt_data; + Py_ssize_t new_text_pos; + Py_ssize_t new_group_pos; + RE_Node* new_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_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; + state->total_cost -= values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + /* 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; + state->total_cost += values[RE_FUZZY_VAL_COST_BASE + data.fuzzy_type]; + + *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) { + RE_State* state; + PatternObject* pattern; + Py_ssize_t found_pos; + Py_ssize_t end_pos; + + state = safe_state->re_state; + pattern = state->pattern; + + /* We haven't matched the required string yet. */ + state->req_pos = -1; + + 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; + + found_pos = string_search(safe_state, pattern->req_string, + state->text_pos, state->slice_end, &is_partial); + if (found_pos < 0) + /* The required string wasn't found. */ + return -1; + + if (is_partial) + /* We found a partial match, so start matching from there. */ + return found_pos; + + /* 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; + + found_pos = string_search_fld(safe_state, pattern->req_string, + state->text_pos, state->slice_end, &end_pos, &is_partial); + if (found_pos < 0) + /* The required string wasn't found. */ + return -1; + + if (is_partial) + /* We found a partial match, so start matching from there. */ + return found_pos; + + /* 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; + + found_pos = string_search_fld_rev(safe_state, pattern->req_string, + state->text_pos, state->slice_start, &end_pos, &is_partial); + if (found_pos < 0) + /* The required string wasn't found. */ + return -1; + + if (is_partial) + /* We found a partial match, so start matching from there. */ + return found_pos; + + /* 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; + + found_pos = string_search_ign(safe_state, pattern->req_string, + state->text_pos, state->slice_end, &is_partial); + if (found_pos < 0) + /* The required string wasn't found. */ + return -1; + + if (is_partial) + /* We found a partial match, so start matching from there. */ + return found_pos; + + /* 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; + + found_pos = string_search_ign_rev(safe_state, pattern->req_string, + state->text_pos, state->slice_start, &is_partial); + if (found_pos < 0) + /* The required string wasn't found. */ + return -1; + + if (is_partial) + /* We found a partial match, so start matching from there. */ + return found_pos; + + /* 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; + + found_pos = string_search_rev(safe_state, pattern->req_string, + state->text_pos, state->slice_start, &is_partial); + if (found_pos < 0) + /* The required string wasn't found. */ + return -1; + + if (is_partial) + /* We found a partial match, so start matching from there. */ + return found_pos; + + /* 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; +} + +/* Performs a depth-first match or search from the context. */ +Py_LOCAL_INLINE(int) basic_match(RE_SafeState* safe_state, RE_Node* start_node, + BOOL search, BOOL recursive_call) { + RE_State* state; + RE_EncodingTable* encoding; + PatternObject* pattern; + 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 folded_pos; + int gfolded_pos; + RE_Node* node; + int status; + TRACE(("<>\n")) + + state = safe_state->re_state; + encoding = state->encoding; + pattern = state->pattern; + + /* Look beyond any initial group node. */ + start_pair.node = start_node; + if (recursive_call) + start_pair.test = locate_test_start(start_node); + else + 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; + + /* 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 || recursive_call) + found_pos = state->text_pos; + else { + found_pos = locate_required_string(safe_state); + 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_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 && !recursive_call) { + /* 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: /* Atomic subpattern. */ + { + RE_Info info; + int status; + 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; + + /* Save the groups. */ + if (!push_groups(safe_state)) + return RE_ERROR_MEMORY; + + save_info(state, &info); + + state->must_advance = FALSE; + + status = basic_match(safe_state, node->nonstring.next_2.node, + FALSE, TRUE); + if (status < 0) + return status; + + reset_guards(state, node->values); + + restore_info(state, &info); + + if (status != RE_ERROR_SUCCESS) + goto backtrack; + + 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, 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, 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, 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, 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_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_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 == 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 == 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 == 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 == 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_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_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 == 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 == 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; + } + + /* 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. */ + { + RE_GroupData* group; + 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. + */ + group = &state->groups[node->values[0] - 1]; + if (group->current_capture >= 0) + node = node->next_1.node; + else + 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_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 == 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 == 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: /* Lookaround. */ + { + RE_Info info; + size_t capture_change; + Py_ssize_t saved_slice_start; + Py_ssize_t saved_slice_end; + Py_ssize_t saved_text_pos; + BOOL too_few_errors; + int status; + TRACE(("%s %d\n", re_op_text[node->op], node->match)) + + /* Save the groups. */ + if (!push_groups(safe_state)) + return RE_ERROR_MEMORY; + + capture_change = state->capture_change; + + /* Save the other info. */ + save_info(state, &info); + + saved_slice_start = state->slice_start; + saved_slice_end = state->slice_end; + saved_text_pos = state->text_pos; + state->slice_start = 0; + state->slice_end = state->text_length; + state->must_advance = FALSE; + + too_few_errors = state->too_few_errors; + + status = basic_match(safe_state, node->nonstring.next_2.node, + FALSE, TRUE); + if (status < 0) + return status; + + reset_guards(state, node->values + 1); + + state->text_pos = saved_text_pos; + state->slice_end = saved_slice_end; + state->slice_start = saved_slice_start; + + /* Restore the other info. */ + restore_info(state, &info); + + if (node->match) { + /* It's a positive lookaround. */ + if (status == RE_ERROR_SUCCESS) { + /* It succeeded, so the groups and certain flags may have + * changed. + */ + if (!add_backtrack(safe_state, RE_OP_LOOKAROUND)) + return RE_ERROR_BACKTRACKING; + + /* We'll restore the groups and flags on backtracking. */ + state->backtrack->lookaround.too_few_errors = + too_few_errors; + state->backtrack->lookaround.capture_change = + capture_change; + } else { + /* It failed, so the groups and certain flags haven't + * changed. + */ + drop_groups(state); + goto backtrack; + } + } else { + /* It's a negative lookaround. */ + if (status == RE_ERROR_SUCCESS) { + /* It succeeded, so the groups and certain flags may have + * changed. We need to restore them. + */ + pop_groups(state); + state->too_few_errors = too_few_errors; + state->capture_change = capture_change; + goto backtrack; + } else + /* It failed, so the groups and certain flags haven't + * changed. + */ + drop_groups(state); + } + + 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, 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, 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, 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, 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: /* 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, + 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, 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, 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, + 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(encoding, + 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)(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(char_at(state->text, + state->text_pos), folded); + gfolded_len = full_case_fold(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(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(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)(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(char_at(state->text, + state->text_pos - 1), folded); + gfolded_len = full_case_fold(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(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(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, 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, 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(encoding, + 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, + 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, + 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, 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, + 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_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(encoding, 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)(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(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; + + folded_len = full_case_fold(char_at(state->text, + state->text_pos), folded); + folded_pos = 0; + } + + if (same_char_ign(encoding, 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) + ++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) + ++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)(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(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; + + folded_len = full_case_fold(char_at(state->text, + state->text_pos - 1), folded); + folded_pos = folded_len; + } + + if (same_char_ign(encoding, 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) + --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) + --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, 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, 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(encoding, 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 && !recursive_call) { + /* 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; + } + } + + 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: /* Atomic subpattern. */ + TRACE(("%s\n", re_op_text[bt_data->op])) + + /* Restore the groups and certain flags and then backtrack. */ + 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. */ + TRACE(("%s\n", re_op_text[bt_data->op])) + + pop_group_return(state); + 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: + { + Py_ssize_t end_pos; + TRACE(("%s\n", re_op_text[bt_data->op])) + + /* Do we have to advance? */ + if (!search) + return RE_ERROR_FAILURE; + + /* Can we advance? */ + state->text_pos = state->match_pos; + end_pos = state->reverse ? state->slice_start : state->slice_end; + if (state->text_pos == end_pos) + 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. */ + state->text_pos += pattern_step; + + 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; + + if (count == node->values[1]) { + /* 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 (;;) { + RE_Position next_position; + + pos -= step; + + if (try_match(state, &node->next_1, pos, &next_position) && + !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(encoding, 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, 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, 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(encoding, 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, 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)(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(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, 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)(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(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, 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, 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, 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, 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 { + /* 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_CALL: /* Group call. */ + TRACE(("%s\n", re_op_text[bt_data->op])) + + pop_group_return(state); + 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_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(encoding, 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, 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, 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(encoding, 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. */ + TRACE(("%s\n", re_op_text[bt_data->op])) + + /* Restore the groups and certain flags and then backtrack. */ + 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)); +} + +/* 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; + Py_ssize_t available; + BOOL get_best; + BOOL enhance_match; + BOOL must_advance; + RE_GroupData* best_groups; + Py_ssize_t best_match_pos; + Py_ssize_t best_text_pos = 0; /* Initialise to stop compiler warning. */ + int status; + Py_ssize_t slice_start; + Py_ssize_t slice_end; + size_t best_fuzzy_counts[RE_FUZZY_COUNT]; + TRACE(("<>\n")) + + state = safe_state->re_state; + pattern = state->pattern; + + /* Release the GIL. */ + release_GIL(safe_state); + + /* Is there enough to search? */ + if (state->reverse) { + if (state->text_pos < state->slice_start) { + acquire_GIL(safe_state); + return FALSE; + } + + available = state->text_pos - state->slice_start; + } else { + if (state->text_pos > state->slice_end) { + acquire_GIL(safe_state); + return FALSE; + } + + available = state->slice_end - state->text_pos; + } + + get_best = (pattern->flags & RE_FLAG_BESTMATCH) != 0; + enhance_match = (pattern->flags & RE_FLAG_ENHANCEMATCH) != 0 && !get_best; + + /* The maximum permitted cost. */ + state->max_cost = pattern->is_fuzzy ? PY_SSIZE_T_MAX : 0; + + best_groups = NULL; + + 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->text_pos = best_match_pos; + state->must_advance = must_advance; + + /* Initialise the state. */ + init_match(state); + + status = RE_ERROR_SUCCESS; + if (state->max_cost == 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, pattern->start_node, search, + FALSE); + + /* Has an error occurred, or is it a partial match? */ + if (status < 0) + break; + + if (status == RE_ERROR_FAILURE || (status == RE_ERROR_SUCCESS && + state->total_cost == 0)) + break; + + if (!get_best && !enhance_match) + break; + + save_fuzzy_counts(state, best_fuzzy_counts); + + if (!get_best && state->text_pos == state->match_pos) + /* We want the first match. The match is already zero-width, so the + * cost can't get any lower (because the fit can't get any better). + */ + break; + + if (best_groups) { + BOOL same; + size_t g; + + /* Did we get the same match as the best so far? */ + same = state->match_pos == best_match_pos && state->text_pos == + best_text_pos; + for (g = 0; same && g < pattern->public_group_count; g++) { + same = state->groups[g].span.start == best_groups[g].span.start + && state->groups[g].span.end == best_groups[g].span.end; + } + + if (same) + break; + } + + /* 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 (state->max_cost == 0) + break; + + /* Reduce the maximum permitted cost and try again. */ + state->max_cost = state->total_cost - 1; + + if (enhance_match) { + 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->slice_start = slice_start; + state->slice_end = slice_end; + + if (best_groups) { + if (status == RE_ERROR_SUCCESS && state->total_cost == 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); + } + } + + 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; + + /* 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) { + Py_ssize_t final_pos; + int i; + + state->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->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; + + /* 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; + 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 = state->backtrack_block.next; + while (current) { + RE_BacktrackBlock* next; + + next = current->next; + re_dealloc(current); + state->backtrack_allocated -= RE_BACKTRACK_BLOCK_SIZE; + current = next; + } + + 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 (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) + { + 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("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) { + RE_GroupData* group; + PyObject* result; + PyObject* slice; + 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++) { + int status; + PyObject* key; + PyObject* value; + + /* 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; +} + +/* 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, match_get_group_by_index(self, + (Py_ssize_t)g, Py_None)); + + kwargs = match_get_group_dict(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; + 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]; + 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); +} + +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; + BOOL is_literal = FALSE; + BOOL is_template = FALSE; + PyObject* replacement = NULL; +#if PY_VERSION_HEX >= 0x02060000 + BOOL is_format = FALSE; +#endif + RE_State state; + RE_SafeState safe_state; + JoinInfo join_info; + Py_ssize_t sub_count; + Py_ssize_t last_pos; + PyObject* item; + Py_ssize_t end_pos; + Py_ssize_t step; + + /* 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. + */ + if (!state_init_2(&state, self, string, &str_info, start, end, FALSE, + concurrent, FALSE, FALSE, is_callable, FALSE)) { +#if PY_VERSION_HEX >= 0x02060000 + release_buffer(&str_info); + +#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. */ + MatchObject* match; + PyObject* args; + size_t g; + PyObject* kwargs; + + /* 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; + + /* The args are a tuple of the capture group matches. */ + args = PyTuple_New((Py_ssize_t)state.pattern->public_group_count + + 1); + if (!args) { + Py_DECREF(match); + goto error; + } + + for (g = 0; g < state.pattern->public_group_count + 1; g++) + /* PyTuple_SetItem borrows the reference. */ + PyTuple_SetItem(args, (Py_ssize_t)g, + match_get_group_by_index(match, (Py_ssize_t)g, Py_None)); + + /* The kwargs are a dict of the named capture group matches. */ + kwargs = match_get_group_dict(match); + if (!kwargs) { + Py_DECREF(args); + Py_DECREF(match); + goto error; + } + + /* Call the 'format' method. */ + item = PyObject_Call(replacement, args, kwargs); + Py_DECREF(kwargs); + 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; +#endif + } else if (is_template) { + /* The replacement is a list template. */ + Py_ssize_t size; + Py_ssize_t i; + + /* 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_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; + } + } + } 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 (!item) + return NULL; + + if (sub_type & RE_SUBN) + return Py_BuildValue("Nn", item, sub_count); + + return item; + +error: + 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; + RE_State state; + int conc; + RE_SafeState safe_state; + PyObject* list; + Py_ssize_t step; + int status; + size_t g; + Py_ssize_t b; + Py_ssize_t e; + + 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; + int partial_side; + size_t i; + + 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); + 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}, + {"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, "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_ATOMIC: + case RE_OP_LOOKAROUND: + { + RE_STATUS_T body_result; + RE_STATUS_T tail_result; + RE_STATUS_T status; + + body_result = add_repeat_guards(pattern, + node->nonstring.next_2.node); + tail_result = add_repeat_guards(pattern, node->next_1.node); + status = max_status_3(result, body_result, tail_result); + node->status = RE_STATUS_VISITED_AG | status; + return status; + } + 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_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_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_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_ATOMIC: + if (!record_subpattern_repeats_and_fuzzy_sections(node, 0, + repeat_count, node->nonstring.next_2.node)) + return FALSE; + node = node->next_1.node; + break; + case RE_OP_BRANCH: + 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; + 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_LOOKAROUND: + if (!record_subpattern_repeats_and_fuzzy_sections(node, 1, + repeat_count, node->nonstring.next_2.node)) + 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 new_count; + size_t i; + + /* 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.has_captures = FALSE; + subargs.is_fuzzy = TRUE; + 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->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; + + args->is_fuzzy = TRUE; + + return RE_ERROR_SUCCESS; +} + +/* Builds an ATOMIC node. */ +Py_LOCAL_INLINE(int) build_ATOMIC(RE_CompileArgs* args) { + RE_Node* atomic_node; + RE_CompileArgs subargs; + RE_Node* success_node; + int status; + + /* 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, 1); + if (!atomic_node) + return RE_ERROR_MEMORY; + + /* The number of repeat indexes. */ + atomic_node->values[0] = 0; + + ++args->code; + + subargs = *args; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + + /* 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; + + /* Create the success node to terminate the subpattern. */ + success_node = create_node(subargs.pattern, RE_OP_SUCCESS, 0, 0, 0); + if (!success_node) + return RE_ERROR_MEMORY; + + /* Append the SUCCESS node. */ + add_node(subargs.end, success_node); + + /* Insert the subpattern. */ + atomic_node->nonstring.next_2.node = subargs.start; + + args->code = subargs.code; + args->min_width = subargs.min_width; + args->has_captures |= subargs.has_captures; + args->is_fuzzy |= subargs.is_fuzzy; + + ++args->code; + + /* Append the node. */ + add_node(args->end, atomic_node); + args->end = atomic_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 smallest_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; + + smallest_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. */ + subargs.min_width = 0; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + status = build_sequence(&subargs); + if (status != RE_ERROR_SUCCESS) + return status; + + smallest_min_width = min_ssize_t(smallest_min_width, + subargs.min_width); + + args->has_captures |= subargs.has_captures; + args->is_fuzzy |= subargs.is_fuzzy; + + /* 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 += smallest_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; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + 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->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 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; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + 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; + if (subargs.has_captures || subargs.visible_captures) + args->has_captures = TRUE; + args->is_fuzzy |= subargs.is_fuzzy; + + ++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; + + 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; + Py_ssize_t min_width; + int status; + + /* codes: opcode, sequence, next, sequence, end. */ + if (args->code + 2 > args->end_code) + return RE_ERROR_ILLEGAL; + + group = args->code[1]; + + args->code += 2; + + /* 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; + subargs.min_width = 0; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + 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; + + min_width = subargs.min_width; + + /* Append the start node. */ + add_node(args->end, start_node); + add_node(start_node, subargs.start); + add_node(subargs.end, end_node); + + if (args->code[0] == RE_OP_NEXT) { + ++args->code; + + subargs.code = args->code; + subargs.min_width = 0; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + 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; + + min_width = min_ssize_t(min_width, subargs.min_width); + + add_node(start_node, subargs.start); + add_node(subargs.end, end_node); + } else { + add_node(start_node, 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_Node* success_node; + RE_CompileArgs subargs; + int status; + + /* 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, + 2); + if (!lookaround_node) + return RE_ERROR_MEMORY; + + /* The number of repeat indexes. */ + lookaround_node->values[1] = 0; + + args->code += 3; + + /* Compile the sequence and check that we've reached the end of the + * subpattern. + */ + subargs = *args; + subargs.forward = forward; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + status = build_sequence(&subargs); + if (status != RE_ERROR_SUCCESS) + return status; + + lookaround_node->values[0] = subargs.has_captures; + + if (subargs.code[0] != RE_OP_END) + return RE_ERROR_ILLEGAL; + + args->code = subargs.code; + args->has_captures |= subargs.has_captures; + args->is_fuzzy |= subargs.is_fuzzy; + ++args->code; + + /* Create the 'SUCCESS' node and append it to the subpattern. */ + success_node = create_node(args->pattern, RE_OP_SUCCESS, 0, 0, 0); + if (!success_node) + return RE_ERROR_MEMORY; + + /* Append the SUCCESS node. */ + add_node(subargs.end, success_node); + + /* Insert the subpattern into the node. */ + lookaround_node->nonstring.next_2.node = subargs.start; + + /* Append the lookaround. */ + add_node(args->end, lookaround_node); + args->end = lookaround_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; + + /* This includes special cases such as optional items, which we'll check + * for and treat specially. They don't need repeat counts, which helps us + * avoid unnecessary work when matching. + */ + 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 == 0 && max_count == 1) { + /* Optional sequence. */ + RE_Node* branch_node; + RE_Node* join_node; + RE_CompileArgs subargs; + + /* Create the start and end nodes. */ + 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; + + /* Compile the sequence and check that we've reached the end of it. */ + subargs = *args; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + 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->has_captures |= subargs.has_captures; + args->is_fuzzy |= subargs.is_fuzzy; + + ++args->code; + + if (greedy) { + /* It's a greedy option. */ + add_node(branch_node, subargs.start); + add_node(branch_node, join_node); + } else { + /* It's a lazy option. */ + add_node(branch_node, join_node); + add_node(branch_node, subargs.start); + } + add_node(subargs.end, join_node); + + /* Append the optional sequence. */ + add_node(args->end, branch_node); + args->end = join_node; + } else if (min_count == 1 && max_count == 1) { + /* Singly-repeated sequence. */ + RE_CompileArgs subargs; + + subargs = *args; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + 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->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.min_width = 0; + subargs.visible_captures = TRUE; + subargs.has_captures = FALSE; + subargs.is_fuzzy = FALSE; + ++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->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 saved_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; + + saved_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 = saved_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_OP_SUCCESS, 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; + + /* 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_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_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_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; + case RE_OP_SUCCESS: + /* Success. */ + status = build_SUCCESS(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.min_width = 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; +} + +/* 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; + size_t req_length; + RE_CODE* req_chars; + Py_ssize_t req_flags; + size_t public_group_count; + Py_ssize_t code_len; + RE_CODE* code; + Py_ssize_t i; + PatternObject* self; + BOOL ascii; + BOOL locale; + BOOL unicode; + 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; + 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. */ + if (!(self->flags & RE_FLAG_UNICODE)) + 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); + } + + 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); + Py_ssize_t folded_charsize; + void (*set_char_at)(void* text, Py_ssize_t pos, Py_UCS4 ch); + RE_EncodingTable* encoding; + 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; + 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)(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(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)(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(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; + int i; + PyObject* result; + + /* 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; + int count; + Py_UCS4 cases[RE_MAX_CASES]; + Py_UCS4 folded[RE_MAX_FOLDED]; + PyObject* result; + int i; + + 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; + else if (flags & RE_FLAG_ASCII) + encoding = &ascii_encoding; + else + encoding = &ascii_encoding; + + /* Get all the simple cases. */ + count = encoding->all_cases((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((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; + + /* 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; + + 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 00000000..33dc1540 --- /dev/null +++ b/lib/regex/_regex.h @@ -0,0 +1,228 @@ +/* + * 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 6.3.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_DEFAULT_BOUNDARY 16 +#define RE_OP_DEFAULT_END_OF_WORD 17 +#define RE_OP_DEFAULT_START_OF_WORD 18 +#define RE_OP_END 19 +#define RE_OP_END_OF_LINE 20 +#define RE_OP_END_OF_LINE_U 21 +#define RE_OP_END_OF_STRING 22 +#define RE_OP_END_OF_STRING_LINE 23 +#define RE_OP_END_OF_STRING_LINE_U 24 +#define RE_OP_END_OF_WORD 25 +#define RE_OP_FUZZY 26 +#define RE_OP_GRAPHEME_BOUNDARY 27 +#define RE_OP_GREEDY_REPEAT 28 +#define RE_OP_GROUP 29 +#define RE_OP_GROUP_CALL 30 +#define RE_OP_GROUP_EXISTS 31 +#define RE_OP_LAZY_REPEAT 32 +#define RE_OP_LOOKAROUND 33 +#define RE_OP_NEXT 34 +#define RE_OP_PROPERTY 35 +#define RE_OP_PROPERTY_IGN 36 +#define RE_OP_PROPERTY_IGN_REV 37 +#define RE_OP_PROPERTY_REV 38 +#define RE_OP_RANGE 39 +#define RE_OP_RANGE_IGN 40 +#define RE_OP_RANGE_IGN_REV 41 +#define RE_OP_RANGE_REV 42 +#define RE_OP_REF_GROUP 43 +#define RE_OP_REF_GROUP_FLD 44 +#define RE_OP_REF_GROUP_FLD_REV 45 +#define RE_OP_REF_GROUP_IGN 46 +#define RE_OP_REF_GROUP_IGN_REV 47 +#define RE_OP_REF_GROUP_REV 48 +#define RE_OP_SEARCH_ANCHOR 49 +#define RE_OP_SET_DIFF 50 +#define RE_OP_SET_DIFF_IGN 51 +#define RE_OP_SET_DIFF_IGN_REV 52 +#define RE_OP_SET_DIFF_REV 53 +#define RE_OP_SET_INTER 54 +#define RE_OP_SET_INTER_IGN 55 +#define RE_OP_SET_INTER_IGN_REV 56 +#define RE_OP_SET_INTER_REV 57 +#define RE_OP_SET_SYM_DIFF 58 +#define RE_OP_SET_SYM_DIFF_IGN 59 +#define RE_OP_SET_SYM_DIFF_IGN_REV 60 +#define RE_OP_SET_SYM_DIFF_REV 61 +#define RE_OP_SET_UNION 62 +#define RE_OP_SET_UNION_IGN 63 +#define RE_OP_SET_UNION_IGN_REV 64 +#define RE_OP_SET_UNION_REV 65 +#define RE_OP_START_OF_LINE 66 +#define RE_OP_START_OF_LINE_U 67 +#define RE_OP_START_OF_STRING 68 +#define RE_OP_START_OF_WORD 69 +#define RE_OP_STRING 70 +#define RE_OP_STRING_FLD 71 +#define RE_OP_STRING_FLD_REV 72 +#define RE_OP_STRING_IGN 73 +#define RE_OP_STRING_IGN_REV 74 +#define RE_OP_STRING_REV 75 +#define RE_OP_STRING_SET 76 +#define RE_OP_STRING_SET_FLD 77 +#define RE_OP_STRING_SET_FLD_REV 78 +#define RE_OP_STRING_SET_IGN 79 +#define RE_OP_STRING_SET_IGN_REV 80 +#define RE_OP_STRING_SET_REV 81 +#define RE_OP_BODY_END 82 +#define RE_OP_BODY_START 83 +#define RE_OP_END_FUZZY 84 +#define RE_OP_END_GREEDY_REPEAT 85 +#define RE_OP_END_GROUP 86 +#define RE_OP_END_LAZY_REPEAT 87 +#define RE_OP_GREEDY_REPEAT_ONE 88 +#define RE_OP_GROUP_RETURN 89 +#define RE_OP_LAZY_REPEAT_ONE 90 +#define RE_OP_MATCH_BODY 91 +#define RE_OP_MATCH_TAIL 92 +#define RE_OP_START_GROUP 93 + +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_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_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_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_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_FUZZY", + "RE_OP_END_GREEDY_REPEAT", + "RE_OP_END_GROUP", + "RE_OP_END_LAZY_REPEAT", + "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_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_core.py b/lib/regex/_regex_core.py new file mode 100644 index 00000000..5adbb524 --- /dev/null +++ b/lib/regex/_regex_core.py @@ -0,0 +1,4086 @@ +# +# 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 + +if sys.version_info < (2, 6): + from Python25 import _regex +elif sys.version_info < (2, 7): + from Python26 import _regex +else: + from Python27 import _regex + + +__all__ = ["A", "ASCII", "B", "BESTMATCH", "D", "DEBUG", "E", "ENHANCEMATCH", + "F", "FULLCASE", "I", "IGNORECASE", "L", "LOCALE", "M", "MULTILINE", "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, set_error=False): + Exception.__init__(self, message) + self.set_error = set_error + +# 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. +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 | 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, "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 + +# 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 +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 +LAZY_REPEAT +LOOKAROUND +NEXT +PROPERTY +PROPERTY_IGN +PROPERTY_IGN_REV +PROPERTY_REV +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 +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, 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 dictionary. + args_dict.clear() + for pattern, pattern_type, flags, args, default_version in cache_dict: + args_dict[pattern, pattern_type, flags, default_version] = args + +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 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 or not sequence: + raise error("nothing to repeat at position %d" % 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 at position %d" % 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 at position %d" % 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 at position %d" % 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 } at position %d" % 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 at position %d" % 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 at position %d" % 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 at position %d" % source.pos) + + if ch in constraints: + raise error("repeated fuzzy constraint at position %d" % 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 at position %d" % 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 at position %d" % 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 at position %d" % 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 at position %d" % 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 (?") + 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) + + # (...: 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) + source.expect(")") + if info.is_open_group(name): + raise error("can't refer to an open group at position %d" % 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 at position %d" % 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 + 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_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 '-' at position %d" % source.pos) + else: + flags_off = 0 + + 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: can't turn off global flag at position %d" % source.pos) + + if flags_on & flags_off: + raise error("bad inline flags: flag turned on and off at position %d" % 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 at position %d" % 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: can't turn flags off at position %d" % 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): + "Parses a name." + name = source.get_while(set(")>"), include=False) + + if not name: + raise error("bad group name at position %d" % source.pos) + + if name.isdigit(): + if not allow_numeric: + raise error("bad group name at position %d" % source.pos) + else: + if not is_identifier(name): + raise error("bad group name at position %d" % 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 at position %d" % source.pos) + if ch in HEX_ESCAPES: + # A hexadecimal escape sequence. + return parse_hex_escape(source, info, HEX_ESCAPES[ch], in_set) + 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("can't refer to an open group at position %d" % 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: + raise error("bad octal escape at position %d" % source.pos) + +def parse_hex_escape(source, info, expected_len, in_set): + "Parses a hex escape sequence." + digits = [] + for i in range(expected_len): + ch = source.get() + if ch not in HEX_DIGITS: + raise error("bad hex escape at position %d" % 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("can't refer to an open group at position %d" % 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 at position %d" % 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 at position %d" % 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_pos=source.pos) + return make_property(info, prop, in_set) + elif ch and ch in "CLMNPSZ": + # An abbreviated property, eg \pL. + prop = lookup_property(None, ch, positive) + return make_property(info, prop, in_set, source_pos=source.pos) + + # 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 ] at position %d" % 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) + if (not isinstance(start, Character) or not start.positive or not + source.match("-")): + # It's not the start of a range. + return start + + # It looks like the start of a range of characters. + saved_pos = source.pos + if source.match("]"): + # We've reached the end of the set, so return both the character and + # hyphen. + source.pos = saved_pos + 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 at position %d" % 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 ] at position %d" % source.pos) + + if negate: + item = item.with_flags(positive=not item.positive) + + return item + + ch = source.get() + if not ch: + raise error("bad set at position %d" % source.pos, True) + + 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, positive=not negate, source_pos=source.pos) + +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[0] == "-": + 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() + +def lookup_property(property, value, positive, source_pos=None): + "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 property: + # Both the property and the value are provided. + prop = PROPERTIES.get(property) + if not prop: + raise error("unknown property at position %d" % source_pos) + + prop_id, value_dict = prop + val_id = value_dict.get(value) + if val_id is None: + raise error("unknown property value at position %d" % 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. + raise error("unknown property at position %d" % 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])] + + 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 at position %d" % 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): + "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("bad hex escape at position %d" % 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 at position %d" % 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) + + source.expect(">") + if name.isdigit(): + index = int(name) + if not 0 <= index <= pattern.groups: + raise error("invalid group at position %d" % 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 & 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, 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, reverse, fuzzy): + self.subpattern.fix_groups(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, reverse, fuzzy): + for b in self.branches: + b.fix_groups(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) + suffix, branches = Branch._split_common_suffix(info, branches) + + # Merge branches starting with the same character. (If a character + # prefix doesn't match in one branch, it won't match in any of the + # others starting with that same character.) + branches = Branch._merge_common_prefixes(info, branches) + + # Try to reduce adjacent single-character branches to sets. + branches = Branch._reduce_to_set(info, branches) + + if len(branches) > 1: + sequence = prefix + [Branch(branches)] + suffix + else: + sequence = prefix + branches + suffix + + return make_sequence(sequence) + + def optimise(self, info): + # Flatten branches within branches. + branches = Branch._flatten_branches(info, self.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(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, 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 at position %d" % self.position) + + if not 0 <= self.group <= self.info.group_count: + raise error("unknown group at position %d" % self.position) + + if self.group > 0 and self.info.open_group_count[self.group] > 1: + raise error("ambiguous group reference at position %d" % 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 at position %d" % 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 + 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, 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 at position %d" % self.position) + + if not 1 <= self.group <= self.info.group_count: + raise error("unknown group at position %d" % self.position) + + self.yes_item.fix_groups(reverse, fuzzy) + self.no_item.fix_groups(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 self.no_item: + 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 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, reverse, fuzzy): + self.subpattern.fix_groups(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. + character_matcher = LazyRepeat(AnyAll(), 1, None).compile(reverse, + fuzzy) + boundary_matcher = [(OP.GRAPHEME_BOUNDARY, 1)] + + return character_matcher + boundary_matcher + + def _dump(self, indent, reverse): + print "%sGRAPHEME" % (INDENT * indent) + + def max_width(self): + return UNLIMITED + +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, reverse, fuzzy): + self.subpattern.fix_groups(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, reverse, fuzzy): + self.info.defined_groups[self.group] = (self, reverse, fuzzy) + self.subpattern.fix_groups(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 LazyRepeat(GreedyRepeat): + _opcode = OP.LAZY_REPEAT + _op_name = "LAZY_REPEAT" + +class LookAround(RegexBase): + _dir_text = {False: "AHEAD", True: "BEHIND"} + + def __new__(cls, behind, positive, subpattern): + if positive and subpattern.is_empty(): + return subpattern + + return RegexBase.__new__(cls) + + def __init__(self, behind, positive, subpattern): + RegexBase.__init__(self) + self.behind = bool(behind) + self.positive = bool(positive) + self.subpattern = subpattern + + def fix_groups(self, reverse, fuzzy): + self.subpattern.fix_groups(self.behind, fuzzy) + + def optimise(self, info): + subpattern = self.subpattern.optimise(info) + + 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.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 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 + 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 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 + 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 + + self._key = self.__class__, self.group, self.case_flags + + def fix_groups(self, 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 at position %d" % self.position) + + if not 1 <= self.group <= self.info.group_count: + raise error("unknown group at position %d" % self.position) + + self._key = self.__class__, self.group, self.case_flags + + def remove_captures(self): + raise error("group reference not allowed at position %d" % 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, reverse, fuzzy): + for s in self.items: + s.fix_groups(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 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 + 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) + + 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 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 + + 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 = ascii("".join(chr(c))).lstrip("bu") + print("{}CHARACTER MATCH {}{}".format(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 + + 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 at position %d" % (substring, 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.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("trailing characters at position %d" % 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") + + 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), + "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(), +}) diff --git a/lib/regex/_regex_unicode.c b/lib/regex/_regex_unicode.c new file mode 100644 index 00000000..663a6bed --- /dev/null +++ b/lib/regex/_regex_unicode.c @@ -0,0 +1,12748 @@ +/* For Unicode version 6.3.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/16", + "1/2", + "1/3", + "1/4", + "1/5", + "1/6", + "1/7", + "1/8", + "1/9", + "10", + "100", + "1000", + "10000", + "100000", + "100000000", + "1000000000000", + "103", + "107", + "11", + "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", + "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", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "4", + "4/5", + "40", + "400", + "4000", + "40000", + "41", + "42", + "43", + "432000", + "44", + "45", + "46", + "47", + "48", + "49", + "5", + "5/2", + "5/6", + "5/8", + "50", + "500", + "5000", + "50000", + "6", + "60", + "600", + "6000", + "60000", + "7", + "7/2", + "7/8", + "70", + "700", + "7000", + "70000", + "8", + "80", + "800", + "8000", + "80000", + "84", + "9", + "9/2", + "90", + "900", + "9000", + "90000", + "91", + "A", + "ABOVE", + "ABOVELEFT", + "ABOVERIGHT", + "AEGEANNUMBERS", + "AHEX", + "AI", + "AIN", + "AL", + "ALAPH", + "ALCHEMICAL", + "ALCHEMICALSYMBOLS", + "ALEF", + "ALETTER", + "ALNUM", + "ALPHA", + "ALPHABETIC", + "ALPHABETICPF", + "ALPHABETICPRESENTATIONFORMS", + "ALPHANUMERIC", + "AMBIGUOUS", + "AN", + "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", + "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", + "BRAI", + "BRAILLE", + "BRAILLEPATTERNS", + "BREAKAFTER", + "BREAKBEFORE", + "BREAKBOTH", + "BREAKSYMBOLS", + "BUGI", + "BUGINESE", + "BUHD", + "BUHID", + "BURUSHASKIYEHBARREE", + "BYZANTINEMUSIC", + "BYZANTINEMUSICALSYMBOLS", + "C", + "C&", + "CAKM", + "CAN", + "CANADIANABORIGINAL", + "CANADIANSYLLABICS", + "CANONICAL", + "CANONICALCOMBININGCLASS", + "CANS", + "CARI", + "CARIAN", + "CARRIAGERETURN", + "CASED", + "CASEDLETTER", + "CASEIGNORABLE", + "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", + "CI", + "CIRCLE", + "CJ", + "CJK", + "CJKCOMPAT", + "CJKCOMPATFORMS", + "CJKCOMPATIBILITY", + "CJKCOMPATIBILITYFORMS", + "CJKCOMPATIBILITYIDEOGRAPHS", + "CJKCOMPATIBILITYIDEOGRAPHSSUPPLEMENT", + "CJKCOMPATIDEOGRAPHS", + "CJKCOMPATIDEOGRAPHSSUP", + "CJKEXTA", + "CJKEXTB", + "CJKEXTC", + "CJKEXTD", + "CJKRADICALSSUP", + "CJKRADICALSSUPPLEMENT", + "CJKSTROKES", + "CJKSYMBOLS", + "CJKSYMBOLSANDPUNCTUATION", + "CJKUNIFIEDIDEOGRAPHS", + "CJKUNIFIEDIDEOGRAPHSEXTENSIONA", + "CJKUNIFIEDIDEOGRAPHSEXTENSIONB", + "CJKUNIFIEDIDEOGRAPHSEXTENSIONC", + "CJKUNIFIEDIDEOGRAPHSEXTENSIOND", + "CL", + "CLOSE", + "CLOSEPARENTHESIS", + "CLOSEPUNCTUATION", + "CM", + "CN", + "CNTRL", + "CO", + "COM", + "COMBININGDIACRITICALMARKS", + "COMBININGDIACRITICALMARKSFORSYMBOLS", + "COMBININGDIACRITICALMARKSSUPPLEMENT", + "COMBININGHALFMARKS", + "COMBININGMARK", + "COMBININGMARKSFORSYMBOLS", + "COMMON", + "COMMONINDICNUMBERFORMS", + "COMMONSEPARATOR", + "COMPAT", + "COMPATJAMO", + "COMPLEXCONTEXT", + "CONDITIONALJAPANESESTARTER", + "CONNECTORPUNCTUATION", + "CONSONANT", + "CONSONANTDEAD", + "CONSONANTFINAL", + "CONSONANTHEADLETTER", + "CONSONANTMEDIAL", + "CONSONANTPLACEHOLDER", + "CONSONANTREPHA", + "CONSONANTSUBJOINED", + "CONTINGENTBREAK", + "CONTROL", + "CONTROLPICTURES", + "COPT", + "COPTIC", + "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", + "DIACRITICALSFORSYMBOLS", + "DIACRITICALSSUP", + "DIGIT", + "DINGBATS", + "DOMINO", + "DOMINOTILES", + "DOUBLEABOVE", + "DOUBLEBELOW", + "DOUBLEQUOTE", + "DQ", + "DSRT", + "DT", + "DUALJOINING", + "E", + "EA", + "EASTASIANWIDTH", + "EGYP", + "EGYPTIANHIEROGLYPHS", + "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", + "GENERALCATEGORY", + "GENERALPUNCTUATION", + "GEOMETRICSHAPES", + "GEOR", + "GEORGIAN", + "GEORGIANSUP", + "GEORGIANSUPPLEMENT", + "GL", + "GLAG", + "GLAGOLITIC", + "GLUE", + "GOTH", + "GOTHIC", + "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", + "HE", + "HEBR", + "HEBREW", + "HEBREWLETTER", + "HEH", + "HEHGOAL", + "HETH", + "HEX", + "HEXDIGIT", + "HIGHPRIVATEUSESURROGATES", + "HIGHPUSURROGATES", + "HIGHSURROGATES", + "HIRA", + "HIRAGANA", + "HL", + "HRKT", + "HST", + "HY", + "HYPHEN", + "ID", + "IDC", + "IDCONTINUE", + "IDEO", + "IDEOGRAPHIC", + "IDEOGRAPHICDESCRIPTIONCHARACTERS", + "IDS", + "IDSB", + "IDSBINARYOPERATOR", + "IDST", + "IDSTART", + "IDSTRINARYOPERATOR", + "IMPERIALARAMAIC", + "IN", + "INDICMATRACATEGORY", + "INDICNUMBERFORMS", + "INDICSYLLABICCATEGORY", + "INFIXNUMERIC", + "INHERITED", + "INIT", + "INITIAL", + "INITIALPUNCTUATION", + "INMC", + "INSC", + "INSCRIPTIONALPAHLAVI", + "INSCRIPTIONALPARTHIAN", + "INSEPARABLE", + "INSEPERABLE", + "INVISIBLE", + "IOTASUBSCRIPT", + "IPAEXT", + "IPAEXTENSIONS", + "IS", + "ISO", + "ISOLATED", + "ITAL", + "JAMO", + "JAMOEXTA", + "JAMOEXTB", + "JAVA", + "JAVANESE", + "JG", + "JL", + "JOINC", + "JOINCAUSING", + "JOINCONTROL", + "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", + "KNDA", + "KNOTTEDHEH", + "KTHI", + "KV", + "L", + "L&", + "LAM", + "LAMADH", + "LANA", + "LAO", + "LAOO", + "LATIN", + "LATIN1", + "LATIN1SUP", + "LATIN1SUPPLEMENT", + "LATINEXTA", + "LATINEXTADDITIONAL", + "LATINEXTB", + "LATINEXTC", + "LATINEXTD", + "LATINEXTENDEDA", + "LATINEXTENDEDADDITIONAL", + "LATINEXTENDEDB", + "LATINEXTENDEDC", + "LATINEXTENDEDD", + "LATN", + "LB", + "LC", + "LE", + "LEADINGJAMO", + "LEFT", + "LEFTANDRIGHT", + "LEFTJOINING", + "LEFTTORIGHT", + "LEFTTORIGHTEMBEDDING", + "LEFTTORIGHTISOLATE", + "LEFTTORIGHTOVERRIDE", + "LEPC", + "LEPCHA", + "LETTER", + "LETTERLIKESYMBOLS", + "LETTERNUMBER", + "LF", + "LIMB", + "LIMBU", + "LINB", + "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&", + "MAHJONG", + "MAHJONGTILES", + "MALAYALAM", + "MAND", + "MANDAIC", + "MANDATORYBREAK", + "MARK", + "MATH", + "MATHALPHANUM", + "MATHEMATICALALPHANUMERICSYMBOLS", + "MATHEMATICALOPERATORS", + "MATHOPERATORS", + "MATHSYMBOL", + "MB", + "MC", + "ME", + "MED", + "MEDIAL", + "MEEM", + "MEETEIMAYEK", + "MEETEIMAYEKEXT", + "MEETEIMAYEKEXTENSIONS", + "MERC", + "MERO", + "MEROITICCURSIVE", + "MEROITICHIEROGLYPHS", + "MIAO", + "MIDLETTER", + "MIDNUM", + "MIDNUMLET", + "MIM", + "MISCARROWS", + "MISCELLANEOUSMATHEMATICALSYMBOLSA", + "MISCELLANEOUSMATHEMATICALSYMBOLSB", + "MISCELLANEOUSSYMBOLS", + "MISCELLANEOUSSYMBOLSANDARROWS", + "MISCELLANEOUSSYMBOLSANDPICTOGRAPHS", + "MISCELLANEOUSTECHNICAL", + "MISCMATHSYMBOLSA", + "MISCMATHSYMBOLSB", + "MISCPICTOGRAPHS", + "MISCSYMBOLS", + "MISCTECHNICAL", + "ML", + "MLYM", + "MN", + "MODIFIERLETTER", + "MODIFIERLETTERS", + "MODIFIERSYMBOL", + "MODIFIERTONELETTERS", + "MODIFYINGLETTER", + "MONG", + "MONGOLIAN", + "MTEI", + "MUSIC", + "MUSICALSYMBOLS", + "MYANMAR", + "MYANMAREXTA", + "MYANMAREXTENDEDA", + "MYMR", + "N", + "N&", + "NA", + "NAN", + "NAR", + "NARROW", + "NB", + "NCHAR", + "ND", + "NEUTRAL", + "NEWLINE", + "NEWTAILUE", + "NEXTLINE", + "NK", + "NKO", + "NKOO", + "NL", + "NO", + "NOBLOCK", + "NOBREAK", + "NOJOININGGROUP", + "NONCHARACTERCODEPOINT", + "NONE", + "NONJOINING", + "NONSPACINGMARK", + "NONSTARTER", + "NOON", + "NOTAPPLICABLE", + "NOTREORDERED", + "NR", + "NS", + "NSM", + "NT", + "NU", + "NUKTA", + "NUMBER", + "NUMBERFORMS", + "NUMERIC", + "NUMERICTYPE", + "NUMERICVALUE", + "NUN", + "NV", + "NYA", + "OALPHA", + "OCR", + "ODI", + "OGAM", + "OGHAM", + "OGREXT", + "OIDC", + "OIDS", + "OLCHIKI", + "OLCK", + "OLDITALIC", + "OLDPERSIAN", + "OLDSOUTHARABIAN", + "OLDTURKIC", + "OLETTER", + "OLOWER", + "OMATH", + "ON", + "OP", + "OPENPUNCTUATION", + "OPTICALCHARACTERRECOGNITION", + "ORIYA", + "ORKH", + "ORYA", + "OSMA", + "OSMANYA", + "OTHER", + "OTHERALPHABETIC", + "OTHERDEFAULTIGNORABLECODEPOINT", + "OTHERGRAPHEMEEXTEND", + "OTHERIDCONTINUE", + "OTHERIDSTART", + "OTHERLETTER", + "OTHERLOWERCASE", + "OTHERMATH", + "OTHERNEUTRAL", + "OTHERNUMBER", + "OTHERPUNCTUATION", + "OTHERSYMBOL", + "OTHERUPPERCASE", + "OUPPER", + "OV", + "OVERLAY", + "OVERSTRUCK", + "P", + "P&", + "PARAGRAPHSEPARATOR", + "PATSYN", + "PATTERNSYNTAX", + "PATTERNWHITESPACE", + "PATWS", + "PC", + "PD", + "PDF", + "PDI", + "PE", + "PF", + "PHAG", + "PHAGSPA", + "PHAISTOS", + "PHAISTOSDISC", + "PHLI", + "PHNX", + "PHOENICIAN", + "PHONETICEXT", + "PHONETICEXTENSIONS", + "PHONETICEXTENSIONSSUPPLEMENT", + "PHONETICEXTSUP", + "PI", + "PLAYINGCARDS", + "PLRD", + "PO", + "POPDIRECTIONALFORMAT", + "POPDIRECTIONALISOLATE", + "POSTFIXNUMERIC", + "PP", + "PR", + "PREFIXNUMERIC", + "PREPEND", + "PRINT", + "PRIVATEUSE", + "PRIVATEUSEAREA", + "PRTI", + "PS", + "PUA", + "PUNCT", + "PUNCTUATION", + "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", + "SHARADA", + "SHAVIAN", + "SHAW", + "SHIN", + "SHRD", + "SINGLEQUOTE", + "SINH", + "SINHALA", + "SK", + "SM", + "SMALL", + "SMALLFORMS", + "SMALLFORMVARIANTS", + "SML", + "SO", + "SOFTDOTTED", + "SORA", + "SORASOMPENG", + "SP", + "SPACE", + "SPACESEPARATOR", + "SPACINGMARK", + "SPACINGMODIFIERLETTERS", + "SPECIALS", + "SQ", + "SQR", + "SQUARE", + "ST", + "STERM", + "SUB", + "SUND", + "SUNDANESE", + "SUNDANESESUP", + "SUNDANESESUPPLEMENT", + "SUP", + "SUPARROWSA", + "SUPARROWSB", + "SUPER", + "SUPERANDSUB", + "SUPERSCRIPTSANDSUBSCRIPTS", + "SUPMATHOPERATORS", + "SUPPLEMENTALARROWSA", + "SUPPLEMENTALARROWSB", + "SUPPLEMENTALMATHEMATICALOPERATORS", + "SUPPLEMENTALPUNCTUATION", + "SUPPLEMENTARYPRIVATEUSEAREAA", + "SUPPLEMENTARYPRIVATEUSEAREAB", + "SUPPUAA", + "SUPPUAB", + "SUPPUNCTUATION", + "SURROGATE", + "SWASHKAF", + "SY", + "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", + "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", + "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: 10595 bytes. */ + +/* properties. */ + +RE_Property re_properties[] = { + { 508, 0, 0}, + { 506, 0, 0}, + { 233, 1, 1}, + { 232, 1, 1}, + { 963, 2, 2}, + { 961, 2, 2}, + {1123, 3, 3}, + {1118, 3, 3}, + { 523, 4, 4}, + { 507, 4, 4}, + { 969, 5, 5}, + { 960, 5, 5}, + { 736, 6, 6}, + { 156, 7, 6}, + { 155, 7, 6}, + { 711, 8, 6}, + { 710, 8, 6}, + {1093, 9, 6}, + {1092, 9, 6}, + { 273, 10, 6}, + { 275, 11, 6}, + { 326, 11, 6}, + { 321, 12, 6}, + { 401, 12, 6}, + { 323, 13, 6}, + { 403, 13, 6}, + { 322, 14, 6}, + { 402, 14, 6}, + { 319, 15, 6}, + { 399, 15, 6}, + { 320, 16, 6}, + { 400, 16, 6}, + { 588, 17, 6}, + { 584, 17, 6}, + { 580, 18, 6}, + { 579, 18, 6}, + {1131, 19, 6}, + {1130, 19, 6}, + {1129, 20, 6}, + {1128, 20, 6}, + { 426, 21, 6}, + { 434, 21, 6}, + { 524, 22, 6}, + { 532, 22, 6}, + { 522, 23, 6}, + { 526, 23, 6}, + { 525, 24, 6}, + { 533, 24, 6}, + {1119, 25, 6}, + {1126, 25, 6}, + { 992, 25, 6}, + { 225, 26, 6}, + { 223, 26, 6}, + { 623, 27, 6}, + { 621, 27, 6}, + { 419, 28, 6}, + { 577, 29, 6}, + { 926, 30, 6}, + { 923, 30, 6}, + {1056, 31, 6}, + {1055, 31, 6}, + { 866, 32, 6}, + { 848, 32, 6}, + { 567, 33, 6}, + { 566, 33, 6}, + { 187, 34, 6}, + { 145, 34, 6}, + { 859, 35, 6}, + { 832, 35, 6}, + { 582, 36, 6}, + { 581, 36, 6}, + { 436, 37, 6}, + { 435, 37, 6}, + { 485, 38, 6}, + { 483, 38, 6}, + { 865, 39, 6}, + { 847, 39, 6}, + { 871, 40, 6}, + { 872, 40, 6}, + { 810, 41, 6}, + { 796, 41, 6}, + { 861, 42, 6}, + { 837, 42, 6}, + { 586, 43, 6}, + { 585, 43, 6}, + { 589, 44, 6}, + { 587, 44, 6}, + { 928, 45, 6}, + {1089, 46, 6}, + {1085, 46, 6}, + { 860, 47, 6}, + { 834, 47, 6}, + { 428, 48, 6}, + { 427, 48, 6}, + { 988, 49, 6}, + { 964, 49, 6}, + { 709, 50, 6}, + { 708, 50, 6}, + { 863, 51, 6}, + { 839, 51, 6}, + { 862, 52, 6}, + { 838, 52, 6}, + {1001, 53, 6}, + {1098, 54, 6}, + {1114, 54, 6}, + { 881, 55, 6}, + { 882, 55, 6}, + { 880, 56, 6}, + { 879, 56, 6}, + { 555, 57, 7}, + { 575, 57, 7}, + { 224, 58, 8}, + { 215, 58, 8}, + { 268, 59, 9}, + { 278, 59, 9}, + { 425, 60, 10}, + { 449, 60, 10}, + { 453, 61, 11}, + { 452, 61, 11}, + { 624, 62, 12}, + { 619, 62, 12}, + { 625, 63, 13}, + { 626, 63, 13}, + { 701, 64, 14}, + { 678, 64, 14}, + { 827, 65, 15}, + { 821, 65, 15}, + { 828, 66, 16}, + { 830, 66, 16}, + { 227, 67, 6}, + { 226, 67, 6}, + { 592, 68, 17}, + { 600, 68, 17}, + { 594, 69, 18}, + { 601, 69, 18}, + { 159, 70, 6}, + { 154, 70, 6}, + { 166, 71, 6}, + { 231, 72, 6}, + { 521, 73, 6}, + { 911, 74, 6}, + {1122, 75, 6}, + {1127, 76, 6}, +}; + +/* properties: 572 bytes. */ + +/* property values. */ + +RE_PropertyValue re_property_values[] = { + {1086, 0, 0}, + { 357, 0, 0}, + {1094, 0, 1}, + { 718, 0, 1}, + { 712, 0, 2}, + { 705, 0, 2}, + {1066, 0, 3}, + { 717, 0, 3}, + { 775, 0, 4}, + { 706, 0, 4}, + { 864, 0, 5}, + { 707, 0, 5}, + { 813, 0, 6}, + { 774, 0, 6}, + { 467, 0, 7}, + { 744, 0, 7}, + { 994, 0, 8}, + { 743, 0, 8}, + { 424, 0, 9}, + { 797, 0, 9}, + { 440, 0, 9}, + { 693, 0, 10}, + { 805, 0, 10}, + { 868, 0, 11}, + { 806, 0, 11}, + { 993, 0, 12}, + {1155, 0, 12}, + { 703, 0, 13}, + {1153, 0, 13}, + { 878, 0, 14}, + {1154, 0, 14}, + { 384, 0, 15}, + { 277, 0, 15}, + { 358, 0, 15}, + { 499, 0, 16}, + { 316, 0, 16}, + { 912, 0, 17}, + { 359, 0, 17}, + {1023, 0, 18}, + { 393, 0, 18}, + { 420, 0, 19}, + { 884, 0, 19}, + { 851, 0, 20}, + { 915, 0, 20}, + { 355, 0, 21}, + { 887, 0, 21}, + { 374, 0, 22}, + { 883, 0, 22}, + { 869, 0, 23}, + { 903, 0, 23}, + { 741, 0, 24}, + { 982, 0, 24}, + { 397, 0, 25}, + { 961, 0, 25}, + { 777, 0, 26}, + { 981, 0, 26}, + { 870, 0, 27}, + { 987, 0, 27}, + { 599, 0, 28}, + { 900, 0, 28}, + { 494, 0, 29}, + { 888, 0, 29}, + { 858, 0, 30}, + { 261, 0, 30}, + { 262, 0, 30}, + { 691, 0, 31}, + { 656, 0, 31}, + { 657, 0, 31}, + { 735, 0, 32}, + { 727, 0, 32}, + { 365, 0, 32}, + { 728, 0, 32}, + { 824, 0, 33}, + { 789, 0, 33}, + { 790, 0, 33}, + { 918, 0, 34}, + { 876, 0, 34}, + { 917, 0, 34}, + { 877, 0, 34}, + {1028, 0, 35}, + { 950, 0, 35}, + { 951, 0, 35}, + { 971, 0, 36}, + {1148, 0, 36}, + {1149, 0, 36}, + { 274, 0, 37}, + { 679, 0, 37}, + { 188, 0, 38}, + { 807, 1, 0}, + { 795, 1, 0}, + { 211, 1, 1}, + { 186, 1, 1}, + { 666, 1, 2}, + { 665, 1, 2}, + { 664, 1, 2}, + { 672, 1, 3}, + { 667, 1, 3}, + { 674, 1, 4}, + { 669, 1, 4}, + { 609, 1, 5}, + { 608, 1, 5}, + { 995, 1, 6}, + { 776, 1, 6}, + { 361, 1, 7}, + { 437, 1, 7}, + { 528, 1, 8}, + { 527, 1, 8}, + { 406, 1, 9}, + { 412, 1, 10}, + { 411, 1, 10}, + { 413, 1, 10}, + { 182, 1, 11}, + { 561, 1, 12}, + { 169, 1, 13}, + {1030, 1, 14}, + { 181, 1, 15}, + { 180, 1, 15}, + {1061, 1, 16}, + { 803, 1, 17}, + { 955, 1, 18}, + { 733, 1, 19}, + { 171, 1, 20}, + { 170, 1, 20}, + { 431, 1, 21}, + { 221, 1, 22}, + { 536, 1, 23}, + { 534, 1, 24}, + { 853, 1, 25}, + {1047, 1, 26}, + {1054, 1, 27}, + { 639, 1, 28}, + { 731, 1, 29}, + { 980, 1, 30}, + {1062, 1, 31}, + { 661, 1, 32}, + {1063, 1, 33}, + { 785, 1, 34}, + { 512, 1, 35}, + { 551, 1, 36}, + { 614, 1, 36}, + { 471, 1, 37}, + { 477, 1, 38}, + { 476, 1, 38}, + { 325, 1, 39}, + {1087, 1, 40}, + {1081, 1, 40}, + { 266, 1, 40}, + { 836, 1, 41}, + { 948, 1, 42}, + {1033, 1, 43}, + { 558, 1, 44}, + { 257, 1, 45}, + {1035, 1, 46}, + { 649, 1, 47}, + { 781, 1, 48}, + {1088, 1, 49}, + {1082, 1, 49}, + { 696, 1, 50}, + {1038, 1, 51}, + { 800, 1, 52}, + { 650, 1, 53}, + { 255, 1, 54}, + {1039, 1, 55}, + { 206, 1, 56}, + {1004, 1, 57}, + { 212, 1, 58}, + { 690, 1, 59}, + { 840, 1, 60}, + {1006, 1, 61}, + {1005, 1, 61}, + {1102, 1, 62}, + {1101, 1, 62}, + { 897, 1, 63}, + { 896, 1, 63}, + { 898, 1, 64}, + { 899, 1, 64}, + { 363, 1, 65}, + { 439, 1, 65}, + { 673, 1, 66}, + { 668, 1, 66}, + { 530, 1, 67}, + { 529, 1, 67}, + { 509, 1, 68}, + { 918, 1, 68}, + {1012, 1, 69}, + {1011, 1, 69}, + { 398, 1, 70}, + { 362, 1, 71}, + { 438, 1, 71}, + { 366, 1, 71}, + { 692, 1, 72}, + { 825, 1, 73}, + { 185, 1, 74}, + { 739, 1, 75}, + { 740, 1, 75}, + { 766, 1, 76}, + { 771, 1, 76}, + { 385, 1, 77}, + { 852, 1, 78}, + { 833, 1, 78}, + { 460, 1, 79}, + { 459, 1, 79}, + { 243, 1, 80}, + { 234, 1, 81}, + { 510, 1, 82}, + { 763, 1, 83}, + { 770, 1, 83}, + { 441, 1, 84}, + { 761, 1, 85}, + { 767, 1, 85}, + {1014, 1, 86}, + {1008, 1, 86}, + { 249, 1, 87}, + { 248, 1, 87}, + {1015, 1, 88}, + {1009, 1, 88}, + { 762, 1, 89}, + { 768, 1, 89}, + {1016, 1, 90}, + {1013, 1, 90}, + { 764, 1, 91}, + { 760, 1, 91}, + { 517, 1, 92}, + { 675, 1, 93}, + { 670, 1, 93}, + { 387, 1, 94}, + { 514, 1, 95}, + { 513, 1, 95}, + {1065, 1, 96}, + { 474, 1, 97}, + { 472, 1, 97}, + { 409, 1, 98}, + { 407, 1, 98}, + {1017, 1, 99}, + {1022, 1, 99}, + { 343, 1, 100}, + { 342, 1, 100}, + { 638, 1, 101}, + { 637, 1, 101}, + { 583, 1, 102}, + { 579, 1, 102}, + { 346, 1, 103}, + { 345, 1, 103}, + { 572, 1, 104}, + { 641, 1, 105}, + { 237, 1, 106}, + { 550, 1, 107}, + { 371, 1, 107}, + { 636, 1, 108}, + { 239, 1, 109}, + { 238, 1, 109}, + { 344, 1, 110}, + { 644, 1, 111}, + { 642, 1, 111}, + { 464, 1, 112}, + { 463, 1, 112}, + { 332, 1, 113}, + { 330, 1, 113}, + { 348, 1, 114}, + { 338, 1, 114}, + {1143, 1, 115}, + {1142, 1, 115}, + { 347, 1, 116}, + { 329, 1, 116}, + {1145, 1, 117}, + {1144, 1, 118}, + { 704, 1, 119}, + {1096, 1, 120}, + { 410, 1, 121}, + { 408, 1, 121}, + { 208, 1, 122}, + { 778, 1, 123}, + { 676, 1, 124}, + { 671, 1, 124}, + {1027, 1, 125}, + { 368, 1, 126}, + { 593, 1, 126}, + { 890, 1, 127}, + { 959, 1, 128}, + { 433, 1, 129}, + { 432, 1, 129}, + { 645, 1, 130}, + { 932, 1, 131}, + { 552, 1, 132}, + { 615, 1, 132}, + { 618, 1, 133}, + { 318, 1, 134}, + { 787, 1, 135}, + { 786, 1, 135}, + {1040, 1, 136}, + { 750, 1, 137}, + { 749, 1, 137}, + { 475, 1, 138}, + { 473, 1, 138}, + { 748, 1, 139}, + { 554, 1, 140}, + { 549, 1, 140}, + { 553, 1, 141}, + { 616, 1, 141}, + { 570, 1, 142}, + { 568, 1, 143}, + { 569, 1, 143}, + { 713, 1, 144}, + { 913, 1, 145}, + { 916, 1, 145}, + { 912, 1, 145}, + { 334, 1, 146}, + { 336, 1, 146}, + { 158, 1, 147}, + { 157, 1, 147}, + { 178, 1, 148}, + { 176, 1, 148}, + {1099, 1, 149}, + {1114, 1, 149}, + {1105, 1, 150}, + { 364, 1, 151}, + { 543, 1, 151}, + { 333, 1, 152}, + { 331, 1, 152}, + { 985, 1, 153}, + { 984, 1, 153}, + { 179, 1, 154}, + { 177, 1, 154}, + { 545, 1, 155}, + { 542, 1, 155}, + { 996, 1, 156}, + { 700, 1, 157}, + { 699, 1, 158}, + { 144, 1, 159}, + { 164, 1, 160}, + { 165, 1, 161}, + { 892, 1, 162}, + { 891, 1, 162}, + { 724, 1, 163}, + { 271, 1, 164}, + { 842, 1, 165}, + { 520, 1, 166}, + {1084, 1, 167}, + { 843, 1, 168}, + { 429, 1, 169}, + { 974, 1, 170}, + { 857, 1, 171}, + { 405, 1, 172}, + { 590, 1, 173}, + { 895, 1, 174}, + { 726, 1, 175}, + { 754, 1, 176}, + { 753, 1, 177}, + { 648, 1, 178}, + { 844, 1, 179}, + { 200, 1, 180}, + { 603, 1, 181}, + { 602, 1, 182}, + { 845, 1, 183}, + { 947, 1, 184}, + { 946, 1, 184}, + { 246, 1, 185}, + { 630, 1, 186}, + { 990, 1, 187}, + { 317, 1, 188}, + { 973, 1, 189}, + {1044, 1, 190}, + { 394, 1, 191}, + { 396, 1, 192}, + { 395, 1, 192}, + { 455, 1, 193}, + { 210, 1, 194}, + { 209, 1, 194}, + { 755, 1, 195}, + { 634, 1, 196}, + { 633, 1, 196}, + { 260, 1, 197}, + { 259, 1, 197}, + { 784, 1, 198}, + { 783, 1, 198}, + { 163, 1, 199}, + { 162, 1, 199}, + {1042, 1, 200}, + {1041, 1, 200}, + { 389, 1, 201}, + { 388, 1, 201}, + { 738, 1, 202}, + { 737, 1, 202}, + { 174, 1, 203}, + { 173, 1, 203}, + { 730, 1, 204}, + { 729, 1, 204}, + { 443, 1, 205}, + { 442, 1, 205}, + { 901, 1, 206}, + { 461, 1, 207}, + { 462, 1, 207}, + { 466, 1, 208}, + { 465, 1, 208}, + { 765, 1, 209}, + { 769, 1, 209}, + { 456, 1, 210}, + {1078, 1, 211}, + {1077, 1, 211}, + { 151, 1, 212}, + { 150, 1, 212}, + { 349, 1, 213}, + { 339, 1, 213}, + { 350, 1, 214}, + { 340, 1, 214}, + { 351, 1, 215}, + { 341, 1, 215}, + { 335, 1, 216}, + { 337, 1, 216}, + {1036, 1, 217}, + {1100, 1, 218}, + {1115, 1, 218}, + {1018, 1, 219}, + {1020, 1, 219}, + {1019, 1, 220}, + {1021, 1, 220}, + {1090, 2, 0}, + {1159, 2, 0}, + { 367, 2, 1}, + {1158, 2, 1}, + { 663, 2, 2}, + { 677, 2, 2}, + { 527, 2, 3}, + { 531, 2, 3}, + { 406, 2, 4}, + { 414, 2, 4}, + { 182, 2, 5}, + { 184, 2, 5}, + { 561, 2, 6}, + { 560, 2, 6}, + { 169, 2, 7}, + { 168, 2, 7}, + {1030, 2, 8}, + {1029, 2, 8}, + {1061, 2, 9}, + {1060, 2, 9}, + { 431, 2, 10}, + { 430, 2, 10}, + { 221, 2, 11}, + { 220, 2, 11}, + { 536, 2, 12}, + { 537, 2, 12}, + { 534, 2, 13}, + { 535, 2, 13}, + { 853, 2, 14}, + { 855, 2, 14}, + {1047, 2, 15}, + {1048, 2, 15}, + {1054, 2, 16}, + {1053, 2, 16}, + { 639, 2, 17}, + { 652, 2, 17}, + { 731, 2, 18}, + { 773, 2, 18}, + { 980, 2, 19}, + { 979, 2, 19}, + {1062, 2, 20}, + { 661, 2, 21}, + { 662, 2, 21}, + {1063, 2, 22}, + {1064, 2, 22}, + { 785, 2, 23}, + { 788, 2, 23}, + { 512, 2, 24}, + { 511, 2, 24}, + { 549, 2, 25}, + { 548, 2, 25}, + { 471, 2, 26}, + { 470, 2, 26}, + { 325, 2, 27}, + { 324, 2, 27}, + { 265, 2, 28}, + { 269, 2, 28}, + { 836, 2, 29}, + { 835, 2, 29}, + { 948, 2, 30}, + { 949, 2, 30}, + { 649, 2, 31}, + { 651, 2, 31}, + { 781, 2, 32}, + { 780, 2, 32}, + { 572, 2, 33}, + { 571, 2, 33}, + { 641, 2, 34}, + { 632, 2, 34}, + { 237, 2, 35}, + { 236, 2, 35}, + { 547, 2, 36}, + { 556, 2, 36}, + {1140, 2, 37}, + {1141, 2, 37}, + { 842, 2, 38}, + { 613, 2, 38}, + { 520, 2, 39}, + { 519, 2, 39}, + { 429, 2, 40}, + { 448, 2, 40}, + { 596, 2, 41}, + {1152, 2, 41}, + { 920, 2, 41}, + {1033, 2, 42}, + {1059, 2, 42}, + { 558, 2, 43}, + { 557, 2, 43}, + { 257, 2, 44}, + { 256, 2, 44}, + {1035, 2, 45}, + {1034, 2, 45}, + { 696, 2, 46}, + { 695, 2, 46}, + {1038, 2, 47}, + {1045, 2, 47}, + { 698, 2, 48}, + { 697, 2, 48}, + {1084, 2, 49}, + {1083, 2, 49}, + { 974, 2, 50}, + { 975, 2, 50}, + { 857, 2, 51}, + { 856, 2, 51}, + { 404, 2, 52}, + { 391, 2, 52}, + { 248, 2, 53}, + { 247, 2, 53}, + { 255, 2, 54}, + { 254, 2, 54}, + { 387, 2, 55}, + { 386, 2, 55}, + { 919, 2, 55}, + { 800, 2, 56}, + {1046, 2, 56}, + { 517, 2, 57}, + { 516, 2, 57}, + {1065, 2, 58}, + {1058, 2, 58}, + {1027, 2, 59}, + {1026, 2, 59}, + { 843, 2, 60}, + {1132, 2, 60}, + { 648, 2, 61}, + { 647, 2, 61}, + { 206, 2, 62}, + { 205, 2, 62}, + { 394, 2, 63}, + {1133, 2, 63}, + { 895, 2, 64}, + { 894, 2, 64}, + { 890, 2, 65}, + { 889, 2, 65}, + { 803, 2, 66}, + { 804, 2, 66}, + {1004, 2, 67}, + {1003, 2, 67}, + { 690, 2, 68}, + { 689, 2, 68}, + { 840, 2, 69}, + { 841, 2, 69}, + {1096, 2, 70}, + {1097, 2, 70}, + { 959, 2, 71}, + { 958, 2, 71}, + { 645, 2, 72}, + { 631, 2, 72}, + { 932, 2, 73}, + { 941, 2, 73}, + { 724, 2, 74}, + { 723, 2, 74}, + { 271, 2, 75}, + { 270, 2, 75}, + { 726, 2, 76}, + { 725, 2, 76}, + { 318, 2, 77}, + {1039, 2, 78}, + { 660, 2, 78}, + {1040, 2, 79}, + {1049, 2, 79}, + { 200, 2, 80}, + { 201, 2, 80}, + { 455, 2, 81}, + { 454, 2, 81}, + { 955, 2, 82}, + { 956, 2, 82}, + { 704, 2, 83}, + { 208, 2, 84}, + { 207, 2, 84}, + { 618, 2, 85}, + { 617, 2, 85}, + { 748, 2, 86}, + { 782, 2, 86}, + { 590, 2, 87}, + { 183, 2, 87}, + { 844, 2, 88}, + { 957, 2, 88}, + { 603, 2, 89}, + { 914, 2, 89}, + { 602, 2, 90}, + { 893, 2, 90}, + { 845, 2, 91}, + { 854, 2, 91}, + { 630, 2, 92}, + { 654, 2, 92}, + { 212, 2, 93}, + { 213, 2, 93}, + { 246, 2, 94}, + { 245, 2, 94}, + { 733, 2, 95}, + { 732, 2, 95}, + { 317, 2, 96}, + { 263, 2, 96}, + { 753, 2, 97}, + { 751, 2, 97}, + { 754, 2, 98}, + { 752, 2, 98}, + { 755, 2, 99}, + { 902, 2, 99}, + { 973, 2, 100}, + { 977, 2, 100}, + { 990, 2, 101}, + { 989, 2, 101}, + {1044, 2, 102}, + {1043, 2, 102}, + { 643, 2, 103}, + { 574, 2, 103}, + { 858, 3, 0}, + {1134, 3, 0}, + { 446, 3, 1}, + { 447, 3, 1}, + { 978, 3, 2}, + { 997, 3, 2}, + { 562, 3, 3}, + { 573, 3, 3}, + { 392, 3, 4}, + { 694, 3, 5}, + { 799, 3, 6}, + { 805, 3, 6}, + { 484, 3, 7}, + { 929, 3, 8}, + { 934, 3, 8}, + { 499, 3, 9}, + { 497, 3, 9}, + { 641, 3, 10}, + { 628, 3, 10}, + { 153, 3, 11}, + { 680, 3, 11}, + { 756, 3, 12}, + { 772, 3, 12}, + { 757, 3, 13}, + { 774, 3, 13}, + { 758, 3, 14}, + { 742, 3, 14}, + { 826, 3, 15}, + { 822, 3, 15}, + { 486, 3, 16}, + { 481, 3, 16}, + { 858, 4, 0}, + {1134, 4, 0}, + { 392, 4, 1}, + { 694, 4, 2}, + { 384, 4, 3}, + { 357, 4, 3}, + { 484, 4, 4}, + { 481, 4, 4}, + { 929, 4, 5}, + { 934, 4, 5}, + { 994, 4, 6}, + { 982, 4, 6}, + { 656, 4, 7}, + {1095, 4, 8}, + {1032, 4, 9}, + { 719, 4, 10}, + { 721, 4, 11}, + { 910, 4, 12}, + { 907, 4, 12}, + { 858, 5, 0}, + {1134, 5, 0}, + { 392, 5, 1}, + { 694, 5, 2}, + { 484, 5, 3}, + { 481, 5, 3}, + { 970, 5, 4}, + { 965, 5, 4}, + { 499, 5, 5}, + { 497, 5, 5}, + { 991, 5, 6}, + { 710, 5, 7}, + { 707, 5, 7}, + {1092, 5, 8}, + {1091, 5, 8}, + { 846, 5, 9}, + { 680, 5, 9}, + { 826, 5, 10}, + { 822, 5, 10}, + { 194, 5, 11}, + { 189, 5, 11}, + {1001, 5, 12}, + {1000, 5, 12}, + { 353, 5, 13}, + { 352, 5, 13}, + { 962, 5, 14}, + { 961, 5, 14}, + { 806, 6, 0}, + { 789, 6, 0}, + { 487, 6, 0}, + { 488, 6, 0}, + {1139, 6, 1}, + {1135, 6, 1}, + {1032, 6, 1}, + {1079, 6, 1}, + { 816, 7, 0}, + { 791, 7, 0}, + { 681, 7, 1}, + { 656, 7, 1}, + {1112, 7, 2}, + {1095, 7, 2}, + {1075, 7, 3}, + {1032, 7, 3}, + { 720, 7, 4}, + { 719, 7, 4}, + { 722, 7, 5}, + { 721, 7, 5}, + { 685, 8, 0}, + { 656, 8, 0}, + { 937, 8, 1}, + { 927, 8, 1}, + { 478, 8, 2}, + { 457, 8, 2}, + { 479, 8, 3}, + { 468, 8, 3}, + { 480, 8, 4}, + { 469, 8, 4}, + { 175, 8, 5}, + { 161, 8, 5}, + { 369, 8, 6}, + { 393, 8, 6}, + { 878, 8, 7}, + { 202, 8, 7}, + { 967, 8, 8}, + { 950, 8, 8}, + {1119, 8, 9}, + {1125, 8, 9}, + { 867, 8, 10}, + { 849, 8, 10}, + { 242, 8, 11}, + { 235, 8, 11}, + { 813, 8, 12}, + { 820, 8, 12}, + { 172, 8, 13}, + { 148, 8, 13}, + { 688, 8, 14}, + { 716, 8, 14}, + { 940, 8, 15}, + { 944, 8, 15}, + { 686, 8, 16}, + { 714, 8, 16}, + { 938, 8, 17}, + { 942, 8, 17}, + { 904, 8, 18}, + { 885, 8, 18}, + { 687, 8, 19}, + { 715, 8, 19}, + { 939, 8, 20}, + { 943, 8, 20}, + { 496, 8, 21}, + { 502, 8, 21}, + { 905, 8, 22}, + { 886, 8, 22}, + { 817, 9, 0}, + { 1, 9, 0}, + { 818, 9, 0}, + { 874, 9, 1}, + { 2, 9, 1}, + { 873, 9, 1}, + { 823, 9, 2}, + { 120, 9, 2}, + { 802, 9, 2}, + { 635, 9, 3}, + { 127, 9, 3}, + { 655, 9, 3}, + {1106, 9, 4}, + { 133, 9, 4}, + {1113, 9, 4}, + { 279, 9, 5}, + { 13, 9, 5}, + { 282, 9, 6}, + { 22, 9, 6}, + { 284, 9, 7}, + { 25, 9, 7}, + { 287, 9, 8}, + { 28, 9, 8}, + { 291, 9, 9}, + { 33, 9, 9}, + { 292, 9, 10}, + { 34, 9, 10}, + { 293, 9, 11}, + { 36, 9, 11}, + { 294, 9, 12}, + { 37, 9, 12}, + { 295, 9, 13}, + { 39, 9, 13}, + { 296, 9, 14}, + { 40, 9, 14}, + { 297, 9, 15}, + { 44, 9, 15}, + { 298, 9, 16}, + { 49, 9, 16}, + { 299, 9, 17}, + { 54, 9, 17}, + { 300, 9, 18}, + { 60, 9, 18}, + { 301, 9, 19}, + { 65, 9, 19}, + { 302, 9, 20}, + { 67, 9, 20}, + { 303, 9, 21}, + { 68, 9, 21}, + { 304, 9, 22}, + { 69, 9, 22}, + { 305, 9, 23}, + { 70, 9, 23}, + { 306, 9, 24}, + { 71, 9, 24}, + { 307, 9, 25}, + { 78, 9, 25}, + { 308, 9, 26}, + { 82, 9, 26}, + { 309, 9, 27}, + { 83, 9, 27}, + { 310, 9, 28}, + { 84, 9, 28}, + { 311, 9, 29}, + { 85, 9, 29}, + { 312, 9, 30}, + { 86, 9, 30}, + { 313, 9, 31}, + { 87, 9, 31}, + { 314, 9, 32}, + { 132, 9, 32}, + { 315, 9, 33}, + { 139, 9, 33}, + { 280, 9, 34}, + { 20, 9, 34}, + { 281, 9, 35}, + { 21, 9, 35}, + { 283, 9, 36}, + { 24, 9, 36}, + { 285, 9, 37}, + { 26, 9, 37}, + { 286, 9, 38}, + { 27, 9, 38}, + { 288, 9, 39}, + { 30, 9, 39}, + { 289, 9, 40}, + { 31, 9, 40}, + { 197, 9, 41}, + { 48, 9, 41}, + { 192, 9, 41}, + { 195, 9, 42}, + { 50, 9, 42}, + { 190, 9, 42}, + { 196, 9, 43}, + { 51, 9, 43}, + { 191, 9, 43}, + { 218, 9, 44}, + { 53, 9, 44}, + { 230, 9, 44}, + { 217, 9, 45}, + { 55, 9, 45}, + { 202, 9, 45}, + { 219, 9, 46}, + { 56, 9, 46}, + { 244, 9, 46}, + { 682, 9, 47}, + { 57, 9, 47}, + { 656, 9, 47}, + { 935, 9, 48}, + { 58, 9, 48}, + { 927, 9, 48}, + { 142, 9, 49}, + { 59, 9, 49}, + { 148, 9, 49}, + { 141, 9, 50}, + { 61, 9, 50}, + { 140, 9, 50}, + { 143, 9, 51}, + { 62, 9, 51}, + { 167, 9, 51}, + { 445, 9, 52}, + { 63, 9, 52}, + { 421, 9, 52}, + { 444, 9, 53}, + { 64, 9, 53}, + { 416, 9, 53}, + { 607, 9, 54}, + { 66, 9, 54}, + { 610, 9, 54}, + { 290, 9, 55}, + { 32, 9, 55}, + { 198, 9, 56}, + { 45, 9, 56}, + { 193, 9, 56}, + { 811, 10, 0}, + { 267, 10, 1}, + { 264, 10, 1}, + { 370, 10, 2}, + { 360, 10, 2}, + { 498, 10, 3}, + { 808, 10, 4}, + { 795, 10, 4}, + { 598, 10, 5}, + { 597, 10, 5}, + { 746, 10, 6}, + { 745, 10, 6}, + { 493, 10, 7}, + { 492, 10, 7}, + { 612, 10, 8}, + { 611, 10, 8}, + { 327, 10, 9}, + { 458, 10, 9}, + {1010, 10, 10}, + {1007, 10, 10}, + {1002, 10, 11}, + {1104, 10, 12}, + {1103, 10, 12}, + {1120, 10, 13}, + { 794, 10, 14}, + { 793, 10, 14}, + { 983, 10, 15}, + { 986, 10, 15}, + { 999, 10, 16}, + { 998, 10, 16}, + { 501, 10, 17}, + { 500, 10, 17}, + { 798, 11, 0}, + { 789, 11, 0}, + { 160, 11, 1}, + { 140, 11, 1}, + { 544, 11, 2}, + { 538, 11, 2}, + {1120, 11, 3}, + {1116, 11, 3}, + { 503, 11, 4}, + { 487, 11, 4}, + { 794, 11, 5}, + { 791, 11, 5}, + { 809, 12, 0}, + { 147, 12, 1}, + { 149, 12, 2}, + { 152, 12, 3}, + { 216, 12, 4}, + { 222, 12, 5}, + { 417, 12, 6}, + { 418, 12, 7}, + { 451, 12, 8}, + { 491, 12, 9}, + { 495, 12, 10}, + { 504, 12, 11}, + { 505, 12, 12}, + { 541, 12, 13}, + { 546, 12, 14}, + {1052, 12, 14}, + { 559, 12, 15}, + { 563, 12, 16}, + { 564, 12, 17}, + { 565, 12, 18}, + { 629, 12, 19}, + { 640, 12, 20}, + { 653, 12, 21}, + { 658, 12, 22}, + { 659, 12, 23}, + { 747, 12, 24}, + { 759, 12, 25}, + { 815, 12, 26}, + { 829, 12, 27}, + { 887, 12, 28}, + { 921, 12, 29}, + { 922, 12, 30}, + { 931, 12, 31}, + { 933, 12, 32}, + { 953, 12, 33}, + { 954, 12, 34}, + { 966, 12, 35}, + { 968, 12, 36}, + { 976, 12, 37}, + {1024, 12, 38}, + {1037, 12, 39}, + {1050, 12, 40}, + {1051, 12, 41}, + {1057, 12, 42}, + {1117, 12, 43}, + {1031, 12, 44}, + {1136, 12, 45}, + {1137, 12, 46}, + {1138, 12, 47}, + {1146, 12, 48}, + {1147, 12, 49}, + {1150, 12, 50}, + {1151, 12, 51}, + { 646, 12, 52}, + { 490, 12, 53}, + { 258, 12, 54}, + { 489, 12, 55}, + { 831, 12, 56}, + { 945, 12, 57}, + { 812, 13, 0}, + {1080, 13, 0}, + { 622, 13, 1}, + { 261, 13, 1}, + { 450, 13, 2}, + { 415, 13, 2}, + { 936, 13, 3}, + { 927, 13, 3}, + { 684, 13, 4}, + { 656, 13, 4}, + {1076, 13, 5}, + {1032, 13, 5}, + {1090, 14, 0}, + {1134, 14, 0}, + { 851, 14, 1}, + { 850, 14, 1}, + { 355, 14, 2}, + { 352, 14, 2}, + { 925, 14, 3}, + { 924, 14, 3}, + { 518, 14, 4}, + { 515, 14, 4}, + { 814, 14, 5}, + { 819, 14, 5}, + { 482, 14, 6}, + { 481, 14, 6}, + { 253, 14, 7}, + {1025, 14, 7}, + { 595, 14, 8}, + { 610, 14, 8}, + { 909, 14, 9}, + { 908, 14, 9}, + { 906, 14, 10}, + { 903, 14, 10}, + { 826, 14, 11}, + { 822, 14, 11}, + { 156, 14, 12}, + { 148, 14, 12}, + { 582, 14, 13}, + { 578, 14, 13}, + { 604, 14, 14}, + { 591, 14, 14}, + { 605, 14, 14}, + { 577, 14, 15}, + { 576, 14, 15}, + { 365, 14, 16}, + { 356, 14, 16}, + { 251, 14, 17}, + { 214, 14, 17}, + { 250, 14, 18}, + { 204, 14, 18}, + { 992, 14, 19}, + { 991, 14, 19}, + { 734, 14, 20}, + { 229, 14, 20}, + { 272, 14, 21}, + { 392, 14, 21}, + { 702, 14, 22}, + { 694, 14, 22}, + { 383, 14, 23}, + { 276, 14, 23}, + { 372, 14, 24}, + { 952, 14, 24}, + { 160, 14, 25}, + { 146, 14, 25}, + { 252, 14, 26}, + { 203, 14, 26}, + {1023, 14, 27}, + { 972, 14, 27}, + {1157, 14, 28}, + {1156, 14, 28}, + { 801, 14, 29}, + { 805, 14, 29}, + {1124, 14, 30}, + {1121, 14, 30}, + { 620, 14, 31}, + { 627, 14, 32}, + { 626, 14, 33}, + { 539, 14, 34}, + { 540, 14, 35}, + { 354, 14, 36}, + { 390, 14, 36}, + { 562, 14, 37}, + { 573, 14, 37}, + { 373, 14, 38}, + { 328, 14, 38}, + { 929, 14, 39}, + { 934, 14, 39}, + { 811, 15, 0}, + { 826, 15, 1}, + { 822, 15, 1}, + { 440, 15, 2}, + { 434, 15, 2}, + { 423, 15, 3}, + { 422, 15, 3}, + { 792, 16, 0}, + { 0, 16, 1}, + { 1, 16, 2}, + { 4, 16, 3}, + { 3, 16, 4}, + { 12, 16, 5}, + { 11, 16, 6}, + { 10, 16, 7}, + { 9, 16, 8}, + { 73, 16, 9}, + { 8, 16, 10}, + { 7, 16, 11}, + { 6, 16, 12}, + { 77, 16, 13}, + { 43, 16, 14}, + { 5, 16, 15}, + { 76, 16, 16}, + { 110, 16, 17}, + { 42, 16, 18}, + { 75, 16, 19}, + { 92, 16, 20}, + { 109, 16, 21}, + { 122, 16, 22}, + { 2, 16, 23}, + { 74, 16, 24}, + { 41, 16, 25}, + { 108, 16, 26}, + { 72, 16, 27}, + { 121, 16, 28}, + { 91, 16, 29}, + { 134, 16, 30}, + { 107, 16, 31}, + { 23, 16, 32}, + { 115, 16, 33}, + { 29, 16, 34}, + { 120, 16, 35}, + { 35, 16, 36}, + { 127, 16, 37}, + { 38, 16, 38}, + { 133, 16, 39}, + { 13, 16, 40}, + { 22, 16, 41}, + { 25, 16, 42}, + { 28, 16, 43}, + { 33, 16, 44}, + { 34, 16, 45}, + { 36, 16, 46}, + { 37, 16, 47}, + { 39, 16, 48}, + { 40, 16, 49}, + { 44, 16, 50}, + { 49, 16, 51}, + { 54, 16, 52}, + { 60, 16, 53}, + { 65, 16, 54}, + { 67, 16, 55}, + { 68, 16, 56}, + { 69, 16, 57}, + { 70, 16, 58}, + { 71, 16, 59}, + { 78, 16, 60}, + { 82, 16, 61}, + { 83, 16, 62}, + { 84, 16, 63}, + { 85, 16, 64}, + { 86, 16, 65}, + { 87, 16, 66}, + { 88, 16, 67}, + { 89, 16, 68}, + { 90, 16, 69}, + { 93, 16, 70}, + { 97, 16, 71}, + { 98, 16, 72}, + { 99, 16, 73}, + { 101, 16, 74}, + { 102, 16, 75}, + { 103, 16, 76}, + { 104, 16, 77}, + { 105, 16, 78}, + { 106, 16, 79}, + { 111, 16, 80}, + { 116, 16, 81}, + { 123, 16, 82}, + { 128, 16, 83}, + { 135, 16, 84}, + { 14, 16, 85}, + { 45, 16, 86}, + { 79, 16, 87}, + { 94, 16, 88}, + { 112, 16, 89}, + { 117, 16, 90}, + { 124, 16, 91}, + { 129, 16, 92}, + { 136, 16, 93}, + { 15, 16, 94}, + { 46, 16, 95}, + { 80, 16, 96}, + { 95, 16, 97}, + { 113, 16, 98}, + { 118, 16, 99}, + { 125, 16, 100}, + { 130, 16, 101}, + { 137, 16, 102}, + { 16, 16, 103}, + { 47, 16, 104}, + { 81, 16, 105}, + { 96, 16, 106}, + { 114, 16, 107}, + { 119, 16, 108}, + { 126, 16, 109}, + { 131, 16, 110}, + { 138, 16, 111}, + { 17, 16, 112}, + { 52, 16, 113}, + { 100, 16, 114}, + { 18, 16, 115}, + { 19, 16, 116}, + { 791, 17, 0}, + { 935, 17, 1}, + { 682, 17, 2}, + {1108, 17, 3}, + { 683, 17, 4}, + {1069, 17, 5}, + { 240, 17, 6}, + {1070, 17, 7}, + {1074, 17, 8}, + {1072, 17, 9}, + {1073, 17, 10}, + { 241, 17, 11}, + {1071, 17, 12}, + { 875, 17, 13}, + { 606, 17, 14}, + { 858, 18, 0}, + { 228, 18, 1}, + {1107, 18, 2}, + { 199, 18, 3}, + { 823, 18, 4}, + {1106, 18, 5}, + {1111, 18, 6}, + {1110, 18, 7}, + {1109, 18, 8}, + { 380, 18, 9}, + { 375, 18, 10}, + { 376, 18, 11}, + { 381, 18, 12}, + { 382, 18, 13}, + { 379, 18, 14}, + { 377, 18, 15}, + { 378, 18, 16}, + { 779, 18, 17}, + {1067, 18, 18}, + {1068, 18, 19}, + { 930, 18, 20}, +}; + +/* property values: 5004 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, 19, 21, 19, 19, 19, 19, 19, 19, 22, 19, 19, + 19, 19, 19, 19, 19, 19, 23, 19, 19, 19, 24, 19, 19, 25, 26, 19, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 27, 7, 28, 29, 19, 19, 19, 19, 19, 19, 19, 30, + 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 31, 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, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 32, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 32, +}; + +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, 76, 123, 124, 125, 126, 127, 76, 76, 76, 76, 76, 76, + 128, 76, 129, 130, 131, 76, 132, 76, 133, 76, 76, 76, 134, 76, 76, 76, + 135, 136, 137, 138, 76, 76, 76, 76, 76, 76, 76, 76, 76, 139, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 34, 34, 34, 34, 34, 34, 140, 76, 141, 76, 76, 76, 76, 76, 76, 76, + 34, 34, 34, 34, 34, 34, 34, 34, 142, 76, 76, 76, 76, 76, 76, 76, + 34, 34, 34, 34, 143, 76, 76, 76, 76, 76, 76, 76, 76, 76, 144, 145, + 146, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 69, 147, 148, 149, 150, 76, 151, 76, 152, 153, 154, 155, 156, 157, 158, 159, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 160, 161, 76, 76, + 162, 163, 164, 165, 166, 76, 167, 168, 169, 170, 171, 172, 173, 174, 175, 76, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 176, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 177, 34, + 178, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 34, 34, 34, 34, 178, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 179, 76, 180, 181, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 182, +}; + +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, 42, 43, 9, 44, 45, 11, 46, 47, 32, 48, 49, 50, 51, 52, + 53, 54, 50, 50, 55, 32, 56, 57, 50, 50, 50, 50, 50, 58, 59, 60, + 61, 62, 50, 32, 63, 50, 50, 50, 50, 50, 64, 65, 66, 50, 67, 68, + 50, 69, 70, 71, 50, 72, 73, 73, 73, 73, 74, 73, 73, 73, 75, 76, + 77, 50, 50, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 84, 85, 92, 93, 94, 95, 96, 97, 98, 85, 99, 100, 101, 89, 102, + 83, 84, 85, 103, 104, 105, 89, 106, 107, 108, 109, 110, 111, 112, 95, 113, + 114, 115, 85, 116, 117, 118, 89, 119, 120, 115, 85, 121, 122, 123, 89, 124, + 120, 115, 50, 125, 126, 127, 89, 128, 129, 130, 50, 131, 132, 133, 73, 134, + 135, 50, 50, 136, 137, 138, 73, 73, 139, 140, 141, 142, 143, 144, 73, 73, + 145, 146, 147, 148, 149, 50, 150, 151, 152, 153, 32, 154, 155, 156, 73, 73, + 50, 50, 157, 158, 159, 160, 161, 162, 163, 164, 9, 9, 165, 50, 50, 166, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 167, 168, 50, 50, + 167, 50, 50, 169, 170, 171, 50, 50, 50, 170, 50, 50, 50, 172, 173, 174, + 50, 175, 50, 50, 50, 50, 50, 176, 177, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 178, 50, 179, 180, 50, 50, 50, 50, 181, 182, + 183, 184, 50, 185, 50, 186, 183, 187, 50, 50, 50, 188, 189, 190, 191, 192, + 193, 191, 50, 50, 194, 50, 50, 195, 50, 50, 196, 50, 50, 50, 50, 197, + 50, 150, 198, 199, 200, 50, 201, 176, 50, 50, 202, 203, 204, 205, 206, 206, + 50, 207, 50, 50, 50, 208, 209, 210, 191, 191, 211, 73, 73, 73, 73, 73, + 212, 50, 50, 213, 214, 159, 215, 216, 217, 50, 218, 66, 50, 50, 219, 220, + 50, 50, 221, 222, 223, 66, 50, 224, 73, 73, 73, 73, 225, 226, 227, 228, + 11, 11, 229, 27, 27, 27, 230, 231, 11, 232, 27, 27, 32, 32, 233, 234, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 235, 13, 13, 13, 13, 13, 13, + 236, 237, 236, 236, 237, 238, 236, 239, 240, 240, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 73, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 267, 268, 269, 270, 206, 271, 272, 206, 273, + 274, 274, 274, 274, 274, 274, 274, 274, 275, 206, 276, 206, 206, 206, 206, 277, + 206, 278, 274, 279, 206, 280, 281, 282, 206, 206, 283, 73, 284, 73, 266, 266, + 266, 285, 206, 206, 206, 206, 286, 266, 206, 206, 206, 206, 206, 206, 206, 206, + 206, 206, 206, 287, 288, 206, 206, 289, 206, 206, 206, 206, 206, 206, 290, 206, + 291, 206, 206, 206, 206, 206, 292, 293, 266, 294, 206, 206, 295, 274, 296, 274, + 297, 298, 274, 274, 274, 299, 274, 300, 206, 206, 206, 274, 301, 175, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 9, 9, 302, 11, 11, 303, 304, 305, + 13, 13, 13, 13, 13, 13, 306, 307, 11, 11, 308, 50, 50, 50, 309, 310, + 50, 311, 312, 312, 312, 312, 32, 32, 313, 314, 315, 316, 73, 73, 73, 73, + 206, 317, 206, 206, 206, 206, 206, 282, 206, 206, 206, 206, 206, 318, 73, 319, + 320, 321, 322, 323, 135, 50, 50, 50, 50, 324, 177, 50, 50, 50, 50, 325, + 326, 50, 201, 135, 50, 50, 50, 50, 327, 328, 50, 51, 206, 206, 282, 50, + 206, 329, 330, 206, 331, 332, 206, 206, 330, 206, 206, 332, 206, 206, 206, 329, + 50, 50, 50, 197, 206, 206, 206, 206, 50, 50, 50, 50, 150, 73, 73, 73, + 50, 333, 50, 50, 50, 50, 50, 50, 150, 206, 206, 206, 283, 50, 50, 224, + 334, 50, 335, 73, 13, 13, 336, 337, 13, 338, 50, 50, 50, 50, 339, 340, + 31, 341, 342, 343, 13, 13, 13, 344, 345, 346, 347, 73, 73, 73, 73, 348, + 349, 50, 350, 351, 50, 50, 50, 352, 353, 50, 50, 354, 355, 191, 32, 356, + 66, 50, 357, 50, 358, 359, 50, 150, 77, 50, 50, 360, 361, 362, 73, 73, + 50, 50, 363, 364, 365, 366, 50, 367, 50, 50, 50, 368, 369, 370, 371, 372, + 373, 374, 312, 73, 73, 73, 73, 73, 73, 73, 73, 73, 50, 50, 375, 191, + 50, 50, 376, 50, 377, 50, 50, 202, 378, 378, 378, 378, 378, 378, 378, 378, + 379, 379, 379, 379, 379, 379, 379, 379, 50, 50, 50, 50, 50, 50, 201, 50, + 50, 50, 50, 50, 50, 380, 73, 73, 381, 382, 383, 384, 385, 50, 50, 50, + 50, 50, 50, 386, 387, 388, 50, 50, 50, 50, 50, 389, 73, 50, 50, 50, + 50, 390, 50, 50, 195, 73, 73, 391, 32, 392, 233, 393, 394, 395, 396, 397, + 50, 50, 50, 50, 50, 50, 50, 398, 399, 2, 3, 4, 5, 400, 401, 402, + 50, 403, 50, 327, 404, 405, 406, 407, 408, 50, 171, 409, 201, 201, 73, 73, + 50, 50, 50, 50, 50, 50, 50, 51, 410, 266, 266, 411, 267, 267, 267, 412, + 413, 319, 73, 73, 73, 206, 206, 414, 50, 150, 50, 50, 50, 101, 73, 73, + 50, 327, 415, 50, 416, 73, 73, 73, 50, 417, 50, 50, 418, 419, 73, 73, + 9, 9, 420, 11, 11, 50, 50, 50, 50, 201, 191, 73, 73, 73, 73, 73, + 421, 50, 50, 422, 50, 423, 73, 73, 50, 424, 50, 425, 73, 73, 73, 73, + 50, 50, 50, 426, 73, 73, 73, 73, 427, 428, 50, 429, 430, 431, 50, 432, + 50, 50, 50, 433, 50, 434, 50, 435, 50, 50, 50, 50, 436, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 266, 437, 438, 50, 50, 439, 440, 441, 442, 73, + 217, 50, 50, 443, 444, 50, 436, 191, 445, 50, 446, 447, 448, 73, 73, 73, + 217, 50, 50, 449, 450, 191, 73, 73, 50, 50, 451, 452, 191, 73, 73, 73, + 50, 50, 50, 50, 50, 50, 327, 73, 267, 267, 267, 267, 267, 267, 453, 448, + 50, 50, 327, 73, 73, 73, 73, 73, 50, 50, 50, 436, 73, 73, 73, 73, + 50, 50, 50, 50, 176, 454, 203, 455, 456, 457, 73, 73, 73, 73, 73, 73, + 458, 73, 73, 73, 73, 73, 73, 73, 206, 206, 206, 206, 206, 206, 206, 318, + 206, 206, 459, 206, 206, 206, 460, 461, 462, 206, 463, 206, 206, 464, 73, 73, + 206, 206, 206, 206, 465, 73, 73, 73, 206, 206, 206, 206, 206, 283, 266, 466, + 9, 467, 11, 468, 469, 470, 236, 9, 471, 472, 473, 474, 475, 9, 467, 11, + 476, 477, 11, 478, 479, 480, 481, 9, 482, 11, 9, 467, 11, 468, 469, 11, + 236, 9, 471, 481, 9, 482, 11, 9, 467, 11, 483, 9, 484, 485, 486, 487, + 11, 488, 9, 489, 490, 491, 492, 11, 493, 9, 494, 11, 495, 496, 496, 496, + 497, 50, 498, 499, 500, 501, 502, 503, 504, 202, 505, 202, 73, 73, 73, 506, + 206, 206, 319, 206, 206, 206, 206, 206, 206, 282, 329, 507, 291, 291, 73, 73, + 508, 206, 329, 206, 206, 206, 319, 206, 206, 284, 73, 73, 73, 73, 509, 206, + 510, 206, 206, 284, 511, 512, 73, 73, 206, 206, 513, 514, 206, 206, 206, 515, + 206, 282, 206, 206, 516, 73, 206, 513, 206, 206, 206, 329, 517, 206, 206, 206, + 206, 206, 206, 206, 206, 206, 206, 518, 206, 206, 206, 464, 282, 206, 519, 73, + 73, 73, 73, 73, 73, 73, 73, 520, 206, 206, 206, 206, 521, 73, 73, 73, + 206, 206, 206, 206, 318, 73, 73, 73, 206, 206, 206, 206, 206, 206, 206, 282, + 50, 50, 50, 50, 50, 311, 73, 73, 50, 50, 50, 176, 50, 50, 50, 50, + 50, 201, 73, 73, 73, 73, 73, 73, 522, 73, 523, 523, 523, 523, 523, 523, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 73, + 379, 379, 379, 379, 379, 379, 379, 524, +}; + +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, 46, + 44, 44, 41, 47, 11, 48, 48, 11, 34, 11, 11, 11, 11, 11, 11, 11, + 11, 49, 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, 50, 34, 32, 34, 11, + 32, 51, 43, 43, 52, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, + 32, 32, 32, 32, 44, 44, 44, 44, 49, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 48, 53, 2, 2, 2, 54, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 55, 56, 44, 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, 46, 44, 44, 44, 44, 44, 64, 64, 65, 8, 9, 66, 2, 67, + 43, 43, 43, 43, 43, 61, 65, 2, 68, 36, 36, 36, 36, 69, 43, 43, + 7, 7, 7, 7, 7, 2, 2, 36, 70, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 71, 43, 43, 43, 72, 51, 43, 43, 73, 74, 75, 43, 43, 36, + 7, 7, 7, 7, 7, 36, 76, 77, 2, 2, 2, 2, 2, 2, 2, 78, + 69, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 79, 80, 36, + 36, 36, 36, 43, 43, 43, 43, 43, 70, 44, 44, 44, 44, 44, 44, 44, + 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 69, 43, 43, + 43, 43, 40, 21, 2, 81, 44, 44, 36, 36, 36, 43, 43, 74, 43, 43, + 43, 43, 74, 43, 74, 43, 43, 44, 2, 2, 2, 2, 2, 2, 2, 46, + 36, 36, 36, 36, 69, 43, 44, 46, 44, 44, 44, 44, 44, 44, 44, 44, + 62, 36, 36, 36, 36, 36, 62, 44, 44, 44, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 79, 43, 82, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 82, 70, 83, 84, 43, 43, 43, 82, 83, 84, 83, + 69, 43, 43, 43, 36, 36, 36, 36, 36, 43, 2, 7, 7, 7, 7, 7, + 85, 36, 36, 36, 80, 36, 36, 36, 58, 83, 80, 36, 36, 36, 62, 80, + 62, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, + 62, 62, 44, 36, 36, 44, 70, 83, 84, 43, 79, 86, 87, 86, 84, 62, + 44, 44, 44, 86, 44, 44, 36, 80, 36, 43, 44, 7, 7, 7, 7, 7, + 36, 20, 27, 27, 27, 88, 44, 44, 58, 82, 80, 36, 36, 62, 44, 80, + 62, 36, 80, 62, 36, 44, 79, 83, 84, 79, 44, 58, 79, 58, 43, 44, + 58, 44, 44, 44, 80, 36, 62, 62, 44, 44, 44, 7, 7, 7, 7, 7, + 43, 36, 69, 44, 44, 44, 44, 44, 58, 82, 80, 36, 36, 36, 36, 80, + 36, 80, 36, 36, 36, 36, 36, 36, 62, 36, 80, 36, 36, 44, 70, 83, + 84, 43, 43, 58, 82, 86, 84, 44, 62, 44, 44, 44, 44, 44, 44, 44, + 66, 44, 44, 44, 44, 44, 44, 44, 62, 36, 80, 36, 36, 44, 70, 84, + 84, 43, 79, 86, 87, 86, 84, 44, 44, 44, 44, 82, 44, 44, 36, 80, + 77, 27, 27, 27, 44, 44, 44, 44, 44, 70, 80, 36, 36, 62, 44, 36, + 62, 36, 36, 44, 80, 62, 62, 36, 44, 80, 62, 44, 36, 62, 44, 36, + 36, 36, 36, 36, 36, 44, 44, 83, 82, 87, 44, 83, 87, 83, 84, 44, + 62, 44, 44, 86, 44, 44, 44, 44, 27, 89, 67, 67, 88, 90, 44, 44, + 86, 83, 80, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 80, 36, 36, 44, 80, 43, 82, 83, 87, 43, 79, 43, 43, 44, + 44, 44, 58, 79, 36, 44, 44, 44, 44, 44, 44, 44, 27, 27, 27, 89, + 44, 83, 80, 36, 36, 36, 62, 36, 36, 36, 80, 36, 36, 44, 70, 84, + 83, 83, 87, 82, 87, 83, 43, 44, 44, 44, 86, 87, 44, 44, 44, 62, + 80, 62, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 62, 80, 83, + 84, 43, 79, 83, 87, 83, 84, 62, 44, 44, 44, 86, 44, 44, 44, 44, + 27, 27, 27, 44, 91, 36, 36, 36, 44, 83, 80, 36, 36, 36, 36, 36, + 36, 36, 36, 62, 44, 36, 36, 36, 36, 80, 36, 36, 36, 36, 80, 44, + 36, 36, 36, 62, 44, 79, 44, 86, 83, 43, 79, 79, 83, 83, 83, 83, + 44, 83, 46, 44, 44, 44, 44, 44, 80, 36, 36, 36, 36, 36, 36, 36, + 69, 36, 43, 43, 43, 79, 44, 57, 36, 36, 36, 74, 43, 43, 43, 61, + 7, 7, 7, 7, 7, 2, 44, 44, 80, 62, 62, 80, 62, 62, 80, 44, + 44, 44, 36, 36, 80, 36, 36, 36, 80, 36, 80, 80, 44, 36, 80, 36, + 69, 36, 43, 43, 43, 58, 70, 44, 36, 36, 62, 81, 43, 43, 43, 44, + 7, 7, 7, 7, 7, 44, 36, 36, 76, 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, 51, 51, 51, 4, 4, 83, 36, 36, 36, 36, 80, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 62, 44, 58, 43, 43, 43, 43, 43, 43, 82, + 43, 43, 61, 43, 36, 36, 69, 43, 43, 43, 43, 43, 58, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 79, 67, 67, 67, 67, 75, 67, 67, 90, 67, + 2, 2, 92, 67, 21, 46, 44, 44, 36, 36, 36, 36, 36, 93, 84, 43, + 82, 43, 43, 43, 84, 82, 84, 70, 7, 7, 7, 7, 7, 2, 2, 2, + 36, 36, 36, 83, 43, 36, 36, 43, 70, 83, 94, 93, 83, 83, 83, 36, + 69, 43, 70, 36, 36, 36, 36, 36, 36, 82, 84, 82, 83, 83, 84, 93, + 7, 7, 7, 7, 7, 83, 84, 67, 11, 11, 11, 49, 44, 44, 49, 44, + 36, 36, 36, 36, 36, 63, 68, 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, + 36, 36, 62, 44, 44, 44, 44, 44, 97, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 63, 71, 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, 44, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 62, 36, + 36, 43, 79, 44, 44, 44, 44, 44, 36, 43, 61, 46, 44, 44, 44, 44, + 36, 43, 44, 44, 44, 44, 44, 44, 62, 43, 44, 44, 44, 44, 44, 44, + 36, 36, 43, 84, 43, 43, 43, 83, 83, 83, 83, 82, 84, 43, 43, 43, + 43, 43, 2, 85, 2, 66, 69, 44, 7, 7, 7, 7, 7, 44, 44, 44, + 27, 27, 27, 27, 27, 44, 44, 44, 2, 2, 2, 103, 2, 60, 43, 65, + 36, 104, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 44, 44, 44, + 36, 36, 36, 36, 69, 62, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44, + 43, 82, 83, 84, 82, 83, 44, 44, 83, 82, 83, 83, 84, 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, 83, 83, 83, 83, 83, 83, 83, 83, + 94, 36, 36, 36, 83, 44, 44, 44, 7, 7, 7, 7, 7, 96, 44, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 36, 36, 36, 69, 82, 84, 44, 2, + 36, 36, 93, 82, 43, 43, 43, 79, 82, 82, 84, 43, 43, 43, 82, 83, + 83, 84, 43, 43, 43, 43, 79, 58, 2, 2, 2, 85, 2, 2, 2, 44, + 43, 43, 94, 36, 36, 36, 36, 36, 36, 36, 82, 43, 43, 82, 82, 83, + 83, 82, 94, 36, 36, 36, 44, 44, 92, 67, 67, 67, 67, 51, 43, 43, + 43, 43, 67, 67, 67, 67, 90, 44, 43, 94, 36, 36, 36, 36, 36, 36, + 93, 43, 43, 83, 43, 84, 83, 36, 36, 36, 36, 82, 43, 83, 84, 84, + 43, 83, 44, 44, 44, 44, 2, 2, 36, 36, 83, 83, 83, 83, 43, 43, + 43, 43, 83, 43, 44, 55, 2, 2, 7, 7, 7, 7, 7, 44, 80, 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, 82, 43, 43, 43, 70, 36, 69, 36, + 36, 83, 70, 62, 44, 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, 105, 40, 40, 43, 43, 43, 79, 44, 44, 44, 44, + 44, 44, 44, 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, 49, 49, 49, 49, 16, 16, 16, 16, 16, 16, 16, 44, + 16, 16, 16, 16, 106, 106, 106, 106, 16, 16, 107, 16, 11, 11, 108, 109, + 41, 16, 107, 16, 11, 11, 108, 41, 16, 16, 44, 16, 11, 11, 110, 41, + 16, 16, 16, 16, 11, 11, 111, 41, 44, 16, 107, 16, 11, 11, 108, 112, + 113, 113, 113, 113, 113, 114, 64, 64, 115, 115, 115, 2, 116, 117, 116, 117, + 2, 2, 2, 2, 118, 64, 64, 119, 2, 2, 2, 2, 120, 121, 2, 122, + 123, 2, 124, 125, 2, 2, 2, 2, 2, 9, 123, 2, 2, 2, 2, 126, + 64, 64, 65, 64, 64, 64, 64, 64, 127, 44, 27, 27, 27, 8, 124, 128, + 27, 27, 27, 27, 27, 8, 124, 100, 40, 40, 40, 40, 40, 40, 81, 44, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 129, 44, 44, + 43, 43, 43, 43, 43, 43, 130, 52, 131, 52, 131, 43, 43, 43, 43, 43, + 79, 44, 44, 44, 44, 44, 44, 44, 67, 132, 67, 133, 67, 34, 11, 16, + 11, 32, 133, 67, 50, 11, 11, 67, 67, 67, 132, 132, 132, 11, 11, 134, + 11, 11, 35, 36, 39, 67, 16, 11, 8, 8, 50, 16, 16, 26, 67, 135, + 27, 27, 27, 27, 27, 27, 27, 27, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 136, 137, 101, 138, 44, 44, 44, 8, 8, 139, 67, 67, 8, 67, 67, + 139, 26, 67, 139, 67, 67, 67, 139, 67, 67, 67, 67, 67, 67, 67, 8, + 67, 139, 139, 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, 140, 141, 67, 67, 67, 67, 67, 67, 67, 67, 139, 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, 44, 44, 44, 44, 44, 44, 67, 67, 67, 90, 44, 44, 44, 44, + 67, 67, 67, 67, 67, 90, 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, 91, 67, 67, 67, 67, 67, 67, 67, + 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, 124, 142, 8, 8, 8, 8, + 8, 8, 8, 4, 4, 4, 4, 4, 8, 124, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 142, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 8, + 8, 8, 8, 8, 8, 8, 4, 8, 8, 8, 139, 26, 8, 8, 144, 44, + 11, 11, 11, 11, 11, 11, 11, 48, 16, 16, 16, 16, 16, 16, 16, 107, + 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11, + 32, 32, 135, 67, 67, 133, 34, 145, 43, 32, 44, 44, 55, 2, 95, 2, + 16, 16, 16, 54, 44, 44, 54, 44, 36, 36, 36, 36, 44, 44, 44, 53, + 46, 44, 44, 44, 44, 44, 44, 58, 36, 36, 36, 62, 44, 44, 44, 44, + 36, 36, 36, 62, 36, 36, 36, 62, 2, 116, 116, 2, 120, 121, 116, 2, + 2, 2, 2, 6, 2, 103, 116, 2, 116, 4, 4, 4, 4, 2, 2, 85, + 2, 2, 2, 2, 2, 115, 44, 44, 67, 67, 67, 67, 67, 91, 67, 67, + 67, 67, 67, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44, + 1, 2, 146, 147, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4, 148, 149, + 150, 101, 101, 101, 101, 43, 43, 83, 151, 40, 40, 67, 101, 152, 63, 67, + 36, 36, 36, 62, 58, 153, 154, 68, 36, 36, 36, 36, 36, 63, 40, 68, + 44, 44, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 62, + 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, + 155, 27, 27, 27, 27, 27, 27, 27, 36, 36, 104, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 156, 2, 7, 7, 7, 7, 7, 36, 44, 44, + 32, 32, 32, 32, 32, 32, 32, 69, 52, 157, 43, 43, 43, 43, 43, 85, + 32, 32, 32, 32, 44, 44, 44, 58, 36, 36, 36, 101, 101, 101, 101, 101, + 43, 2, 2, 2, 44, 44, 44, 44, 41, 41, 41, 154, 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, 158, 34, 107, + 32, 32, 44, 44, 44, 44, 44, 44, 32, 32, 32, 32, 32, 48, 44, 44, + 44, 44, 44, 44, 40, 35, 36, 36, 36, 70, 36, 70, 36, 69, 36, 36, + 36, 93, 84, 82, 67, 67, 44, 44, 27, 27, 27, 67, 159, 44, 44, 44, + 36, 36, 2, 2, 44, 44, 44, 44, 83, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 83, 83, 83, 83, 83, 83, 83, 83, 79, 44, 44, 44, 44, 2, + 43, 36, 36, 36, 2, 71, 44, 44, 36, 36, 36, 43, 43, 43, 43, 2, + 36, 36, 36, 69, 43, 43, 43, 43, 43, 83, 44, 44, 44, 44, 44, 55, + 36, 69, 83, 43, 43, 83, 82, 83, 160, 2, 2, 2, 2, 2, 2, 53, + 7, 7, 7, 7, 7, 44, 44, 2, 36, 36, 36, 36, 69, 43, 43, 82, + 84, 82, 84, 79, 44, 44, 44, 44, 36, 69, 36, 36, 36, 36, 82, 44, + 7, 7, 7, 7, 7, 44, 2, 2, 68, 36, 36, 76, 67, 93, 44, 44, + 70, 43, 70, 69, 70, 36, 36, 43, 69, 62, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 80, 104, 2, 36, 36, 36, 36, 36, 93, 43, 83, + 2, 104, 161, 79, 44, 44, 44, 44, 80, 36, 36, 62, 80, 36, 36, 62, + 80, 36, 36, 62, 44, 44, 44, 44, 36, 93, 84, 83, 82, 160, 84, 44, + 36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 62, 44, 80, 36, 36, + 162, 162, 162, 162, 162, 162, 162, 162, 163, 163, 163, 163, 163, 163, 163, 163, + 36, 36, 36, 36, 36, 44, 44, 44, 16, 16, 16, 107, 44, 44, 44, 44, + 44, 54, 16, 16, 44, 44, 80, 70, 36, 36, 36, 36, 164, 36, 36, 36, + 36, 36, 36, 62, 36, 36, 62, 62, 36, 80, 62, 36, 36, 36, 36, 36, + 36, 41, 41, 41, 41, 41, 41, 41, 41, 44, 44, 44, 44, 44, 44, 44, + 44, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 4, + 44, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 159, 44, + 2, 2, 2, 165, 125, 44, 44, 44, 6, 166, 167, 143, 143, 143, 143, 143, + 143, 143, 125, 165, 125, 2, 122, 168, 2, 46, 2, 2, 148, 143, 143, 125, + 2, 169, 8, 144, 66, 2, 44, 44, 36, 36, 62, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 62, 78, 55, 2, 3, 2, 4, 5, 6, 2, + 16, 16, 16, 16, 16, 17, 18, 124, 125, 4, 2, 36, 36, 36, 36, 36, + 68, 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, 170, 88, 129, 26, 8, 139, 90, 44, 44, 44, 44, 78, 64, 67, 44, + 36, 36, 36, 36, 36, 36, 80, 36, 36, 36, 36, 36, 36, 62, 36, 80, + 2, 46, 44, 171, 27, 27, 27, 27, 27, 27, 44, 91, 67, 67, 67, 67, + 101, 101, 138, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 96, 44, 44, + 67, 67, 67, 67, 67, 67, 51, 44, 27, 27, 44, 44, 44, 44, 44, 44, + 147, 36, 36, 36, 36, 102, 44, 44, 36, 36, 36, 36, 36, 36, 36, 55, + 36, 36, 44, 44, 36, 36, 36, 36, 172, 101, 101, 44, 44, 44, 44, 44, + 11, 11, 11, 11, 16, 16, 16, 16, 36, 36, 36, 44, 62, 36, 36, 36, + 36, 36, 36, 80, 62, 44, 62, 80, 36, 36, 36, 55, 27, 27, 27, 27, + 36, 36, 36, 27, 27, 27, 44, 55, 36, 36, 36, 36, 36, 44, 44, 55, + 36, 36, 36, 36, 44, 44, 44, 36, 69, 43, 58, 79, 44, 44, 43, 43, + 36, 36, 80, 36, 80, 36, 36, 36, 36, 36, 44, 44, 43, 79, 44, 58, + 27, 27, 27, 27, 44, 44, 44, 44, 2, 2, 2, 2, 46, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 173, 30, 36, 36, 36, 44, 55, 2, 2, 2, + 36, 36, 36, 44, 27, 27, 27, 27, 36, 62, 44, 44, 27, 27, 27, 27, + 36, 36, 36, 36, 62, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27, 96, + 84, 94, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, + 43, 43, 43, 61, 2, 2, 2, 44, 44, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 7, 7, 7, 7, 7, 83, 84, 43, 82, 84, 61, 174, 2, + 2, 44, 44, 44, 44, 44, 44, 44, 43, 70, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 69, 43, 43, 84, 43, 43, 43, 79, 7, 7, 7, 7, 7, + 2, 2, 44, 44, 44, 44, 44, 44, 36, 93, 83, 43, 43, 43, 43, 82, + 94, 36, 63, 2, 46, 44, 44, 44, 36, 36, 36, 36, 36, 69, 84, 83, + 43, 43, 43, 84, 44, 44, 44, 44, 101, 102, 44, 44, 44, 44, 44, 44, + 93, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 87, + 44, 44, 44, 44, 44, 44, 44, 58, 43, 73, 40, 40, 40, 40, 40, 40, + 36, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 90, 91, 67, 67, 67, + 67, 67, 175, 84, 43, 67, 175, 83, 83, 176, 64, 64, 64, 177, 43, 43, + 43, 75, 51, 43, 43, 43, 67, 67, 67, 67, 67, 67, 67, 43, 43, 67, + 67, 67, 67, 67, 67, 67, 67, 44, 67, 43, 75, 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, 107, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 48, 11, 44, 48, 49, 48, 49, 11, 48, 11, + 11, 11, 11, 16, 16, 54, 54, 16, 16, 16, 54, 16, 16, 16, 16, 16, + 16, 16, 11, 49, 11, 48, 49, 11, 11, 11, 48, 11, 11, 11, 48, 16, + 16, 16, 16, 16, 11, 49, 11, 48, 11, 11, 48, 48, 44, 11, 11, 11, + 48, 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, 36, 36, 80, 36, 36, 36, 36, 36, + 80, 62, 62, 80, 80, 36, 36, 36, 36, 62, 36, 36, 80, 80, 44, 44, + 44, 62, 44, 80, 80, 80, 80, 36, 80, 62, 62, 80, 80, 80, 80, 80, + 80, 62, 62, 80, 36, 62, 36, 36, 36, 62, 36, 36, 80, 36, 62, 62, + 36, 36, 36, 36, 36, 80, 36, 36, 80, 36, 80, 36, 36, 80, 36, 36, + 8, 44, 44, 44, 44, 44, 44, 44, 91, 67, 67, 67, 67, 67, 67, 90, + 27, 27, 27, 27, 27, 96, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, + 67, 90, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 90, 44, 44, 44, + 67, 44, 44, 44, 44, 44, 44, 44, 90, 44, 44, 44, 44, 44, 44, 44, + 67, 67, 67, 91, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90, 44, + 67, 67, 90, 67, 67, 90, 44, 44, 90, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 91, 67, 90, 44, 67, 67, 67, 67, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 91, 67, 67, 90, 44, 91, 67, 67, 67, 67, 67, + 78, 44, 44, 44, 44, 44, 44, 44, 64, 64, 64, 64, 64, 64, 64, 64, + 163, 163, 163, 163, 163, 163, 163, 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, 23, 0, 1, 23, + 1, 0, 0, 1, 24, 1, 27, 6, 7, 7, 0, 4, 0, 2, 0, 23, + 19, 0, 0, 25, 0, 6, 19, 6, 23, 6, 6, 23, 5, 0, 5, 23, + 16, 16, 16, 0, 23, 25, 27, 27, 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, + 27, 25, 11, 27, 27, 0, 0, 27, 23, 27, 5, 8, 8, 5, 23, 11, + 11, 0, 19, 5, 12, 5, 5, 20, 21, 0, 10, 10, 10, 0, 19, 23, + 5, 4, 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, + 24, 0, 2, 6, 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, 26, 0, 11, 23, 10, 5, 11, 23, 16, 27, 8, + 8, 16, 16, 6, +}; + +/* General_Category: 8556 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, 6, 7, 7, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 11, 12, 12, 12, 12, 13, 14, 15, 15, 15, 16, + 17, 18, 19, 20, 21, 20, 22, 20, 20, 20, 20, 20, 20, 23, 20, 20, + 20, 20, 20, 20, 20, 20, 24, 20, 20, 20, 25, 20, 20, 26, 27, 20, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 29, 30, 31, 32, 20, 20, 20, 20, 20, 20, 20, 33, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 34, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, +}; + +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, 85, 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, 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, 108, 108, 108, 108, 109, 110, 110, 110, 110, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 119, 119, 119, 119, 119, 119, + 125, 119, 126, 127, 128, 119, 129, 119, 130, 119, 119, 119, 131, 119, 119, 119, + 132, 133, 134, 135, 119, 119, 119, 119, 119, 119, 119, 119, 119, 136, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 137, 137, 137, 137, 137, 137, 137, 137, 138, 119, 119, 119, 119, 119, 119, 119, + 139, 139, 139, 139, 139, 139, 139, 139, 140, 119, 119, 119, 119, 119, 119, 119, + 141, 141, 141, 141, 142, 119, 119, 119, 119, 119, 119, 119, 119, 119, 143, 144, + 145, 145, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 146, 146, 147, 147, 148, 119, 149, 119, 150, 150, 150, 150, 150, 150, 150, 150, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 151, 151, 119, 119, + 152, 153, 154, 154, 155, 155, 156, 156, 156, 156, 156, 156, 157, 158, 159, 119, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 163, 164, + 165, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 166, 166, 166, 166, 167, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 168, 119, 169, 170, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +}; + +static RE_UINT8 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, 19, 19, 19, 19, 19, + 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, + 59, 59, 59, 59, 59, 60, 60, 60, 19, 19, 19, 19, 61, 62, 62, 62, + 63, 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, + 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, + 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 70, 70, 70, 71, 71, 71, + 72, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, + 75, 75, 75, 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, + 77, 77, 77, 77, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 82, 82, 82, 82, 82, 82, + 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 85, 85, 85, 86, 87, 87, 87, 87, 87, 87, 87, 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, 93, 93, 94, 94, 94, 94, 94, 94, 94, 94, + 95, 95, 95, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 98, 98, + 99, 99, 99, 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 19, 102, + 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, + 106, 106, 106, 107, 107, 107, 107, 107, 107, 108, 109, 109, 110, 110, 110, 111, + 112, 112, 112, 112, 112, 112, 112, 112, 113, 113, 113, 113, 113, 113, 113, 113, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 115, 115, 115, 115, + 116, 116, 116, 116, 116, 116, 116, 116, 117, 117, 117, 117, 117, 117, 117, 117, + 117, 118, 118, 118, 118, 119, 119, 119, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 122, 122, 122, 122, 122, 122, + 123, 123, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, + 125, 125, 125, 126, 127, 127, 127, 127, 128, 128, 128, 128, 128, 128, 129, 129, + 130, 130, 130, 131, 131, 131, 132, 132, 133, 133, 133, 133, 133, 133, 19, 19, + 134, 134, 134, 134, 134, 134, 135, 135, 136, 136, 136, 136, 136, 136, 137, 137, + 138, 138, 138, 19, 19, 19, 19, 19, 19, 19, 19, 19, 139, 139, 139, 139, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, + 142, 142, 142, 142, 142, 142, 142, 142, 143, 143, 143, 143, 143, 143, 143, 143, + 144, 144, 144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, + 146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 147, 147, 147, 148, 148, 148, + 148, 148, 148, 148, 148, 148, 148, 148, 149, 150, 151, 152, 152, 153, 153, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 156, 157, 157, 157, 157, 157, 157, 157, 157, + 158, 158, 158, 158, 158, 158, 158, 158, 159, 159, 159, 159, 160, 160, 160, 160, + 160, 161, 161, 161, 161, 162, 162, 162, 19, 19, 19, 19, 19, 19, 19, 19, + 163, 163, 164, 164, 164, 164, 19, 19, 165, 165, 165, 166, 166, 19, 19, 19, + 167, 167, 168, 168, 168, 168, 19, 19, 169, 169, 169, 169, 169, 170, 170, 170, + 171, 171, 171, 19, 19, 19, 19, 19, 172, 172, 172, 172, 173, 173, 19, 19, + 174, 174, 175, 175, 19, 19, 19, 19, 176, 176, 177, 177, 177, 177, 177, 177, + 178, 178, 178, 178, 178, 178, 179, 179, 180, 180, 180, 180, 181, 181, 182, 182, + 183, 183, 183, 183, 183, 19, 19, 19, 19, 19, 19, 19, 19, 19, 184, 184, + 185, 185, 185, 185, 185, 185, 185, 185, 186, 186, 186, 186, 186, 187, 187, 187, + 188, 188, 188, 188, 188, 19, 19, 19, 189, 189, 189, 189, 189, 189, 19, 19, + 190, 190, 190, 190, 190, 19, 19, 19, 191, 191, 191, 191, 191, 191, 191, 191, + 192, 192, 192, 192, 192, 192, 192, 192, 193, 193, 193, 193, 193, 193, 193, 193, + 193, 193, 193, 19, 19, 19, 19, 19, 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 19, 19, 19, 19, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 19, 19, 19, 19, 19, 19, 196, 196, 196, 196, 196, 196, 196, 196, + 197, 197, 197, 197, 197, 197, 197, 197, 198, 198, 198, 198, 198, 198, 198, 198, + 199, 199, 199, 199, 199, 19, 19, 19, 200, 200, 200, 200, 200, 200, 201, 201, + 202, 202, 202, 202, 202, 202, 202, 202, 203, 203, 203, 203, 203, 203, 203, 203, + 204, 204, 204, 205, 205, 205, 205, 205, 205, 205, 206, 206, 206, 206, 206, 206, + 207, 207, 207, 207, 207, 207, 207, 207, 208, 208, 208, 208, 208, 208, 208, 208, + 209, 209, 209, 209, 209, 209, 209, 209, 210, 210, 210, 210, 210, 19, 19, 19, + 211, 211, 211, 211, 211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 19, 19, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 19, 19, 19, 19, 19, 19, + 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 19, 19, 19, 19, 19, 19, + 217, 217, 217, 217, 217, 217, 217, 217, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 218, 218, 218, 19, 219, 219, 219, 219, 219, 219, 219, 219, + 220, 220, 220, 220, 220, 220, 220, 220, +}; + +static RE_UINT8 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, +}; + +static RE_UINT8 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, +}; + +/* Block: 4288 bytes. */ + +RE_UINT32 re_get_block(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_block_stage_1[f] << 4; + 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, 14, 19, 14, 20, 14, 14, 14, 14, 14, 14, 21, 14, 14, + 14, 14, 14, 14, 14, 14, 22, 14, 14, 14, 23, 14, 14, 24, 25, 14, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 26, 7, 27, 28, 14, 14, 14, 14, 14, 14, 14, 29, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 30, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 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, 62, 59, + 63, 63, 59, 59, 59, 59, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 59, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 81, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 82, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 85, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 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, 98, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 72, 72, 99, 100, 101, 102, 103, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 65, 114, 115, 116, 117, 118, 65, 65, 65, 65, 65, 65, + 119, 65, 120, 121, 122, 65, 123, 65, 124, 65, 65, 65, 125, 65, 65, 65, + 126, 127, 128, 129, 65, 65, 65, 65, 65, 65, 65, 65, 65, 130, 65, 65, + 131, 131, 131, 131, 131, 131, 132, 65, 133, 65, 65, 65, 65, 65, 65, 65, + 134, 134, 134, 134, 134, 134, 134, 134, 135, 65, 65, 65, 65, 65, 65, 65, + 136, 136, 136, 136, 137, 65, 65, 65, 65, 65, 65, 65, 65, 65, 138, 139, + 140, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 59, 141, 142, 143, 144, 65, 145, 65, 146, 147, 148, 59, 59, 149, 59, 150, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 151, 152, 65, 65, + 153, 154, 155, 156, 157, 65, 158, 159, 160, 161, 162, 163, 164, 165, 60, 65, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 166, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 167, 72, + 168, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 72, 72, 72, 72, 168, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 169, 65, 170, 171, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, +}; + +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, 16, 17, 18, 19, 17, 18, 20, 21, 22, 22, 23, 22, 24, 25, + 26, 27, 28, 28, 29, 30, 31, 32, 28, 28, 28, 28, 28, 33, 28, 28, + 34, 35, 35, 35, 36, 28, 28, 28, 37, 37, 37, 38, 39, 39, 39, 40, + 41, 41, 42, 43, 44, 45, 46, 46, 46, 46, 47, 46, 46, 46, 48, 49, + 50, 50, 50, 50, 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, 46, 124, + 125, 126, 126, 127, 126, 128, 46, 46, 129, 130, 131, 132, 133, 134, 46, 46, + 135, 135, 135, 135, 136, 135, 137, 138, 135, 136, 135, 139, 139, 140, 46, 46, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 142, 142, 143, 142, 142, 144, + 145, 145, 145, 145, 145, 145, 145, 145, 146, 146, 146, 146, 147, 148, 146, 146, + 147, 146, 146, 149, 150, 151, 146, 146, 146, 150, 146, 146, 146, 152, 146, 153, + 146, 154, 155, 155, 155, 155, 155, 156, 157, 157, 157, 157, 157, 157, 157, 157, + 158, 159, 160, 160, 160, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 171, 171, 171, 171, 172, 173, 173, 174, 175, 176, 176, 176, 176, 176, 177, + 176, 176, 178, 157, 157, 157, 157, 179, 180, 181, 182, 182, 183, 184, 185, 186, + 187, 187, 188, 187, 189, 190, 171, 171, 191, 192, 193, 193, 193, 194, 193, 195, + 196, 196, 197, 46, 46, 46, 46, 46, 198, 198, 198, 198, 199, 198, 198, 200, + 201, 201, 201, 201, 202, 202, 202, 203, 204, 204, 204, 205, 206, 207, 207, 207, + 46, 46, 46, 46, 208, 209, 210, 211, 4, 4, 212, 4, 4, 213, 214, 215, + 4, 4, 4, 216, 8, 8, 217, 218, 11, 219, 11, 11, 219, 220, 11, 221, + 11, 11, 11, 222, 222, 223, 11, 224, 225, 0, 0, 0, 0, 0, 226, 227, + 228, 229, 0, 230, 46, 8, 8, 231, 0, 0, 232, 233, 234, 0, 4, 4, + 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 236, 0, 0, 237, 46, 230, 46, 0, 0, + 238, 0, 0, 0, 0, 0, 0, 0, 239, 239, 239, 239, 239, 239, 239, 239, + 0, 0, 0, 0, 240, 241, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 242, 242, 243, 242, 242, 243, 4, 4, 244, 244, 244, 244, 244, 244, 244, 245, + 142, 142, 143, 246, 246, 246, 247, 248, 146, 249, 250, 250, 250, 250, 14, 14, + 0, 0, 0, 251, 46, 46, 46, 46, 252, 253, 252, 252, 252, 252, 252, 254, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 255, 46, 251, + 256, 0, 257, 258, 259, 260, 260, 260, 260, 261, 262, 263, 263, 263, 263, 264, + 265, 266, 267, 268, 145, 145, 145, 145, 269, 0, 266, 270, 0, 0, 236, 263, + 145, 269, 0, 0, 0, 0, 145, 271, 0, 0, 0, 0, 0, 263, 263, 272, + 263, 263, 263, 263, 263, 273, 0, 0, 252, 252, 252, 255, 0, 0, 0, 0, + 252, 252, 252, 252, 274, 46, 46, 46, 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, 46, 14, 14, 14, 14, 14, 281, 282, 282, 282, 282, 282, 283, + 0, 0, 284, 4, 4, 4, 4, 4, 285, 286, 287, 46, 46, 46, 46, 288, + 289, 289, 290, 241, 291, 291, 291, 292, 293, 293, 293, 293, 294, 295, 50, 296, + 297, 297, 297, 298, 298, 299, 145, 300, 301, 301, 301, 301, 302, 303, 46, 46, + 304, 304, 304, 305, 306, 307, 141, 308, 309, 309, 309, 309, 310, 311, 312, 313, + 314, 315, 250, 46, 46, 46, 46, 46, 46, 46, 46, 46, 312, 312, 316, 317, + 145, 145, 318, 145, 319, 145, 145, 320, 252, 252, 252, 252, 252, 252, 321, 252, + 252, 252, 252, 252, 252, 322, 46, 46, 323, 324, 22, 325, 326, 28, 28, 28, + 28, 28, 28, 28, 327, 328, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 329, 46, 28, 28, 28, 28, 330, 28, 28, 331, 46, 46, 332, + 8, 241, 217, 0, 0, 333, 334, 335, 28, 28, 28, 28, 28, 28, 28, 336, + 238, 0, 1, 2, 1, 2, 337, 262, 263, 338, 145, 269, 339, 340, 341, 342, + 343, 344, 345, 346, 347, 347, 46, 46, 344, 344, 344, 344, 344, 344, 344, 348, + 349, 0, 0, 350, 11, 11, 11, 11, 351, 251, 46, 46, 46, 0, 0, 352, + 353, 354, 355, 355, 355, 356, 46, 46, 357, 358, 359, 360, 361, 46, 46, 46, + 362, 363, 364, 364, 365, 366, 46, 46, 367, 367, 367, 367, 367, 368, 368, 368, + 369, 370, 371, 46, 46, 46, 46, 46, 372, 373, 373, 374, 375, 376, 46, 46, + 377, 378, 379, 380, 46, 46, 46, 46, 381, 381, 382, 383, 46, 46, 46, 46, + 384, 385, 386, 387, 388, 389, 390, 390, 391, 391, 391, 392, 393, 394, 395, 396, + 397, 397, 397, 397, 398, 46, 46, 46, 46, 46, 46, 46, 46, 46, 28, 49, + 399, 399, 399, 399, 400, 401, 399, 46, 402, 402, 402, 402, 403, 404, 405, 406, + 407, 407, 407, 408, 409, 46, 46, 46, 410, 410, 410, 410, 411, 412, 46, 46, + 413, 413, 413, 414, 415, 46, 46, 46, 416, 416, 416, 416, 416, 416, 416, 416, + 416, 416, 416, 416, 416, 416, 417, 46, 416, 416, 416, 416, 416, 416, 418, 419, + 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 421, 46, 46, 46, 46, 46, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 422, 46, 46, 46, 46, + 423, 423, 423, 423, 424, 423, 423, 425, 426, 423, 46, 46, 46, 46, 46, 46, + 427, 46, 46, 46, 46, 46, 46, 46, 0, 0, 0, 0, 0, 0, 0, 428, + 0, 0, 429, 0, 0, 0, 430, 431, 432, 0, 433, 0, 0, 434, 46, 46, + 11, 11, 11, 11, 435, 46, 46, 46, 0, 0, 0, 0, 0, 237, 0, 436, + 0, 0, 0, 0, 0, 226, 0, 0, 0, 437, 438, 439, 440, 0, 0, 0, + 441, 442, 0, 443, 444, 445, 0, 0, 0, 0, 446, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 447, 0, 0, 0, 448, 28, 449, 450, 451, 452, 453, 454, + 455, 456, 457, 456, 46, 46, 46, 327, 0, 0, 251, 0, 0, 0, 0, 0, + 0, 236, 228, 458, 238, 238, 46, 46, 230, 0, 228, 0, 0, 0, 251, 0, + 0, 230, 46, 46, 46, 46, 459, 0, 460, 0, 0, 230, 461, 436, 46, 46, + 0, 0, 462, 463, 0, 0, 0, 240, 0, 236, 0, 0, 464, 46, 0, 462, + 0, 0, 0, 228, 445, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 465, + 0, 0, 0, 434, 236, 0, 466, 46, 46, 46, 46, 46, 46, 46, 46, 467, + 0, 0, 0, 0, 468, 46, 46, 46, 0, 0, 0, 0, 428, 46, 46, 46, + 252, 252, 252, 252, 252, 469, 46, 46, 252, 252, 252, 470, 252, 252, 252, 252, + 252, 321, 46, 46, 46, 46, 46, 46, 471, 46, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 46, +}; + +static RE_UINT8 re_script_stage_4[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 0, 0, 0, 2, 2, 3, 0, 0, 4, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 7, 6, 8, 6, 6, 9, + 8, 8, 10, 10, 6, 11, 11, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 12, 6, 6, 6, 6, 6, 6, 6, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 16, 14, 14, 14, 14, + 14, 14, 14, 14, 8, 8, 8, 8, 17, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 17, 18, 18, 18, + 18, 18, 18, 18, 20, 19, 8, 17, 21, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 8, 8, 8, 8, + 22, 22, 22, 22, 22, 23, 8, 8, 22, 22, 23, 8, 8, 8, 8, 8, + 24, 24, 25, 24, 24, 24, 26, 24, 24, 24, 24, 24, 24, 27, 25, 27, + 24, 24, 24, 24, 24, 24, 24, 24, 26, 24, 24, 24, 24, 28, 5, 5, + 5, 5, 5, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 24, 24, 24, + 29, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 27, 24, + 30, 30, 30, 30, 30, 30, 30, 31, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 32, 31, 30, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 8, 8, 8, 8, 8, 8, 8, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 35, 8, 8, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 8, 36, 36, 36, 36, 36, 36, 36, 37, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 8, 39, + 8, 8, 8, 8, 8, 8, 8, 8, 25, 24, 24, 24, 24, 24, 25, 8, + 8, 8, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, + 40, 40, 40, 40, 40, 40, 40, 40, 41, 42, 40, 40, 40, 40, 40, 40, + 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 43, 40, 40, 40, + 44, 45, 44, 45, 45, 45, 46, 44, 46, 44, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 46, 45, 45, 45, 46, 46, 8, 45, 45, 8, 45, 45, + 45, 45, 46, 44, 46, 44, 45, 46, 8, 8, 8, 44, 8, 8, 45, 44, + 45, 45, 8, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 8, 8, + 47, 48, 47, 48, 48, 49, 8, 47, 49, 47, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 49, 48, 48, 48, 49, 48, 47, 49, 48, 8, 49, 48, + 48, 49, 8, 47, 49, 47, 48, 8, 47, 8, 8, 8, 47, 48, 49, 49, + 8, 8, 8, 48, 48, 48, 48, 48, 48, 48, 48, 8, 8, 8, 8, 8, + 50, 51, 50, 51, 51, 51, 51, 50, 51, 50, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 52, 51, 51, 51, 52, 51, 50, 51, 51, 8, 51, 51, + 51, 51, 51, 50, 51, 50, 51, 8, 52, 8, 8, 8, 8, 8, 8, 8, + 51, 51, 8, 51, 51, 51, 51, 51, 51, 8, 8, 8, 8, 8, 8, 8, + 53, 54, 53, 54, 54, 54, 55, 53, 55, 53, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 55, 54, 54, 54, 55, 54, 53, 54, 54, 8, 54, 54, + 54, 54, 55, 53, 55, 53, 54, 8, 8, 8, 8, 54, 8, 8, 54, 53, + 54, 54, 8, 54, 54, 54, 54, 54, 54, 54, 54, 54, 8, 8, 8, 8, + 8, 56, 57, 56, 56, 58, 8, 56, 58, 56, 56, 8, 57, 58, 58, 56, + 8, 57, 58, 8, 56, 58, 8, 56, 56, 56, 56, 56, 56, 8, 8, 56, + 56, 58, 8, 56, 58, 56, 56, 8, 58, 8, 8, 57, 8, 8, 8, 8, + 8, 8, 8, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 58, 8, 8, + 59, 60, 59, 60, 60, 60, 61, 60, 61, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 61, 60, 60, 60, 60, 60, 59, 60, 60, 8, 59, 60, + 60, 60, 61, 60, 61, 60, 60, 8, 8, 8, 59, 61, 60, 8, 8, 8, + 60, 60, 8, 60, 60, 60, 60, 60, 8, 8, 8, 8, 60, 60, 60, 60, + 8, 62, 63, 62, 62, 62, 64, 62, 64, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 64, 62, 62, 62, 62, 62, 63, 62, 62, 8, 62, 62, + 62, 62, 64, 62, 64, 62, 62, 8, 8, 8, 63, 64, 8, 8, 8, 64, + 62, 62, 8, 62, 62, 62, 62, 62, 63, 64, 8, 8, 8, 8, 8, 8, + 8, 65, 66, 65, 65, 65, 67, 65, 67, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 67, 66, 65, + 65, 65, 67, 65, 67, 65, 65, 67, 8, 8, 8, 66, 8, 8, 8, 8, + 65, 65, 8, 65, 65, 65, 65, 65, 65, 65, 65, 8, 66, 65, 65, 65, + 8, 68, 69, 68, 68, 68, 68, 68, 68, 68, 68, 70, 8, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 69, 68, 68, 68, 68, 69, 8, + 68, 68, 68, 70, 8, 70, 8, 69, 68, 68, 70, 70, 68, 68, 68, 68, + 8, 68, 70, 8, 8, 8, 8, 8, 71, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 8, 20, + 72, 72, 72, 72, 72, 72, 8, 8, 74, 75, 75, 74, 75, 75, 74, 8, + 8, 8, 76, 76, 74, 76, 76, 76, 74, 76, 74, 74, 8, 76, 74, 76, + 76, 76, 76, 76, 76, 74, 76, 8, 76, 76, 75, 75, 76, 76, 76, 8, + 76, 76, 76, 76, 76, 8, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 78, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 8, + 78, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 77, + 77, 77, 80, 0, 81, 79, 8, 8, 82, 82, 82, 82, 82, 82, 82, 82, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 8, 8, 84, 8, + 83, 83, 83, 83, 83, 85, 83, 83, 86, 86, 86, 86, 86, 86, 86, 86, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 88, 87, 87, 8, + 87, 87, 87, 88, 88, 87, 87, 8, 88, 87, 87, 8, 87, 87, 87, 88, + 88, 87, 87, 8, 87, 87, 87, 87, 87, 87, 87, 88, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 88, 89, 87, 87, 87, 87, 87, 87, 87, 88, 8, + 87, 87, 87, 87, 87, 8, 8, 8, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 91, 8, 8, 8, 8, 8, 92, 92, 92, 92, 92, 92, 92, 92, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 94, 8, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 0, 95, + 97, 8, 8, 8, 8, 8, 8, 8, 98, 98, 98, 98, 98, 98, 99, 98, + 98, 98, 99, 8, 8, 8, 8, 8, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 101, 9, 8, 8, 8, 8, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 8, 8, 8, 8, 8, 8, 103, 103, 103, 103, 103, 103, 104, 103, + 104, 103, 8, 8, 8, 8, 8, 8, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 8, 105, 105, 105, 105, 105, 8, 8, 8, + 106, 0, 107, 106, 106, 106, 106, 108, 106, 106, 106, 106, 106, 8, 8, 8, + 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 8, 8, 8, 8, + 106, 106, 106, 106, 106, 108, 8, 8, 92, 92, 92, 8, 8, 8, 8, 8, + 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 110, 8, + 109, 109, 109, 109, 109, 109, 8, 8, 110, 8, 109, 109, 109, 109, 109, 109, + 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 8, + 111, 111, 112, 8, 8, 8, 8, 8, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 8, 8, 113, 113, 113, 113, 113, 8, 8, 8, + 113, 113, 113, 113, 113, 114, 8, 113, 115, 115, 115, 115, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 8, 115, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 117, 116, 116, 116, 116, 116, 116, 117, 118, + 116, 116, 116, 116, 116, 8, 8, 8, 116, 116, 116, 116, 116, 116, 116, 8, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 8, 8, + 119, 119, 119, 119, 119, 119, 120, 8, 121, 121, 121, 121, 121, 121, 121, 121, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 8, 8, 8, 8, 122, 122, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 8, 124, 123, 123, + 123, 123, 123, 123, 123, 8, 124, 123, 125, 125, 125, 125, 125, 125, 125, 125, + 121, 121, 121, 121, 8, 8, 8, 8, 5, 126, 5, 5, 5, 5, 5, 5, + 126, 5, 5, 5, 126, 0, 127, 0, 0, 0, 126, 9, 8, 8, 8, 8, + 2, 2, 2, 6, 6, 128, 2, 2, 2, 2, 2, 2, 2, 2, 129, 6, + 6, 2, 2, 6, 6, 130, 2, 2, 2, 2, 2, 2, 131, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 129, 5, 5, 5, 132, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 5, 5, 6, 6, 6, 8, 6, 6, 6, 8, + 6, 6, 6, 6, 12, 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 8, + 6, 6, 11, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 12, 6, + 8, 6, 11, 6, 6, 6, 6, 11, 0, 0, 0, 0, 0, 0, 5, 0, + 0, 0, 9, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 9, 2, 2, 2, 2, 2, 2, 133, 8, + 0, 0, 0, 0, 0, 9, 8, 8, 132, 8, 8, 8, 8, 8, 8, 8, + 0, 0, 0, 10, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 2, 3, 8, 8, 8, + 0, 0, 8, 8, 8, 8, 8, 8, 0, 0, 0, 9, 8, 8, 8, 8, + 20, 0, 0, 0, 0, 0, 0, 0, 134, 134, 134, 134, 134, 134, 134, 134, + 0, 0, 0, 0, 0, 0, 9, 8, 0, 0, 0, 0, 0, 8, 8, 8, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 136, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 8, 8, 137, 13, 13, 13, + 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 8, 8, 8, 139, + 140, 8, 8, 8, 8, 8, 8, 139, 87, 87, 87, 88, 8, 8, 8, 8, + 87, 87, 87, 88, 87, 87, 87, 88, 0, 0, 0, 0, 0, 0, 8, 8, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 142, 141, 141, + 141, 141, 8, 8, 8, 8, 8, 8, 141, 141, 141, 8, 8, 8, 8, 8, + 0, 0, 143, 143, 0, 0, 0, 0, 143, 141, 141, 141, 141, 5, 5, 86, + 0, 0, 0, 0, 141, 141, 0, 0, 144, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 146, 147, 126, 148, 145, + 149, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 151, 149, 150, 8, 8, 152, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, + 153, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 154, + 4, 4, 4, 4, 4, 155, 8, 8, 86, 86, 86, 86, 86, 86, 86, 156, + 150, 150, 150, 150, 150, 150, 150, 157, 150, 150, 150, 150, 0, 0, 0, 0, + 141, 141, 141, 141, 141, 141, 158, 8, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 160, 8, 159, 159, 159, 160, 8, 8, 8, 8, + 161, 161, 161, 161, 161, 161, 161, 161, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 8, 8, 14, 14, 14, 14, 8, 8, 8, 163, + 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 8, 8, 8, 8, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 2, 133, + 2, 2, 8, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2, 133, 8, 8, + 8, 8, 8, 8, 2, 2, 2, 2, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 8, 8, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 166, 166, 8, 8, 8, 8, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 168, 8, 8, 8, 8, 167, 167, 167, 167, 167, 167, 8, 8, 8, + 40, 40, 40, 40, 40, 40, 8, 8, 169, 169, 169, 169, 169, 169, 169, 169, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 8, 8, 8, 8, 8, 171, + 86, 86, 86, 86, 86, 86, 154, 8, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 20, 172, 172, 172, 172, 172, 8, 8, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 174, 8, 8, 8, 8, + 173, 173, 173, 173, 173, 173, 173, 8, 173, 173, 173, 173, 173, 8, 173, 173, + 82, 82, 82, 82, 82, 82, 8, 8, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 176, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 177, 175, 175, + 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 179, 8, 8, 8, 8, + 89, 87, 87, 88, 89, 87, 87, 88, 89, 87, 87, 88, 8, 8, 8, 8, + 178, 178, 178, 178, 178, 178, 178, 8, 178, 178, 178, 178, 178, 8, 8, 8, + 86, 86, 8, 8, 8, 8, 8, 8, 86, 86, 86, 154, 8, 153, 86, 86, + 86, 86, 86, 86, 86, 86, 8, 8, 141, 141, 141, 141, 141, 141, 141, 8, + 141, 141, 141, 141, 141, 8, 8, 8, 2, 2, 2, 133, 8, 8, 8, 8, + 8, 17, 18, 18, 8, 8, 21, 22, 22, 22, 22, 23, 22, 22, 23, 23, + 22, 21, 23, 22, 22, 22, 22, 22, 24, 8, 8, 8, 8, 8, 8, 8, + 8, 180, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, + 8, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 8, 8, 8, 8, + 24, 24, 24, 24, 24, 24, 27, 8, 0, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0, 8, 8, 24, 24, 25, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 25, 20, 0, 0, 0, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 0, 8, 86, 86, 86, 8, 86, 86, 86, + 8, 86, 86, 86, 8, 86, 154, 8, 0, 0, 0, 9, 0, 0, 0, 9, + 8, 8, 8, 8, 20, 0, 0, 8, 181, 181, 181, 181, 181, 181, 182, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 183, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 183, 181, 182, 181, 181, 181, 181, 181, 181, 181, 8, + 181, 181, 181, 181, 181, 183, 8, 8, 0, 9, 8, 20, 0, 0, 0, 0, + 0, 0, 8, 20, 0, 0, 0, 0, 6, 6, 6, 6, 6, 11, 8, 8, + 0, 0, 0, 0, 0, 0, 127, 8, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 185, 8, 186, 186, 186, 186, 186, 186, 186, 186, + 187, 8, 8, 8, 8, 8, 8, 8, 188, 188, 188, 188, 188, 188, 188, 188, + 188, 188, 188, 188, 188, 188, 188, 189, 188, 188, 8, 8, 8, 8, 8, 8, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 191, 8, 8, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 193, + 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 8, 8, 194, 194, 194, 194, + 194, 194, 194, 8, 8, 8, 8, 8, 195, 195, 195, 195, 195, 195, 195, 195, + 196, 196, 196, 196, 196, 196, 196, 196, 197, 197, 197, 197, 197, 197, 197, 197, + 197, 197, 197, 197, 197, 197, 197, 8, 197, 197, 197, 197, 197, 8, 8, 8, + 198, 198, 198, 8, 199, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, + 198, 198, 198, 200, 199, 8, 199, 200, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 202, 201, 201, 201, 201, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 203, 203, 203, 203, 203, 8, 204, 205, 205, 205, 205, 205, 205, 205, 205, + 205, 205, 205, 205, 205, 8, 8, 206, 207, 207, 207, 207, 207, 207, 207, 207, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 8, 8, 8, 208, + 209, 209, 210, 211, 8, 8, 209, 209, 209, 209, 210, 209, 210, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 8, 8, 209, 211, 8, 210, + 209, 209, 209, 209, 8, 8, 8, 8, 209, 209, 209, 209, 211, 8, 8, 8, + 212, 212, 212, 212, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 8, 214, 213, 213, 213, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 8, 215, 215, 215, 215, 216, 216, 216, 216, 216, 216, 216, 216, + 216, 217, 8, 8, 216, 216, 216, 216, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 219, 8, 8, 8, 220, 220, 220, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 220, 220, 8, 8, 220, 220, 220, 220, 220, 220, 220, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 8, 8, 8, 8, 8, 8, 8, + 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 223, 8, 8, 8, + 222, 222, 222, 222, 222, 8, 8, 8, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 225, 224, 224, 224, 224, 224, 224, 224, 8, 8, 8, 8, 8, 8, + 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 227, 8, 8, 8, + 226, 226, 226, 226, 226, 8, 8, 8, 228, 228, 228, 228, 228, 228, 228, 228, + 228, 228, 228, 228, 8, 8, 8, 8, 228, 228, 228, 228, 228, 8, 8, 8, + 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, + 229, 230, 8, 8, 8, 8, 8, 8, 229, 229, 8, 8, 8, 8, 8, 8, + 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, + 164, 164, 164, 164, 233, 8, 8, 8, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 234, 235, 8, 8, 8, 8, 8, 234, 234, 234, 234, 234, 234, 234, 235, + 8, 8, 8, 8, 8, 8, 8, 236, 237, 8, 8, 8, 8, 8, 8, 8, + 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, 0, 9, 20, 0, 0, 0, + 0, 0, 0, 127, 5, 0, 0, 0, 0, 0, 0, 0, 0, 127, 5, 5, + 5, 126, 127, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 8, 6, 6, 6, 8, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 9, 0, + 8, 9, 20, 9, 20, 0, 9, 0, 0, 0, 0, 0, 0, 20, 20, 0, + 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 9, 20, 0, + 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 20, 0, 9, + 0, 0, 9, 9, 8, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, + 24, 24, 180, 24, 24, 24, 24, 24, 180, 25, 25, 180, 180, 24, 24, 24, + 24, 25, 24, 24, 180, 180, 8, 8, 8, 25, 8, 180, 180, 180, 180, 24, + 180, 25, 25, 180, 180, 180, 180, 180, 180, 25, 25, 180, 24, 25, 24, 24, + 24, 25, 24, 24, 180, 24, 25, 25, 24, 24, 24, 24, 24, 180, 24, 24, + 24, 24, 24, 24, 24, 24, 8, 8, 180, 24, 180, 24, 24, 180, 24, 24, + 20, 0, 0, 0, 0, 0, 0, 9, 8, 8, 8, 0, 0, 0, 0, 0, + 238, 9, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 9, 8, 8, 8, + 9, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 20, 0, 0, 0, 0, + 0, 0, 9, 0, 0, 9, 8, 8, 0, 0, 0, 0, 20, 0, 9, 8, + 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 20, 0, 0, + 9, 8, 20, 0, 0, 0, 0, 0, 141, 141, 141, 158, 8, 8, 8, 8, + 141, 141, 158, 8, 8, 8, 8, 8, 20, 8, 8, 8, 8, 8, 8, 8, +}; + +static RE_UINT8 re_script_stage_5[] = { + 1, 1, 1, 2, 2, 2, 2, 1, 35, 35, 41, 41, 3, 3, 1, 3, + 0, 0, 1, 0, 3, 1, 3, 0, 0, 3, 55, 55, 4, 4, 4, 41, + 41, 4, 0, 5, 5, 5, 5, 0, 0, 1, 0, 6, 6, 6, 6, 0, + 7, 7, 7, 0, 1, 7, 7, 1, 7, 41, 41, 7, 8, 8, 0, 8, + 8, 0, 9, 9, 66, 66, 66, 0, 82, 82, 82, 0, 95, 95, 95, 0, + 10, 10, 10, 41, 41, 10, 0, 10, 0, 11, 11, 11, 11, 0, 0, 12, + 12, 12, 12, 0, 0, 13, 13, 13, 13, 0, 0, 14, 14, 14, 14, 0, + 15, 15, 0, 15, 15, 0, 0, 16, 16, 16, 16, 0, 17, 17, 0, 17, + 17, 0, 18, 18, 0, 18, 18, 0, 19, 19, 0, 19, 19, 0, 0, 20, + 20, 20, 20, 0, 0, 21, 21, 0, 21, 21, 22, 22, 0, 22, 22, 0, + 22, 1, 1, 22, 23, 23, 24, 24, 0, 24, 24, 1, 25, 25, 26, 26, + 26, 0, 0, 26, 27, 27, 27, 0, 28, 28, 29, 29, 29, 0, 30, 30, + 30, 1, 30, 0, 42, 42, 42, 0, 43, 43, 43, 1, 44, 44, 45, 45, + 45, 0, 31, 31, 32, 32, 32, 1, 32, 0, 46, 46, 46, 0, 47, 47, + 47, 0, 56, 56, 56, 0, 54, 54, 78, 78, 78, 0, 0, 78, 62, 62, + 62, 0, 67, 67, 93, 93, 68, 68, 0, 68, 69, 69, 41, 1, 1, 41, + 3, 4, 2, 3, 3, 2, 4, 2, 41, 0, 2, 0, 53, 53, 57, 57, + 57, 0, 0, 55, 58, 58, 0, 58, 58, 0, 36, 36, 0, 36, 1, 36, + 0, 33, 33, 33, 33, 0, 0, 41, 1, 33, 1, 34, 34, 34, 34, 1, + 0, 35, 0, 25, 25, 0, 35, 0, 25, 1, 34, 0, 36, 0, 37, 37, + 37, 0, 83, 83, 70, 70, 0, 4, 84, 84, 59, 59, 65, 65, 71, 71, + 71, 0, 72, 72, 73, 73, 0, 73, 85, 85, 77, 77, 77, 0, 79, 79, + 79, 0, 0, 79, 86, 86, 86, 0, 0, 7, 48, 48, 0, 48, 48, 0, + 74, 74, 74, 0, 75, 75, 75, 0, 38, 38, 38, 0, 39, 39, 39, 0, + 49, 49, 0, 49, 60, 60, 40, 40, 50, 50, 51, 51, 52, 52, 52, 0, + 0, 52, 87, 87, 0, 87, 64, 64, 0, 64, 76, 76, 0, 76, 98, 98, + 97, 97, 61, 61, 0, 61, 61, 0, 88, 88, 80, 80, 0, 80, 89, 89, + 90, 90, 90, 0, 91, 91, 91, 0, 94, 94, 92, 92, 101, 101, 101, 0, + 96, 96, 96, 0, 100, 100, 100, 0, 102, 102, 63, 63, 63, 0, 81, 81, + 81, 0, 84, 0, 99, 99, 99, 0, 0, 99, 34, 33, 33, 1, +}; + +/* Script: 8046 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] << 3; + f = code >> 1; + code ^= f << 1; + pos = (RE_UINT32)re_script_stage_4[pos + f] << 1; + 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, 4, 4, 13, 4, 4, 4, 4, 14, 4, 15, 16, 17, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 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, +}; + +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, 57, 57, 57, 57, 57, 57, + 100, 57, 101, 102, 103, 57, 104, 57, 105, 57, 57, 57, 57, 57, 57, 57, + 106, 107, 108, 109, 57, 57, 57, 57, 57, 57, 57, 57, 57, 110, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 2, 2, 2, 2, 2, 2, 111, 57, 112, 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, 113, 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, 114, 57, 57, 57, 57, 57, 57, 57, 57, 57, 115, 116, + 117, 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, 118, 119, 120, 57, 57, 57, 121, 122, 123, 2, 2, 124, 125, 126, + 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, 127, 128, 57, 57, + 57, 57, 57, 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, + 130, 57, 131, 132, 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, 0, 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, 59, 17, 0, 0, 0, 0, 0, 0, 60, 19, 19, 61, + 62, 7, 7, 7, 7, 7, 7, 63, 19, 19, 64, 7, 65, 4, 6, 6, + 66, 67, 68, 7, 7, 59, 69, 70, 71, 72, 73, 74, 65, 4, 75, 0, + 66, 76, 68, 7, 7, 59, 77, 78, 79, 80, 81, 82, 83, 4, 84, 0, + 66, 25, 24, 7, 7, 59, 85, 70, 31, 86, 87, 0, 65, 4, 0, 0, + 66, 67, 68, 7, 7, 59, 85, 70, 71, 80, 88, 74, 65, 4, 28, 0, + 89, 90, 91, 92, 93, 90, 7, 94, 95, 96, 97, 0, 83, 4, 0, 0, + 66, 20, 59, 7, 7, 59, 98, 99, 100, 96, 101, 75, 65, 4, 0, 0, + 102, 20, 59, 7, 7, 59, 98, 70, 100, 96, 101, 103, 65, 4, 104, 0, + 102, 20, 59, 7, 7, 7, 7, 105, 100, 106, 73, 0, 65, 4, 0, 107, + 102, 7, 14, 107, 7, 7, 24, 108, 14, 109, 110, 19, 0, 0, 111, 0, + 0, 0, 0, 0, 0, 0, 112, 113, 73, 61, 4, 114, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 112, 115, 0, 116, 4, 114, 0, 0, 0, 0, + 87, 0, 0, 117, 4, 114, 118, 119, 7, 6, 7, 7, 7, 17, 30, 19, + 100, 120, 19, 30, 19, 19, 19, 121, 122, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 123, 19, 61, 4, 114, 88, 124, 125, 116, 126, 0, + 127, 31, 4, 128, 7, 7, 7, 7, 25, 129, 7, 7, 7, 7, 7, 130, + 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, 131, 0, 0, 0, 0, + 7, 7, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 17, 0, + 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, 67, 7, 7, + 6, 7, 7, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 90, 87, 0, + 7, 20, 132, 0, 7, 7, 132, 0, 7, 7, 133, 0, 7, 20, 134, 0, + 0, 0, 0, 0, 0, 0, 60, 19, 19, 19, 135, 136, 4, 114, 0, 0, + 0, 137, 4, 114, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, + 7, 7, 7, 7, 7, 138, 7, 7, 7, 7, 7, 7, 7, 7, 139, 0, + 7, 7, 7, 17, 19, 135, 19, 135, 83, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 19, 19, 140, 117, 4, 114, 0, 0, 0, 0, + 7, 7, 141, 135, 0, 0, 0, 0, 0, 0, 142, 61, 19, 19, 19, 71, + 4, 114, 4, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 143, 7, 7, 7, 7, 7, 144, 19, 143, 145, 4, 114, 0, 123, 135, 0, + 146, 7, 7, 7, 64, 147, 4, 52, 7, 7, 7, 7, 50, 19, 135, 0, + 7, 7, 7, 7, 144, 19, 19, 0, 4, 148, 4, 52, 7, 7, 7, 139, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 19, 19, 150, 151, 0, + 7, 7, 7, 7, 7, 7, 7, 7, 19, 19, 19, 19, 61, 0, 0, 60, + 7, 7, 139, 139, 7, 7, 7, 7, 139, 139, 7, 152, 7, 7, 7, 139, + 7, 7, 7, 7, 7, 7, 20, 153, 154, 17, 155, 145, 7, 17, 154, 17, + 0, 156, 0, 157, 158, 159, 0, 160, 161, 0, 162, 0, 163, 164, 28, 165, + 0, 0, 7, 17, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 140, 0, + 166, 107, 108, 167, 18, 168, 7, 169, 170, 171, 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, 172, 7, 7, 7, 7, 7, 7, 75, 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, 173, 174, 0, + 7, 7, 7, 7, 25, 129, 7, 7, 7, 7, 7, 7, 7, 165, 0, 73, + 7, 7, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 19, 19, 19, 19, + 0, 0, 0, 0, 0, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 129, 0, 0, 0, 0, 127, 175, 93, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 176, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 178, + 170, 7, 7, 7, 7, 139, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 14, 0, 0, 7, 7, 7, 9, 0, 0, 0, 0, 0, 0, 177, 177, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, 177, 177, 177, 177, 179, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 0, 0, 0, 0, 0, + 7, 17, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 139, + 7, 17, 7, 7, 4, 180, 0, 0, 7, 7, 7, 7, 7, 141, 149, 181, + 7, 7, 7, 73, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 117, 0, + 0, 0, 165, 7, 107, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 182, 145, 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 183, 184, 7, 7, 39, 0, 0, 0, 7, 7, 7, 7, 7, 7, 145, 0, + 27, 7, 7, 7, 7, 7, 144, 19, 121, 0, 4, 114, 19, 19, 27, 185, + 4, 52, 7, 7, 50, 116, 7, 7, 141, 19, 135, 0, 7, 7, 7, 17, + 62, 7, 7, 7, 7, 7, 39, 19, 140, 165, 4, 114, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 64, 61, 0, 184, 186, 4, 114, 0, 0, 0, 187, + 0, 0, 0, 0, 0, 0, 125, 188, 81, 0, 0, 0, 7, 39, 189, 0, + 190, 190, 190, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 39, 191, 4, 114, + 7, 7, 7, 7, 145, 0, 7, 7, 14, 192, 7, 7, 7, 7, 7, 145, + 14, 0, 192, 193, 33, 194, 195, 196, 197, 33, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 75, 0, 0, 0, 192, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 139, 0, 0, 7, 7, 7, 7, 7, 7, + 7, 7, 107, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 7, 145, + 19, 19, 198, 0, 61, 0, 199, 0, 0, 200, 201, 0, 0, 0, 20, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 202, + 203, 3, 0, 204, 6, 7, 7, 8, 6, 7, 7, 9, 205, 177, 177, 177, + 177, 177, 177, 206, 7, 7, 7, 14, 107, 107, 107, 207, 0, 0, 0, 208, + 7, 98, 7, 7, 14, 7, 7, 209, 7, 139, 7, 139, 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, 136, + 7, 7, 7, 17, 7, 7, 7, 7, 7, 7, 87, 0, 0, 0, 0, 0, + 7, 7, 7, 14, 0, 0, 7, 7, 7, 9, 0, 0, 0, 0, 0, 0, + 7, 7, 7, 139, 7, 7, 7, 7, 145, 7, 167, 0, 0, 0, 0, 0, + 7, 7, 7, 139, 4, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 139, 59, 7, 7, 7, 7, 25, 210, 7, 7, 139, 0, 0, 0, 0, 0, + 7, 7, 139, 0, 7, 7, 7, 75, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 7, 7, 172, 0, 0, 0, 0, 0, 0, 0, 0, + 211, 60, 98, 6, 7, 7, 145, 79, 0, 0, 0, 0, 7, 7, 7, 17, + 7, 7, 7, 7, 7, 7, 139, 0, 7, 7, 139, 0, 7, 7, 9, 0, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 87, 0, 0, 0, 0, 0, 0, + 146, 7, 7, 7, 7, 7, 7, 19, 61, 0, 0, 0, 83, 4, 0, 0, + 146, 7, 7, 7, 7, 7, 19, 212, 0, 0, 7, 7, 7, 87, 4, 114, + 146, 7, 7, 7, 141, 19, 213, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 146, 7, 7, 7, 7, 7, 39, 19, 214, 0, 4, 114, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 39, 19, 0, 4, 114, 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, 7, 7, 7, 7, 9, 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, 87, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 7, 7, 7, 17, 0, 64, 19, 19, 19, 19, 61, + 0, 73, 146, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142, 216, 217, 218, + 219, 135, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 221, 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, 222, 223, 7, 224, 98, 7, 7, 7, 7, 7, 7, 7, + 25, 225, 20, 20, 7, 7, 7, 226, 153, 107, 59, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 139, 7, 7, 7, 59, 7, 7, 130, 7, 7, 7, 130, + 7, 7, 20, 7, 7, 7, 20, 7, 7, 14, 7, 7, 7, 14, 7, 7, + 7, 59, 7, 7, 7, 59, 7, 7, 130, 227, 4, 4, 4, 4, 4, 4, + 98, 7, 7, 7, 228, 6, 130, 229, 166, 230, 228, 152, 228, 130, 130, 82, + 7, 24, 7, 145, 231, 24, 7, 145, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 233, 233, 233, + 234, 0, 0, 0, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, + 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, 38, 41, 21, + 42, 43, 44, 9, 9, 45, 21, 46, 21, 47, 48, 27, 49, 50, 0, 51, + 52, 9, 40, 8, 9, 53, 54, 0, 49, 9, 21, 16, 55, 0, 56, 21, + 21, 57, 57, 58, 57, 0, 22, 9, 0, 21, 21, 40, 21, 9, 53, 59, + 57, 21, 53, 60, 30, 8, 9, 50, 50, 9, 20, 17, 16, 59, 21, 61, + 61, 62, 0, 63, 0, 25, 16, 0, 10, 64, 22, 65, 16, 48, 40, 63, + 61, 58, 66, 0, 8, 20, 0, 60, 27, 67, 22, 8, 31, 58, 19, 0, + 0, 68, 69, 8, 10, 17, 22, 16, 65, 22, 64, 19, 16, 68, 40, 68, + 48, 58, 19, 63, 9, 8, 16, 45, 21, 48, 0, 32, 68, 8, 0, 13, + 65, 0, 10, 45, 48, 62, 17, 9, 9, 28, 70, 63, 21, 71, 68, 0, + 66, 21, 40, 0, 72, 0, 31, 73, 21, 58, 58, 0, 0, 74, 66, 68, + 9, 57, 21, 73, 0, 70, 63, 21, 58, 68, 48, 61, 30, 73, 68, 21, + 75, 58, 0, 28, 10, 9, 10, 30, 53, 73, 53, 0, 76, 0, 21, 0, + 0, 66, 63, 77, 78, 0, 9, 16, 73, 0, 9, 41, 0, 30, 21, 44, + 9, 21, 9, 0, 79, 9, 21, 27, 72, 8, 40, 21, 44, 52, 53, 80, + 81, 81, 9, 20, 17, 22, 9, 17, 0, 82, 83, 0, 0, 84, 85, 86, + 0, 11, 87, 88, 0, 87, 37, 89, 37, 37, 0, 64, 13, 64, 8, 16, + 22, 25, 16, 9, 0, 8, 16, 13, 0, 17, 64, 41, 27, 0, 90, 91, + 92, 93, 94, 94, 95, 94, 94, 95, 49, 0, 21, 96, 50, 10, 97, 97, + 41, 9, 64, 0, 9, 58, 63, 0, 73, 68, 17, 98, 8, 10, 40, 58, + 64, 9, 0, 99, 100, 33, 33, 34, 33, 101, 102, 100, 103, 88, 11, 87, + 0, 104, 5, 105, 9, 106, 0, 107, 108, 0, 0, 109, 94, 110, 17, 19, + 111, 0, 10, 25, 19, 50, 57, 32, 40, 14, 21, 112, 44, 19, 93, 0, + 58, 30, 113, 37, 114, 21, 40, 30, 68, 58, 68, 73, 13, 65, 8, 22, + 25, 8, 10, 8, 25, 10, 9, 60, 65, 50, 81, 0, 81, 8, 8, 8, + 0, 115, 116, 116, 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, 0, + 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, 0, 0, 0, 13, 13, 0, 0, + 7, 7, 7, 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, 7, 11, 7, 7, + 0, 0, 15, 15, 7, 0, 0, 7, 7, 7, 11, 0, 0, 0, 0, 7, + 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, 7, 7, 7, 9, 9, 9, 9, 7, 0, 0, 8, 8, + 8, 8, 8, 8, +}; + +/* Word_Break: 3946 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, 2, 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, + 10, 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, 1, 1, 1, 1, 1, 1, 1, 1, 47, 1, 1, 1, 1, 1, + 48, 49, 1, 1, 1, 1, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 51, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 52, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 42, 55, 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, 24, + 25, 2, 2, 26, 27, 28, 29, 2, 30, 2, 2, 31, 32, 33, 29, 2, + 34, 2, 2, 35, 36, 16, 2, 37, 34, 2, 2, 35, 38, 2, 29, 2, + 30, 2, 2, 39, 32, 40, 29, 2, 41, 2, 2, 42, 43, 33, 2, 2, + 44, 2, 2, 45, 46, 47, 29, 2, 48, 2, 2, 49, 50, 47, 29, 2, + 48, 2, 2, 42, 51, 33, 29, 2, 48, 2, 2, 2, 52, 53, 2, 48, + 2, 2, 2, 54, 55, 2, 2, 2, 2, 2, 2, 56, 57, 2, 2, 2, + 2, 58, 2, 59, 2, 2, 2, 60, 61, 62, 5, 63, 64, 2, 2, 2, + 2, 2, 65, 66, 2, 67, 13, 68, 69, 70, 2, 2, 2, 2, 2, 2, + 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 73, 74, 74, 74, 74, 74, + 2, 2, 2, 2, 2, 65, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 75, 2, 75, 2, 29, 2, 29, 2, 2, 2, 76, 77, 78, 2, 2, + 79, 2, 2, 2, 2, 2, 2, 2, 2, 2, 80, 2, 2, 2, 2, 2, + 2, 2, 81, 82, 2, 2, 2, 2, 2, 2, 2, 83, 2, 2, 2, 2, + 2, 84, 2, 2, 2, 85, 86, 87, 2, 2, 2, 2, 2, 2, 2, 2, + 88, 2, 2, 89, 90, 2, 12, 19, 91, 2, 92, 2, 2, 2, 93, 94, + 2, 2, 95, 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 98, 99, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 100, 101, + 102, 2, 103, 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, 104, 105, + 2, 2, 2, 2, 2, 2, 2, 104, 2, 2, 2, 2, 2, 2, 5, 5, + 2, 2, 106, 2, 2, 2, 2, 2, 2, 107, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 104, 108, 2, 104, 2, 2, 2, 2, 2, 105, + 109, 2, 110, 2, 2, 2, 2, 2, 111, 2, 2, 112, 113, 2, 5, 105, + 2, 2, 114, 2, 115, 94, 71, 116, 25, 2, 2, 117, 118, 2, 2, 2, + 2, 2, 119, 120, 121, 2, 2, 2, 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, 72, 132, 74, 74, 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, 100, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 2, 2, 2, 2, 2, 135, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, + 136, 2, 2, 137, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 138, 2, 2, 139, 100, 2, 2, 2, 91, 2, 2, 140, 2, 2, 2, 2, + 141, 2, 142, 143, 2, 2, 2, 2, 91, 2, 2, 144, 118, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 145, 146, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 147, 148, 149, 104, 141, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 150, 151, 152, 2, 153, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 75, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 154, 155, + 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, 12, + 3, 3, 7, 6, 14, 3, 3, 3, 3, 15, 6, 16, 6, 17, 18, 8, + 19, 3, 3, 3, 6, 6, 13, 3, 3, 15, 6, 6, 6, 3, 3, 3, + 3, 15, 10, 6, 6, 9, 9, 8, 3, 3, 9, 3, 3, 6, 6, 6, + 6, 6, 6, 13, 20, 3, 3, 3, 3, 3, 21, 22, 23, 6, 24, 25, + 9, 6, 3, 3, 15, 3, 3, 3, 26, 3, 3, 3, 3, 3, 3, 27, + 23, 28, 29, 30, 3, 7, 3, 3, 31, 3, 3, 3, 3, 3, 3, 22, + 32, 7, 17, 8, 8, 19, 3, 3, 23, 10, 33, 30, 3, 3, 3, 18, + 3, 15, 3, 3, 34, 3, 3, 3, 3, 3, 3, 21, 35, 36, 37, 30, + 38, 3, 3, 3, 3, 3, 3, 15, 24, 39, 18, 8, 3, 11, 3, 3, + 36, 3, 3, 3, 3, 3, 3, 40, 41, 42, 37, 8, 23, 22, 37, 30, + 3, 3, 34, 7, 43, 44, 45, 46, 47, 6, 13, 3, 3, 7, 6, 13, + 47, 6, 10, 14, 3, 3, 6, 8, 3, 3, 8, 3, 3, 48, 19, 36, + 9, 6, 6, 20, 6, 18, 3, 9, 6, 6, 9, 6, 6, 6, 6, 14, + 3, 34, 3, 3, 3, 3, 3, 9, 49, 6, 31, 32, 3, 36, 8, 15, + 9, 14, 3, 3, 34, 32, 3, 19, 3, 3, 3, 19, 50, 50, 50, 50, + 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 15, 14, 3, 3, + 3, 53, 6, 54, 45, 41, 23, 6, 6, 3, 3, 19, 3, 3, 7, 55, + 3, 3, 19, 3, 20, 46, 24, 3, 41, 45, 23, 3, 3, 38, 56, 3, + 3, 7, 57, 3, 3, 58, 6, 13, 44, 9, 6, 24, 46, 6, 6, 17, + 6, 59, 3, 3, 3, 49, 20, 24, 41, 59, 3, 3, 60, 3, 3, 3, + 61, 54, 53, 62, 3, 21, 54, 63, 54, 3, 3, 3, 3, 45, 45, 6, + 6, 43, 3, 3, 13, 6, 6, 6, 49, 6, 14, 19, 36, 14, 3, 3, + 6, 13, 3, 3, 3, 3, 3, 6, 3, 3, 4, 64, 3, 3, 0, 65, + 3, 3, 3, 7, 8, 3, 3, 3, 3, 3, 15, 6, 3, 3, 11, 3, + 13, 6, 6, 8, 34, 34, 7, 3, 66, 67, 3, 3, 62, 3, 3, 3, + 3, 45, 45, 45, 45, 14, 3, 3, 3, 15, 6, 8, 3, 7, 6, 6, + 50, 50, 50, 68, 7, 43, 54, 24, 59, 3, 3, 3, 3, 3, 9, 20, + 67, 32, 3, 3, 7, 3, 3, 69, 18, 17, 14, 15, 3, 3, 66, 54, + 3, 70, 3, 3, 66, 25, 35, 30, 71, 72, 72, 72, 72, 72, 72, 71, + 72, 72, 72, 72, 72, 72, 71, 72, 72, 71, 72, 72, 72, 3, 3, 3, + 51, 73, 74, 52, 52, 52, 52, 3, 3, 3, 3, 34, 0, 0, 0, 3, + 9, 11, 3, 6, 3, 3, 13, 7, 75, 3, 3, 3, 3, 3, 6, 6, + 46, 20, 32, 5, 13, 3, 3, 3, 3, 7, 6, 23, 6, 14, 3, 3, + 66, 43, 6, 20, 3, 3, 7, 25, 6, 53, 3, 3, 38, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 76, 3, 77, 8, 61, 78, 0, 79, 6, + 13, 9, 6, 3, 3, 3, 15, 8, 3, 80, 81, 81, 81, 81, 81, 81, +}; + +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, 0, 0, 0, 4, 4, 4, 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, 0, 6, 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, + 0, 0, 6, 0, 4, 6, 6, 4, 0, 6, 4, 6, 6, 0, 0, 0, + 4, 4, 6, 0, 0, 6, 4, 4, 6, 6, 0, 0, 6, 4, 6, 4, + 4, 4, 3, 3, 3, 3, 3, 0, 0, 0, 0, 6, 6, 4, 4, 6, + 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, + 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: 2336 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, 9, 9, 15, 9, 9, 9, 9, 16, 9, 17, 18, 9, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19, 20, 9, 9, 9, 21, + 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, + 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, 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, 33, 33, 33, 63, 64, 65, 66, 67, 33, 33, 33, + 68, 69, 33, 33, 33, 33, 70, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 17, 17, 17, 71, 72, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 17, 17, 17, 17, 73, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 17, 17, 74, 33, 33, 33, 33, 75, + 76, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 77, 78, 33, 79, 80, 81, 82, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 83, 33, + 17, 17, 17, 17, 17, 17, 84, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 85, 86, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 17, 17, 86, 33, 33, 33, 33, 33, + 87, 88, 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, 62, 71, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 73, 83, 84, 85, 86, 83, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 55, 97, 98, 99, 55, 100, 101, 102, 103, 104, 105, 106, 55, + 41, 107, 108, 109, 110, 29, 111, 112, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 113, 41, 114, 115, 116, 41, 117, 41, 118, 119, 120, 41, 41, 121, + 94, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 122, 123, 41, 41, 124, + 125, 126, 127, 128, 41, 129, 130, 131, 132, 41, 41, 133, 41, 134, 41, 135, + 136, 137, 138, 139, 41, 140, 141, 55, 142, 41, 143, 144, 145, 146, 55, 55, + 147, 129, 148, 149, 150, 151, 41, 152, 41, 153, 154, 155, 55, 55, 156, 157, + 18, 18, 18, 18, 18, 18, 23, 158, 8, 8, 8, 8, 159, 8, 8, 8, + 160, 161, 162, 163, 161, 164, 165, 166, 167, 168, 169, 170, 171, 55, 172, 173, + 174, 175, 176, 30, 177, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 178, 179, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 180, 30, 181, + 55, 55, 182, 183, 55, 55, 184, 185, 55, 55, 55, 55, 186, 55, 187, 188, + 29, 189, 190, 191, 8, 8, 8, 192, 18, 193, 41, 194, 195, 196, 196, 23, + 197, 198, 55, 55, 55, 55, 55, 55, 199, 200, 94, 41, 201, 94, 41, 112, + 202, 203, 41, 41, 204, 205, 55, 206, 41, 41, 41, 41, 41, 135, 55, 55, + 41, 41, 41, 41, 41, 41, 207, 55, 41, 41, 41, 41, 207, 55, 206, 208, + 209, 210, 8, 211, 212, 41, 41, 213, 214, 215, 8, 216, 217, 218, 55, 219, + 220, 221, 41, 222, 223, 129, 224, 225, 50, 226, 227, 136, 58, 228, 229, 55, + 41, 230, 231, 232, 41, 233, 234, 235, 236, 237, 55, 55, 55, 55, 41, 238, + 41, 41, 41, 41, 41, 239, 240, 241, 41, 41, 41, 242, 41, 41, 243, 55, + 244, 245, 246, 41, 41, 247, 248, 41, 41, 249, 206, 41, 250, 41, 251, 252, + 253, 254, 255, 256, 41, 41, 41, 257, 258, 2, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 55, 41, 41, 41, 205, 55, 55, 41, 121, 55, 55, 55, 268, + 55, 55, 55, 55, 136, 41, 269, 55, 262, 206, 270, 55, 271, 41, 272, 55, + 29, 273, 274, 41, 271, 131, 55, 55, 275, 276, 135, 55, 55, 55, 55, 55, + 135, 243, 55, 55, 41, 277, 55, 55, 278, 279, 280, 136, 55, 55, 55, 55, + 41, 135, 135, 281, 55, 55, 55, 55, 41, 41, 282, 55, 55, 55, 55, 55, + 150, 283, 284, 79, 150, 285, 286, 287, 150, 288, 289, 55, 150, 228, 290, 55, + 55, 55, 55, 55, 41, 291, 131, 55, 41, 41, 41, 204, 55, 55, 55, 55, + 41, 41, 41, 292, 55, 55, 55, 55, 41, 204, 55, 55, 55, 55, 55, 55, + 41, 293, 55, 55, 55, 55, 55, 55, 41, 41, 294, 295, 296, 55, 55, 55, + 297, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 298, 299, 300, 55, 55, + 55, 55, 301, 55, 55, 55, 55, 55, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 302, 303, 315, 305, 316, 317, 318, 309, 319, 320, 321, + 322, 323, 324, 189, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 55, 55, + 41, 41, 41, 41, 41, 41, 195, 55, 41, 121, 41, 41, 41, 41, 41, 41, + 271, 55, 55, 55, 55, 55, 55, 55, 335, 336, 336, 336, 55, 55, 55, 55, + 23, 23, 23, 23, 23, 23, 23, 337, +}; + +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, 39, 0, 47, 22, 48, 32, 11, 11, 11, + 49, 11, 11, 15, 15, 15, 15, 15, 15, 15, 15, 50, 33, 34, 25, 25, + 25, 25, 25, 25, 15, 51, 30, 32, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 15, 15, 15, 15, 52, 44, 53, 25, 25, 25, 25, 25, + 28, 26, 26, 29, 25, 25, 25, 25, 25, 25, 0, 0, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 22, 54, 55, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 56, 0, 57, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 58, + 59, 58, 0, 0, 36, 36, 36, 36, 36, 36, 60, 0, 36, 0, 0, 0, + 61, 62, 0, 63, 44, 44, 64, 65, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 66, 44, 44, 44, 44, 44, 7, 7, 67, 68, 69, 36, 36, 36, + 36, 36, 36, 36, 36, 70, 44, 71, 44, 72, 73, 74, 7, 7, 75, 76, + 77, 0, 0, 78, 79, 36, 36, 36, 36, 36, 36, 36, 44, 44, 44, 44, + 44, 44, 64, 80, 36, 36, 36, 36, 36, 81, 44, 44, 82, 0, 0, 0, + 7, 7, 75, 36, 36, 36, 36, 36, 36, 36, 66, 44, 44, 41, 83, 0, + 36, 36, 36, 36, 36, 81, 84, 44, 44, 85, 85, 86, 0, 0, 0, 0, + 36, 36, 36, 36, 36, 36, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 87, 36, 36, 88, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 64, + 44, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 81, 89, + 44, 44, 44, 44, 85, 44, 36, 36, 81, 90, 7, 7, 80, 36, 80, 36, + 57, 80, 36, 76, 76, 36, 36, 36, 36, 36, 87, 36, 43, 40, 41, 89, + 44, 91, 91, 92, 0, 93, 0, 94, 81, 95, 7, 7, 41, 0, 0, 0, + 57, 80, 60, 96, 76, 36, 36, 36, 36, 36, 87, 36, 87, 97, 41, 73, + 64, 93, 91, 86, 98, 0, 80, 43, 0, 95, 7, 7, 74, 99, 0, 0, + 57, 80, 36, 94, 94, 36, 36, 36, 36, 36, 87, 36, 87, 80, 41, 89, + 44, 58, 58, 86, 88, 0, 0, 0, 81, 95, 7, 7, 0, 0, 0, 0, + 44, 91, 91, 86, 0, 100, 0, 94, 81, 95, 7, 7, 54, 0, 0, 0, + 101, 80, 60, 40, 87, 41, 97, 87, 96, 88, 60, 40, 36, 36, 41, 100, + 64, 100, 73, 86, 88, 93, 0, 0, 0, 95, 7, 7, 0, 0, 0, 0, + 57, 80, 36, 87, 87, 36, 36, 36, 36, 36, 87, 36, 36, 80, 41, 102, + 44, 73, 73, 86, 0, 59, 41, 0, 100, 80, 36, 87, 87, 36, 36, 36, + 36, 36, 87, 36, 36, 80, 41, 89, 44, 73, 73, 86, 0, 59, 0, 103, + 81, 95, 7, 7, 97, 0, 0, 0, 36, 36, 36, 36, 36, 36, 60, 102, + 44, 73, 73, 92, 0, 93, 0, 0, 81, 95, 7, 7, 0, 0, 40, 36, + 100, 80, 36, 36, 36, 60, 40, 36, 36, 36, 36, 36, 94, 36, 36, 54, + 36, 60, 104, 93, 44, 105, 44, 44, 0, 0, 0, 0, 100, 0, 0, 0, + 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 79, 44, 64, 0, + 36, 66, 44, 64, 7, 7, 106, 0, 97, 76, 43, 54, 0, 36, 80, 36, + 80, 107, 40, 80, 79, 44, 58, 82, 36, 43, 44, 86, 7, 7, 106, 36, + 88, 0, 0, 0, 0, 0, 86, 0, 7, 7, 106, 0, 0, 108, 109, 110, + 36, 36, 80, 36, 36, 36, 36, 36, 36, 36, 36, 88, 57, 44, 44, 44, + 44, 73, 36, 85, 44, 44, 57, 44, 44, 44, 44, 44, 44, 44, 44, 111, + 0, 104, 0, 0, 0, 0, 0, 0, 36, 36, 66, 44, 44, 44, 44, 112, + 7, 7, 113, 0, 36, 81, 74, 81, 89, 72, 44, 74, 85, 69, 36, 36, + 81, 44, 44, 84, 7, 7, 114, 86, 11, 49, 0, 115, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 60, 36, 36, 36, 87, 41, 36, 60, 87, 41, + 36, 36, 87, 41, 36, 36, 36, 36, 36, 36, 36, 36, 87, 41, 36, 60, + 87, 41, 36, 36, 36, 60, 36, 36, 36, 36, 36, 36, 87, 41, 36, 36, + 36, 36, 36, 36, 36, 36, 60, 57, 116, 9, 117, 0, 0, 0, 0, 0, + 36, 36, 36, 36, 0, 0, 0, 0, 36, 36, 36, 36, 36, 88, 0, 0, + 36, 36, 36, 118, 36, 36, 36, 36, 119, 36, 36, 36, 36, 36, 120, 121, + 36, 36, 60, 40, 88, 0, 0, 0, 36, 36, 36, 87, 81, 111, 0, 0, + 36, 36, 36, 36, 81, 122, 0, 0, 36, 36, 36, 36, 81, 0, 0, 0, + 36, 36, 36, 87, 123, 0, 0, 0, 36, 36, 36, 36, 36, 44, 44, 44, + 44, 44, 44, 44, 44, 96, 0, 99, 7, 7, 106, 0, 0, 0, 0, 0, + 124, 0, 125, 126, 7, 7, 106, 0, 36, 36, 36, 36, 36, 36, 0, 0, + 36, 36, 127, 0, 36, 36, 36, 36, 36, 36, 36, 36, 36, 41, 0, 0, + 36, 36, 36, 36, 36, 36, 36, 88, 44, 44, 44, 0, 44, 44, 44, 0, + 0, 90, 7, 7, 36, 36, 36, 36, 36, 36, 36, 41, 36, 88, 0, 0, + 36, 36, 36, 0, 44, 44, 44, 44, 69, 36, 86, 0, 7, 7, 106, 0, + 36, 36, 36, 36, 36, 66, 44, 0, 36, 36, 36, 36, 36, 85, 44, 64, + 44, 44, 44, 44, 44, 44, 44, 91, 7, 7, 106, 0, 7, 7, 106, 0, + 0, 96, 128, 0, 0, 0, 0, 0, 44, 69, 36, 36, 36, 36, 36, 36, + 44, 69, 36, 0, 7, 7, 113, 129, 0, 0, 93, 44, 44, 0, 0, 0, + 112, 36, 36, 36, 36, 36, 36, 36, 85, 44, 44, 74, 7, 7, 75, 36, + 36, 81, 44, 44, 44, 0, 0, 0, 36, 44, 44, 44, 44, 44, 9, 117, + 7, 7, 106, 80, 7, 7, 75, 36, 36, 36, 36, 36, 36, 36, 36, 130, + 0, 0, 0, 0, 64, 44, 44, 44, 44, 44, 69, 79, 81, 131, 0, 0, + 44, 64, 0, 0, 0, 0, 0, 44, 25, 25, 25, 25, 25, 34, 15, 27, + 15, 15, 11, 11, 15, 39, 11, 132, 15, 15, 11, 11, 15, 15, 11, 11, + 15, 39, 11, 132, 15, 15, 133, 133, 15, 15, 11, 11, 15, 15, 15, 39, + 15, 15, 11, 11, 15, 134, 11, 135, 46, 134, 11, 136, 15, 46, 11, 0, + 15, 15, 11, 136, 46, 134, 11, 136, 137, 137, 138, 139, 140, 141, 142, 142, + 0, 143, 144, 145, 0, 0, 146, 147, 0, 148, 147, 0, 0, 0, 0, 149, + 61, 150, 61, 61, 21, 0, 0, 151, 0, 0, 0, 146, 15, 15, 15, 42, + 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 111, 0, 0, 0, + 47, 152, 153, 154, 23, 115, 10, 132, 0, 155, 48, 156, 11, 38, 157, 33, + 0, 158, 39, 159, 0, 0, 0, 0, 160, 38, 88, 0, 0, 0, 0, 0, + 0, 0, 142, 0, 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 161, 11, 11, 15, 15, 39, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 162, 0, 0, 142, 142, 142, 5, 0, 0, + 0, 146, 0, 0, 0, 0, 0, 0, 0, 163, 142, 142, 0, 0, 0, 0, + 4, 142, 142, 142, 142, 142, 121, 0, 0, 0, 0, 0, 0, 0, 142, 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, 152, 165, 53, 0, 0, 0, 15, 166, 0, 21, 36, 36, 36, 36, + 36, 36, 0, 96, 0, 0, 0, 93, 36, 36, 36, 36, 36, 60, 0, 0, + 36, 60, 36, 60, 36, 60, 36, 60, 142, 142, 142, 5, 0, 0, 0, 5, + 142, 142, 5, 167, 0, 0, 0, 0, 168, 80, 142, 142, 5, 142, 142, 169, + 80, 36, 81, 44, 80, 41, 36, 88, 36, 36, 36, 36, 36, 60, 59, 80, + 0, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 41, 80, 36, 36, 36, + 36, 36, 36, 60, 0, 0, 0, 0, 36, 36, 36, 36, 36, 36, 60, 0, + 0, 0, 0, 0, 36, 36, 36, 36, 36, 36, 36, 88, 0, 0, 0, 0, + 36, 36, 36, 36, 36, 36, 36, 170, 36, 36, 36, 171, 36, 36, 36, 36, + 7, 7, 75, 0, 0, 0, 0, 0, 25, 25, 25, 172, 64, 44, 44, 173, + 25, 25, 25, 25, 25, 25, 0, 93, 36, 36, 36, 36, 174, 9, 0, 0, + 0, 0, 0, 0, 0, 96, 36, 36, 175, 25, 25, 25, 27, 25, 25, 25, + 25, 25, 25, 25, 15, 15, 26, 30, 25, 25, 176, 177, 25, 0, 0, 0, + 25, 25, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 36, + 180, 180, 66, 36, 36, 36, 36, 36, 66, 44, 0, 0, 0, 0, 0, 0, + 36, 36, 36, 36, 36, 129, 0, 0, 74, 36, 36, 36, 36, 36, 36, 36, + 44, 111, 0, 129, 7, 7, 106, 0, 44, 44, 44, 44, 74, 36, 96, 0, + 36, 81, 44, 174, 36, 36, 36, 36, 36, 66, 44, 44, 44, 0, 0, 0, + 36, 36, 36, 36, 66, 44, 44, 44, 111, 0, 147, 96, 7, 7, 106, 0, + 36, 36, 85, 44, 44, 64, 0, 0, 66, 36, 36, 86, 7, 7, 106, 181, + 36, 36, 36, 36, 36, 60, 182, 0, 36, 36, 36, 36, 89, 72, 69, 81, + 127, 0, 0, 0, 0, 0, 96, 41, 36, 36, 66, 44, 183, 184, 0, 0, + 80, 60, 80, 60, 80, 60, 0, 0, 36, 60, 36, 60, 0, 0, 0, 0, + 66, 44, 185, 86, 7, 7, 106, 0, 36, 0, 0, 0, 36, 36, 36, 36, + 36, 60, 96, 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, 186, 15, 0, 187, 36, 36, 87, 36, 36, 60, 36, 43, + 94, 87, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 41, 0, 0, 0, + 0, 0, 0, 0, 96, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 188, + 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, 189, 4, 121, 0, + 44, 64, 0, 0, 190, 169, 142, 142, 142, 191, 121, 0, 6, 192, 193, 162, + 140, 0, 0, 0, 36, 87, 36, 36, 36, 36, 36, 36, 36, 36, 36, 194, + 56, 0, 5, 6, 0, 0, 195, 9, 14, 15, 15, 15, 15, 15, 16, 196, + 197, 198, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 81, + 36, 36, 36, 36, 36, 36, 36, 60, 40, 36, 40, 36, 40, 36, 40, 88, + 0, 0, 0, 0, 0, 0, 199, 0, 36, 36, 36, 80, 36, 36, 36, 36, + 36, 60, 36, 36, 36, 36, 60, 94, 36, 36, 36, 41, 36, 36, 36, 41, + 0, 0, 0, 0, 0, 0, 0, 98, 36, 36, 36, 36, 88, 0, 0, 0, + 36, 36, 60, 0, 0, 0, 0, 0, 36, 36, 36, 36, 36, 36, 36, 41, + 36, 0, 36, 36, 80, 41, 0, 0, 11, 11, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 36, 36, 36, 36, 36, 41, 87, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 94, 88, 76, 36, 36, 36, 36, 36, 36, 0, 40, + 85, 59, 0, 44, 36, 80, 80, 36, 36, 36, 36, 36, 36, 0, 64, 93, + 0, 0, 0, 0, 0, 129, 0, 0, 36, 36, 36, 36, 60, 0, 0, 0, + 36, 36, 88, 0, 0, 0, 0, 0, 36, 36, 36, 36, 36, 36, 44, 44, + 44, 185, 117, 0, 0, 0, 0, 0, 36, 36, 36, 36, 44, 44, 64, 200, + 147, 0, 0, 0, 36, 36, 36, 36, 36, 36, 88, 0, 7, 7, 106, 0, + 36, 66, 44, 44, 44, 201, 7, 7, 181, 0, 0, 0, 0, 0, 0, 0, + 69, 202, 0, 0, 7, 7, 106, 0, 36, 36, 66, 44, 44, 44, 0, 0, + 60, 0, 0, 0, 0, 0, 0, 0, 36, 36, 36, 36, 36, 36, 88, 0, + 36, 88, 0, 0, 85, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 64, + 0, 0, 0, 93, 112, 36, 36, 36, 41, 0, 0, 0, 0, 0, 0, 0, + 0, 57, 86, 57, 203, 61, 204, 44, 64, 57, 44, 0, 0, 0, 0, 0, + 0, 0, 100, 86, 0, 0, 0, 0, 100, 111, 0, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 11, 154, 15, 15, 15, 15, 15, 15, 11, 11, 11, + 11, 11, 11, 154, 15, 134, 15, 15, 15, 15, 11, 11, 11, 11, 11, 11, + 154, 15, 15, 15, 15, 15, 15, 48, 47, 205, 10, 48, 11, 154, 166, 14, + 15, 14, 15, 15, 11, 11, 11, 11, 11, 11, 154, 15, 15, 15, 15, 15, + 15, 49, 22, 10, 11, 48, 11, 206, 15, 15, 15, 15, 15, 15, 49, 22, + 11, 155, 161, 11, 206, 15, 15, 15, 15, 15, 15, 11, 11, 11, 11, 11, + 11, 154, 15, 15, 15, 15, 15, 15, 11, 11, 11, 154, 15, 15, 15, 15, + 154, 15, 15, 15, 15, 15, 15, 11, 11, 11, 11, 11, 11, 154, 15, 15, + 15, 15, 15, 15, 11, 11, 11, 11, 15, 39, 11, 11, 11, 11, 11, 11, + 206, 15, 15, 15, 15, 15, 24, 15, 33, 11, 11, 11, 11, 11, 22, 15, + 15, 15, 15, 15, 15, 134, 15, 11, 11, 11, 11, 11, 11, 206, 15, 15, + 15, 15, 15, 24, 15, 33, 11, 11, 15, 15, 134, 15, 11, 11, 11, 11, + 11, 11, 206, 15, 15, 15, 15, 15, 24, 15, 27, 95, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 36, 80, 36, 36, 36, 36, 36, 36, + 97, 76, 80, 36, 60, 36, 107, 0, 103, 96, 107, 80, 97, 76, 107, 107, + 97, 76, 60, 36, 60, 36, 80, 43, 36, 36, 94, 36, 36, 36, 36, 0, + 80, 80, 94, 36, 36, 36, 36, 0, 20, 0, 0, 0, 0, 0, 0, 0, + 61, 61, 61, 61, 61, 61, 61, 61, 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, 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, 12, 14, 12, 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, 0, 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, 9, 9, + 9, 0, 0, 0, 3, 9, 3, 3, 12, 12, 10, 10, 3, 0, 0, 3, + 3, 3, 9, 0, 0, 0, 0, 3, 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, 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, + 8, 8, 0, 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, 13, 13, 13, 0, 0, 0, 13, 13, + 8, 7, 7, 8, 7, 8, 7, 3, 7, 7, 0, 7, 0, 0, 12, 9, + 6, 14, 12, 0, 0, 13, 13, 13, 9, 9, 0, 12, 9, 0, 12, 12, + 8, 7, 9, 3, 3, 3, 0, 9, 3, 3, 0, 12, 0, 0, 8, 7, + 9, 0, 0, 8, 7, 8, 7, 0, 8, 7, 8, 0, 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, 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, 3, 3, 5, + 5, 5, 5, 3, 0, 8, 8, 0, 8, 0, 7, 7, +}; + +/* Sentence_Break: 5596 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 13, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 24, 7, 25, 26, 13, 13, 13, 13, 13, 13, 13, 27, + 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, 31, 31, 31, + 58, 59, 60, 61, 62, 31, 31, 31, 63, 64, 31, 31, 31, 31, 65, 31, + 1, 1, 1, 66, 67, 31, 31, 31, 1, 1, 1, 1, 68, 31, 31, 31, + 1, 1, 69, 31, 31, 31, 31, 70, 71, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 72, 73, 74, 75, 31, 31, 31, 31, 31, 31, 76, 31, + 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, 1, 1, 1, 1, 78, + 79, 31, 31, 31, 31, 31, 31, 31, 1, 1, 79, 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, 38, 47, 50, 51, 52, 53, 54, 0, + 55, 56, 57, 49, 58, 56, 59, 60, 58, 61, 62, 63, 64, 65, 66, 67, + 15, 68, 69, 0, 70, 71, 72, 0, 73, 0, 74, 75, 76, 77, 0, 0, + 4, 78, 25, 79, 80, 4, 81, 82, 4, 4, 83, 4, 84, 85, 86, 4, + 87, 4, 88, 0, 89, 4, 4, 90, 15, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 91, 1, 4, 4, 92, 93, 94, 94, 95, 4, 96, 97, 0, + 0, 4, 4, 98, 4, 99, 4, 100, 77, 101, 25, 102, 4, 103, 104, 0, + 105, 4, 106, 107, 0, 108, 0, 0, 4, 109, 110, 0, 4, 111, 4, 112, + 4, 100, 113, 114, 0, 0, 0, 115, 4, 4, 4, 4, 4, 4, 0, 0, + 116, 4, 117, 114, 4, 118, 119, 120, 0, 0, 0, 121, 122, 0, 0, 0, + 123, 124, 125, 4, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 127, 4, 104, 4, 128, 106, 4, 4, 4, 4, 129, + 4, 81, 4, 130, 131, 132, 132, 4, 0, 133, 0, 0, 0, 0, 0, 0, + 134, 135, 15, 4, 136, 15, 4, 82, 137, 138, 4, 4, 139, 68, 0, 25, + 4, 4, 4, 4, 4, 100, 0, 0, 4, 4, 4, 4, 4, 4, 31, 0, + 4, 4, 4, 4, 31, 0, 25, 114, 140, 141, 4, 142, 143, 4, 4, 89, + 144, 145, 4, 4, 146, 147, 0, 148, 149, 16, 4, 94, 4, 4, 49, 150, + 28, 99, 151, 77, 4, 152, 133, 0, 4, 131, 153, 154, 4, 106, 155, 156, + 157, 158, 0, 0, 0, 0, 4, 147, 4, 4, 4, 4, 4, 159, 160, 105, + 4, 4, 4, 161, 4, 4, 162, 0, 163, 164, 165, 4, 4, 27, 166, 4, + 4, 114, 25, 4, 167, 4, 16, 168, 0, 0, 0, 169, 4, 4, 4, 77, + 0, 1, 1, 170, 4, 106, 171, 0, 172, 173, 174, 0, 4, 4, 4, 68, + 0, 0, 4, 90, 0, 0, 0, 0, 0, 0, 0, 0, 77, 4, 175, 0, + 106, 25, 147, 0, 114, 4, 176, 0, 4, 4, 4, 4, 114, 0, 0, 0, + 177, 178, 100, 0, 0, 0, 0, 0, 100, 162, 0, 0, 4, 179, 0, 0, + 180, 94, 0, 77, 0, 0, 0, 0, 4, 100, 100, 151, 0, 0, 0, 0, + 4, 4, 126, 0, 0, 0, 0, 0, 4, 4, 181, 0, 145, 32, 25, 126, + 4, 151, 0, 0, 4, 4, 182, 0, 0, 0, 0, 0, 4, 100, 0, 0, + 4, 4, 4, 139, 0, 0, 0, 0, 4, 4, 4, 183, 0, 0, 0, 0, + 4, 139, 0, 0, 0, 0, 0, 0, 4, 32, 0, 0, 0, 0, 0, 0, + 4, 4, 184, 106, 166, 0, 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 186, 4, 187, 188, 189, 4, 190, 191, 192, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 193, 194, 82, 186, 186, 128, 128, 195, 195, 196, 0, + 189, 197, 198, 199, 200, 201, 0, 0, 4, 4, 4, 4, 4, 4, 131, 0, + 4, 90, 4, 4, 4, 4, 4, 4, 114, 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, 60, 64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 191, 255, + 3, 252, 255, 255, 255, 0, 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, 253, 31, 0, 0, 240, 3, 255, 127, 255, 255, 255, 239, + 255, 223, 225, 255, 15, 0, 254, 254, 238, 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, 0, 159, 25, 192, 176, 15, 0, 2, 0, + 236, 199, 61, 214, 24, 199, 255, 195, 199, 29, 129, 0, 238, 223, 253, 255, + 255, 253, 239, 227, 223, 29, 96, 3, 236, 223, 253, 255, 223, 29, 96, 64, + 15, 0, 6, 0, 255, 255, 255, 231, 223, 93, 128, 0, 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, 31, 0, 255, 159, 255, 255, + 255, 199, 1, 0, 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, 15, 255, 1, 255, 63, 31, 0, 255, 15, 255, 255, + 255, 3, 0, 0, 255, 255, 255, 15, 255, 255, 255, 127, 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, + 255, 255, 63, 63, 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, 255, 255, 255, 128, + 0, 0, 128, 255, 252, 255, 255, 255, 255, 121, 15, 0, 255, 7, 0, 0, + 0, 0, 0, 255, 187, 247, 255, 255, 0, 0, 252, 8, 255, 255, 7, 0, + 255, 255, 247, 255, 255, 63, 0, 0, 255, 255, 127, 4, 5, 0, 0, 56, + 255, 255, 60, 0, 126, 126, 126, 0, 127, 127, 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, 63, 253, 255, 255, 255, 255, 191, 145, 255, 255, 255, 192, + 111, 240, 239, 254, 63, 0, 0, 0, 30, 0, 0, 0, 7, 0, 0, 0, + 31, 0, 255, 255, 3, 0, 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, 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, +}; + +/* Alphabetic: 1817 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, + 6, 3, 7, 3, 3, 3, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10, 3, 11, + 3, 3, 12, 3, 3, 3, 3, 3, 3, 3, 13, 14, 3, 3, 3, 3, +}; + +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, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, + 5, 5, 5, 5, 32, 5, 5, 5, 33, 34, 35, 36, 34, 37, 38, 39, + 0, 0, 0, 40, 41, 0, 0, 0, 42, 43, 44, 26, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 26, 46, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 47, 48, 5, 5, 5, 49, 15, 50, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 51, 52, 0, 0, 0, 0, 53, 5, 54, 55, 56, 0, 57, + 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 59, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 61, 62, 63, 31, 64, 65, 66, 67, 68, 69, 70, 71, 72, 61, 62, 73, + 31, 64, 74, 60, 67, 75, 76, 77, 78, 74, 79, 26, 80, 67, 81, 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, 0, 0, 0, 254, 255, 255, 255, 255, 0, 0, 0, + 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, 0, 168, 170, 171, 170, 170, 170, 255, 149, 170, 80, 10, 0, + 170, 2, 0, 0, 0, 0, 0, 7, 127, 0, 248, 0, 0, 255, 255, 255, + 255, 255, 0, 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: 697 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] << 3; + f = code >> 9; + code ^= f << 9; + pos = (RE_UINT32)re_lowercase_stage_3[pos + f] << 4; + 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, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5, + 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +}; + +static RE_UINT8 re_uppercase_stage_3[] = { + 0, 1, 2, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, + 6, 3, 7, 3, 3, 3, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10, + 3, 3, 11, 3, 3, 3, 3, 3, 3, 3, 12, 13, 3, 3, 3, 3, +}; + +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, 0, 0, 0, + 0, 0, 0, 0, 0, 18, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 25, 3, 3, 3, 26, 27, 28, 29, 0, 30, 31, 32, + 0, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 19, 36, 0, 0, 0, + 0, 0, 0, 0, 0, 37, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 18, 38, 0, 39, 3, 3, 3, 40, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 41, 42, 0, 0, 0, 0, 43, 3, 44, 45, 46, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 18, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 48, 49, 50, + 51, 61, 62, 54, 55, 51, 63, 64, 65, 66, 37, 38, 54, 67, 68, 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, 0, 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, 0, 254, 255, 255, 255, 127, 0, + 191, 32, 0, 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, 0, 84, 85, 84, 85, + 85, 85, 0, 106, 85, 40, 5, 0, 85, 5, 0, 0, 255, 0, 0, 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, 255, 255, 63, 0, 1, 0, 0, 0, + 252, 255, 255, 7, 0, 0, 0, 240, 255, 255, 31, 0, 255, 1, 0, 0, + 0, 4, 0, 0, +}; + +/* Uppercase: 629 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] << 4; + f = code >> 12; + code ^= f << 12; + pos = (RE_UINT32)re_uppercase_stage_2[pos + f] << 3; + f = code >> 9; + code ^= f << 9; + pos = (RE_UINT32)re_uppercase_stage_3[pos + f] << 4; + 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, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5, + 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +}; + +static RE_UINT8 re_cased_stage_3[] = { + 0, 1, 2, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 5, 6, + 7, 3, 8, 3, 3, 3, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 11, 3, 12, + 3, 3, 13, 3, 3, 3, 3, 3, 3, 3, 14, 15, 3, 3, 3, 3, +}; + +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, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 36, 37, 4, 4, 4, 4, 38, 4, 21, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 39, 40, 0, 0, 0, 0, 41, 4, 4, 42, 43, 0, 44, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, + 4, 4, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 47, 4, 48, 49, 50, 4, 51, 52, 53, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 54, 55, 5, 47, 47, 36, 36, 56, 56, 57, 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, 60, 64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 191, 255, + 3, 252, 255, 255, 255, 0, 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, + 255, 255, 255, 0, 252, 255, 255, 255, 255, 120, 15, 0, 255, 7, 0, 0, + 0, 0, 0, 7, 127, 0, 248, 0, 255, 255, 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, 253, 255, 255, 247, + 255, 253, 255, 255, 247, 15, 0, 0, +}; + +/* Cased: 617 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] << 4; + f = code >> 12; + code ^= f << 12; + pos = (RE_UINT32)re_cased_stage_2[pos + f] << 3; + f = code >> 9; + code ^= f << 9; + pos = (RE_UINT32)re_cased_stage_3[pos + f] << 4; + 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, 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, + 16, 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, 1, 1, 1, 1, 1, 1, + 1, 1, 43, 1, 1, 1, 1, 1, 44, 45, 1, 1, 1, 1, 46, 1, + 1, 1, 1, 1, 1, 1, 1, 47, 1, 48, 49, 1, 1, 1, 1, 1, + 50, 51, 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, + 0, 44, 45, 35, 0, 40, 46, 35, 0, 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, 0, 0, 118, 119, 17, 0, 120, 121, 122, + 0, 0, 0, 0, 0, 0, 0, 123, 2, 0, 0, 0, 0, 124, 78, 0, + 125, 126, 127, 0, 0, 0, 0, 108, 1, 2, 3, 17, 44, 0, 0, 128, + 0, 0, 0, 0, 0, 0, 0, 129, 130, 131, 0, 0, 0, 0, 0, 0, + 32, 132, 126, 0, 78, 133, 0, 0, 28, 134, 0, 0, 78, 135, 0, 0, + 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 137, 0, 0, 0, + 0, 0, 0, 138, 139, 140, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, + 32, 6, 6, 6, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 142, +}; + +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, 31, 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, 240, 255, 255, 127, + 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, 0, 0, 15, 0, 0, 0, + 0, 0, 208, 23, 0, 248, 15, 0, 3, 0, 0, 0, 60, 11, 0, 0, + 64, 163, 3, 0, 0, 240, 207, 0, 0, 0, 0, 63, 0, 0, 247, 255, + 253, 33, 16, 0, 0, 240, 255, 255, 255, 7, 0, 1, 0, 0, 0, 248, + 127, 0, 0, 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, 128, 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, 157, 193, 2, 0, 0, 32, 0, 48, 88, 0, 32, 33, 0, 0, + 0, 0, 252, 255, 255, 255, 8, 0, 127, 0, 0, 0, 0, 0, 36, 0, + 8, 0, 0, 14, 0, 0, 0, 32, 110, 240, 0, 0, 0, 0, 0, 135, + 0, 0, 0, 255, 0, 0, 120, 38, 128, 239, 31, 0, 0, 0, 192, 127, + 0, 40, 191, 0, 0, 128, 255, 255, 128, 3, 248, 255, 231, 15, 0, 0, + 0, 60, 0, 0, 28, 0, 0, 0, 255, 255, 0, 0, +}; + +/* Case_Ignorable: 1254 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, 1, 1, 1, 1, 1, 1, 1, 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, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 9, + 6, 10, 6, 6, 11, 6, 6, 6, 6, 6, 6, 6, 12, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 13, 14, 6, 6, 6, 6, 6, 6, 6, 15, + 6, 6, 6, 6, 16, 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, + 3, 3, 3, 3, 25, 3, 3, 3, 26, 27, 28, 29, 27, 30, 31, 32, + 0, 33, 0, 19, 34, 0, 0, 0, 0, 0, 0, 0, 0, 35, 19, 0, + 18, 36, 0, 37, 3, 3, 3, 38, 0, 0, 3, 39, 40, 0, 0, 0, + 0, 41, 3, 42, 43, 44, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 18, 45, 0, 0, 0, 0, 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, 0, 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, 0, 254, 255, 255, 255, 127, 0, + 191, 32, 0, 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, 0, 84, 85, 84, 85, 85, 85, 0, 106, 85, 40, 5, 0, + 85, 5, 0, 0, 255, 0, 0, 0, +}; + +/* Changes_When_Lowercased: 490 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, 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_uppercased_stage_2[] = { + 0, 1, 1, 2, 3, 4, 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, 6, + 7, 1, 1, 1, 1, 1, 1, 1, 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_uppercased_stage_3[] = { + 0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 7, 8, 9, 6, 10, 6, 6, 11, 6, 6, 6, + 6, 6, 6, 6, 12, 13, 6, 6, 6, 6, 6, 6, 6, 6, 14, 15, + 6, 6, 6, 16, 6, 6, 6, 17, 6, 6, 6, 6, 18, 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, 30, 0, 0, 0, 0, + 5, 5, 5, 5, 31, 5, 5, 5, 32, 33, 34, 35, 24, 36, 37, 38, + 0, 0, 39, 23, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 41, + 0, 23, 42, 43, 5, 5, 5, 44, 24, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 46, 47, 0, 0, 0, 0, 48, 5, 49, 50, 51, 0, 0, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 53, 54, 0, 0, 0, 0, 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, 10, 105, 139, 38, 32, + 9, 31, 4, 0, 32, 0, 0, 0, 0, 0, 138, 56, 0, 0, 1, 0, + 0, 240, 255, 255, 255, 127, 227, 170, 170, 170, 39, 9, 0, 0, 255, 255, + 255, 255, 255, 255, 2, 168, 170, 170, 84, 213, 170, 170, 170, 0, 0, 0, + 254, 255, 255, 255, 255, 0, 0, 0, 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, 0, + 168, 170, 168, 170, 170, 170, 0, 148, 170, 16, 10, 0, 170, 2, 0, 0, + 127, 0, 248, 0, 0, 255, 255, 255, 255, 255, 0, 0, +}; + +/* Changes_When_Uppercased: 534 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 >> 15; + code = ch ^ (f << 15); + pos = (RE_UINT32)re_changes_when_uppercased_stage_1[f] << 4; + f = code >> 11; + code ^= f << 11; + pos = (RE_UINT32)re_changes_when_uppercased_stage_2[pos + f] << 3; + 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, 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_titlecased_stage_2[] = { + 0, 1, 1, 2, 3, 4, 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, 6, + 7, 1, 1, 1, 1, 1, 1, 1, 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_titlecased_stage_3[] = { + 0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 7, 8, 9, 6, 10, 6, 6, 11, 6, 6, 6, + 6, 6, 6, 6, 12, 13, 6, 6, 6, 6, 6, 6, 6, 6, 14, 15, + 6, 6, 6, 16, 6, 6, 6, 17, 6, 6, 6, 6, 18, 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, 30, 0, 0, 0, 0, + 5, 5, 5, 5, 31, 5, 5, 5, 32, 33, 34, 35, 33, 36, 37, 38, + 0, 0, 39, 23, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 41, + 0, 23, 42, 43, 5, 5, 5, 44, 24, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 46, 47, 0, 0, 0, 0, 48, 5, 49, 50, 51, 0, 0, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 53, 54, 0, 0, 0, 0, 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, 10, 105, 139, 38, 32, + 9, 31, 4, 0, 32, 0, 0, 0, 0, 0, 138, 56, 0, 0, 1, 0, + 0, 240, 255, 255, 255, 127, 227, 170, 170, 170, 39, 9, 0, 0, 255, 255, + 255, 255, 255, 255, 2, 168, 170, 170, 84, 213, 170, 170, 170, 0, 0, 0, + 254, 255, 255, 255, 255, 0, 0, 0, 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, 0, + 168, 170, 168, 170, 170, 170, 0, 148, 170, 16, 10, 0, 170, 2, 0, 0, + 127, 0, 248, 0, 0, 255, 255, 255, 255, 255, 0, 0, +}; + +/* Changes_When_Titlecased: 534 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 >> 15; + code = ch ^ (f << 15); + pos = (RE_UINT32)re_changes_when_titlecased_stage_1[f] << 4; + f = code >> 11; + code ^= f << 11; + pos = (RE_UINT32)re_changes_when_titlecased_stage_2[pos + f] << 3; + 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, 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_casefolded_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, 1, 1, 1, 1, 1, 1, 1, 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_casefolded_stage_3[] = { + 0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 9, + 6, 10, 6, 6, 11, 6, 6, 6, 6, 6, 6, 6, 12, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 13, 14, 6, 6, 6, 15, 6, 6, 6, 16, + 6, 6, 6, 6, 17, 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, + 4, 4, 4, 4, 28, 4, 4, 4, 29, 30, 31, 32, 20, 33, 34, 35, + 0, 36, 0, 21, 37, 0, 0, 0, 0, 0, 0, 0, 0, 38, 21, 0, + 20, 39, 0, 40, 4, 4, 4, 41, 0, 0, 4, 42, 43, 0, 0, 0, + 0, 44, 4, 45, 46, 47, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 20, 49, 0, 0, 0, 0, 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, 0, + 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, 0, 254, 255, 255, 255, 127, 0, 128, 0, 0, 0, 191, 32, 0, 0, + 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, 0, + 84, 85, 84, 85, 85, 85, 0, 106, 85, 40, 5, 0, 85, 5, 0, 0, + 127, 0, 248, 0, 255, 0, 0, 0, +}; + +/* Changes_When_Casefolded: 514 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 >> 15; + code = ch ^ (f << 15); + pos = (RE_UINT32)re_changes_when_casefolded_stage_1[f] << 4; + f = code >> 11; + code ^= f << 11; + pos = (RE_UINT32)re_changes_when_casefolded_stage_2[pos + f] << 3; + 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, 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_casemapped_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, 1, 1, 1, 1, 1, 1, 1, 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_casemapped_stage_3[] = { + 0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 6, 6, 6, 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, 15, 16, 6, 6, 6, 17, 6, 6, 6, 18, + 6, 6, 6, 6, 19, 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, 25, 0, 0, 0, 0, 4, 4, 4, 4, 26, 4, 4, 4, + 27, 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, 48, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 4, 4, 49, 0, 0, 0, 0, 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, 10, 105, 139, 38, 32, + 9, 31, 4, 0, 32, 0, 0, 0, 0, 0, 207, 56, 64, 215, 255, 255, + 251, 255, 255, 255, 255, 255, 227, 255, 255, 255, 183, 239, 3, 252, 255, 255, + 255, 0, 254, 255, 255, 255, 127, 0, 254, 255, 255, 255, 255, 0, 0, 0, + 191, 32, 0, 0, 0, 0, 0, 34, 255, 255, 255, 79, 255, 255, 63, 63, + 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, 0, + 252, 255, 252, 255, 255, 255, 0, 254, 255, 56, 15, 0, 255, 7, 0, 0, + 127, 0, 248, 0, 255, 255, 0, 0, +}; + +/* Changes_When_Casemapped: 530 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 >> 15; + code = ch ^ (f << 15); + pos = (RE_UINT32)re_changes_when_casemapped_stage_1[f] << 4; + f = code >> 11; + code ^= f << 11; + pos = (RE_UINT32)re_changes_when_casemapped_stage_2[pos + f] << 3; + 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 13, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 24, 7, 25, 26, 13, 13, 13, 13, 13, 13, 13, 27, + 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, 31, 31, 31, + 56, 57, 58, 59, 60, 31, 31, 31, 61, 62, 31, 31, 31, 31, 63, 31, + 1, 1, 1, 64, 65, 31, 31, 31, 1, 1, 1, 1, 66, 31, 31, 31, + 1, 1, 67, 31, 31, 31, 31, 68, 69, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 70, 71, 72, 73, 31, 31, 31, 31, 31, 31, 74, 31, + 1, 1, 1, 1, 1, 1, 75, 1, 1, 1, 1, 1, 1, 1, 1, 76, + 77, 31, 31, 31, 31, 31, 31, 31, 1, 1, 77, 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, 36, 45, 48, 49, 50, 51, 46, 0, + 52, 53, 54, 47, 52, 53, 55, 56, 52, 57, 58, 59, 60, 61, 62, 0, + 14, 63, 62, 0, 64, 65, 66, 0, 67, 0, 68, 69, 70, 0, 0, 0, + 4, 71, 72, 73, 74, 4, 75, 76, 4, 4, 77, 4, 78, 79, 80, 4, + 81, 4, 82, 0, 23, 4, 4, 83, 14, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 84, 1, 4, 4, 85, 86, 87, 87, 88, 4, 89, 90, 0, + 0, 4, 4, 91, 4, 92, 4, 93, 94, 0, 16, 95, 4, 96, 97, 0, + 98, 4, 83, 0, 0, 99, 0, 0, 100, 89, 101, 0, 102, 103, 4, 104, + 4, 105, 106, 107, 0, 0, 0, 108, 4, 4, 4, 4, 4, 4, 0, 0, + 109, 4, 110, 107, 4, 111, 112, 113, 0, 0, 0, 114, 115, 0, 0, 0, + 116, 117, 118, 4, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 120, 121, 4, 4, 4, 4, 122, 4, 75, 4, 123, 98, 124, 124, 0, + 125, 126, 14, 4, 127, 14, 4, 76, 100, 128, 4, 4, 129, 82, 0, 16, + 4, 4, 4, 4, 4, 93, 0, 0, 4, 4, 4, 4, 4, 4, 69, 0, + 4, 4, 4, 4, 69, 0, 16, 107, 130, 131, 4, 132, 91, 4, 4, 23, + 133, 134, 4, 4, 135, 18, 0, 136, 137, 138, 4, 89, 134, 89, 0, 139, + 26, 140, 62, 94, 32, 141, 142, 0, 4, 119, 143, 144, 4, 145, 146, 147, + 148, 149, 0, 0, 0, 0, 4, 138, 4, 4, 4, 4, 4, 150, 151, 152, + 4, 4, 4, 153, 4, 4, 154, 0, 155, 156, 157, 4, 4, 87, 158, 4, + 4, 107, 16, 4, 159, 4, 15, 160, 0, 0, 0, 161, 4, 4, 4, 94, + 0, 1, 1, 162, 4, 121, 163, 0, 164, 165, 166, 0, 4, 4, 4, 82, + 0, 0, 4, 83, 0, 0, 0, 0, 0, 0, 0, 0, 94, 4, 167, 0, + 121, 16, 18, 0, 107, 4, 168, 0, 4, 4, 4, 4, 107, 0, 0, 0, + 169, 170, 93, 0, 0, 0, 0, 0, 93, 154, 0, 0, 4, 171, 0, 0, + 172, 89, 0, 94, 0, 0, 0, 0, 4, 93, 93, 141, 0, 0, 0, 0, + 4, 4, 119, 0, 0, 0, 0, 0, 102, 91, 0, 0, 102, 23, 16, 119, + 102, 62, 0, 0, 102, 141, 173, 0, 0, 0, 0, 0, 4, 18, 0, 0, + 4, 4, 4, 129, 0, 0, 0, 0, 4, 4, 4, 138, 0, 0, 0, 0, + 4, 129, 0, 0, 0, 0, 0, 0, 4, 30, 0, 0, 0, 0, 0, 0, + 4, 4, 174, 0, 158, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 175, 4, 176, 177, 178, 4, 179, 180, 181, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 182, 183, 76, 175, 175, 120, 120, 184, 184, 143, 0, + 178, 185, 186, 187, 188, 189, 0, 0, 4, 4, 4, 4, 4, 4, 98, 0, + 4, 83, 4, 4, 4, 4, 4, 4, 107, 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, 60, + 64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 191, 255, 3, 252, 255, 255, + 255, 0, 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, 253, 31, 0, 0, + 240, 255, 255, 255, 255, 255, 255, 35, 0, 0, 1, 255, 3, 0, 254, 254, + 224, 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, 0, + 0, 0, 0, 176, 3, 0, 2, 0, 232, 199, 61, 214, 24, 199, 255, 3, + 224, 223, 253, 255, 255, 253, 239, 35, 0, 0, 0, 3, 0, 0, 0, 64, + 3, 0, 6, 0, 255, 255, 255, 39, 0, 64, 0, 0, 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, 31, 0, + 255, 159, 255, 255, 255, 199, 1, 0, 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, 31, 255, 63, 31, 0, + 255, 15, 0, 0, 254, 0, 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, 255, 255, 63, 63, 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, 255, 255, 255, 127, 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, 121, 15, 0, + 0, 0, 0, 255, 187, 247, 255, 255, 7, 0, 0, 0, 0, 0, 252, 8, + 63, 0, 255, 255, 255, 255, 7, 0, 0, 128, 0, 0, 247, 15, 0, 0, + 255, 255, 127, 4, 255, 255, 98, 62, 5, 0, 0, 56, 255, 7, 28, 0, + 126, 126, 126, 0, 127, 127, 0, 0, 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, + 15, 255, 62, 0, 63, 253, 255, 255, 255, 255, 191, 145, 255, 255, 255, 192, + 1, 0, 239, 254, 30, 0, 0, 0, 31, 0, 1, 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, 150, 254, 247, 10, 132, 234, 150, 170, 150, 247, 247, 94, + 255, 251, 255, 15, 238, 251, 255, 15, +}; + +/* ID_Start: 1753 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 13, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 24, 7, 25, 26, 13, 13, 13, 13, 13, 13, 13, 27, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 28, 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, 31, 31, 31, + 56, 57, 58, 59, 60, 31, 31, 31, 61, 62, 31, 31, 31, 31, 63, 31, + 1, 1, 1, 64, 65, 31, 31, 31, 1, 1, 1, 1, 66, 31, 31, 31, + 1, 1, 67, 31, 31, 31, 31, 68, 69, 31, 31, 31, 31, 31, 31, 31, + 31, 70, 71, 31, 72, 73, 74, 75, 31, 31, 31, 31, 31, 31, 76, 31, + 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, 1, 1, 1, 1, 78, + 79, 31, 31, 31, 31, 31, 31, 31, 1, 1, 79, 31, 31, 31, 31, 31, + 31, 80, 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, 14, 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, 33, 42, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 44, 54, 55, 56, 57, 54, 58, 59, 60, 61, 62, 63, 64, + 16, 65, 66, 0, 67, 68, 69, 0, 70, 71, 72, 73, 74, 75, 76, 0, + 6, 6, 77, 6, 78, 6, 79, 80, 6, 6, 81, 6, 82, 83, 84, 6, + 85, 6, 58, 86, 87, 6, 6, 88, 16, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 89, 3, 6, 6, 90, 91, 88, 92, 93, 6, 6, 94, 95, + 96, 6, 6, 97, 6, 98, 6, 99, 75, 100, 101, 102, 6, 103, 104, 0, + 29, 6, 105, 106, 107, 108, 0, 0, 6, 6, 109, 110, 6, 6, 6, 92, + 6, 97, 111, 78, 0, 0, 112, 113, 6, 6, 6, 6, 6, 6, 6, 114, + 115, 6, 116, 78, 6, 117, 118, 119, 0, 120, 121, 122, 123, 0, 123, 124, + 125, 126, 127, 6, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 129, 105, 6, 6, 6, 6, 130, 6, 79, 6, 131, 113, 132, 132, 6, + 133, 134, 16, 6, 135, 16, 6, 80, 136, 137, 6, 6, 138, 65, 0, 24, + 6, 6, 6, 6, 6, 99, 0, 0, 6, 6, 6, 6, 6, 6, 139, 0, + 6, 6, 6, 6, 139, 0, 24, 78, 140, 141, 6, 142, 143, 6, 6, 26, + 144, 145, 6, 6, 146, 147, 0, 148, 6, 149, 6, 92, 6, 6, 150, 151, + 6, 152, 92, 75, 6, 6, 153, 0, 6, 113, 154, 155, 6, 6, 156, 157, + 158, 159, 0, 0, 0, 0, 6, 160, 6, 6, 6, 6, 6, 161, 162, 29, + 6, 6, 6, 152, 6, 6, 163, 0, 164, 165, 166, 6, 6, 26, 167, 6, + 6, 78, 24, 6, 168, 6, 149, 169, 87, 170, 171, 172, 6, 6, 6, 75, + 1, 2, 3, 101, 6, 105, 173, 0, 174, 175, 176, 0, 6, 6, 6, 65, + 0, 0, 6, 88, 0, 0, 0, 177, 0, 0, 0, 0, 75, 6, 178, 0, + 105, 24, 147, 0, 78, 6, 179, 0, 6, 6, 6, 6, 78, 95, 0, 0, + 180, 181, 99, 0, 0, 0, 0, 0, 99, 163, 0, 0, 6, 182, 0, 0, + 183, 184, 0, 75, 0, 0, 0, 0, 6, 99, 99, 185, 0, 0, 0, 0, + 6, 6, 128, 0, 0, 0, 0, 0, 6, 6, 186, 50, 6, 65, 24, 187, + 6, 188, 0, 0, 6, 6, 150, 0, 0, 0, 0, 0, 6, 97, 95, 0, + 6, 6, 6, 138, 0, 0, 0, 0, 6, 6, 6, 189, 0, 0, 0, 0, + 6, 138, 0, 0, 0, 0, 0, 0, 6, 190, 0, 0, 0, 0, 0, 0, + 6, 6, 191, 105, 192, 0, 0, 0, 193, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 194, 195, 196, 0, 0, 0, 0, 197, 0, 0, 0, 0, 0, + 6, 6, 188, 6, 198, 199, 200, 6, 201, 202, 203, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 204, 205, 80, 188, 188, 129, 129, 206, 206, 207, 6, + 200, 208, 209, 210, 211, 212, 0, 0, 6, 6, 6, 6, 6, 6, 113, 0, + 6, 88, 6, 6, 6, 6, 6, 6, 78, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 6, 87, +}; + +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, 60, 192, 215, 255, 255, 251, 255, 255, 255, + 255, 255, 191, 255, 251, 252, 255, 255, 255, 0, 254, 255, 255, 255, 127, 2, + 254, 255, 255, 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, 253, 31, 0, 0, 240, 255, 255, 127, + 207, 255, 254, 254, 238, 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, 0, 159, 57, 192, 176, 207, 255, 2, 0, 236, 199, 61, 214, + 24, 199, 255, 195, 199, 61, 129, 0, 192, 255, 0, 0, 238, 223, 253, 255, + 255, 253, 239, 227, 223, 61, 96, 3, 236, 223, 253, 255, 255, 253, 239, 243, + 223, 61, 96, 64, 207, 255, 6, 0, 255, 255, 255, 231, 223, 125, 128, 0, + 207, 255, 0, 252, 236, 255, 127, 252, 255, 255, 251, 47, 127, 132, 95, 255, + 0, 0, 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, 31, 0, 255, 159, 255, 255, 255, 199, 1, 0, 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, 15, 255, 15, 192, 255, 255, 255, 255, 63, 31, 0, 255, 15, 255, 255, + 255, 3, 255, 7, 255, 255, 255, 127, 255, 255, 255, 159, 255, 3, 255, 3, + 128, 0, 0, 0, 255, 15, 255, 3, 0, 248, 15, 0, 255, 227, 255, 255, + 0, 0, 247, 255, 255, 255, 127, 0, 127, 0, 0, 240, 255, 255, 63, 63, + 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, + 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, 255, 255, 255, 128, + 0, 0, 128, 255, 252, 255, 255, 255, 255, 121, 15, 0, 255, 7, 0, 0, + 0, 0, 0, 255, 255, 0, 0, 0, 31, 0, 255, 3, 255, 255, 255, 8, + 255, 63, 255, 255, 1, 128, 255, 3, 255, 63, 255, 3, 255, 255, 127, 12, + 7, 0, 0, 56, 255, 255, 124, 0, 126, 126, 126, 0, 127, 127, 0, 0, + 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, 127, 0, 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, 15, 255, 62, 0, + 63, 253, 255, 255, 255, 255, 191, 145, 255, 255, 255, 192, 111, 240, 239, 254, + 255, 255, 15, 135, 255, 255, 7, 0, 127, 0, 0, 0, 255, 1, 255, 3, + 255, 255, 223, 255, 7, 0, 0, 0, 255, 255, 255, 1, 31, 0, 255, 255, + 0, 128, 255, 255, 3, 0, 0, 0, 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, + 150, 254, 247, 10, 132, 234, 150, 170, 150, 247, 247, 94, 255, 251, 255, 15, + 238, 251, 255, 15, +}; + +/* ID_Continue: 1894 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 13, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 24, 7, 25, 26, 13, 13, 13, 13, 13, 13, 13, 27, + 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, 31, 31, 31, + 57, 58, 59, 60, 61, 31, 31, 31, 62, 63, 31, 31, 31, 31, 64, 31, + 1, 1, 1, 65, 66, 31, 31, 31, 1, 1, 1, 1, 67, 31, 31, 31, + 1, 1, 68, 31, 31, 31, 31, 69, 70, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 71, 72, 73, 74, 31, 31, 31, 31, 31, 31, 75, 31, + 1, 1, 1, 1, 1, 1, 76, 1, 1, 1, 1, 1, 1, 1, 1, 77, + 78, 31, 31, 31, 31, 31, 31, 31, 1, 1, 78, 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, 36, 45, 48, 49, 50, 51, 46, 0, + 52, 53, 54, 47, 52, 53, 55, 56, 52, 57, 58, 59, 60, 61, 62, 0, + 14, 63, 62, 0, 64, 65, 66, 0, 67, 0, 68, 69, 70, 0, 0, 0, + 4, 71, 72, 73, 74, 4, 75, 76, 4, 4, 77, 4, 78, 79, 80, 4, + 81, 4, 82, 0, 23, 4, 4, 83, 14, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 84, 1, 4, 4, 85, 86, 87, 87, 88, 4, 89, 90, 0, + 0, 4, 4, 91, 4, 92, 4, 93, 94, 0, 16, 95, 4, 96, 97, 0, + 98, 4, 83, 0, 0, 99, 0, 0, 100, 89, 101, 0, 102, 103, 4, 104, + 4, 105, 106, 107, 0, 0, 0, 108, 4, 4, 4, 4, 4, 4, 0, 0, + 109, 4, 110, 107, 4, 111, 112, 113, 0, 0, 0, 114, 115, 0, 0, 0, + 116, 117, 118, 4, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 120, 121, 4, 4, 4, 4, 122, 4, 75, 4, 123, 98, 124, 124, 0, + 125, 126, 14, 4, 127, 14, 4, 76, 100, 128, 4, 4, 129, 82, 0, 16, + 4, 4, 4, 4, 4, 93, 0, 0, 4, 4, 4, 4, 4, 4, 69, 0, + 4, 4, 4, 4, 69, 0, 16, 107, 130, 131, 4, 132, 91, 4, 4, 23, + 133, 134, 4, 4, 135, 18, 0, 136, 137, 138, 4, 89, 134, 89, 0, 139, + 26, 140, 62, 94, 32, 141, 142, 0, 4, 119, 143, 144, 4, 145, 146, 147, + 148, 149, 0, 0, 0, 0, 4, 138, 4, 4, 4, 4, 4, 150, 151, 152, + 4, 4, 4, 153, 4, 4, 154, 0, 155, 156, 157, 4, 4, 87, 158, 4, + 4, 4, 107, 32, 4, 4, 4, 4, 4, 107, 16, 4, 159, 4, 15, 160, + 0, 0, 0, 161, 4, 4, 4, 94, 0, 1, 1, 162, 107, 121, 163, 0, + 164, 165, 166, 0, 4, 4, 4, 82, 0, 0, 4, 83, 0, 0, 0, 0, + 0, 0, 0, 0, 94, 4, 167, 0, 121, 16, 18, 0, 107, 4, 168, 0, + 4, 4, 4, 4, 107, 0, 0, 0, 169, 170, 93, 0, 0, 0, 0, 0, + 93, 154, 0, 0, 4, 171, 0, 0, 172, 89, 0, 94, 0, 0, 0, 0, + 4, 93, 93, 141, 0, 0, 0, 0, 4, 4, 119, 0, 0, 0, 0, 0, + 102, 91, 0, 0, 102, 23, 16, 119, 102, 62, 0, 0, 102, 141, 173, 0, + 0, 0, 0, 0, 4, 18, 0, 0, 4, 4, 4, 129, 0, 0, 0, 0, + 4, 4, 4, 138, 0, 0, 0, 0, 4, 129, 0, 0, 0, 0, 0, 0, + 4, 30, 0, 0, 0, 0, 0, 0, 4, 4, 174, 0, 158, 0, 0, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 4, 4, 175, 4, 176, 177, 178, 4, + 179, 180, 181, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 182, 183, 76, + 175, 175, 120, 120, 184, 184, 143, 0, 178, 185, 186, 187, 188, 189, 0, 0, + 4, 4, 4, 4, 4, 4, 98, 0, 4, 83, 4, 4, 4, 4, 4, 4, + 107, 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, 56, + 64, 215, 255, 255, 251, 255, 255, 255, 255, 255, 191, 255, 3, 252, 255, 255, + 255, 0, 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, 253, 31, 0, 0, + 240, 255, 255, 255, 255, 255, 255, 35, 0, 0, 1, 255, 3, 0, 254, 254, + 224, 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, 0, + 0, 0, 0, 176, 3, 0, 2, 0, 232, 199, 61, 214, 24, 199, 255, 3, + 224, 223, 253, 255, 255, 253, 239, 35, 0, 0, 0, 3, 0, 0, 0, 64, + 3, 0, 6, 0, 255, 255, 255, 39, 0, 64, 0, 0, 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, 31, 0, + 255, 159, 255, 255, 255, 199, 1, 0, 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, 31, 255, 63, 31, 0, + 255, 15, 0, 0, 254, 0, 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, 255, 255, 63, 63, 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, 255, 255, 255, 127, 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, 121, 15, 0, + 0, 0, 0, 255, 187, 247, 255, 255, 7, 0, 0, 0, 0, 0, 252, 8, + 63, 0, 255, 255, 255, 255, 7, 0, 0, 128, 0, 0, 247, 15, 0, 0, + 255, 255, 127, 4, 255, 255, 98, 62, 5, 0, 0, 56, 255, 7, 28, 0, + 126, 126, 126, 0, 127, 127, 0, 0, 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, + 15, 255, 62, 0, 63, 253, 255, 255, 255, 255, 191, 145, 255, 255, 255, 192, + 1, 0, 239, 254, 30, 0, 0, 0, 31, 0, 1, 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, 150, 254, 247, 10, 132, 234, 150, 170, 150, 247, 247, 94, + 255, 251, 255, 15, 238, 251, 255, 15, +}; + +/* XID_Start: 1761 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 13, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 24, 7, 25, 26, 13, 13, 13, 13, 13, 13, 13, 27, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 28, 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, 31, 31, 31, + 57, 58, 59, 60, 61, 31, 31, 31, 62, 63, 31, 31, 31, 31, 64, 31, + 1, 1, 1, 65, 66, 31, 31, 31, 1, 1, 1, 1, 67, 31, 31, 31, + 1, 1, 68, 31, 31, 31, 31, 69, 70, 31, 31, 31, 31, 31, 31, 31, + 31, 71, 72, 31, 73, 74, 75, 76, 31, 31, 31, 31, 31, 31, 77, 31, + 1, 1, 1, 1, 1, 1, 78, 1, 1, 1, 1, 1, 1, 1, 1, 79, + 80, 31, 31, 31, 31, 31, 31, 31, 1, 1, 80, 31, 31, 31, 31, 31, + 31, 81, 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, 14, 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, 33, 42, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 44, 54, 55, 56, 57, 54, 58, 59, 60, 61, 62, 63, 64, + 16, 65, 66, 0, 67, 68, 69, 0, 70, 71, 72, 73, 74, 75, 76, 0, + 6, 6, 77, 6, 78, 6, 79, 80, 6, 6, 81, 6, 82, 83, 84, 6, + 85, 6, 58, 86, 87, 6, 6, 88, 16, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 89, 3, 6, 6, 90, 91, 88, 92, 93, 6, 6, 94, 95, + 96, 6, 6, 97, 6, 98, 6, 99, 75, 100, 101, 102, 6, 103, 104, 0, + 29, 6, 105, 106, 107, 108, 0, 0, 6, 6, 109, 110, 6, 6, 6, 92, + 6, 97, 111, 78, 0, 0, 112, 113, 6, 6, 6, 6, 6, 6, 6, 114, + 115, 6, 116, 78, 6, 117, 118, 119, 0, 120, 121, 122, 123, 0, 123, 124, + 125, 126, 127, 6, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 129, 105, 6, 6, 6, 6, 130, 6, 79, 6, 131, 113, 132, 132, 6, + 133, 134, 16, 6, 135, 16, 6, 80, 136, 137, 6, 6, 138, 65, 0, 24, + 6, 6, 6, 6, 6, 99, 0, 0, 6, 6, 6, 6, 6, 6, 139, 0, + 6, 6, 6, 6, 139, 0, 24, 78, 140, 141, 6, 142, 143, 6, 6, 26, + 144, 145, 6, 6, 146, 147, 0, 148, 6, 149, 6, 92, 6, 6, 150, 151, + 6, 152, 92, 75, 6, 6, 153, 0, 6, 113, 154, 155, 6, 6, 156, 157, + 158, 159, 0, 0, 0, 0, 6, 160, 6, 6, 6, 6, 6, 161, 162, 29, + 6, 6, 6, 152, 6, 6, 163, 0, 164, 165, 166, 6, 6, 26, 167, 6, + 6, 6, 78, 168, 6, 6, 6, 6, 6, 78, 24, 6, 169, 6, 149, 1, + 87, 170, 171, 172, 6, 6, 6, 75, 1, 2, 3, 101, 6, 105, 173, 0, + 174, 175, 176, 0, 6, 6, 6, 65, 0, 0, 6, 88, 0, 0, 0, 177, + 0, 0, 0, 0, 75, 6, 178, 0, 105, 24, 147, 0, 78, 6, 179, 0, + 6, 6, 6, 6, 78, 95, 0, 0, 180, 181, 99, 0, 0, 0, 0, 0, + 99, 163, 0, 0, 6, 182, 0, 0, 183, 184, 0, 75, 0, 0, 0, 0, + 6, 99, 99, 185, 0, 0, 0, 0, 6, 6, 128, 0, 0, 0, 0, 0, + 6, 6, 186, 50, 6, 65, 24, 187, 6, 188, 0, 0, 6, 6, 150, 0, + 0, 0, 0, 0, 6, 97, 95, 0, 6, 6, 6, 138, 0, 0, 0, 0, + 6, 6, 6, 189, 0, 0, 0, 0, 6, 138, 0, 0, 0, 0, 0, 0, + 6, 190, 0, 0, 0, 0, 0, 0, 6, 6, 191, 105, 192, 0, 0, 0, + 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, 195, 196, 0, 0, + 0, 0, 197, 0, 0, 0, 0, 0, 6, 6, 188, 6, 198, 199, 200, 6, + 201, 202, 203, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 204, 205, 80, + 188, 188, 129, 129, 206, 206, 207, 6, 200, 208, 209, 210, 211, 212, 0, 0, + 6, 6, 6, 6, 6, 6, 113, 0, 6, 88, 6, 6, 6, 6, 6, 6, + 78, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 87, +}; + +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, 56, 192, 215, 255, 255, 251, 255, 255, 255, + 255, 255, 191, 255, 251, 252, 255, 255, 255, 0, 254, 255, 255, 255, 127, 2, + 254, 255, 255, 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, 253, 31, 0, 0, 240, 255, 255, 127, + 207, 255, 254, 254, 238, 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, 0, 159, 57, 192, 176, 207, 255, 2, 0, 236, 199, 61, 214, + 24, 199, 255, 195, 199, 61, 129, 0, 192, 255, 0, 0, 238, 223, 253, 255, + 255, 253, 239, 227, 223, 61, 96, 3, 236, 223, 253, 255, 255, 253, 239, 243, + 223, 61, 96, 64, 207, 255, 6, 0, 255, 255, 255, 231, 223, 125, 128, 0, + 207, 255, 0, 252, 236, 255, 127, 252, 255, 255, 251, 47, 127, 132, 95, 255, + 0, 0, 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, 31, 0, 255, 159, 255, 255, 255, 199, 1, 0, 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, 15, 255, 15, 192, 255, 255, 255, 255, 63, 31, 0, 255, 15, 255, 255, + 255, 3, 255, 7, 255, 255, 255, 127, 255, 255, 255, 159, 255, 3, 255, 3, + 128, 0, 0, 0, 255, 15, 255, 3, 0, 248, 15, 0, 255, 227, 255, 255, + 0, 0, 247, 255, 255, 255, 127, 0, 127, 0, 0, 240, 255, 255, 63, 63, + 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, + 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, 255, 255, 255, 128, + 0, 0, 128, 255, 252, 255, 255, 255, 255, 121, 15, 0, 255, 7, 0, 0, + 0, 0, 0, 255, 255, 0, 0, 0, 31, 0, 255, 3, 255, 255, 255, 8, + 255, 63, 255, 255, 1, 128, 255, 3, 255, 63, 255, 3, 255, 255, 127, 12, + 7, 0, 0, 56, 255, 255, 124, 0, 126, 126, 126, 0, 127, 127, 0, 0, + 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, 127, 0, 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, 15, 255, 62, 0, + 63, 253, 255, 255, 255, 255, 191, 145, 255, 255, 255, 192, 111, 240, 239, 254, + 255, 255, 15, 135, 255, 255, 7, 0, 127, 0, 0, 0, 255, 1, 255, 3, + 255, 255, 223, 255, 7, 0, 0, 0, 255, 255, 255, 1, 31, 0, 255, 255, + 0, 128, 255, 255, 3, 0, 0, 0, 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, + 150, 254, 247, 10, 132, 234, 150, 170, 150, 247, 247, 94, 255, 251, 255, 15, + 238, 251, 255, 15, +}; + +/* XID_Continue: 1902 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, 1, 2, 1, 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, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, +}; + +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, 6, 1, 1, 7, 1, 1, 1, 1, 1, + 8, 8, 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, 11, 1, 1, 1, 1, 1, 1, + 12, 12, 12, 12, 12, 12, 12, 12, +}; + +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, 13, 0, 0, 0, 0, + 14, 14, 14, 14, 14, 14, 14, 14, +}; + +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, 0, 0, 248, 7, 255, 255, 255, 255, +}; + +/* Default_Ignorable_Code_Point: 344 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 >> 14; + code = ch ^ (f << 14); + pos = (RE_UINT32)re_default_ignorable_code_point_stage_1[f] << 3; + 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, 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, + 16, 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, 0, 0, 0, 0, 0, 0, + 0, 0, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 39, 0, + 0, 0, 0, 0, 0, 0, 0, 40, 0, 41, 42, 0, 0, 0, 0, 0, + 0, 43, 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, + 0, 38, 39, 24, 0, 40, 41, 24, 0, 36, 27, 24, 0, 0, 42, 0, + 0, 43, 44, 0, 0, 45, 46, 0, 47, 48, 0, 49, 50, 51, 52, 0, + 0, 53, 54, 55, 56, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, + 58, 58, 59, 59, 0, 60, 61, 0, 62, 0, 0, 0, 0, 63, 0, 0, + 0, 64, 0, 0, 0, 0, 0, 0, 65, 0, 66, 67, 0, 0, 0, 0, + 68, 69, 35, 16, 70, 71, 0, 72, 0, 73, 0, 0, 0, 0, 74, 75, + 0, 0, 0, 0, 0, 0, 1, 76, 77, 0, 0, 0, 0, 0, 13, 78, + 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, 80, 0, 0, 0, 1, + 0, 81, 0, 0, 82, 0, 0, 0, 0, 0, 0, 83, 80, 0, 0, 84, + 85, 86, 0, 0, 0, 0, 87, 88, 0, 89, 90, 0, 21, 91, 0, 0, + 0, 92, 93, 0, 0, 94, 25, 95, 0, 0, 0, 0, 0, 0, 0, 96, + 36, 0, 0, 0, 0, 0, 0, 0, 2, 97, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 99, 100, 0, 0, 0, 0, 0, 0, 25, 101, 97, 0, 70, 102, 0, 0, + 21, 103, 0, 0, 70, 104, 0, 0, 0, 0, 0, 0, 0, 105, 0, 0, + 0, 0, 0, 0, 106, 0, 0, 0, 0, 0, 0, 107, 108, 109, 0, 0, + 0, 0, 110, 0, 0, 0, 0, 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, + 240, 255, 255, 127, 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, 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, + 15, 0, 0, 0, 0, 0, 208, 23, 3, 0, 0, 0, 60, 11, 0, 0, + 64, 163, 3, 0, 0, 240, 207, 0, 0, 0, 247, 255, 253, 33, 16, 0, + 127, 0, 0, 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, + 0, 126, 102, 0, 8, 16, 0, 0, 0, 0, 157, 193, 0, 48, 64, 0, + 32, 33, 0, 0, 127, 0, 0, 0, 0, 0, 0, 32, 110, 240, 0, 0, + 0, 0, 0, 135, 0, 0, 0, 255, 0, 0, 120, 6, 128, 239, 31, 0, + 0, 0, 192, 127, 0, 40, 191, 0, 0, 128, 7, 0, 160, 195, 7, 248, + 231, 15, 0, 0, 0, 60, 0, 0, 28, 0, 0, 0, +}; + +/* Grapheme_Extend: 1062 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, +}; + +static RE_UINT8 re_grapheme_base_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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 24, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 25, 7, 26, 27, 13, 13, 13, 13, 13, 13, 13, 28, + 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_grapheme_base_stage_3[] = { + 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 1, 16, 17, 1, 1, 18, 19, 20, 21, 22, 23, 24, 25, 1, 26, + 27, 28, 1, 29, 30, 1, 1, 31, 1, 1, 1, 32, 33, 34, 35, 36, + 37, 38, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 41, + 1, 1, 1, 1, 42, 1, 43, 44, 45, 46, 47, 48, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 49, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 1, 51, 52, 1, 53, 54, 55, 56, 57, 58, 59, 60, 50, 50, 50, + 61, 62, 63, 64, 65, 50, 66, 50, 67, 68, 50, 50, 50, 50, 69, 50, + 1, 1, 1, 70, 71, 50, 50, 50, 1, 1, 1, 1, 72, 50, 50, 50, + 1, 1, 73, 50, 50, 50, 50, 74, 75, 50, 50, 50, 50, 50, 50, 50, + 76, 77, 78, 79, 80, 81, 82, 83, 50, 50, 50, 50, 50, 50, 84, 50, + 85, 86, 87, 88, 89, 90, 91, 92, 1, 1, 1, 1, 1, 1, 93, 1, + 1, 1, 1, 1, 1, 1, 1, 94, 95, 50, 50, 50, 50, 50, 50, 50, + 1, 1, 95, 50, 50, 50, 50, 50, +}; + +static RE_UINT8 re_grapheme_base_stage_4[] = { + 0, 1, 1, 2, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 4, 5, 6, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, + 1, 8, 9, 10, 11, 12, 13, 14, 15, 1, 16, 17, 1, 1, 18, 19, + 20, 21, 22, 1, 1, 23, 1, 24, 25, 26, 27, 0, 0, 28, 0, 0, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 33, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 56, 60, 61, 62, 63, 64, 65, 66, 10, 67, 68, 0, 69, 70, 71, 0, + 72, 73, 74, 75, 76, 77, 78, 0, 1, 79, 80, 81, 82, 1, 83, 1, + 1, 1, 84, 1, 85, 86, 87, 1, 88, 1, 89, 90, 91, 1, 1, 92, + 1, 1, 1, 1, 90, 1, 1, 93, 94, 95, 96, 97, 1, 98, 99, 100, + 101, 1, 1, 102, 1, 103, 1, 104, 90, 105, 106, 107, 1, 108, 109, 1, + 110, 1, 111, 112, 100, 113, 0, 0, 114, 115, 116, 117, 118, 119, 1, 120, + 1, 121, 122, 1, 0, 0, 123, 124, 1, 1, 1, 1, 1, 1, 0, 0, + 125, 1, 126, 127, 1, 128, 129, 130, 131, 132, 1, 133, 134, 89, 0, 0, + 1, 1, 1, 1, 135, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 136, + 1, 137, 16, 1, 1, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 138, 0, 0, 0, 0, 0, 1, 139, 2, 1, 1, 1, 1, 140, + 1, 83, 1, 141, 142, 143, 143, 0, 1, 144, 0, 0, 145, 1, 1, 136, + 1, 1, 1, 1, 1, 1, 104, 146, 1, 135, 10, 1, 147, 1, 1, 1, + 148, 149, 1, 1, 139, 89, 1, 150, 2, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 104, 1, 1, 1, 1, 1, 1, 1, 1, 151, 0, + 1, 1, 1, 1, 152, 1, 153, 1, 1, 154, 1, 155, 102, 1, 1, 156, + 1, 1, 1, 1, 157, 16, 0, 158, 159, 160, 1, 102, 1, 1, 161, 162, + 1, 163, 164, 90, 29, 165, 166, 0, 1, 167, 168, 144, 1, 169, 170, 171, + 172, 173, 0, 0, 0, 0, 1, 174, 1, 1, 1, 1, 1, 150, 175, 144, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 176, 1, 1, 91, 0, + 177, 178, 179, 1, 1, 1, 180, 1, 1, 1, 181, 1, 182, 1, 183, 184, + 185, 181, 186, 187, 1, 1, 1, 90, 10, 1, 1, 1, 127, 2, 188, 189, + 190, 191, 192, 0, 1, 1, 1, 89, 193, 194, 1, 1, 195, 0, 181, 90, + 0, 0, 0, 0, 90, 1, 93, 0, 2, 150, 16, 0, 196, 1, 197, 0, + 1, 1, 1, 1, 127, 198, 0, 0, 199, 200, 201, 0, 0, 0, 0, 0, + 202, 203, 0, 0, 1, 204, 0, 0, 205, 136, 206, 1, 0, 0, 0, 0, + 1, 207, 208, 209, 0, 0, 0, 0, 1, 1, 210, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 211, 102, 212, 21, 118, 213, 214, 215, + 29, 216, 217, 0, 118, 218, 215, 0, 0, 0, 0, 0, 1, 219, 198, 0, + 1, 1, 1, 220, 0, 0, 0, 0, 1, 1, 1, 221, 0, 0, 0, 0, + 1, 220, 0, 0, 0, 0, 0, 0, 1, 222, 0, 0, 0, 0, 0, 0, + 1, 1, 223, 2, 224, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 104, 1, 226, 1, 227, 228, 229, 127, 0, + 1, 1, 230, 0, 0, 0, 0, 0, 1, 1, 142, 96, 0, 0, 0, 0, + 1, 1, 128, 1, 231, 232, 233, 1, 234, 235, 236, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 237, 1, 1, 1, 1, 1, 1, 1, 1, 238, 1, + 233, 239, 240, 241, 242, 243, 0, 244, 1, 108, 1, 1, 136, 245, 246, 0, + 131, 139, 1, 108, 89, 0, 0, 247, 248, 89, 249, 0, 0, 0, 0, 0, + 1, 250, 1, 90, 136, 1, 251, 93, 1, 2, 211, 1, 1, 1, 1, 252, + 1, 127, 150, 183, 0, 0, 0, 253, 1, 1, 254, 0, 1, 1, 255, 0, + 1, 1, 1, 136, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 142, 0, + 1, 92, 1, 1, 1, 1, 1, 1, 127, 0, 0, 0, 0, 0, 0, 0, +}; + +static RE_UINT8 re_grapheme_base_stage_5[] = { + 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 127, 255, 223, 255, 255, + 0, 0, 255, 124, 240, 215, 255, 255, 251, 255, 255, 255, 7, 252, 255, 255, + 255, 0, 254, 255, 255, 255, 127, 254, 254, 255, 255, 255, 255, 134, 0, 0, + 0, 0, 0, 64, 73, 0, 255, 255, 255, 7, 31, 0, 192, 255, 0, 200, + 255, 7, 0, 0, 255, 255, 254, 255, 255, 255, 63, 64, 96, 194, 255, 255, + 255, 63, 253, 255, 255, 255, 0, 0, 0, 224, 255, 255, 63, 0, 2, 0, + 255, 7, 240, 7, 255, 255, 63, 4, 16, 1, 255, 127, 255, 255, 255, 65, + 253, 31, 0, 0, 248, 255, 255, 255, 255, 255, 255, 235, 1, 222, 1, 255, + 243, 255, 255, 254, 236, 159, 249, 255, 255, 253, 197, 163, 129, 89, 0, 176, + 195, 255, 255, 15, 232, 135, 249, 255, 255, 253, 109, 195, 1, 0, 0, 94, + 192, 255, 28, 0, 232, 191, 251, 255, 255, 253, 237, 227, 1, 26, 1, 0, + 195, 255, 3, 0, 255, 253, 237, 35, 129, 25, 0, 176, 195, 255, 255, 0, + 232, 199, 61, 214, 24, 199, 255, 131, 198, 29, 1, 0, 192, 255, 255, 7, + 238, 223, 253, 255, 255, 253, 239, 35, 30, 0, 0, 3, 195, 255, 0, 255, + 236, 223, 253, 255, 255, 253, 239, 99, 155, 13, 0, 64, 195, 255, 6, 0, + 255, 255, 255, 167, 193, 93, 0, 0, 195, 255, 63, 254, 236, 255, 127, 252, + 255, 255, 251, 47, 127, 0, 3, 127, 0, 0, 28, 0, 255, 255, 13, 128, + 127, 128, 255, 15, 150, 37, 240, 254, 174, 236, 13, 32, 95, 0, 255, 243, + 255, 255, 255, 252, 255, 255, 95, 253, 255, 254, 255, 255, 255, 31, 0, 128, + 32, 31, 0, 0, 0, 0, 0, 192, 191, 223, 255, 7, 255, 31, 2, 153, + 255, 255, 255, 60, 254, 255, 225, 255, 155, 223, 255, 223, 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, 7, 255, 255, 255, 31, 255, 255, 255, 3, + 255, 255, 31, 0, 255, 255, 1, 0, 255, 223, 3, 0, 255, 255, 99, 0, + 255, 255, 3, 0, 255, 223, 1, 0, 255, 255, 79, 192, 191, 1, 240, 31, + 255, 3, 255, 3, 255, 7, 255, 3, 255, 255, 255, 0, 255, 5, 255, 255, + 255, 255, 63, 0, 120, 14, 251, 1, 241, 255, 255, 255, 255, 63, 31, 0, + 255, 15, 255, 255, 255, 3, 255, 199, 255, 255, 127, 198, 255, 255, 191, 0, + 26, 224, 7, 0, 255, 63, 0, 0, 240, 255, 255, 255, 255, 255, 47, 232, + 251, 15, 255, 255, 255, 7, 240, 31, 252, 255, 255, 255, 195, 244, 255, 255, + 191, 92, 12, 240, 255, 15, 48, 248, 255, 227, 255, 255, 255, 0, 8, 0, + 2, 222, 111, 0, 255, 255, 63, 63, 63, 63, 255, 170, 255, 255, 255, 63, + 255, 255, 223, 255, 223, 255, 207, 239, 255, 255, 220, 127, 255, 7, 255, 255, + 255, 128, 255, 255, 0, 0, 243, 255, 255, 127, 255, 31, 255, 3, 255, 255, + 255, 255, 15, 0, 127, 0, 0, 0, 255, 31, 255, 3, 255, 127, 255, 255, + 255, 127, 12, 254, 255, 128, 1, 0, 255, 255, 127, 0, 127, 127, 127, 127, + 255, 255, 255, 15, 255, 255, 255, 251, 0, 0, 255, 15, 255, 255, 127, 248, + 224, 255, 255, 255, 255, 63, 254, 255, 15, 0, 255, 255, 255, 31, 0, 0, + 255, 31, 255, 255, 127, 0, 255, 255, 255, 15, 0, 0, 255, 127, 8, 192, + 255, 255, 252, 0, 255, 127, 15, 0, 0, 0, 0, 255, 187, 247, 255, 255, + 159, 15, 255, 3, 15, 192, 255, 3, 0, 0, 252, 15, 63, 192, 255, 255, + 127, 0, 12, 128, 255, 255, 55, 236, 255, 191, 255, 195, 255, 129, 25, 0, + 247, 47, 255, 243, 255, 255, 98, 62, 5, 0, 0, 248, 255, 207, 63, 0, + 126, 126, 126, 0, 127, 127, 0, 0, 223, 30, 255, 3, 127, 248, 255, 255, + 255, 63, 255, 255, 127, 0, 248, 160, 255, 255, 127, 95, 219, 255, 255, 255, + 3, 0, 248, 255, 0, 0, 255, 255, 255, 255, 252, 255, 255, 0, 0, 0, + 0, 0, 255, 63, 0, 0, 255, 3, 255, 255, 247, 255, 127, 15, 223, 255, + 252, 252, 252, 28, 127, 127, 0, 48, 255, 239, 255, 255, 127, 255, 255, 183, + 255, 63, 255, 63, 135, 255, 255, 255, 255, 255, 143, 255, 255, 7, 255, 15, + 255, 255, 255, 191, 15, 255, 63, 0, 255, 3, 0, 0, 63, 253, 255, 255, + 255, 255, 191, 145, 255, 255, 191, 255, 255, 255, 255, 143, 255, 255, 255, 131, + 255, 255, 255, 192, 1, 0, 239, 254, 255, 0, 255, 1, 255, 255, 63, 254, + 255, 255, 63, 255, 255, 255, 7, 255, 255, 1, 0, 0, 253, 255, 255, 255, + 128, 63, 252, 255, 255, 255, 135, 217, 3, 0, 255, 255, 255, 1, 255, 3, + 127, 16, 192, 255, 15, 0, 0, 0, 255, 255, 63, 128, 255, 215, 64, 0, + 255, 127, 0, 0, 7, 0, 15, 0, 255, 255, 255, 1, 31, 0, 255, 255, + 0, 0, 248, 255, 3, 0, 0, 0, 127, 254, 255, 255, 95, 60, 0, 0, + 24, 240, 255, 255, 255, 195, 255, 255, 35, 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, 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, 255, 127, 254, 127, 254, 255, 254, 255, 192, 255, 255, 255, + 7, 0, 255, 255, 255, 1, 3, 0, 1, 0, 191, 255, 223, 7, 0, 0, + 255, 255, 255, 30, 0, 0, 0, 248, 225, 255, 0, 0, 63, 0, 0, 0, +}; + +/* Grapheme_Base: 2169 bytes. */ + +RE_UINT32 re_get_grapheme_base(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_grapheme_base_stage_1[f] << 5; + f = code >> 11; + code ^= f << 11; + pos = (RE_UINT32)re_grapheme_base_stage_2[pos + f] << 3; + f = code >> 8; + code ^= f << 8; + pos = (RE_UINT32)re_grapheme_base_stage_3[pos + f] << 3; + f = code >> 5; + code ^= f << 5; + pos = (RE_UINT32)re_grapheme_base_stage_4[pos + f] << 5; + 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, 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_grapheme_link_stage_2[] = { + 0, 1, 2, 3, 0, 4, 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, + 0, 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, +}; + +static RE_UINT8 re_grapheme_link_stage_3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 4, + 5, 0, 0, 0, 0, 0, 0, 6, 0, 0, 7, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 0, 0, 10, 11, 12, 13, 0, 0, 0, 0, + 0, 0, 14, 0, 0, 0, 0, 0, 15, 16, 0, 0, 0, 0, 17, 0, +}; + +static RE_UINT8 re_grapheme_link_stage_4[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, + 6, 6, 0, 0, 0, 0, 7, 0, 0, 0, 0, 8, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 9, 0, 10, 0, 0, 0, 11, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 15, 0, 0, + 0, 16, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 14, 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, +}; + +/* Grapheme_Link: 374 bytes. */ + +RE_UINT32 re_get_grapheme_link(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_link_stage_1[f] << 4; + f = code >> 11; + code ^= f << 11; + pos = (RE_UINT32)re_grapheme_link_stage_2[pos + f] << 3; + f = code >> 8; + code ^= f << 8; + pos = (RE_UINT32)re_grapheme_link_stage_3[pos + f] << 3; + 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, 1, 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, 1, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4, +}; + +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, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 5, 1, 1, 6, 7, 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, + 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: 193 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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_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, 9, 9, 9, 9, 18, 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, 1, 17, + 18, 1, 19, 1, 1, 20, 21, 1, 22, 1, 1, 1, 1, 1, 1, 1, + 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 24, 1, 1, 1, 25, 1, 1, 1, 1, 1, 1, 1, + 1, 26, 1, 1, 27, 28, 1, 1, 29, 30, 31, 32, 33, 34, 1, 35, + 1, 1, 1, 1, 36, 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 38, + 39, 1, 40, 1, 1, 1, 41, 1, 42, 43, 44, 45, 1, 1, 1, 1, + 46, 1, 1, 1, 1, 1, 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, 0, 18, 0, 19, 0, 0, 0, 0, 0, 11, 0, + 0, 20, 0, 0, 0, 0, 21, 0, 0, 22, 0, 23, 0, 24, 25, 0, + 0, 26, 0, 0, 27, 0, 0, 0, 0, 0, 0, 23, 28, 0, 0, 0, + 0, 0, 0, 29, 0, 0, 0, 30, 0, 0, 31, 0, 0, 32, 0, 0, + 0, 0, 25, 0, 0, 0, 33, 0, 0, 0, 34, 35, 0, 0, 0, 36, + 0, 0, 37, 0, 1, 0, 0, 38, 34, 0, 39, 0, 0, 0, 40, 0, + 34, 0, 0, 0, 0, 41, 0, 0, 0, 0, 42, 0, 0, 23, 43, 0, + 0, 0, 44, 0, 0, 0, 45, 0, 0, 0, 0, 46, +}; + +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, 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, 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, 0, 252, 128, 63, 0, 0, 3, 0, 0, 0, + 14, 0, 0, 0, 96, 0, 0, 0, 0, 0, 15, 0, +}; + +/* Terminal_Punctuation: 676 bytes. */ + +RE_UINT32 re_get_terminal_punctuation(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_terminal_punctuation_stage_1[f] << 4; + 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, 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_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, + 6, 10, 11, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 12, 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, 0, 0, 0, + 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, + 24, 25, 26, 27, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, + 0, 0, 29, 0, 0, 0, 0, 0, 30, 31, 0, 0, 0, 0, 32, 0, + 0, 0, 0, 0, 0, 0, 0, 33, +}; + +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, 19, 20, 28, 18, 18, 20, 28, 18, + 18, 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, 10, 47, 0, + 48, 0, 49, 50, 0, 0, 0, 0, 51, 52, 15, 0, 53, 54, 0, 55, + 0, 56, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 43, 57, 58, + 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 59, 42, 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, 71, 0, 0, 0, 0, 0, 0, 0, + 53, 72, 73, 0, 26, 74, 0, 0, 53, 64, 0, 0, 53, 75, 0, 0, + 0, 0, 0, 0, 0, 76, 0, 0, 0, 0, 35, 77, 0, 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, 240, 3, 255, 127, 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, 1, 3, 0, 0, + 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, 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, 110, 240, 0, 0, + 0, 0, 0, 255, 63, 0, 0, 0, 0, 0, 255, 1, 0, 0, 248, 255, + 0, 248, 63, 0, 255, 255, 255, 127, +}; + +/* Other_Alphabetic: 786 bytes. */ + +RE_UINT32 re_get_other_alphabetic(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_alphabetic_stage_1[f] << 4; + 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, 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, 0, 0, 0, 8, +}; + +static RE_UINT8 re_ideographic_stage_3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 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, 2, 2, 4, 0, 0, 0, 0, 5, 6, 0, 0, + 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 8, 9, 0, 0, 0, + 0, 0, 0, 0, 2, 9, 0, 0, +}; + +static RE_UINT8 re_ideographic_stage_4[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, + 2, 2, 2, 2, 2, 2, 2, 4, 0, 0, 0, 0, 2, 2, 2, 2, + 2, 5, 2, 6, 0, 0, 0, 0, 2, 2, 2, 7, 2, 2, 2, 2, + 2, 2, 2, 2, 8, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 0, +}; + +static RE_UINT8 re_ideographic_stage_5[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 254, 3, 0, 7, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, + 255, 31, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 63, 255, 255, + 255, 255, 255, 3, 0, 0, 0, 0, 255, 255, 127, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 255, 255, 31, 0, 255, 255, 255, 63, 0, 0, 0, 0, +}; + +/* Ideographic: 297 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] << 4; + f = code >> 12; + code ^= f << 12; + pos = (RE_UINT32)re_ideographic_stage_2[pos + f] << 3; + f = code >> 9; + code ^= f << 9; + pos = (RE_UINT32)re_ideographic_stage_3[pos + f] << 3; + f = code >> 6; + code ^= f << 6; + pos = (RE_UINT32)re_ideographic_stage_4[pos + f] << 6; + 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, + 4, 4, 10, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 11, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, +}; + +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, + 36, 37, 1, 1, 1, 1, 38, 1, 1, 1, 1, 1, 1, 1, 1, 39, + 1, 40, 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, 0, 0, 0, + 0, 37, 38, 39, 0, 40, 0, 0, 0, 41, 0, 42, 0, 0, 4, 43, + 0, 44, 5, 17, 0, 0, 45, 46, 0, 0, 0, 0, 0, 47, 48, 49, + 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 0, 0, 0, 0, 0, + 0, 52, 0, 0, 53, 0, 0, 22, 0, 0, 0, 54, 0, 0, 0, 55, + 56, 57, 0, 0, 58, 0, 0, 20, 0, 0, 0, 0, 0, 0, 38, 59, + 0, 60, 61, 0, 0, 61, 2, 0, 0, 0, 0, 62, 0, 15, 63, 64, + 0, 0, 0, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 66, 0, 0, 0, 0, 0, 0, 0, 1, 2, 67, 68, 0, 0, 69, + 0, 0, 0, 0, 0, 70, 0, 0, 0, 71, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, + 0, 0, 0, 73, 74, 75, 0, 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, 240, 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, 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, 0, + 0, 240, 255, 255, 240, 255, 0, 0, 0, 0, 0, 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, 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, 0, 0, 0, 8, 7, 0, 0, 0, + 0, 0, 64, 0, 0, 48, 0, 0, 127, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 192, 8, 0, 0, 0, 0, 0, 0, 6, 0, 0, 24, 0, + 0, 128, 255, 255, 128, 227, 7, 248, 231, 15, 0, 0, 0, 60, 0, 0, +}; + +/* Diacritic: 849 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, +}; + +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, 2, 2, 2, 2, 2, 2, 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_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, +}; + +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, 0, 0, 0, 0, 18, 0, 0, 19, 20, + 0, 0, 0, 18, 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, +}; + +/* Extender: 349 bytes. */ + +RE_UINT32 re_get_extender(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_extender_stage_1[f] << 5; + 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, 2, 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, 0, 0, 0, 13, 0, 14, +}; + +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, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 3, +}; + +/* Other_Lowercase: 273 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, +}; + +static RE_UINT8 re_other_uppercase_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_other_uppercase_stage_3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 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, +}; + +static RE_UINT8 re_other_uppercase_stage_5[] = { + 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 192, 255, +}; + +/* Other_Uppercase: 117 bytes. */ + +RE_UINT32 re_get_other_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_other_uppercase_stage_1[f] << 4; + f = code >> 12; + code ^= f << 12; + pos = (RE_UINT32)re_other_uppercase_stage_2[pos + f] << 4; + 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, 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, +}; + +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, 7, 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, 0, 8, 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, 32, 192, 7, 0, +}; + +/* Other_Grapheme_Extend: 249 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, 0, 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, 0, 0, 0, +}; + +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, 0, 0, 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, 31, 0, 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, 0, 0, 0, 0, +}; + +/* Unified_Ideograph: 257 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, 8, 8, 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, + 255, 255, 255, 255, +}; + +/* 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, 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, 1, 1, 1, 1, 1, +}; + +static RE_UINT8 re_logical_order_exception_stage_3[] = { + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 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, 2, 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, 96, 26, +}; + +/* Logical_Order_Exception: 121 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, 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, 1, 1, 1, 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_sterm_stage_2[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 3, 3, 9, 10, 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, 11, 12, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 13, + 3, 3, 14, 3, 15, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +}; + +static RE_UINT8 re_sterm_stage_3[] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, + 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 9, 1, 1, 1, 1, 1, 10, 1, 1, 1, 1, 1, 11, 1, 12, 1, + 13, 1, 14, 1, 1, 15, 16, 1, 17, 1, 1, 1, 1, 1, 1, 1, + 18, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 1, 1, 1, + 20, 1, 1, 1, 1, 1, 1, 1, 1, 21, 1, 1, 22, 23, 1, 1, + 24, 25, 26, 27, 28, 29, 1, 30, 1, 1, 1, 1, 31, 1, 32, 1, + 1, 1, 1, 1, 33, 1, 1, 1, 34, 35, 36, 37, 1, 1, 1, 1, +}; + +static RE_UINT8 re_sterm_stage_4[] = { + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 7, + 0, 0, 0, 8, 0, 0, 9, 0, 0, 0, 0, 10, 0, 0, 0, 11, + 0, 12, 0, 0, 13, 0, 0, 0, 0, 0, 8, 0, 0, 14, 0, 0, + 0, 0, 15, 0, 0, 16, 0, 17, 0, 18, 19, 0, 0, 11, 0, 0, + 20, 0, 0, 0, 0, 0, 0, 4, 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, 28, 0, 0, 29, 0, + 1, 0, 0, 30, 0, 0, 23, 0, 0, 0, 31, 0, 0, 17, 32, 0, + 0, 0, 33, 0, 0, 0, 34, 0, +}; + +static RE_UINT8 re_sterm_stage_5[] = { + 0, 0, 0, 0, 2, 64, 0, 128, 0, 0, 0, 80, 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, + 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, 0, 0, 0, +}; + +/* STerm: 568 bytes. */ + +RE_UINT32 re_get_sterm(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_sterm_stage_1[f] << 4; + f = code >> 10; + code ^= f << 10; + pos = (RE_UINT32)re_sterm_stage_2[pos + f] << 3; + f = code >> 7; + code ^= f << 7; + pos = (RE_UINT32)re_sterm_stage_3[pos + f] << 2; + 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, 5, 5, 11, 12, 13, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, +}; + +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, 2, 41, 42, 43, 44, 2, 45, 2, 2, 2, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 52, 52, 52, 57, 58, 52, + 2, 2, 52, 52, 52, 52, 59, 2, 2, 60, 61, 62, 63, 64, 52, 65, + 66, 67, 2, 68, 69, 70, 71, 72, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 74, 2, 2, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 2, 85, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 86, 87, 87, 87, 88, 89, 90, 91, 92, 93, + 2, 2, 94, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 96, 96, 97, 96, 98, 96, 99, 96, 96, 96, 96, 96, 100, 96, 96, 96, + 101, 102, 103, 104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 105, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 106, + 2, 2, 107, 108, 109, 2, 110, 2, 2, 2, 2, 2, 2, 111, 112, 113, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 87, 114, 96, 96, + 115, 116, 117, 2, 2, 2, 118, 119, 120, 121, 122, 123, 124, 125, 126, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 127, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 127, + 128, 128, 129, 130, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +}; + +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, 44, + 45, 11, 11, 46, 47, 48, 49, 11, 50, 11, 11, 51, 52, 11, 49, 53, + 54, 11, 11, 51, 55, 50, 11, 56, 54, 11, 11, 51, 57, 11, 49, 58, + 50, 11, 11, 59, 52, 60, 49, 11, 61, 11, 11, 11, 62, 11, 11, 63, + 11, 11, 11, 64, 65, 66, 49, 67, 11, 11, 11, 51, 68, 11, 49, 11, + 11, 11, 11, 11, 52, 11, 49, 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, 60, 11, 11, 11, + 11, 11, 81, 82, 11, 83, 84, 85, 86, 87, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 81, 11, 11, 11, 88, 11, 11, 11, 11, 11, 11, + 4, 11, 11, 11, 11, 11, 11, 11, 89, 90, 11, 11, 11, 11, 11, 11, + 11, 91, 11, 91, 11, 49, 11, 49, 11, 11, 11, 92, 93, 94, 11, 88, + 95, 11, 11, 11, 11, 11, 11, 11, 11, 11, 96, 11, 11, 11, 11, 11, + 11, 11, 97, 98, 99, 11, 11, 11, 11, 11, 11, 11, 11, 100, 16, 16, + 11, 101, 11, 11, 11, 102, 103, 104, 105, 11, 11, 106, 61, 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, 116, 111, + 11, 11, 11, 117, 118, 119, 119, 120, 121, 16, 122, 123, 124, 125, 126, 127, + 128, 11, 129, 129, 129, 17, 17, 84, 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, 141, 11, 16, 16, + 142, 143, 11, 11, 11, 11, 144, 16, 16, 16, 145, 16, 16, 16, 16, 16, + 146, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 147, 88, 11, 11, + 11, 11, 11, 11, 11, 11, 148, 149, 11, 11, 11, 11, 11, 11, 11, 150, + 11, 11, 11, 11, 11, 11, 17, 17, 16, 16, 16, 151, 11, 11, 11, 11, + 16, 152, 16, 16, 16, 16, 16, 139, 16, 16, 16, 16, 16, 137, 11, 151, + 153, 16, 154, 155, 11, 11, 11, 11, 11, 156, 4, 11, 11, 11, 11, 157, + 11, 11, 11, 11, 16, 16, 139, 11, 11, 120, 11, 11, 11, 16, 11, 158, + 11, 11, 11, 146, 159, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 160, + 11, 11, 11, 11, 11, 100, 11, 161, 11, 11, 11, 11, 16, 16, 16, 16, + 11, 16, 16, 16, 140, 11, 11, 11, 119, 11, 11, 11, 11, 11, 150, 162, + 11, 150, 11, 11, 11, 11, 11, 108, 16, 16, 163, 11, 11, 11, 11, 11, + 164, 11, 11, 11, 11, 11, 11, 11, 165, 11, 166, 167, 11, 11, 11, 168, + 11, 11, 11, 11, 115, 11, 17, 108, 11, 11, 169, 11, 170, 108, 11, 11, + 45, 11, 11, 171, 11, 11, 11, 11, 11, 11, 172, 173, 174, 11, 11, 11, + 11, 11, 11, 175, 50, 11, 68, 60, 11, 11, 11, 11, 11, 11, 176, 11, + 11, 177, 178, 26, 26, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 179, 29, 29, 29, 29, 29, 29, 29, 29, 29, 8, 8, 180, + 17, 88, 116, 16, 16, 181, 182, 29, 29, 29, 29, 29, 29, 29, 29, 183, + 184, 3, 4, 5, 4, 5, 137, 11, 11, 11, 11, 11, 11, 11, 185, 186, + 187, 11, 11, 11, 16, 16, 16, 16, 141, 151, 11, 11, 11, 11, 11, 87, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 188, 26, 26, 26, 26, 26, 26, + 189, 26, 26, 190, 26, 26, 26, 26, 26, 26, 26, 191, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 192, 193, 50, 11, 11, 194, 116, 14, 137, 11, + 108, 11, 11, 195, 11, 11, 11, 11, 45, 11, 196, 197, 11, 11, 11, 11, + 108, 11, 11, 198, 11, 11, 11, 11, 11, 11, 199, 200, 11, 11, 11, 11, + 150, 45, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 201, 202, + 203, 11, 204, 11, 11, 11, 11, 11, 16, 16, 16, 16, 205, 11, 11, 11, + 16, 16, 16, 16, 16, 140, 11, 11, 11, 11, 11, 11, 11, 157, 11, 11, + 11, 206, 11, 11, 161, 11, 11, 11, 135, 11, 11, 11, 207, 208, 208, 208, + 29, 29, 29, 29, 29, 29, 29, 209, 16, 16, 151, 16, 16, 16, 16, 16, + 16, 139, 210, 211, 146, 146, 11, 11, 212, 11, 11, 11, 11, 11, 133, 11, + 16, 16, 4, 213, 16, 16, 16, 147, 16, 139, 16, 16, 214, 11, 16, 4, + 16, 16, 16, 210, 215, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 216, + 16, 16, 16, 217, 139, 16, 218, 11, 11, 11, 11, 11, 11, 11, 11, 5, + 16, 16, 16, 16, 219, 11, 11, 11, 16, 16, 16, 16, 137, 11, 11, 11, + 16, 16, 16, 16, 16, 16, 16, 139, 11, 11, 11, 11, 11, 11, 11, 220, + 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, 40, 25, 25, 25, + 25, 25, 25, 39, 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, 30, 12, 64, 12, 12, 12, 64, 28, 65, 29, + 29, 61, 12, 12, 60, 66, 59, 61, 67, 12, 12, 12, 12, 12, 12, 65, + 12, 58, 12, 12, 58, 12, 12, 12, 59, 12, 12, 61, 13, 10, 68, 12, + 12, 12, 12, 62, 59, 62, 69, 29, 12, 64, 12, 12, 12, 12, 10, 70, + 12, 12, 12, 29, 12, 12, 58, 12, 62, 71, 12, 12, 61, 25, 57, 30, + 12, 28, 25, 57, 61, 25, 66, 59, 12, 12, 25, 29, 12, 12, 29, 12, + 12, 72, 73, 26, 60, 25, 25, 57, 25, 69, 12, 60, 25, 25, 60, 25, + 25, 25, 25, 59, 12, 12, 12, 60, 69, 25, 64, 64, 12, 12, 29, 62, + 59, 12, 12, 12, 60, 59, 12, 12, 58, 64, 12, 61, 12, 12, 12, 61, + 10, 10, 26, 12, 74, 12, 12, 12, 12, 12, 13, 11, 62, 59, 12, 12, + 12, 66, 25, 29, 12, 58, 60, 25, 25, 12, 30, 61, 10, 10, 75, 76, + 12, 12, 61, 12, 57, 28, 59, 12, 58, 12, 60, 12, 11, 26, 12, 12, + 12, 12, 12, 23, 12, 28, 65, 12, 12, 58, 25, 57, 71, 60, 25, 59, + 28, 25, 25, 65, 25, 12, 12, 12, 12, 69, 57, 59, 12, 12, 28, 25, + 29, 12, 12, 12, 62, 29, 66, 12, 12, 58, 29, 72, 12, 12, 12, 25, + 25, 62, 12, 12, 57, 25, 25, 25, 69, 25, 59, 61, 12, 59, 12, 12, + 25, 57, 12, 12, 12, 12, 12, 77, 26, 12, 12, 24, 12, 12, 12, 24, + 12, 12, 12, 22, 78, 78, 79, 80, 10, 10, 81, 82, 83, 84, 10, 10, + 10, 85, 10, 10, 10, 10, 10, 86, 0, 87, 88, 0, 89, 8, 90, 70, + 8, 8, 90, 70, 83, 83, 83, 83, 17, 70, 26, 12, 12, 20, 11, 23, + 10, 77, 91, 92, 12, 12, 23, 12, 10, 11, 23, 26, 12, 12, 91, 12, + 93, 10, 10, 10, 10, 26, 12, 12, 10, 20, 10, 10, 10, 12, 12, 12, + 10, 70, 12, 12, 10, 10, 70, 12, 10, 10, 8, 8, 8, 8, 8, 12, + 12, 12, 23, 10, 10, 10, 10, 24, 24, 10, 10, 10, 10, 10, 10, 11, + 12, 24, 70, 28, 29, 12, 24, 10, 12, 12, 12, 28, 10, 10, 10, 12, + 10, 10, 17, 10, 94, 11, 10, 10, 11, 12, 62, 29, 11, 23, 12, 24, + 12, 12, 95, 11, 12, 12, 13, 12, 12, 12, 12, 70, 12, 12, 12, 10, + 12, 13, 70, 12, 12, 12, 12, 13, 96, 25, 25, 97, 26, 12, 12, 12, + 12, 12, 11, 12, 58, 58, 28, 12, 12, 64, 10, 12, 12, 12, 98, 12, + 12, 10, 12, 12, 12, 62, 25, 29, 12, 28, 25, 25, 28, 62, 29, 59, + 12, 12, 60, 57, 64, 64, 12, 12, 28, 12, 12, 59, 69, 65, 59, 62, + 12, 61, 59, 61, 12, 12, 12, 99, 34, 34, 100, 34, 40, 40, 40, 101, + 40, 40, 40, 102, 103, 104, 10, 105, 106, 70, 107, 12, 40, 40, 40, 108, + 109, 5, 6, 7, 5, 110, 10, 70, 0, 0, 111, 112, 91, 12, 12, 12, + 34, 34, 34, 113, 31, 33, 34, 25, 34, 34, 114, 52, 34, 34, 115, 10, + 35, 35, 35, 35, 35, 35, 35, 116, 12, 12, 25, 25, 28, 57, 64, 12, + 12, 28, 25, 60, 25, 59, 12, 12, 12, 62, 25, 57, 12, 12, 28, 61, + 25, 66, 12, 12, 12, 28, 29, 12, 117, 0, 118, 25, 57, 60, 25, 12, + 12, 12, 62, 29, 119, 120, 12, 12, 12, 91, 12, 12, 13, 12, 12, 121, + 8, 8, 8, 8, 122, 40, 40, 40, 10, 10, 10, 70, 24, 10, 10, 70, + 8, 8, 123, 12, 10, 17, 10, 10, 10, 20, 70, 12, 20, 10, 10, 10, + 10, 10, 24, 11, 10, 10, 10, 26, 10, 10, 12, 12, 11, 24, 10, 10, + 12, 12, 12, 124, +}; + +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, 0, 0, 4, 1, 12, 12, 12, + 12, 12, 1, 12, 1, 12, 12, 1, 1, 1, 1, 1, 5, 5, 5, 5, + 5, 13, 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, 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, 0, 10, 10, 4, 10, 4, 4, 0, 11, 10, 10, 10, + 10, 10, 11, 11, 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, 0, + 0, 0, 11, 11, +}; + +/* Bidi_Class: 3216 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, 2, 2, 2, 6, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 33, 0, + 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, + 36, 37, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 39, 40, 0, 0, 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, 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, 38, 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, 0, 0, 0, + 0, 45, 46, 47, 0, 48, 0, 49, 0, 50, 0, 0, 0, 0, 51, 52, + 0, 0, 0, 0, 0, 0, 53, 54, 0, 0, 0, 0, 0, 0, 55, 56, + 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 58, 0, 0, 0, 59, + 0, 60, 0, 0, 61, 0, 0, 0, 0, 0, 0, 62, 63, 0, 0, 64, + 65, 0, 0, 0, 0, 0, 46, 66, 0, 67, 68, 0, 0, 69, 70, 0, + 0, 0, 0, 0, 0, 71, 72, 73, 0, 0, 0, 0, 0, 0, 0, 24, + 74, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 76, 77, 78, 0, 0, 0, 0, 0, 0, + 0, 0, 65, 0, 0, 79, 0, 0, 80, 81, 0, 0, 0, 0, 70, 0, + 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 83, 84, 85, 0, 0, + 0, 0, 86, 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, 0, 21, 43, 51, 52, 21, 35, 53, + 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, 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, 53, 9, 12, 4, + 85, 8, 86, 76, 0, 57, 0, 0, 21, 1, 21, 87, 88, 1, 1, 1, + 1, 53, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 90, 1, 91, 57, + 78, 92, 93, 4, 57, 0, 0, 0, 0, 0, 0, 19, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 94, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 95, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, + 0, 0, 0, 19, 0, 1, 1, 49, 0, 0, 0, 0, 0, 0, 0, 19, + 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, 98, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 94, 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, 53, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 76, 0, 0, 0, 102, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 103, 94, 0, 0, 0, 0, 0, 0, 104, 0, + 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 77, 0, 0, + 0, 0, 0, 0, 0, 105, 0, 0, 0, 106, 107, 108, 109, 0, 98, 4, + 110, 48, 23, 0, 0, 0, 0, 0, 0, 0, 38, 49, 0, 0, 0, 0, + 38, 57, 0, 0, 0, 0, 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, 50, 45, 45, 45, + 22, 23, 24, 50, 50, 50, 50, 0, 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, 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, 0, 0, 0, 45, 50, 0, 50, 50, + 45, 0, 0, 50, 0, 0, 21, 0, 0, 45, 0, 50, 50, 1, 45, 0, + 0, 4, 2, 0, 0, 0, 4, 2, 0, 43, 43, 1, 1, 1, 0, 0, + 0, 48, 43, 43, 43, 43, 43, 0, 45, 45, 45, 0, +}; + +/* Canonical_Combining_Class: 1828 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] << 5; + f = code >> 8; + code ^= f << 8; + pos = (RE_UINT32)re_canonical_combining_class_stage_2[pos + f] << 3; + 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, 7, 34, 7, 7, 7, 7, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 36, 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, 35, 37, 38, 39, 40, 41, 42, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 43, 44, 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, 45, 7, 7, 46, 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, 50, 7, + 7, 51, 52, 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, 35, 35, 53, 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, 146, 0, 0, 0, 0, 0, 0, 0, 147, + 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, 148, 149, 6, 6, 6, 81, 6, 6, 6, 6, 6, 6, 78, 0, 0, + 150, 151, 152, 153, 154, 155, 156, 156, 157, 156, 158, 159, 0, 160, 161, 162, + 163, 163, 163, 163, 163, 163, 164, 165, 165, 166, 167, 167, 167, 168, 169, 170, + 163, 171, 172, 173, 0, 174, 175, 176, 177, 178, 165, 179, 180, 0, 0, 181, + 0, 182, 0, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 192, 193, 194, + 195, 196, 196, 196, 196, 196, 197, 198, 198, 198, 198, 199, 200, 201, 202, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 204, 0, 0, 0, 0, 0, + 0, 0, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 205, 206, 0, 0, 0, 0, 207, 14, 0, 0, 0, + 208, 208, 208, 208, 208, 209, 208, 208, 208, 210, 211, 212, 213, 208, 208, 208, + 214, 215, 208, 216, 217, 218, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 219, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 220, 208, 208, 208, + 213, 208, 221, 222, 223, 224, 225, 226, 227, 228, 229, 228, 0, 0, 0, 0, + 230, 102, 231, 142, 142, 0, 232, 0, 0, 233, 0, 0, 0, 0, 0, 0, + 234, 142, 142, 235, 236, 237, 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, 25, 0, 0, 0, 0, 0, 55, 0, + 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, 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: 2872 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, 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, 1, 1, 1, 1, 1, 1, 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_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, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 13, 39, 9, 29, 22, 24, 45, 45, 31, 43, 57, 0, 0, 0, +}; + +/* Joining_Group: 481 bytes. */ + +RE_UINT32 re_get_joining_group(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_joining_group_stage_1[f] << 4; + f = code >> 12; + code ^= f << 12; + pos = (RE_UINT32)re_joining_group_stage_2[pos + f] << 5; + 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, 2, 2, 3, 2, 4, 5, 2, 2, 6, 2, 2, 7, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 2, 2, 2, 2, 2, +}; + +static RE_UINT8 re_joining_type_stage_2[] = { + 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 1, 1, 16, 1, 1, 1, 17, 18, 19, 20, 21, 22, 23, 1, 1, + 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 26, 1, 1, + 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 28, 1, 29, 30, 31, 32, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 33, 1, 1, 34, 35, + 1, 36, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 1, 1, 1, + 38, 39, 1, 1, 1, 1, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 41, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 42, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 44, 45, 1, 1, 1, 1, 1, 1, 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_type_stage_3[] = { + 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, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 0, 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, 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, 0, 0, 0, 37, 38, + 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, + 0, 0, 0, 55, 56, 57, 43, 0, 0, 0, 0, 51, 58, 0, 43, 0, + 0, 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, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, + 0, 86, 0, 0, 0, 87, 88, 89, 0, 0, 0, 0, 0, 0, 0, 0, + 90, 0, 0, 91, 53, 0, 92, 90, 93, 0, 94, 0, 0, 0, 95, 93, + 0, 0, 96, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 99, 100, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 101, 96, + 102, 0, 103, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 2, 2, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 93, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 105, 0, 0, 0, 0, 0, 0, 106, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 20, 107, 0, 20, 0, 0, 0, 0, 0, 93, + 108, 0, 57, 0, 15, 15, 15, 109, 0, 0, 0, 0, 100, 0, 2, 93, + 0, 0, 110, 0, 111, 93, 0, 0, 39, 0, 0, 112, 0, 0, 0, 0, + 0, 0, 113, 114, 115, 0, 0, 0, 0, 0, 0, 116, 44, 0, 117, 52, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 0, + 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 121, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 123, 101, 0, 0, 0, 93, 0, 0, 124, 0, 0, 0, 0, + 39, 0, 125, 126, 0, 0, 0, 0, 93, 0, 0, 127, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 129, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 20, 39, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 130, 131, 132, 0, 105, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, +}; + +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, 33, 12, 13, 15, 40, 5, 0, + 41, 15, 25, 42, 0, 2, 2, 2, 2, 2, 2, 8, 8, 0, 0, 0, + 0, 0, 43, 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, 43, 0, 0, 43, 0, 0, 0, 9, 0, 0, 1, 0, 0, 0, 37, + 9, 37, 28, 4, 0, 7, 0, 0, 0, 43, 0, 4, 0, 0, 43, 0, + 37, 44, 0, 0, 1, 2, 8, 0, 0, 3, 2, 8, 1, 2, 6, 9, + 0, 0, 2, 4, 0, 0, 4, 0, 0, 45, 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, 43, 7, 0, 1, + 37, 9, 0, 0, 0, 6, 2, 4, 0, 43, 5, 2, 2, 0, 0, 1, + 0, 46, 47, 4, 15, 15, 0, 0, 0, 46, 15, 15, 15, 15, 48, 0, + 8, 3, 9, 0, 43, 0, 5, 0, 0, 3, 27, 0, 0, 43, 2, 8, + 44, 5, 2, 9, 3, 2, 2, 27, 2, 0, 0, 0, 0, 28, 8, 9, + 0, 0, 3, 2, 4, 0, 0, 0, 37, 4, 6, 0, 0, 43, 4, 45, + 0, 0, 0, 2, 2, 37, 0, 0, 8, 2, 2, 2, 28, 2, 9, 1, + 0, 9, 0, 0, 2, 8, 0, 0, 0, 0, 3, 49, 0, 0, 37, 8, + 2, 9, 37, 2, 0, 0, 37, 4, 0, 0, 7, 0, 8, 2, 2, 4, + 43, 43, 3, 0, 50, 0, 0, 0, 0, 37, 2, 4, 0, 3, 2, 2, + 3, 37, 4, 9, 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, 43, + 0, 0, 5, 0, 5, 7, 0, 2, 0, 0, 8, 3, 0, 0, 2, 2, + 3, 8, 7, 1, 0, 3, 2, 5, 2, 9, 0, 0, 0, 37, 2, 8, + 0, 0, 3, 1, 2, 6, 0, 0, 0, 3, 4, 0, 3, 2, 2, 2, + 8, 5, 2, 0, +}; + +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, 2, 0, 2, 2, 3, 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, +}; + +/* Joining_Type: 1896 bytes. */ + +RE_UINT32 re_get_joining_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_joining_type_stage_1[f] << 5; + f = code >> 8; + code ^= f << 8; + pos = (RE_UINT32)re_joining_type_stage_2[pos + f] << 4; + 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, 10, 10, 16, 10, 10, 10, 10, 17, 10, 18, 19, 20, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 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, +}; + +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, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 79, 79, 79, 79, 110, 111, 2, 2, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 72, 122, 123, 124, 2, 125, 72, 72, 72, 72, 72, 72, + 126, 72, 127, 128, 129, 72, 130, 72, 131, 72, 72, 72, 132, 72, 72, 72, + 133, 134, 135, 136, 72, 72, 72, 72, 72, 72, 72, 72, 72, 137, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 2, 2, 2, 2, 2, 2, 138, 72, 139, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 2, 2, 2, 2, 140, 141, 142, 2, 143, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 2, 2, 2, 2, 144, 72, 72, 72, 72, 72, 72, 72, 72, 72, 145, 146, + 147, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 2, 148, 149, 150, 151, 72, 152, 72, 153, 154, 155, 2, 2, 156, 2, 157, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 158, 159, 72, 72, + 160, 161, 162, 163, 164, 72, 165, 166, 167, 168, 169, 170, 171, 172, 173, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 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, 174, + 175, 72, 176, 177, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, +}; + +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, 20, 21, 4, 22, 21, 4, + 23, 24, 1, 25, 26, 27, 28, 29, 30, 31, 4, 4, 32, 1, 33, 34, + 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 4, 1, 40, 4, 4, 4, + 4, 4, 41, 42, 37, 4, 32, 43, 4, 44, 45, 46, 4, 47, 48, 48, + 48, 48, 49, 48, 48, 48, 50, 51, 52, 4, 4, 53, 1, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 58, 59, 66, 67, 68, 69, 70, + 71, 18, 59, 72, 73, 74, 63, 75, 57, 58, 59, 72, 76, 77, 63, 20, + 78, 79, 80, 81, 82, 83, 69, 84, 85, 86, 59, 87, 88, 89, 63, 90, + 91, 86, 59, 92, 88, 93, 63, 94, 91, 86, 4, 95, 96, 97, 63, 98, + 99, 100, 4, 101, 102, 103, 48, 104, 105, 106, 106, 107, 108, 109, 48, 48, + 110, 111, 112, 113, 114, 115, 48, 48, 116, 117, 37, 118, 56, 4, 119, 120, + 121, 122, 1, 123, 124, 125, 48, 48, 106, 106, 106, 106, 126, 106, 106, 106, + 106, 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, 74, 145, 146, 4, 147, 4, 148, 145, 149, + 106, 106, 106, 106, 106, 150, 151, 140, 152, 151, 4, 4, 4, 4, 4, 20, + 4, 4, 153, 4, 4, 4, 4, 154, 4, 119, 155, 155, 156, 106, 157, 158, + 106, 106, 159, 106, 160, 161, 4, 4, 4, 162, 106, 106, 106, 163, 106, 164, + 151, 151, 157, 48, 48, 48, 48, 48, 165, 4, 4, 166, 167, 168, 169, 170, + 171, 4, 172, 37, 4, 4, 41, 173, 4, 4, 166, 174, 175, 37, 4, 176, + 48, 48, 48, 48, 20, 177, 178, 179, 4, 4, 4, 4, 1, 1, 180, 181, + 4, 182, 4, 4, 182, 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, 4, 4, + 4, 220, 221, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 222, + 4, 4, 223, 48, 224, 48, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, + 225, 225, 225, 225, 205, 225, 225, 227, 225, 228, 229, 230, 231, 232, 233, 4, + 234, 235, 4, 236, 237, 4, 238, 239, 4, 240, 4, 241, 242, 243, 244, 245, + 246, 4, 4, 4, 4, 247, 248, 249, 225, 250, 4, 4, 251, 4, 252, 4, + 253, 254, 4, 4, 4, 255, 4, 256, 4, 4, 4, 4, 119, 257, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 4, 4, 46, 4, 4, 46, 4, 4, + 4, 4, 4, 4, 4, 4, 258, 259, 4, 4, 128, 4, 4, 4, 260, 261, + 4, 223, 262, 262, 262, 262, 1, 1, 263, 264, 265, 266, 48, 48, 48, 48, + 267, 268, 267, 267, 267, 267, 267, 222, 267, 267, 267, 267, 267, 267, 267, 267, + 267, 267, 267, 267, 267, 269, 48, 270, 271, 272, 273, 274, 275, 267, 276, 267, + 277, 278, 279, 267, 276, 267, 277, 280, 281, 267, 282, 283, 267, 267, 267, 267, + 284, 267, 267, 285, 267, 267, 222, 286, 267, 284, 267, 267, 287, 267, 267, 267, + 267, 267, 267, 267, 267, 267, 267, 284, 267, 267, 267, 267, 4, 4, 4, 4, + 267, 288, 267, 267, 267, 267, 267, 267, 289, 267, 267, 267, 290, 4, 4, 176, + 291, 4, 292, 48, 4, 4, 258, 293, 4, 294, 4, 4, 4, 4, 4, 295, + 46, 296, 224, 48, 48, 48, 48, 90, 297, 4, 298, 299, 4, 4, 4, 300, + 301, 4, 4, 166, 302, 151, 1, 303, 37, 4, 304, 4, 305, 306, 129, 307, + 52, 4, 4, 308, 309, 310, 48, 48, 4, 4, 311, 180, 312, 313, 106, 159, + 106, 106, 106, 106, 314, 315, 32, 316, 317, 318, 262, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 4, 4, 319, 151, 320, 321, 322, 323, 322, 324, 322, 320, + 321, 322, 323, 322, 324, 322, 320, 321, 322, 323, 322, 324, 322, 320, 321, 322, + 323, 322, 324, 322, 320, 321, 322, 323, 322, 324, 322, 320, 321, 322, 323, 322, + 324, 322, 320, 321, 322, 323, 322, 324, 322, 320, 321, 322, 323, 322, 324, 322, + 323, 322, 325, 130, 326, 132, 132, 327, 328, 328, 328, 328, 328, 328, 328, 328, + 223, 329, 330, 331, 332, 4, 4, 4, 4, 4, 4, 4, 333, 334, 4, 4, + 4, 4, 4, 335, 48, 4, 4, 4, 4, 336, 4, 4, 20, 48, 48, 337, + 1, 338, 180, 339, 340, 341, 342, 185, 4, 4, 4, 4, 4, 4, 4, 343, + 344, 345, 267, 346, 267, 347, 348, 349, 4, 350, 4, 46, 351, 352, 353, 354, + 355, 4, 137, 356, 184, 184, 48, 48, 4, 4, 4, 4, 4, 4, 4, 224, + 357, 4, 4, 358, 4, 4, 4, 4, 224, 359, 48, 48, 48, 4, 4, 360, + 4, 119, 4, 4, 4, 74, 48, 48, 4, 46, 296, 4, 224, 48, 48, 48, + 4, 361, 4, 4, 362, 363, 48, 48, 4, 184, 151, 48, 48, 48, 48, 48, + 364, 4, 4, 365, 4, 366, 48, 48, 4, 367, 4, 368, 48, 48, 48, 48, + 4, 4, 4, 369, 48, 48, 48, 48, 370, 371, 4, 372, 20, 373, 4, 4, + 4, 4, 4, 374, 4, 375, 4, 376, 4, 4, 4, 4, 377, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 4, 46, 171, 4, 4, 378, 379, 336, 380, 48, + 171, 4, 4, 381, 382, 4, 377, 151, 171, 4, 305, 383, 384, 48, 48, 48, + 171, 4, 4, 308, 385, 151, 48, 48, 4, 4, 32, 386, 151, 48, 48, 48, + 4, 4, 4, 4, 4, 4, 46, 48, 4, 4, 4, 4, 4, 4, 387, 384, + 4, 4, 4, 4, 4, 388, 4, 4, 389, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 390, 4, 4, 46, 48, 48, 48, 48, 48, + 4, 4, 4, 377, 48, 48, 48, 48, 4, 4, 4, 4, 141, 391, 1, 51, + 392, 171, 48, 48, 48, 48, 48, 48, 393, 48, 48, 48, 48, 48, 48, 48, + 4, 4, 4, 4, 4, 4, 4, 154, 4, 4, 22, 4, 4, 4, 394, 1, + 395, 4, 396, 4, 4, 184, 48, 48, 4, 4, 4, 4, 397, 48, 48, 48, + 4, 4, 4, 4, 4, 223, 4, 333, 4, 4, 4, 4, 4, 185, 4, 4, + 4, 145, 398, 399, 400, 4, 4, 4, 401, 402, 4, 403, 404, 86, 4, 4, + 4, 4, 375, 4, 4, 4, 4, 4, 4, 4, 4, 4, 405, 406, 406, 406, + 400, 4, 407, 408, 409, 410, 411, 412, 413, 359, 414, 359, 48, 48, 48, 333, + 267, 267, 270, 267, 267, 267, 267, 267, 267, 222, 284, 415, 283, 283, 48, 48, + 416, 225, 417, 225, 225, 225, 418, 225, 225, 416, 48, 48, 48, 48, 419, 420, + 421, 267, 267, 285, 422, 393, 48, 48, 267, 267, 423, 424, 267, 267, 267, 289, + 267, 222, 267, 425, 426, 48, 267, 423, 267, 267, 267, 284, 427, 267, 267, 267, + 267, 267, 428, 429, 267, 267, 267, 430, 431, 432, 433, 434, 296, 267, 435, 48, + 48, 48, 48, 48, 48, 48, 48, 436, 267, 267, 267, 267, 437, 48, 48, 48, + 267, 267, 267, 267, 269, 48, 48, 48, 4, 4, 4, 4, 4, 4, 4, 296, + 267, 267, 267, 267, 267, 267, 267, 282, 438, 48, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 48, +}; + +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, + 14, 14, 14, 14, 36, 36, 36, 36, 39, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 38, 39, 14, 14, 14, 14, 14, 14, 14, 40, 41, 36, 42, + 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, + 19, 45, 0, 46, 36, 36, 36, 36, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 48, 36, 36, 47, 49, 38, 36, 36, 36, 36, 36, + 14, 14, 38, 14, 50, 51, 13, 14, 0, 0, 0, 0, 0, 52, 53, 54, + 14, 14, 14, 14, 14, 19, 0, 0, 12, 12, 12, 12, 12, 55, 56, 14, + 45, 14, 14, 14, 14, 14, 14, 14, 14, 14, 57, 0, 0, 0, 45, 19, + 0, 0, 45, 19, 45, 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, 53, 39, 14, 14, 14, 14, 0, 0, 0, 0, 0, + 45, 36, 36, 36, 36, 36, 36, 36, 0, 0, 14, 14, 58, 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, 38, 14, 14, 14, 14, 14, 38, 36, + 36, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, + 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 45, 0, + 19, 0, 0, 0, 14, 14, 14, 14, 14, 0, 59, 12, 12, 12, 12, 12, + 14, 14, 14, 14, 39, 14, 14, 14, 43, 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, 45, 0, 0, 0, 53, 43, 53, 43, 0, 38, + 36, 36, 36, 43, 36, 36, 14, 39, 14, 0, 36, 12, 12, 12, 12, 12, + 14, 51, 14, 14, 50, 9, 36, 36, 43, 0, 39, 14, 14, 38, 36, 39, + 38, 14, 39, 38, 14, 36, 53, 0, 0, 53, 36, 43, 53, 43, 0, 36, + 43, 36, 36, 36, 39, 14, 38, 38, 36, 36, 36, 12, 12, 12, 12, 12, + 0, 14, 19, 36, 36, 36, 36, 36, 43, 0, 39, 14, 14, 14, 14, 39, + 38, 14, 39, 14, 14, 36, 45, 0, 0, 0, 0, 43, 0, 43, 0, 36, + 38, 36, 36, 36, 36, 36, 36, 36, 9, 36, 36, 36, 36, 36, 36, 36, + 0, 0, 53, 43, 53, 43, 0, 36, 36, 36, 36, 0, 36, 36, 14, 39, + 36, 45, 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, 53, 36, 0, 53, 0, 0, 36, 38, 36, 36, 43, 36, 36, 36, 36, + 14, 14, 14, 14, 9, 38, 36, 36, 43, 0, 39, 14, 14, 14, 38, 14, + 38, 14, 14, 14, 14, 14, 14, 14, 14, 14, 39, 14, 14, 36, 39, 0, + 0, 0, 53, 0, 53, 0, 0, 36, 36, 36, 43, 53, 14, 36, 36, 36, + 36, 36, 36, 36, 14, 14, 14, 14, 36, 0, 39, 14, 14, 14, 38, 14, + 14, 14, 39, 14, 14, 36, 45, 0, 36, 36, 43, 53, 36, 36, 36, 38, + 39, 38, 36, 36, 36, 36, 36, 36, 14, 14, 14, 14, 14, 38, 39, 0, + 0, 0, 53, 0, 53, 0, 0, 38, 36, 36, 36, 43, 36, 36, 36, 36, + 14, 14, 14, 36, 60, 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, 53, 36, 43, 0, 0, 53, 53, 0, 0, 0, 0, + 36, 0, 38, 36, 36, 36, 36, 36, 61, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 36, 42, + 62, 62, 62, 62, 62, 62, 62, 64, 12, 12, 12, 12, 12, 59, 36, 36, + 61, 63, 63, 61, 63, 63, 61, 36, 36, 36, 62, 62, 61, 62, 62, 62, + 61, 62, 61, 61, 36, 62, 61, 62, 62, 62, 62, 62, 62, 61, 62, 36, + 62, 62, 63, 63, 62, 62, 62, 36, 12, 12, 12, 12, 12, 36, 62, 62, + 32, 65, 29, 65, 66, 67, 68, 54, 54, 69, 57, 14, 0, 14, 14, 14, + 14, 14, 44, 19, 19, 70, 70, 0, 14, 14, 14, 14, 14, 14, 38, 36, + 43, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 14, 14, 19, 0, + 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 59, + 14, 14, 14, 45, 14, 14, 38, 14, 65, 71, 14, 14, 72, 73, 36, 36, + 12, 12, 12, 12, 12, 59, 14, 14, 12, 12, 12, 12, 12, 62, 62, 62, + 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, 43, 0, 27, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 36, 36, 36, 14, 14, 38, 36, 36, 36, 36, 36, + 77, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 16, 78, 36, + 14, 14, 14, 14, 14, 27, 59, 14, 14, 14, 14, 14, 14, 14, 38, 14, + 14, 0, 53, 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, + 62, 62, 59, 79, 77, 80, 62, 36, 12, 12, 12, 12, 12, 36, 36, 36, + 14, 54, 59, 29, 54, 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, 54, 12, 12, 12, 12, 12, 62, 62, 62, 62, 62, 62, 62, 36, + 62, 62, 63, 36, 36, 36, 36, 36, 62, 62, 62, 62, 62, 62, 36, 36, + 62, 62, 62, 62, 62, 36, 36, 36, 12, 12, 12, 12, 12, 63, 36, 62, + 14, 14, 14, 19, 0, 0, 36, 14, 62, 62, 62, 62, 62, 62, 62, 63, + 62, 62, 62, 62, 62, 62, 63, 43, 0, 0, 45, 14, 14, 14, 14, 14, + 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 45, 14, 14, 14, 36, 36, + 12, 12, 12, 12, 12, 59, 27, 59, 77, 14, 14, 14, 14, 19, 0, 0, + 0, 0, 14, 14, 14, 14, 38, 36, 0, 45, 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, 59, 59, 12, 12, 12, 12, 12, 36, 39, 14, + 14, 14, 14, 14, 14, 14, 14, 59, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 45, 14, 19, 14, 14, 0, 45, 38, 36, 36, 36, 36, + 0, 0, 0, 53, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 0, + 14, 14, 14, 36, 14, 14, 14, 36, 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, + 59, 59, 59, 82, 59, 83, 0, 0, 82, 59, 84, 25, 85, 86, 85, 86, + 28, 14, 87, 88, 89, 0, 0, 33, 51, 51, 51, 51, 7, 90, 91, 14, + 14, 14, 92, 93, 91, 14, 14, 14, 14, 14, 14, 77, 59, 59, 27, 59, + 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, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 53, 36, 36, 36, 36, 36, 36, 36, 14, 50, 24, 14, 50, 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, 36, 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, 25, 14, 14, 14, 97, 14, 14, 14, 14, 14, 14, 16, 98, 14, 14, + 97, 97, 36, 36, 36, 36, 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, + 97, 97, 24, 25, 24, 14, 14, 28, 14, 14, 97, 28, 99, 97, 97, 97, + 14, 14, 14, 14, 100, 97, 14, 14, 25, 25, 14, 14, 14, 14, 14, 14, + 28, 24, 28, 24, 101, 25, 28, 24, 14, 14, 14, 14, 14, 14, 14, 100, + 14, 14, 14, 14, 14, 14, 14, 28, 14, 14, 14, 14, 14, 14, 100, 97, + 97, 97, 97, 97, 101, 28, 102, 100, 97, 102, 101, 28, 97, 28, 101, 102, + 97, 24, 14, 14, 28, 101, 28, 28, 102, 97, 97, 102, 97, 101, 102, 97, + 103, 97, 99, 14, 97, 97, 97, 14, 14, 14, 14, 24, 14, 7, 85, 5, + 14, 54, 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, 98, 14, 14, 14, 14, + 14, 14, 14, 70, 70, 70, 70, 70, 14, 16, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 104, 98, 14, 14, 14, 14, 14, 14, 14, 70, 70, 14, 14, + 14, 14, 14, 14, 14, 14, 70, 14, 14, 14, 24, 28, 28, 36, 36, 36, + 14, 14, 14, 14, 14, 14, 14, 19, 0, 14, 36, 36, 105, 59, 77, 106, + 14, 14, 14, 14, 36, 36, 36, 39, 41, 36, 36, 36, 36, 36, 36, 43, + 14, 14, 14, 38, 14, 14, 14, 38, 85, 85, 85, 85, 85, 85, 85, 59, + 59, 59, 59, 27, 107, 14, 85, 14, 85, 70, 70, 70, 70, 59, 59, 57, + 59, 27, 77, 14, 14, 108, 36, 36, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 103, 97, 97, 97, 97, 97, 36, 36, 36, 36, 36, + 97, 97, 97, 97, 97, 97, 36, 36, 18, 109, 110, 97, 70, 70, 70, 70, + 70, 97, 70, 70, 70, 70, 111, 112, 97, 97, 97, 97, 97, 0, 0, 0, + 97, 97, 113, 97, 97, 110, 114, 97, 115, 116, 116, 116, 116, 97, 97, 97, + 97, 116, 97, 97, 97, 97, 97, 97, 97, 116, 116, 116, 97, 97, 97, 117, + 97, 97, 116, 118, 43, 119, 91, 114, 120, 116, 116, 116, 116, 97, 97, 97, + 97, 97, 116, 117, 97, 110, 121, 114, 36, 36, 103, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 36, 103, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 122, 97, 97, 97, 97, 97, 122, 36, 36, + 123, 123, 123, 123, 123, 123, 123, 123, 97, 97, 97, 97, 28, 28, 28, 28, + 97, 97, 110, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 122, 36, + 97, 97, 97, 122, 36, 36, 36, 36, 14, 14, 14, 14, 14, 14, 27, 106, + 12, 12, 12, 12, 12, 14, 36, 36, 0, 45, 0, 0, 0, 0, 0, 14, + 14, 14, 14, 14, 36, 36, 36, 43, 0, 27, 59, 59, 36, 36, 36, 36, + 14, 14, 36, 36, 36, 36, 36, 36, 14, 45, 14, 45, 14, 19, 14, 14, + 14, 19, 0, 0, 14, 14, 36, 36, 14, 14, 14, 14, 124, 36, 36, 36, + 14, 14, 65, 54, 36, 36, 36, 36, 0, 14, 14, 14, 14, 14, 14, 14, + 0, 0, 53, 36, 36, 36, 36, 59, 0, 14, 14, 14, 14, 14, 36, 36, + 14, 14, 14, 0, 0, 0, 0, 59, 14, 14, 14, 19, 0, 0, 0, 0, + 0, 0, 36, 36, 36, 36, 36, 39, 74, 74, 74, 74, 74, 74, 125, 36, + 14, 19, 0, 0, 0, 0, 0, 0, 45, 14, 14, 27, 59, 14, 14, 39, + 12, 12, 12, 12, 12, 36, 36, 14, 14, 14, 14, 14, 19, 0, 0, 0, + 14, 19, 14, 14, 14, 14, 0, 36, 12, 12, 12, 12, 12, 36, 27, 59, + 62, 63, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 62, 62, + 59, 14, 19, 53, 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, + 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 127, 127, 127, + 127, 127, 126, 127, 127, 127, 127, 127, 127, 127, 36, 36, 36, 36, 36, 36, + 75, 75, 75, 128, 36, 129, 76, 76, 76, 76, 76, 76, 76, 76, 36, 36, + 130, 130, 130, 130, 130, 130, 130, 130, 36, 39, 14, 14, 36, 36, 131, 132, + 47, 47, 47, 47, 49, 47, 47, 47, 47, 47, 47, 48, 47, 47, 48, 48, + 47, 131, 48, 47, 47, 47, 47, 47, 14, 36, 36, 36, 36, 36, 36, 36, + 36, 39, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 70, + 36, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 124, 36, + 133, 134, 58, 135, 136, 36, 36, 36, 97, 97, 137, 104, 104, 104, 104, 104, + 104, 104, 109, 137, 109, 97, 97, 97, 109, 78, 91, 54, 137, 104, 104, 109, + 97, 97, 97, 122, 138, 139, 36, 36, 14, 14, 14, 14, 14, 14, 38, 140, + 105, 97, 6, 97, 70, 97, 109, 109, 97, 97, 97, 97, 97, 91, 97, 141, + 97, 97, 97, 97, 97, 137, 142, 97, 97, 97, 97, 97, 97, 137, 142, 137, + 112, 70, 93, 143, 123, 123, 123, 123, 144, 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, 97, 138, 145, 14, 14, 14, 38, + 36, 36, 36, 36, 43, 0, 146, 36, 14, 14, 14, 14, 14, 14, 39, 14, + 14, 14, 14, 14, 14, 38, 14, 39, 59, 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, 14, 14, 14, 14, 14, 81, + 14, 14, 36, 36, 14, 14, 14, 14, 77, 14, 14, 36, 36, 36, 36, 36, + 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, 14, 14, 14, 14, 14, 36, 81, + 14, 14, 14, 14, 14, 36, 36, 39, 14, 14, 14, 14, 36, 36, 36, 14, + 19, 0, 43, 53, 36, 36, 0, 0, 14, 14, 39, 14, 39, 14, 14, 14, + 14, 14, 36, 36, 0, 53, 36, 43, 59, 59, 59, 59, 38, 36, 36, 36, + 14, 14, 14, 36, 81, 59, 59, 59, 14, 14, 14, 36, 14, 14, 14, 14, + 14, 38, 36, 36, 14, 14, 14, 14, 14, 14, 14, 14, 38, 36, 36, 36, + 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 1, 77, 14, 14, 36, + 14, 14, 14, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 45, 14, 59, + 59, 36, 36, 36, 36, 36, 36, 36, 0, 0, 53, 12, 12, 12, 12, 12, + 59, 59, 36, 36, 36, 36, 36, 36, 45, 14, 27, 77, 41, 36, 36, 36, + 0, 0, 0, 0, 36, 36, 36, 36, 14, 38, 36, 36, 36, 36, 36, 36, + 14, 14, 14, 14, 147, 70, 112, 14, 14, 98, 14, 70, 70, 14, 14, 14, + 14, 14, 14, 14, 16, 112, 14, 14, 19, 0, 0, 0, 0, 0, 0, 0, + 36, 36, 36, 36, 36, 36, 36, 43, 97, 36, 36, 36, 36, 36, 36, 36, + 14, 14, 19, 0, 0, 14, 19, 0, 0, 45, 19, 0, 0, 0, 14, 14, + 14, 14, 14, 14, 14, 0, 0, 14, 14, 0, 45, 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, 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, 103, 97, 97, 97, 97, 97, 97, 122, + 28, 28, 28, 28, 28, 148, 36, 36, 28, 28, 28, 28, 28, 28, 28, 38, + 28, 28, 28, 28, 28, 14, 36, 36, 36, 36, 36, 149, 149, 149, 149, 149, + 149, 149, 149, 149, 149, 149, 149, 149, 97, 122, 36, 36, 36, 36, 36, 36, + 97, 97, 97, 97, 122, 36, 36, 36, 122, 36, 36, 36, 36, 36, 36, 36, + 97, 97, 97, 103, 97, 97, 97, 97, 97, 97, 99, 100, 97, 97, 100, 97, + 97, 97, 122, 97, 97, 122, 36, 36, 122, 97, 97, 97, 97, 97, 97, 97, + 100, 100, 100, 97, 97, 97, 97, 99, 99, 100, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 103, 97, 122, 36, 14, 14, 14, 100, 97, 97, 97, 97, + 97, 97, 97, 99, 14, 14, 14, 14, 14, 14, 100, 97, 97, 97, 97, 97, + 97, 14, 14, 14, 14, 14, 14, 36, 97, 97, 97, 97, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 103, 97, 97, 122, 36, 103, 97, 97, 97, 97, 97, + 43, 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, 0, 12, 0, 0, 12, + 0, 8, 18, 0, 0, 9, 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, + 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, 13, 13, 2, 12, 13, 12, 12, 13, 13, 25, 25, 13, 0, 13, + 2, 1, 0, 6, 6, 18, 1, 18, 26, 26, 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, 1, 1, 25, 0, 39, 39, +}; + +/* Line_Break: 7668 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, 11, 11, 11, 11, 11, 11, 11, 16, 11, 17, + 18, 11, 19, 20, 11, 11, 21, 11, 11, 11, 11, 11, 11, 11, 11, 22, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 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, 1, 57, 58, 1, 1, 1, 59, 60, 61, 62, 1, 1, 63, 1, + 64, 65, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 67, 1, 1, 1, 68, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 69, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 70, 71, 1, 1, 1, 1, 1, 1, 1, 72, 73, 74, 1, 1, 1, 1, + 1, 1, 1, 75, 1, 1, 1, 1, 1, 76, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, + 1, 1, 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 75, 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, 0, 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, 0, 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, 35, 0, 0, 0, 0, 68, 69, 0, 0, 0, 70, 0, + 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, + 0, 0, 71, 71, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, + 0, 0, 76, 77, 0, 0, 0, 1, 0, 78, 0, 0, 0, 0, 1, 0, + 19, 19, 19, 79, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 81, 82, 83, 0, 0, 0, 0, 0, 0, 0, + 58, 0, 0, 43, 0, 0, 0, 84, 0, 58, 0, 0, 0, 0, 0, 0, + 0, 35, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, + 87, 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, + 13, 0, 0, 0, 42, 40, 0, 0, 0, 0, 51, 0, 0, 0, 0, 19, + 0, 0, 17, 13, 52, 0, 0, 0, 0, 0, 0, 53, 23, 25, 19, 10, + 0, 0, 54, 55, 56, 1, 0, 0, 0, 0, 5, 1, 9, 0, 0, 0, + 19, 19, 7, 0, 0, 5, 1, 1, 1, 1, 1, 1, 23, 57, 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, 1, 1, 1, 1, 1, 0, 0, + 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 2, 2, 2, 0, 0, 0, 0, 0, +}; + +/* Numeric_Type: 2088 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, 11, 11, 11, 11, 11, 11, 11, 16, 11, 17, + 18, 11, 19, 20, 11, 11, 21, 11, 11, 11, 11, 11, 11, 11, 11, 22, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 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, 1, 57, 58, 1, 1, 1, 59, 60, 61, 62, 1, 1, 63, 1, + 64, 65, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 67, 1, 1, 1, 68, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 69, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 70, 71, 1, 1, 1, 1, 1, 1, 1, 72, 73, 74, 1, 1, 1, 1, + 1, 1, 1, 75, 1, 1, 1, 1, 1, 76, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, + 1, 1, 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 79, 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, 0, 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, 0, 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, 78, 79, 0, 0, 0, 80, 0, + 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, + 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 84, 0, 0, 0, 0, + 0, 0, 85, 85, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, + 0, 0, 87, 88, 0, 0, 0, 1, 0, 89, 0, 0, 0, 0, 1, 0, + 90, 91, 92, 93, 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 95, 96, 97, 0, 0, 0, 0, 0, 0, 0, + 98, 0, 0, 99, 0, 0, 0, 100, 0, 101, 0, 0, 0, 0, 0, 0, + 0, 102, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, + 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, + 0, 0, 0, 0, 106, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 109, 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, 103, 0, 0, 0, 0, 0, + 133, 0, 0, 0, 0, 0, 0, 0, 134, 0, 135, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 136, 137, 0, 0, 0, 0, 0, 0, 0, 0, 138, 139, + 0, 0, 0, 0, 0, 140, 141, 0, 34, 142, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 143, 0, 0, 0, 0, 0, 0, 34, 142, + 34, 35, 144, 145, 146, 147, 148, 149, 0, 0, 0, 0, 48, 49, 50, 150, + 151, 152, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, + 8, 9, 49, 153, 35, 154, 2, 155, 156, 157, 9, 158, 159, 158, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 0, 0, 0, 0, 0, 0, 0, + 34, 35, 144, 145, 171, 0, 0, 0, 0, 0, 0, 7, 8, 9, 1, 2, + 172, 8, 9, 1, 2, 172, 8, 9, 173, 49, 174, 0, 0, 0, 0, 0, + 70, 0, 0, 0, 0, 0, 0, 0, 0, 175, 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, 176, 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, 177, 0, 0, 0, 0, 0, 0, 0, 0, 178, 0, 0, 0, +}; + +static RE_UINT8 re_numeric_value_stage_5[] = { + 0, 0, 0, 0, 2, 23, 25, 27, 29, 31, 33, 35, 37, 39, 0, 0, + 0, 0, 25, 27, 0, 23, 0, 0, 11, 15, 19, 0, 0, 0, 2, 23, + 25, 27, 29, 31, 33, 35, 37, 39, 3, 6, 9, 11, 19, 46, 0, 0, + 0, 0, 11, 15, 19, 3, 6, 9, 40, 85, 94, 0, 23, 25, 27, 0, + 40, 85, 94, 11, 15, 19, 0, 0, 37, 39, 15, 24, 26, 28, 30, 32, + 34, 36, 38, 1, 0, 23, 25, 27, 37, 39, 40, 50, 60, 70, 80, 81, + 82, 83, 84, 85, 103, 0, 0, 0, 0, 0, 47, 48, 49, 0, 0, 0, + 37, 39, 23, 0, 2, 0, 0, 0, 7, 5, 4, 12, 18, 10, 14, 16, + 20, 8, 21, 6, 13, 17, 22, 23, 23, 25, 27, 29, 31, 33, 35, 37, + 39, 40, 41, 42, 80, 85, 89, 94, 94, 98, 103, 0, 0, 33, 80, 107, + 112, 2, 0, 0, 43, 44, 45, 46, 47, 48, 49, 50, 0, 0, 2, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 23, 25, 27, 37, 39, 40, 2, + 0, 0, 23, 25, 27, 29, 31, 33, 35, 37, 39, 40, 39, 40, 23, 25, + 0, 15, 0, 0, 0, 0, 0, 2, 40, 50, 60, 0, 27, 29, 0, 0, + 39, 40, 0, 0, 40, 50, 60, 70, 80, 81, 82, 83, 0, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 0, 31, 0, 0, + 0, 0, 0, 25, 0, 0, 31, 0, 0, 35, 0, 0, 23, 0, 0, 35, + 0, 0, 0, 103, 0, 27, 0, 0, 0, 39, 0, 0, 25, 0, 0, 0, + 31, 0, 29, 0, 0, 0, 0, 115, 40, 0, 0, 0, 0, 0, 0, 94, + 27, 0, 0, 0, 85, 0, 0, 0, 115, 0, 0, 0, 0, 0, 116, 0, + 0, 25, 0, 37, 0, 33, 0, 0, 0, 40, 0, 94, 50, 60, 0, 0, + 70, 0, 0, 0, 0, 27, 27, 27, 0, 0, 0, 29, 0, 0, 23, 0, + 0, 0, 39, 50, 0, 0, 40, 0, 37, 0, 0, 0, 0, 0, 35, 0, + 0, 0, 39, 0, 0, 0, 85, 0, 0, 0, 29, 0, 0, 0, 25, 0, + 0, 94, 0, 0, 0, 0, 33, 0, 33, 0, 0, 0, 0, 0, 2, 0, + 35, 37, 39, 2, 11, 15, 19, 3, 6, 9, 0, 0, 0, 0, 0, 27, + 0, 0, 0, 40, 0, 33, 0, 33, 0, 40, 0, 0, 0, 0, 0, 23, + 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, 11, 15, 23, 31, + 80, 89, 98, 107, 31, 40, 80, 85, 89, 94, 98, 31, 40, 80, 85, 89, + 94, 103, 107, 40, 23, 23, 23, 25, 25, 25, 25, 31, 40, 40, 40, 40, + 40, 60, 80, 80, 80, 80, 85, 87, 89, 89, 89, 89, 80, 15, 15, 18, + 19, 0, 0, 0, 23, 31, 40, 80, 0, 84, 0, 0, 0, 0, 93, 0, + 0, 23, 25, 40, 50, 85, 0, 0, 23, 25, 27, 40, 50, 85, 94, 103, + 0, 0, 23, 40, 50, 85, 25, 27, 40, 50, 85, 94, 0, 23, 80, 0, + 39, 40, 50, 60, 70, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 15, 11, 12, 18, 0, 50, 60, 70, 80, 81, 82, 83, 84, + 85, 94, 2, 23, 35, 37, 39, 29, 39, 23, 25, 27, 37, 39, 23, 25, + 27, 29, 31, 25, 27, 27, 29, 31, 23, 25, 27, 27, 29, 31, 113, 114, + 29, 31, 27, 27, 29, 29, 29, 29, 33, 35, 35, 35, 37, 37, 39, 39, + 39, 39, 25, 27, 29, 31, 33, 23, 25, 27, 29, 29, 31, 31, 25, 27, + 23, 25, 12, 18, 21, 12, 18, 6, 11, 8, 11, 0, 83, 84, 0, 0, + 37, 39, 2, 23, 2, 2, 23, 25, 35, 37, 39, 0, 29, 0, 0, 0, + 0, 0, 0, 60, 0, 29, 0, 0, 39, 0, 0, 0, +}; + +/* Numeric_Value: 2876 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_Matra_Category. */ + +static RE_UINT8 re_indic_matra_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_matra_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, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static RE_UINT8 re_indic_matra_category_stage_3[] = { + 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, 5, 6, 7, 4, 0, + 0, 0, 0, 5, 8, 0, 0, 0, 0, 0, 0, 5, 9, 0, 4, 0, + 0, 0, 0, 10, 11, 12, 4, 0, 0, 0, 0, 13, 14, 7, 0, 0, + 0, 0, 0, 15, 16, 17, 4, 0, 0, 0, 0, 10, 18, 19, 4, 0, + 0, 0, 0, 13, 20, 7, 4, 0, 0, 0, 0, 0, 21, 22, 0, 23, + 0, 0, 0, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 28, 29, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 30, 31, 0, 32, 33, 34, 35, 36, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 37, 0, 38, 0, 38, 0, 0, 0, 39, 40, 41, 0, 0, + 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, + 0, 45, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 48, 49, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 23, + 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 52, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 54, 55, 0, 0, 0, + 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 58, 59, 0, 0, 0, + 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 63, 64, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, + 66, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 68, 69, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, + 0, 0, 71, 72, 0, 0, 0, 0, 0, 0, 0, 73, 44, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 69, 0, 0, 0, 0, +}; + +static RE_UINT8 re_indic_matra_category_stage_4[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, + 3, 4, 5, 6, 1, 7, 3, 8, 0, 0, 9, 4, 0, 0, 0, 0, + 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 3, 4, 10, 11, 12, 13, 14, 0, 0, 0, 0, 15, 0, 0, 0, 0, + 3, 10, 0, 9, 16, 9, 17, 0, 3, 4, 5, 9, 18, 15, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 3, 4, 10, 11, 20, 13, 21, 0, + 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 17, 10, 0, 22, 12, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 6, + 1, 7, 25, 6, 26, 6, 6, 0, 0, 0, 9, 10, 0, 0, 0, 0, + 27, 7, 25, 18, 28, 29, 6, 0, 0, 0, 15, 25, 0, 0, 0, 0, + 7, 3, 10, 22, 12, 23, 24, 0, 0, 0, 0, 0, 0, 16, 0, 15, + 7, 6, 10, 10, 2, 30, 23, 31, 0, 7, 0, 0, 0, 0, 0, 0, + 19, 7, 6, 6, 4, 10, 0, 0, 32, 32, 33, 9, 0, 0, 0, 16, + 19, 7, 6, 6, 4, 9, 0, 0, 32, 32, 34, 0, 0, 0, 0, 0, + 35, 36, 4, 37, 37, 6, 6, 0, 36, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 15, 19, 17, 38, 6, 6, 0, 39, 16, 0, 0, + 0, 0, 0, 7, 4, 0, 0, 0, 0, 25, 0, 15, 25, 0, 0, 0, + 9, 6, 16, 0, 0, 0, 0, 0, 0, 15, 40, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 19, 0, 0, 17, 10, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 6, 17, 4, 41, + 42, 22, 23, 0, 25, 0, 0, 0, 9, 43, 0, 0, 0, 0, 0, 0, + 6, 44, 45, 46, 16, 0, 0, 0, 7, 7, 2, 22, 7, 8, 7, 7, + 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 38, 2, 0, 0, + 47, 1, 19, 6, 17, 5, 44, 22, 22, 40, 16, 0, 0, 0, 0, 0, + 0, 0, 15, 6, 4, 48, 49, 22, 23, 18, 25, 0, 0, 0, 0, 0, + 0, 0, 17, 8, 6, 25, 0, 0, 0, 0, 0, 2, 50, 7, 10, 0, + 0, 0, 0, 16, 0, 0, 0, 0, 0, 15, 3, 1, 0, 0, 0, 0, + 0, 0, 15, 7, 7, 7, 7, 7, 7, 7, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 35, 4, 17, 4, 10, 0, 15, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 6, 4, 22, 16, 0, 51, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 6, 17, 52, 40, 10, 0, 0, 0, 0, 0, 0, + 1, 6, 53, 54, 55, 56, 33, 16, 0, 0, 0, 0, 0, 11, 5, 8, + 0, 0, 0, 43, 0, 0, 0, 0, 0, 15, 19, 7, 44, 25, 35, 0, + 57, 4, 9, 58, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 39, + 0, 0, 0, 0, 6, 6, 4, 4, 4, 6, 6, 16, 0, 0, 0, 0, + 2, 3, 5, 1, 3, 0, 0, 0, 0, 0, 0, 9, 6, 4, 40, 37, + 17, 59, 16, 0, 0, 0, 0, 0, 0, 15, 8, 4, 4, 4, 6, 18, + 0, 0, 0, 0, 0, 0, 9, 8, +}; + +static RE_UINT8 re_indic_matra_category_stage_5[] = { + 0, 0, 5, 1, 1, 2, 1, 6, 6, 6, 6, 5, 5, 5, 1, 1, + 2, 1, 0, 5, 6, 0, 0, 2, 2, 0, 0, 4, 4, 6, 0, 1, + 5, 0, 5, 6, 5, 8, 1, 5, 9, 0, 10, 6, 2, 2, 4, 4, + 4, 5, 1, 0, 7, 0, 8, 1, 8, 0, 8, 8, 9, 2, 4, 1, + 3, 3, 3, 1, 3, 0, 0, 6, 5, 7, 7, 7, 6, 2, 0, 14, + 2, 5, 9, 10, 4, 2, 14, 0, 6, 1, 1, 8, 8, 5, 14, 1, + 6, 11, 7, 12, 2, 9, 11, 0, 5, 2, 6, 3, 3, 5, 5, 3, + 1, 3, 0, 13, 13, 0, 6, 14, +}; + +/* Indic_Matra_Category: 1336 bytes. */ + +RE_UINT32 re_get_indic_matra_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_matra_category_stage_1[f] << 5; + f = code >> 8; + code ^= f << 8; + pos = (RE_UINT32)re_indic_matra_category_stage_2[pos + f] << 4; + f = code >> 4; + code ^= f << 4; + pos = (RE_UINT32)re_indic_matra_category_stage_3[pos + f] << 3; + f = code >> 1; + code ^= f << 1; + pos = (RE_UINT32)re_indic_matra_category_stage_4[pos + f] << 1; + value = re_indic_matra_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, + 1, 1, 1, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 16, 17, 18, 19, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 1, 1, 1, 1, 1, + 21, 22, 1, 1, 1, 1, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +static RE_UINT8 re_indic_syllabic_category_stage_3[] = { + 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, 0, 0, 0, 0, 0, 0, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 8, 16, + 17, 11, 12, 18, 19, 20, 0, 21, 22, 23, 12, 24, 25, 0, 8, 0, + 10, 11, 12, 24, 26, 27, 8, 28, 29, 30, 31, 32, 33, 34, 0, 0, + 35, 36, 12, 37, 38, 39, 8, 0, 40, 36, 12, 41, 38, 42, 8, 0, + 40, 36, 4, 43, 44, 34, 8, 45, 46, 47, 4, 48, 49, 50, 0, 51, + 52, 4, 53, 54, 55, 0, 0, 0, 56, 57, 58, 59, 60, 61, 0, 0, + 0, 0, 0, 0, 62, 4, 63, 64, 65, 66, 67, 68, 0, 0, 0, 0, + 4, 4, 69, 70, 0, 71, 72, 73, 74, 75, 0, 0, 0, 0, 0, 0, + 76, 77, 78, 77, 78, 79, 76, 80, 4, 4, 81, 82, 83, 84, 0, 0, + 85, 63, 86, 87, 0, 4, 88, 89, 4, 4, 90, 91, 92, 0, 0, 0, + 4, 93, 4, 4, 94, 95, 96, 97, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 78, 4, 99, 100, 0, 0, 0, 101, 4, 102, 103, 4, 4, 104, 105, + 4, 4, 106, 107, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, + 111, 4, 112, 0, 4, 113, 114, 115, 116, 117, 4, 118, 119, 0, 0, 0, + 120, 4, 121, 4, 122, 123, 0, 0, 124, 4, 4, 125, 126, 0, 0, 0, + 127, 4, 128, 129, 130, 0, 4, 131, 4, 4, 4, 132, 133, 0, 134, 135, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 137, 138, 0, + 139, 140, 4, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 142, 78, 4, 143, 144, 0, 0, 0, 145, 4, 4, 146, 0, 0, 0, 0, + 147, 4, 148, 149, 0, 0, 0, 0, 150, 151, 4, 152, 153, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 154, 4, 155, 156, 0, 0, 0, 0, +}; + +static RE_UINT8 re_indic_syllabic_category_stage_4[] = { + 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 3, 3, 3, 4, 5, 5, + 5, 5, 5, 5, 5, 5, 6, 7, 8, 8, 8, 9, 0, 10, 5, 5, + 11, 0, 0, 0, 12, 3, 13, 5, 14, 15, 3, 16, 16, 4, 5, 5, + 5, 5, 17, 5, 18, 19, 20, 7, 8, 21, 21, 22, 0, 23, 0, 24, + 20, 0, 0, 0, 14, 15, 25, 26, 17, 27, 20, 28, 29, 23, 21, 30, + 0, 0, 13, 18, 31, 32, 0, 0, 14, 15, 3, 33, 33, 4, 5, 5, + 17, 13, 20, 7, 8, 34, 34, 30, 8, 21, 21, 30, 0, 35, 0, 24, + 36, 0, 0, 0, 37, 15, 25, 12, 38, 39, 27, 17, 40, 41, 42, 19, + 5, 5, 20, 35, 29, 35, 43, 30, 0, 23, 0, 0, 14, 15, 3, 38, + 38, 4, 5, 5, 5, 13, 20, 44, 8, 43, 43, 30, 0, 45, 20, 0, + 46, 15, 3, 38, 5, 13, 20, 7, 0, 45, 0, 47, 5, 5, 42, 44, + 8, 43, 43, 48, 0, 0, 49, 50, 46, 15, 3, 3, 3, 25, 19, 5, + 24, 5, 5, 36, 5, 42, 51, 23, 8, 52, 8, 8, 35, 0, 0, 0, + 13, 5, 5, 5, 5, 5, 5, 42, 8, 8, 53, 0, 8, 34, 54, 55, + 27, 56, 18, 36, 0, 5, 13, 5, 13, 57, 19, 27, 8, 8, 34, 58, + 8, 59, 54, 60, 0, 0, 0, 20, 5, 5, 13, 5, 5, 5, 5, 41, + 10, 8, 8, 61, 62, 63, 64, 65, 66, 66, 67, 66, 66, 66, 66, 66, + 66, 66, 66, 68, 69, 3, 70, 8, 8, 71, 72, 73, 74, 11, 75, 76, + 77, 78, 79, 80, 81, 82, 5, 5, 83, 84, 54, 85, 0, 0, 86, 87, + 88, 5, 5, 17, 6, 89, 0, 0, 88, 5, 5, 5, 6, 0, 0, 0, + 90, 0, 0, 0, 91, 3, 3, 3, 3, 35, 8, 8, 8, 61, 92, 93, + 94, 0, 0, 95, 96, 5, 5, 5, 8, 8, 97, 0, 98, 99, 100, 0, + 101, 102, 102, 103, 104, 105, 0, 0, 5, 5, 5, 0, 8, 8, 8, 8, + 106, 99, 107, 0, 5, 108, 8, 0, 5, 5, 5, 69, 88, 109, 99, 110, + 111, 8, 8, 8, 8, 79, 107, 0, 112, 113, 3, 3, 5, 114, 8, 8, + 8, 115, 5, 0, 116, 3, 117, 5, 118, 8, 119, 120, 0, 0, 121, 122, + 5, 123, 8, 8, 124, 0, 0, 0, 5, 125, 8, 106, 99, 126, 0, 0, + 0, 0, 0, 13, 127, 0, 0, 0, 0, 0, 0, 1, 33, 128, 129, 5, + 108, 8, 0, 0, 5, 5, 5, 130, 131, 132, 133, 5, 134, 0, 0, 0, + 135, 3, 3, 3, 117, 5, 5, 5, 5, 136, 8, 8, 8, 89, 0, 0, + 0, 0, 19, 5, 130, 102, 137, 107, 5, 108, 8, 138, 139, 0, 0, 0, + 140, 3, 4, 88, 141, 8, 8, 142, 89, 0, 0, 0, 3, 117, 5, 5, + 5, 5, 81, 8, 143, 144, 0, 0, 99, 99, 99, 145, 13, 0, 146, 0, + 8, 8, 8, 84, 147, 0, 0, 0, 117, 5, 108, 8, 0, 148, 0, 0, + 5, 5, 5, 74, 149, 5, 150, 99, 151, 8, 29, 152, 81, 45, 0, 153, + 5, 13, 13, 5, 5, 0, 0, 154, 155, 15, 3, 3, 5, 5, 8, 8, + 8, 53, 0, 0, 156, 3, 3, 4, 8, 8, 157, 0, 156, 88, 5, 5, + 5, 108, 8, 8, 158, 89, 0, 0, 156, 3, 3, 3, 4, 5, 5, 5, + 108, 8, 8, 8, 63, 0, 0, 0, 3, 3, 117, 5, 5, 5, 129, 159, + 8, 160, 0, 0, +}; + +static RE_UINT8 re_indic_syllabic_category_stage_5[] = { + 0, 0, 0, 0, 9, 0, 0, 0, 1, 1, 1, 2, 6, 6, 6, 6, + 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 7, 4, 3, 7, 7, + 7, 7, 7, 7, 7, 5, 7, 7, 0, 7, 7, 7, 6, 6, 7, 7, + 0, 0, 6, 6, 0, 10, 10, 10, 0, 1, 1, 2, 0, 6, 6, 6, + 6, 0, 0, 6, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 10, 10, + 10, 10, 0, 0, 7, 0, 0, 7, 7, 5, 11, 0, 0, 0, 0, 7, + 10, 10, 0, 10, 6, 6, 6, 0, 0, 0, 0, 6, 0, 10, 10, 0, + 4, 0, 7, 7, 7, 7, 7, 0, 7, 5, 0, 0, 1, 0, 9, 9, + 0, 14, 0, 0, 6, 6, 0, 6, 7, 7, 0, 7, 0, 0, 7, 7, + 0, 10, 0, 0, 0, 0, 1, 17, 6, 0, 6, 6, 6, 10, 0, 0, + 0, 0, 0, 10, 10, 0, 0, 0, 10, 10, 10, 0, 7, 0, 7, 7, + 0, 3, 7, 7, 0, 7, 7, 0, 0, 0, 1, 2, 0, 0, 10, 0, + 7, 5, 12, 0, 0, 0, 11, 11, 11, 11, 11, 11, 0, 0, 5, 0, + 7, 0, 7, 0, 7, 7, 5, 0, 19, 19, 19, 19, 0, 1, 5, 0, + 10, 0, 0, 10, 0, 10, 0, 10, 14, 14, 0, 0, 7, 0, 0, 0, + 0, 1, 0, 0, 7, 7, 1, 2, 7, 7, 1, 1, 5, 3, 0, 0, + 16, 16, 16, 16, 16, 13, 13, 13, 13, 13, 13, 13, 0, 13, 13, 13, + 13, 0, 0, 0, 10, 6, 6, 6, 6, 6, 6, 7, 7, 7, 1, 19, + 2, 5, 5, 14, 14, 14, 14, 10, 10, 10, 6, 6, 7, 7, 10, 10, + 10, 10, 14, 14, 14, 10, 7, 19, 19, 10, 10, 7, 7, 19, 19, 19, + 19, 19, 10, 10, 10, 7, 7, 7, 7, 10, 10, 10, 10, 10, 14, 7, + 7, 7, 7, 19, 19, 19, 10, 19, 0, 0, 19, 19, 7, 7, 0, 0, + 6, 6, 6, 10, 5, 0, 0, 0, 10, 0, 7, 7, 10, 10, 10, 6, + 7, 20, 20, 0, 12, 0, 0, 0, 0, 5, 5, 0, 3, 0, 0, 0, + 9, 10, 10, 10, 7, 13, 13, 13, 15, 15, 1, 15, 15, 15, 15, 15, + 15, 0, 0, 0, 10, 10, 10, 8, 8, 8, 8, 8, 8, 8, 0, 0, + 18, 18, 18, 18, 18, 0, 0, 0, 7, 15, 15, 15, 19, 19, 0, 0, + 10, 10, 10, 7, 10, 14, 14, 15, 15, 15, 15, 0, 5, 7, 7, 7, + 1, 1, 1, 12, 2, 6, 6, 6, 4, 7, 7, 7, 5, 10, 10, 10, + 1, 12, 2, 6, 6, 6, 10, 10, 10, 13, 13, 13, 7, 7, 5, 5, + 13, 13, 10, 10, 0, 0, 3, 10, 10, 10, 15, 15, 6, 6, 4, 7, + 15, 15, 5, 5, 13, 13, 7, 7, 1, 1, 0, 4, 0, 0, 2, 2, + 6, 6, 5, 10, 10, 10, 10, 1, 10, 10, 8, 8, 8, 8, 10, 10, + 10, 10, 8, 13, 13, 10, 10, 10, 10, 13, 10, 1, 1, 2, 6, 6, + 15, 7, 7, 7, 8, 8, 8, 19, 7, 7, 7, 15, 15, 15, 15, 5, + 1, 1, 12, 2, 10, 10, 10, 4, 7, 13, 14, 14, 7, 7, 7, 14, + 14, 14, 14, 0, 15, 15, 0, 0, 0, 0, 10, 19, 18, 19, 18, 0, + 0, 2, 5, 0, 10, 6, 10, 10, 10, 10, 10, 15, 15, 15, 15, 7, + 19, 5, 0, 0, 7, 0, 1, 2, 0, 0, 0, 5, 1, 1, 2, 0, + 1, 1, 2, 6, 7, 5, 4, 0, 7, 7, 7, 5, 2, 7, 7, 7, + 7, 7, 5, 4, +}; + +/* Indic_Syllabic_Category: 1952 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 13, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 24, 7, 25, 26, 13, 13, 13, 13, 13, 13, 13, 27, + 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, 31, 31, 31, + 58, 59, 60, 61, 62, 31, 31, 31, 63, 64, 31, 31, 31, 31, 65, 31, + 1, 1, 1, 66, 67, 31, 31, 31, 1, 1, 1, 1, 68, 31, 31, 31, + 1, 1, 69, 31, 31, 31, 31, 70, 71, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 72, 73, 74, 75, 31, 31, 31, 31, 31, 31, 76, 31, + 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, 1, 1, 1, 1, 78, + 79, 31, 31, 31, 31, 31, 31, 31, 1, 1, 79, 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, 38, 47, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 49, 59, 57, 60, 61, 59, 62, 63, 64, 65, 66, 67, 68, + 16, 69, 70, 0, 71, 72, 73, 0, 74, 75, 76, 77, 78, 79, 0, 0, + 5, 80, 81, 82, 83, 5, 84, 85, 5, 5, 86, 5, 87, 88, 89, 5, + 90, 5, 91, 0, 92, 5, 5, 93, 16, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 94, 2, 5, 5, 95, 96, 97, 97, 98, 5, 99, 100, 75, + 1, 5, 5, 101, 5, 102, 5, 103, 79, 104, 105, 106, 5, 107, 108, 0, + 109, 5, 110, 111, 108, 112, 0, 0, 5, 113, 114, 0, 5, 115, 5, 116, + 5, 103, 117, 118, 0, 0, 0, 119, 5, 5, 5, 5, 5, 5, 0, 0, + 120, 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, 75, 5, 132, 110, 5, 5, 5, 5, 133, + 5, 84, 5, 134, 135, 136, 136, 5, 0, 137, 0, 0, 0, 0, 0, 0, + 138, 139, 16, 5, 140, 16, 5, 85, 141, 142, 5, 5, 143, 69, 0, 26, + 5, 5, 5, 5, 5, 103, 0, 0, 5, 5, 5, 5, 5, 5, 31, 0, + 5, 5, 5, 5, 31, 0, 26, 118, 144, 145, 5, 146, 147, 5, 5, 92, + 148, 149, 5, 5, 150, 151, 0, 152, 153, 17, 5, 97, 5, 5, 154, 155, + 5, 102, 156, 79, 5, 157, 158, 0, 5, 135, 159, 160, 5, 110, 161, 162, + 163, 164, 0, 0, 0, 0, 5, 165, 5, 5, 5, 5, 5, 166, 167, 109, + 5, 5, 5, 168, 5, 5, 169, 0, 170, 171, 172, 5, 5, 28, 173, 5, + 5, 118, 26, 5, 174, 5, 17, 175, 0, 0, 0, 176, 5, 5, 5, 79, + 1, 2, 2, 105, 5, 110, 177, 0, 178, 179, 180, 0, 5, 5, 5, 69, + 0, 0, 5, 93, 0, 0, 0, 0, 0, 0, 0, 0, 79, 5, 181, 0, + 110, 26, 151, 0, 118, 5, 182, 0, 5, 5, 5, 5, 118, 75, 0, 0, + 183, 184, 103, 0, 0, 0, 0, 0, 103, 169, 0, 0, 5, 185, 0, 0, + 186, 97, 0, 79, 0, 0, 0, 0, 5, 103, 103, 156, 0, 0, 0, 0, + 5, 5, 130, 0, 0, 0, 0, 0, 5, 5, 187, 55, 149, 32, 26, 188, + 5, 189, 0, 0, 5, 5, 190, 0, 0, 0, 0, 0, 5, 103, 75, 0, + 5, 5, 5, 143, 0, 0, 0, 0, 5, 5, 5, 191, 0, 0, 0, 0, + 5, 143, 0, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 0, 0, 0, + 5, 5, 192, 110, 173, 0, 0, 0, 193, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 194, 5, 195, 196, 197, 5, 198, 199, 200, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 201, 202, 85, 194, 194, 132, 132, 203, 203, 204, 5, + 197, 205, 206, 207, 208, 209, 0, 0, 5, 5, 5, 5, 5, 5, 135, 0, + 5, 93, 5, 5, 5, 5, 5, 5, 118, 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, 60, 64, 215, 255, 255, 251, 255, 255, 255, + 255, 255, 191, 255, 3, 252, 255, 255, 255, 0, 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, 253, 31, 0, 0, 240, 3, 255, 127, 255, 255, 255, 239, + 255, 223, 225, 255, 207, 255, 254, 254, 238, 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, 0, 159, 25, 192, 176, 207, 255, 2, 0, + 236, 199, 61, 214, 24, 199, 255, 195, 199, 29, 129, 0, 192, 255, 0, 0, + 238, 223, 253, 255, 255, 253, 239, 227, 223, 29, 96, 3, 236, 223, 253, 255, + 223, 29, 96, 64, 207, 255, 6, 0, 255, 255, 255, 231, 223, 93, 128, 0, + 207, 255, 0, 252, 236, 255, 127, 252, 255, 255, 251, 47, 127, 128, 95, 255, + 0, 0, 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, 31, 0, 255, 159, 255, 255, 255, 199, 1, 0, + 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, 15, 255, 1, 192, 255, 255, 255, 255, 63, 31, 0, 255, 15, 255, 255, + 255, 3, 255, 3, 255, 255, 255, 15, 255, 255, 255, 127, 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, + 255, 255, 63, 63, 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, 255, 255, 255, 128, + 0, 0, 128, 255, 252, 255, 255, 255, 255, 121, 15, 0, 255, 7, 0, 0, + 0, 0, 0, 255, 187, 247, 255, 255, 15, 0, 255, 3, 0, 0, 252, 8, + 255, 255, 7, 0, 255, 255, 247, 255, 0, 128, 255, 3, 255, 63, 255, 3, + 255, 255, 127, 4, 5, 0, 0, 56, 255, 255, 60, 0, 126, 126, 126, 0, + 127, 127, 0, 0, 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, 63, 253, 255, 255, + 255, 255, 191, 145, 255, 255, 255, 192, 111, 240, 239, 254, 63, 0, 0, 0, + 255, 1, 255, 3, 255, 255, 199, 255, 30, 0, 255, 3, 7, 0, 0, 0, + 31, 0, 255, 255, 3, 0, 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, 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: 1849 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 24, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 25, 7, 26, 27, 13, 13, 13, 13, 13, 13, 13, 28, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 29, 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, 30, +}; + +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, 30, 1, 1, 1, 31, 32, 33, 34, 35, + 36, 37, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40, + 1, 1, 1, 1, 41, 1, 42, 43, 44, 45, 46, 47, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 48, 49, 49, 49, 49, 49, 49, 49, 49, + 1, 1, 50, 51, 1, 52, 53, 54, 55, 56, 57, 58, 59, 49, 49, 49, + 60, 61, 62, 63, 64, 49, 65, 49, 66, 67, 49, 49, 49, 49, 68, 49, + 1, 1, 1, 69, 70, 49, 49, 49, 1, 1, 1, 1, 71, 49, 49, 49, + 1, 1, 72, 49, 49, 49, 49, 73, 74, 49, 49, 49, 49, 49, 49, 49, + 75, 76, 77, 78, 79, 80, 81, 82, 49, 49, 49, 49, 49, 49, 83, 49, + 84, 85, 86, 87, 88, 89, 90, 91, 1, 1, 1, 1, 1, 1, 92, 1, + 1, 1, 1, 1, 1, 1, 1, 93, 94, 49, 49, 49, 49, 49, 49, 49, + 1, 1, 94, 49, 49, 49, 49, 49, 95, 96, 49, 49, 49, 49, 49, 49, + 1, 1, 1, 1, 1, 1, 1, 97, +}; + +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, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 22, 31, 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, 21, 62, 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, + 70, 85, 86, 87, 2, 88, 89, 2, 90, 2, 3, 91, 80, 92, 0, 0, + 2, 2, 88, 70, 2, 2, 2, 93, 2, 94, 95, 2, 0, 0, 10, 76, + 2, 2, 2, 2, 2, 2, 2, 96, 97, 2, 98, 79, 2, 99, 100, 101, + 102, 103, 3, 104, 105, 16, 106, 74, 2, 2, 2, 2, 107, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 77, 2, 108, 109, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 110, 0, 0, 0, 0, 0, + 2, 111, 3, 2, 2, 2, 2, 112, 2, 64, 2, 113, 76, 114, 114, 2, + 2, 56, 0, 0, 115, 2, 2, 77, 2, 2, 2, 2, 2, 2, 84, 116, + 1, 2, 1, 2, 8, 2, 2, 2, 117, 118, 2, 2, 111, 16, 2, 119, + 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 84, 2, 2, + 2, 2, 2, 2, 2, 2, 120, 0, 2, 2, 2, 2, 121, 2, 122, 2, + 2, 123, 2, 2, 124, 2, 2, 82, 2, 2, 2, 2, 125, 109, 0, 126, + 2, 127, 2, 82, 2, 2, 128, 56, 2, 2, 129, 70, 2, 2, 130, 0, + 2, 76, 131, 56, 2, 2, 132, 76, 133, 134, 0, 0, 0, 0, 2, 135, + 2, 2, 2, 2, 2, 119, 136, 56, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 137, 2, 2, 71, 0, 138, 139, 140, 2, 2, 2, 141, 2, + 2, 2, 106, 2, 142, 2, 143, 144, 71, 122, 145, 146, 2, 2, 2, 91, + 1, 2, 2, 2, 2, 3, 147, 148, 149, 150, 151, 0, 2, 2, 2, 16, + 152, 153, 2, 2, 154, 0, 106, 79, 0, 0, 0, 0, 70, 2, 74, 0, + 3, 119, 109, 0, 155, 2, 156, 0, 2, 2, 2, 2, 79, 157, 0, 0, + 158, 159, 160, 0, 0, 0, 0, 0, 161, 162, 0, 0, 2, 163, 0, 0, + 164, 165, 166, 2, 0, 0, 0, 0, 2, 167, 168, 169, 0, 0, 0, 0, + 2, 2, 170, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 2, 2, 171, 172, 2, 2, 173, 174, 2, 99, 175, 0, 2, 2, 174, 0, + 0, 0, 0, 0, 2, 82, 157, 0, 2, 2, 2, 176, 0, 0, 0, 0, + 2, 2, 2, 177, 0, 0, 0, 0, 2, 176, 0, 0, 0, 0, 0, 0, + 2, 178, 0, 0, 0, 0, 0, 0, 2, 2, 179, 3, 180, 0, 0, 0, + 181, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 84, + 2, 182, 2, 2, 2, 2, 79, 0, 2, 2, 183, 0, 0, 0, 0, 0, + 2, 2, 76, 15, 0, 0, 0, 0, 2, 2, 99, 2, 62, 184, 185, 2, + 186, 187, 188, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 189, 2, 2, + 2, 2, 2, 2, 2, 2, 190, 2, 185, 191, 192, 193, 194, 195, 0, 196, + 2, 88, 2, 2, 77, 197, 198, 0, 83, 111, 2, 88, 16, 0, 0, 199, + 200, 16, 201, 0, 0, 0, 0, 0, 2, 202, 2, 70, 77, 2, 203, 74, + 2, 3, 204, 2, 2, 2, 2, 205, 2, 79, 119, 143, 0, 0, 0, 206, + 2, 2, 207, 0, 2, 2, 183, 0, 2, 2, 2, 77, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 76, 0, 2, 72, 2, 2, 2, 2, 2, 2, + 79, 0, 0, 0, 0, 0, 0, 0, 208, 2, 2, 2, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 172, 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, 124, 240, 215, 255, 255, 251, 255, 255, 255, 255, 0, 254, 255, + 255, 255, 127, 254, 255, 134, 254, 255, 255, 0, 255, 255, 255, 7, 31, 0, + 223, 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, 253, 31, 0, 0, + 240, 255, 255, 127, 255, 255, 255, 254, 238, 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, 0, 159, 57, 192, 176, 207, 255, 255, 0, + 236, 199, 61, 214, 24, 199, 255, 195, 199, 61, 129, 0, 192, 255, 255, 7, + 238, 223, 253, 255, 255, 253, 239, 227, 223, 61, 96, 3, 207, 255, 0, 255, + 236, 223, 253, 255, 255, 253, 239, 243, 223, 61, 96, 64, 207, 255, 6, 0, + 255, 255, 255, 231, 223, 125, 128, 0, 207, 255, 63, 254, 236, 255, 127, 252, + 255, 255, 251, 47, 127, 132, 95, 255, 0, 0, 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, 223, 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, 31, 0, 254, 255, 255, 31, 255, 255, 1, 0, 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, 63, 0, 0, 255, 255, 15, 240, 255, 255, 255, 248, 255, 227, 255, 255, + 127, 0, 0, 240, 255, 255, 63, 63, 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, 3, 255, 255, + 127, 0, 0, 0, 255, 7, 0, 0, 255, 31, 255, 3, 255, 127, 255, 255, + 255, 255, 15, 254, 255, 128, 1, 128, 127, 127, 127, 127, 255, 255, 255, 251, + 0, 0, 255, 15, 224, 255, 255, 255, 255, 63, 254, 255, 15, 0, 255, 255, + 255, 31, 0, 0, 255, 31, 255, 255, 127, 0, 255, 255, 255, 15, 0, 0, + 255, 255, 255, 128, 255, 127, 15, 0, 0, 0, 0, 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, 0, 0, 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, 7, 255, 15, 255, 255, 255, 191, + 15, 255, 63, 0, 255, 3, 0, 0, 63, 253, 255, 255, 255, 255, 191, 145, + 255, 255, 191, 255, 255, 255, 255, 143, 255, 255, 255, 131, 255, 255, 255, 192, + 111, 240, 239, 254, 255, 255, 15, 135, 255, 0, 255, 1, 255, 255, 63, 254, + 255, 255, 63, 255, 255, 255, 7, 255, 255, 1, 0, 0, 255, 63, 252, 255, + 255, 255, 0, 0, 3, 0, 255, 255, 255, 1, 255, 3, 15, 0, 0, 0, + 255, 127, 0, 0, 7, 0, 15, 0, 255, 255, 255, 1, 31, 0, 255, 255, + 0, 128, 255, 255, 3, 0, 0, 0, 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, 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, 127, 254, 255, 254, 255, 192, 255, 255, 255, + 7, 0, 255, 255, 255, 1, 3, 0, 1, 0, 191, 255, 223, 7, 0, 0, + 253, 255, 255, 255, 255, 255, 255, 30, 0, 0, 0, 248, 225, 255, 0, 0, + 2, 0, 0, 0, +}; + +/* Graph: 2046 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 24, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 25, 7, 26, 27, 13, 13, 13, 13, 13, 13, 13, 28, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 29, 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, 30, +}; + +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, 30, 1, 1, 1, 31, 32, 33, 34, 35, + 36, 37, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40, + 1, 1, 1, 1, 41, 1, 42, 43, 44, 45, 46, 47, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 48, 49, 49, 49, 49, 49, 49, 49, 49, + 1, 1, 50, 51, 1, 52, 53, 54, 55, 56, 57, 58, 59, 49, 49, 49, + 60, 61, 62, 63, 64, 49, 65, 49, 66, 67, 49, 49, 49, 49, 68, 49, + 1, 1, 1, 69, 70, 49, 49, 49, 1, 1, 1, 1, 71, 49, 49, 49, + 1, 1, 72, 49, 49, 49, 49, 73, 74, 49, 49, 49, 49, 49, 49, 49, + 75, 76, 77, 78, 79, 80, 81, 82, 49, 49, 49, 49, 49, 49, 83, 49, + 84, 85, 86, 87, 88, 89, 90, 91, 1, 1, 1, 1, 1, 1, 92, 1, + 1, 1, 1, 1, 1, 1, 1, 93, 94, 49, 49, 49, 49, 49, 49, 49, + 1, 1, 94, 49, 49, 49, 49, 49, 95, 96, 49, 49, 49, 49, 49, 49, + 1, 1, 1, 1, 1, 1, 1, 97, +}; + +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, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 22, 31, 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, 21, 62, 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, + 70, 84, 85, 86, 1, 87, 88, 1, 89, 1, 2, 90, 79, 91, 0, 0, + 1, 1, 87, 70, 1, 1, 1, 92, 1, 93, 94, 1, 0, 0, 10, 75, + 1, 1, 1, 1, 1, 1, 1, 95, 96, 1, 97, 78, 1, 98, 99, 100, + 1, 101, 1, 102, 103, 16, 104, 73, 1, 1, 1, 1, 105, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 76, 1, 106, 107, 1, 1, 1, 1, 1, + 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 108, 0, 0, 0, 0, 0, + 1, 109, 2, 1, 1, 1, 1, 110, 1, 64, 1, 111, 75, 112, 112, 1, + 1, 56, 0, 0, 113, 1, 1, 76, 1, 1, 1, 1, 1, 1, 83, 114, + 1, 1, 8, 1, 7, 1, 1, 1, 115, 116, 1, 1, 109, 16, 1, 117, + 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 83, 1, 1, + 1, 1, 1, 1, 1, 1, 118, 0, 1, 1, 1, 1, 119, 1, 120, 1, + 1, 121, 1, 1, 122, 1, 1, 81, 1, 1, 1, 1, 123, 107, 0, 124, + 1, 125, 1, 81, 1, 1, 126, 56, 1, 1, 127, 70, 1, 1, 128, 0, + 1, 75, 129, 56, 1, 1, 130, 75, 131, 132, 0, 0, 0, 0, 1, 133, + 1, 1, 1, 1, 1, 117, 134, 56, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 135, 1, 1, 71, 0, 136, 137, 138, 1, 1, 1, 139, 1, + 1, 1, 104, 1, 140, 1, 141, 142, 71, 120, 143, 144, 1, 1, 1, 90, + 8, 1, 1, 1, 1, 2, 145, 146, 147, 148, 149, 0, 1, 1, 1, 16, + 150, 151, 1, 1, 152, 0, 104, 78, 0, 0, 0, 0, 70, 1, 73, 0, + 2, 117, 107, 0, 153, 1, 154, 0, 1, 1, 1, 1, 78, 155, 0, 0, + 156, 157, 158, 0, 0, 0, 0, 0, 159, 160, 0, 0, 1, 161, 0, 0, + 162, 163, 164, 1, 0, 0, 0, 0, 1, 165, 166, 167, 0, 0, 0, 0, + 1, 1, 168, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 1, 1, 169, 170, 1, 1, 171, 172, 1, 98, 173, 0, 1, 1, 172, 0, + 0, 0, 0, 0, 1, 81, 155, 0, 1, 1, 1, 174, 0, 0, 0, 0, + 1, 1, 1, 175, 0, 0, 0, 0, 1, 174, 0, 0, 0, 0, 0, 0, + 1, 176, 0, 0, 0, 0, 0, 0, 1, 1, 177, 2, 178, 0, 0, 0, + 179, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 83, + 1, 180, 1, 1, 1, 1, 78, 0, 1, 1, 181, 0, 0, 0, 0, 0, + 1, 1, 75, 15, 0, 0, 0, 0, 1, 1, 98, 1, 62, 182, 183, 1, + 184, 185, 186, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 187, 1, 1, + 1, 1, 1, 1, 1, 1, 188, 1, 183, 189, 190, 191, 192, 193, 0, 194, + 1, 87, 1, 1, 76, 195, 196, 0, 82, 109, 1, 87, 16, 0, 0, 197, + 198, 16, 199, 0, 0, 0, 0, 0, 1, 200, 1, 70, 76, 1, 201, 73, + 1, 2, 202, 1, 1, 1, 1, 203, 1, 78, 117, 141, 0, 0, 0, 204, + 1, 1, 205, 0, 1, 1, 181, 0, 1, 1, 1, 76, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 75, 0, 1, 72, 1, 1, 1, 1, 1, 1, + 78, 0, 0, 0, 0, 0, 0, 0, 206, 1, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 170, 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, 124, + 240, 215, 255, 255, 251, 255, 255, 255, 255, 0, 254, 255, 255, 255, 127, 254, + 254, 255, 255, 255, 255, 134, 254, 255, 255, 0, 255, 255, 255, 7, 31, 0, + 223, 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, 253, 31, 0, 0, + 240, 255, 255, 127, 255, 255, 255, 254, 238, 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, 0, 159, 57, 192, 176, 207, 255, 255, 0, + 236, 199, 61, 214, 24, 199, 255, 195, 199, 61, 129, 0, 192, 255, 255, 7, + 238, 223, 253, 255, 255, 253, 239, 227, 223, 61, 96, 3, 207, 255, 0, 255, + 236, 223, 253, 255, 255, 253, 239, 243, 223, 61, 96, 64, 207, 255, 6, 0, + 255, 255, 255, 231, 223, 125, 128, 0, 207, 255, 63, 254, 236, 255, 127, 252, + 255, 255, 251, 47, 127, 132, 95, 255, 0, 0, 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, 223, 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, 31, 0, 255, 255, 1, 0, 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, 63, 0, 0, + 255, 255, 15, 240, 255, 255, 255, 248, 255, 227, 255, 255, 127, 0, 0, 240, + 255, 255, 63, 63, 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, 3, 255, 255, 127, 0, 0, 0, 255, 7, 0, 0, + 255, 31, 255, 3, 255, 127, 255, 255, 255, 255, 15, 254, 255, 128, 1, 128, + 127, 127, 127, 127, 255, 255, 255, 251, 0, 0, 255, 15, 224, 255, 255, 255, + 255, 63, 254, 255, 15, 0, 255, 255, 255, 31, 0, 0, 255, 31, 255, 255, + 127, 0, 255, 255, 255, 15, 0, 0, 255, 255, 255, 128, 255, 127, 15, 0, + 0, 0, 0, 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, 0, 0, 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, 7, 255, 15, 255, 255, 255, 191, 15, 255, 63, 0, 255, 3, 0, 0, + 63, 253, 255, 255, 255, 255, 191, 145, 255, 255, 191, 255, 255, 255, 255, 143, + 255, 255, 255, 131, 255, 255, 255, 192, 111, 240, 239, 254, 255, 255, 15, 135, + 255, 0, 255, 1, 255, 255, 63, 254, 255, 255, 63, 255, 255, 255, 7, 255, + 255, 1, 0, 0, 255, 63, 252, 255, 255, 255, 0, 0, 3, 0, 255, 255, + 255, 1, 255, 3, 15, 0, 0, 0, 255, 127, 0, 0, 7, 0, 15, 0, + 255, 255, 255, 1, 31, 0, 255, 255, 0, 128, 255, 255, 3, 0, 0, 0, + 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, 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, 127, + 254, 255, 254, 255, 192, 255, 255, 255, 7, 0, 255, 255, 255, 1, 3, 0, + 1, 0, 191, 255, 223, 7, 0, 0, 253, 255, 255, 255, 255, 255, 255, 30, + 0, 0, 0, 248, 225, 255, 0, 0, 2, 0, 0, 0, +}; + +/* Print: 2038 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, 13, 18, 13, 19, 13, 13, 13, 13, 13, 13, 20, 13, 13, + 13, 13, 13, 13, 13, 13, 21, 13, 13, 13, 22, 13, 13, 23, 13, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 24, 7, 25, 26, 13, 13, 13, 13, 13, 13, 13, 27, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 28, 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, 31, 31, 31, + 58, 59, 60, 61, 62, 31, 31, 31, 63, 64, 31, 31, 31, 31, 65, 31, + 1, 1, 1, 66, 67, 31, 31, 31, 1, 1, 1, 1, 68, 31, 31, 31, + 1, 1, 69, 31, 31, 31, 31, 70, 71, 31, 31, 31, 31, 31, 31, 31, + 31, 72, 73, 31, 74, 75, 76, 77, 31, 31, 31, 31, 31, 31, 78, 31, + 1, 1, 1, 1, 1, 1, 79, 1, 1, 1, 1, 1, 1, 1, 1, 80, + 81, 31, 31, 31, 31, 31, 31, 31, 1, 1, 81, 31, 31, 31, 31, 31, + 31, 82, 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, 13, 16, 17, 18, + 19, 6, 6, 20, 6, 6, 21, 22, 23, 6, 24, 6, 6, 25, 6, 26, + 6, 27, 28, 0, 0, 29, 0, 30, 6, 6, 6, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 32, 41, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 43, 53, 54, 55, 56, 53, 57, 58, 59, 60, 61, 62, 63, + 15, 64, 65, 0, 66, 67, 68, 0, 69, 70, 71, 72, 73, 74, 75, 0, + 6, 6, 76, 6, 77, 6, 78, 79, 6, 6, 80, 6, 81, 82, 83, 6, + 84, 6, 57, 0, 85, 6, 6, 86, 15, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 87, 3, 6, 6, 88, 89, 86, 90, 91, 6, 6, 92, 93, + 94, 6, 6, 95, 6, 96, 6, 97, 74, 98, 99, 100, 6, 101, 102, 0, + 28, 6, 103, 104, 102, 105, 0, 0, 6, 6, 106, 107, 6, 6, 6, 90, + 6, 95, 108, 77, 0, 0, 109, 110, 6, 6, 6, 6, 6, 6, 6, 111, + 112, 6, 113, 77, 6, 114, 115, 116, 117, 118, 119, 120, 121, 0, 23, 122, + 123, 124, 125, 6, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 127, 6, 93, 6, 128, 103, 6, 6, 6, 6, 129, + 6, 78, 6, 130, 110, 131, 131, 6, 0, 132, 0, 0, 0, 0, 0, 0, + 133, 134, 15, 6, 135, 15, 6, 79, 136, 137, 6, 6, 138, 64, 0, 23, + 6, 6, 6, 6, 6, 97, 0, 0, 6, 6, 6, 6, 6, 6, 139, 0, + 6, 6, 6, 6, 139, 0, 23, 77, 140, 141, 6, 142, 143, 6, 6, 25, + 144, 145, 6, 6, 146, 147, 0, 148, 6, 149, 6, 90, 6, 6, 150, 151, + 6, 152, 90, 74, 6, 6, 153, 0, 6, 110, 154, 155, 6, 6, 156, 157, + 158, 159, 0, 0, 0, 0, 6, 160, 6, 6, 6, 6, 6, 161, 162, 28, + 6, 6, 6, 152, 6, 6, 163, 0, 164, 165, 166, 6, 6, 25, 167, 6, + 6, 77, 23, 6, 168, 6, 149, 169, 85, 170, 171, 172, 6, 6, 6, 74, + 1, 2, 3, 99, 6, 103, 173, 0, 174, 175, 176, 0, 6, 6, 6, 64, + 0, 0, 6, 86, 0, 0, 0, 177, 0, 0, 0, 0, 74, 6, 122, 0, + 103, 23, 147, 0, 77, 6, 178, 0, 6, 6, 6, 6, 77, 93, 0, 0, + 179, 180, 97, 0, 0, 0, 0, 0, 97, 163, 0, 0, 6, 181, 0, 0, + 182, 183, 0, 74, 0, 0, 0, 0, 6, 97, 97, 184, 0, 0, 0, 0, + 6, 6, 126, 0, 0, 0, 0, 0, 6, 6, 185, 49, 6, 64, 23, 186, + 6, 187, 0, 0, 6, 6, 150, 0, 0, 0, 0, 0, 6, 95, 93, 0, + 6, 6, 6, 138, 0, 0, 0, 0, 6, 6, 6, 188, 0, 0, 0, 0, + 6, 138, 0, 0, 0, 0, 0, 0, 6, 189, 0, 0, 0, 0, 0, 0, + 6, 6, 190, 103, 191, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 193, 194, 195, 0, 0, 0, 0, 196, 0, 0, 0, 0, 0, + 6, 6, 187, 6, 197, 198, 199, 6, 200, 201, 202, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 203, 204, 79, 187, 187, 128, 128, 205, 205, 206, 6, + 199, 207, 208, 209, 210, 211, 0, 0, 6, 6, 6, 6, 6, 6, 110, 0, + 6, 86, 6, 6, 6, 6, 6, 6, 77, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 6, 85, +}; + +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, 60, 64, 215, 255, 255, 251, 255, 255, 255, + 255, 255, 191, 255, 255, 0, 254, 255, 255, 255, 127, 2, 254, 255, 255, 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, 253, 31, 0, 0, 240, 255, 255, 127, 207, 255, 254, 254, + 238, 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, 0, + 159, 57, 192, 176, 207, 255, 2, 0, 236, 199, 61, 214, 24, 199, 255, 195, + 199, 61, 129, 0, 192, 255, 0, 0, 238, 223, 253, 255, 255, 253, 239, 227, + 223, 61, 96, 3, 236, 223, 253, 255, 255, 253, 239, 243, 223, 61, 96, 64, + 207, 255, 6, 0, 255, 255, 255, 231, 223, 125, 128, 0, 207, 255, 0, 252, + 236, 255, 127, 252, 255, 255, 251, 47, 127, 132, 95, 255, 0, 0, 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, 31, 0, 255, 159, 255, 255, + 255, 199, 1, 0, 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, 15, 255, 15, 192, 255, 255, 255, + 255, 63, 31, 0, 255, 15, 255, 255, 255, 3, 255, 3, 255, 255, 255, 127, + 255, 255, 255, 159, 128, 0, 0, 0, 255, 15, 255, 3, 0, 248, 15, 0, + 255, 227, 255, 255, 0, 0, 247, 255, 255, 255, 127, 0, 127, 0, 0, 240, + 255, 255, 63, 63, 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, 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, 255, 255, 255, 128, + 0, 0, 128, 255, 252, 255, 255, 255, 255, 121, 15, 0, 255, 7, 0, 0, + 0, 0, 0, 255, 255, 0, 0, 0, 31, 0, 255, 3, 255, 255, 255, 8, + 255, 63, 255, 255, 1, 128, 255, 3, 255, 63, 255, 3, 255, 255, 127, 12, + 7, 0, 0, 56, 255, 255, 124, 0, 126, 126, 126, 0, 127, 127, 0, 0, + 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, 127, 0, 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, 15, 255, 62, 0, 63, 253, 255, 255, + 255, 255, 191, 145, 255, 255, 255, 192, 111, 240, 239, 254, 255, 255, 15, 135, + 255, 255, 7, 0, 127, 0, 0, 0, 255, 1, 255, 3, 255, 255, 223, 255, + 7, 0, 0, 0, 255, 255, 255, 1, 31, 0, 255, 255, 0, 128, 255, 255, + 3, 0, 0, 0, 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, 150, 254, 247, 10, + 132, 234, 150, 170, 150, 247, 247, 94, 255, 251, 255, 15, 238, 251, 255, 15, +}; + +/* Word: 1906 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, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 5, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, + 8, 4, 9, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 10, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 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_xdigit_stage_3[] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 4, + 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 6, 6, 7, 1, + 4, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 8, 1, 9, 6, 1, 10, 6, 11, 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, 1, 1, 7, 1, 1, 1, + 1, 6, 13, 6, 6, 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, 14, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, + 5, 3, 15, 6, 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, 16, +}; + +static RE_UINT8 re_xdigit_stage_4[] = { + 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, + 0, 0, 3, 0, 0, 0, 0, 4, 0, 0, 1, 0, 0, 3, 0, 0, + 1, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 5, 0, 3, 0, 0, 0, 1, 2, 2, 0, 0, 6, 0, 0, + 0, 0, 7, 8, +}; + +static RE_UINT8 re_xdigit_stage_5[] = { + 0, 0, 0, 0, 0, 0, 255, 3, 126, 0, 0, 0, 255, 3, 0, 0, + 192, 255, 0, 0, 255, 3, 255, 3, 0, 0, 192, 255, 0, 192, 255, 255, + 255, 255, 255, 255, +}; + +/* XDigit: 393 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] << 5; + f = code >> 11; + code ^= f << 11; + pos = (RE_UINT32)re_xdigit_stage_2[pos + f] << 4; + f = code >> 7; + code ^= f << 7; + pos = (RE_UINT32)re_xdigit_stage_3[pos + f] << 2; + f = code >> 5; + code ^= f << 5; + pos = (RE_UINT32)re_xdigit_stage_4[pos + f] << 5; + pos += code; + value = (re_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, 6, 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, 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, 15, 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, 18, + 6, 6, 6, 6, 19, 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_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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 18, 18, 18, 63, 64, + 65, 65, 11, 11, 11, 11, 15, 15, 15, 15, 66, 66, 18, 18, 18, 18, + 67, 68, 18, 18, 18, 18, 18, 18, 69, 70, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 0, 71, 72, 72, 72, 73, 0, 74, 75, 75, 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, 0, 0, 0, 0, 0, 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, 77, 77, 77, 78, 79, 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, 0, 0, 0, 0, 0, 0, 0, 0, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 81, 18, 18, 18, + 18, 18, 82, 83, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 84, 85, 86, 87, 84, 85, 84, 85, 86, 87, 88, 89, 84, 85, 90, 91, + 84, 85, 84, 85, 84, 85, 92, 93, 94, 95, 96, 97, 98, 99, 94, 100, + 0, 0, 0, 0, 101, 102, 103, 0, 0, 104, 0, 0, 105, 105, 106, 106, + 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 108, 109, 109, 109, 110, 110, 110, 111, 0, 0, + 72, 72, 72, 72, 72, 73, 75, 75, 75, 75, 75, 76, 112, 113, 114, 115, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 37, 116, 117, 0, + 118, 118, 118, 118, 119, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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, 82, 0, 0, + 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 68, 18, 68, 18, 18, 18, 18, 18, 18, 18, 0, 121, + 18, 122, 37, 0, 18, 123, 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, 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, + 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 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_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, 0, 0, 0, 0, + 58, 0, 0, 61, 0, 62, 63, 0, 64, 65, 0, 66, 0, 0, 0, 65, + 0, 67, 68, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, + 71, 0, 0, 71, 0, 0, 0, 0, 71, 72, 73, 73, 74, 0, 0, 0, + 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 0, 0, + 14, 15, 14, 15, 0, 0, 14, 15, 0, 0, 0, 33, 33, 33, 0, 0, + 0, 0, 0, 0, 0, 0, 77, 0, 78, 78, 78, 0, 79, 0, 80, 80, + 81, 1, 82, 1, 1, 83, 1, 1, 84, 85, 86, 1, 87, 1, 1, 1, + 88, 89, 0, 90, 1, 1, 91, 1, 1, 92, 1, 1, 93, 94, 94, 94, + 95, 5, 96, 5, 5, 97, 5, 5, 98, 99, 100, 5, 101, 5, 5, 5, + 102, 103, 104, 105, 5, 5, 106, 5, 5, 107, 5, 5, 108, 109, 109, 110, + 111, 112, 0, 0, 0, 113, 114, 115, 116, 117, 118, 0, 119, 120, 0, 14, + 15, 121, 14, 15, 0, 45, 45, 45, 122, 122, 122, 122, 122, 122, 122, 122, + 123, 123, 123, 123, 123, 123, 123, 123, 14, 15, 0, 0, 0, 0, 0, 0, + 0, 0, 14, 15, 14, 15, 14, 15, 124, 14, 15, 14, 15, 14, 15, 14, + 15, 14, 15, 14, 15, 14, 15, 125, 0, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 0, + 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 0, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 0, 128, 0, 0, 0, 0, 0, 128, 0, 0, + 0, 129, 0, 0, 0, 130, 0, 0, 131, 132, 14, 15, 14, 15, 14, 15, + 14, 15, 14, 15, 14, 15, 0, 0, 0, 0, 0, 133, 0, 0, 134, 0, + 110, 110, 110, 110, 110, 110, 110, 110, 115, 115, 115, 115, 115, 115, 115, 115, + 110, 110, 110, 110, 110, 110, 0, 0, 115, 115, 115, 115, 115, 115, 0, 0, + 0, 110, 0, 110, 0, 110, 0, 110, 0, 115, 0, 115, 0, 115, 0, 115, + 135, 135, 136, 136, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 0, 0, + 110, 110, 0, 141, 0, 0, 0, 0, 115, 115, 142, 142, 143, 0, 144, 0, + 0, 0, 0, 141, 0, 0, 0, 0, 145, 145, 145, 145, 143, 0, 0, 0, + 110, 110, 0, 146, 0, 0, 0, 0, 115, 115, 147, 147, 0, 0, 0, 0, + 110, 110, 0, 148, 0, 118, 0, 0, 115, 115, 149, 149, 121, 0, 0, 0, + 150, 150, 151, 151, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 152, 0, + 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 156, 0, 157, 157, 157, 157, 157, 157, 157, 157, + 158, 158, 158, 158, 158, 158, 158, 158, 0, 0, 0, 14, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 0, 0, 0, 0, 0, 0, + 14, 15, 161, 162, 163, 164, 165, 14, 15, 14, 15, 14, 15, 166, 167, 168, + 169, 0, 14, 15, 0, 14, 15, 0, 0, 0, 0, 0, 0, 0, 170, 170, + 0, 0, 0, 14, 15, 14, 15, 0, 0, 0, 14, 15, 0, 0, 0, 0, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 0, 171, + 0, 0, 0, 0, 0, 171, 0, 0, 0, 14, 15, 14, 15, 172, 14, 15, + 0, 0, 0, 14, 15, 173, 0, 0, 14, 15, 174, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 14, 15, 0, 175, 175, 175, 175, 175, 175, 175, 175, + 176, 176, 176, 176, 176, 176, 176, 176, +}; + +/* All_Cases: 1984 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}}, + {{ -207, 0, 0}}, + {{ 42280, 0, 0}}, + {{ 42308, 0, 0}}, + {{ -209, 0, 0}}, + {{ -211, 0, 0}}, + {{ 10743, 0, 0}}, + {{ 10749, 0, 0}}, + {{ -213, 0, 0}}, + {{ -214, 0, 0}}, + {{ 10727, 0, 0}}, + {{ -218, 0, 0}}, + {{ -69, 0, 0}}, + {{ -217, 0, 0}}, + {{ -71, 0, 0}}, + {{ -219, 0, 0}}, + {{ 84, 116, 7289}}, + {{ 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}}, + {{ -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}}, + {{ 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}}, + {{ 40, 0, 0}}, + {{ -40, 0, 0}}, +}; + +/* All_Cases: 2124 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, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 9, + 6, 10, 6, 6, 11, 6, 6, 6, 6, 6, 6, 6, 12, 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, 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, + 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, 15, + 6, 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, +}; + +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, 0, + 28, 29, 1, 2, 30, 31, 0, 0, 32, 33, 34, 6, 6, 6, 35, 36, + 37, 37, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, + 38, 7, 6, 6, 6, 6, 6, 6, 39, 40, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 0, 41, 42, 42, 42, 43, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 44, 44, 44, 44, 45, 46, 0, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 47, 48, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 0, 49, 0, 50, 0, 49, 0, 49, 0, 50, 0, 51, 0, 49, 0, 0, + 0, 49, 0, 49, 0, 49, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56, + 0, 0, 0, 0, 57, 58, 59, 0, 0, 0, 0, 0, 60, 60, 0, 0, + 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 62, 63, 63, 63, 0, 0, 0, 0, 0, 0, + 42, 42, 42, 42, 42, 43, 0, 0, 0, 0, 0, 0, 64, 65, 66, 67, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 23, 68, 32, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 47, 0, 0, + 6, 6, 6, 0, 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, 69, + 6, 70, 23, 0, 6, 71, 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, + 72, 72, 72, 72, 72, 0, 0, 0, 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_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, 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, 3, 0, 3, 0, 3, 0, 0, 0, + 0, 0, 0, 49, 0, 0, 50, 0, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 0, 0, 0, 51, 0, 51, 0, 51, 0, 51, + 51, 51, 52, 52, 53, 0, 54, 0, 55, 55, 55, 55, 53, 0, 0, 0, + 51, 51, 56, 56, 0, 0, 0, 0, 51, 51, 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, 0, 0, 0, 0, 0, + 77, 77, 77, 77, 77, 77, 77, 77, +}; + +/* Simple_Case_Folding: 1456 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, + -58, + -7615, + -8, + -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, + 40, +}; + +/* Simple_Case_Folding: 312 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, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 9, + 6, 10, 6, 6, 11, 6, 6, 6, 6, 6, 6, 6, 12, 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, 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, + 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, 15, 6, 6, 6, 16, + 6, 6, 6, 6, 17, 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_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, 0, + 30, 31, 32, 2, 33, 34, 35, 0, 36, 37, 38, 7, 7, 7, 39, 40, + 41, 41, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, + 42, 43, 7, 7, 7, 7, 7, 7, 44, 45, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 46, 47, 47, 47, 48, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 50, 50, 50, 50, 51, 52, 0, 0, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 53, 54, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 55, 0, 56, 0, 55, 0, 55, 0, 56, 57, 58, 0, 55, 0, 0, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 0, 0, 0, 0, 75, 76, 77, 0, 0, 0, 0, 0, 78, 78, 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, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 80, 81, 81, 81, 0, 0, 0, 0, 0, 0, + 47, 47, 47, 47, 47, 48, 0, 0, 0, 0, 0, 0, 82, 83, 84, 85, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 25, 86, 36, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 87, 0, 0, + 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 43, 7, 43, 7, 7, 7, 7, 7, 7, 7, 0, 88, + 7, 89, 25, 0, 7, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 91, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, + 93, 93, 93, 93, 93, 0, 0, 0, 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_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, 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, 4, 0, 4, 0, 4, 0, 56, 57, + 58, 59, 60, 61, 0, 0, 62, 0, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 0, 0, 64, 0, 65, 0, 66, 0, 67, 0, + 0, 63, 0, 63, 0, 63, 0, 63, 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, + 63, 63, 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, + 63, 63, 93, 93, 0, 0, 0, 0, 0, 0, 94, 95, 96, 0, 97, 98, + 63, 63, 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, 0, 0, 0, 0, 0, 125, 126, 127, 128, 129, 130, 131, 0, + 0, 0, 0, 132, 133, 134, 135, 136, 137, 137, 137, 137, 137, 137, 137, 137, +}; + +/* Full_Case_Folding: 1656 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}}, + { -7726, { 817, 0}}, + { -7715, { 776, 0}}, + { -7713, { 778, 0}}, + { -7712, { 778, 0}}, + { -7737, { 702, 0}}, + { -58, { 0, 0}}, + { -7723, { 115, 0}}, + { -8, { 0, 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}}, + {-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: 1104 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_matra_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, +}; diff --git a/lib/regex/_regex_unicode.h b/lib/regex/_regex_unicode.h new file mode 100644 index 00000000..fa8114be --- /dev/null +++ b/lib/regex/_regex_unicode.h @@ -0,0 +1,218 @@ +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_UINT8 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_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[1160]; +extern RE_Property re_properties[143]; +extern RE_PropertyValue re_property_values[1251]; +extern RE_UINT16 re_expand_on_folding[104]; +extern RE_GetPropertyFunc re_get_property[77]; + +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_matra_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); +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/regex.py b/lib/regex/regex.py new file mode 100644 index 00000000..e5e40d1f --- /dev/null +++ b/lib/regex/regex.py @@ -0,0 +1,684 @@ +# +# 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...) The substring matched by the group is accessible by + 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 the text matched by the group named name. + \G Matches the empty string, but only at the position where + the search started. + \L 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. + 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. + E e ENHANCEMATCH Attempt to improve the fit after finding the first + fuzzy match. + 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", "R", "REVERSE", "T", "TEMPLATE", "U", "UNICODE", + "V0", "VERSION0", "V1", "VERSION1", "X", "VERBOSE", "W", "WORD", "error", + "Regex"] + +__version__ = "2.4.45" + +# -------------------------------------------------------------------- +# 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() + +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." + if isinstance(pattern, unicode): + s = [] + if special_only: + for c in pattern: + if c in _METACHARS: + s.append(u"\\") + s.append(c) + elif c == u"\x00": + s.append(u"\\000") + else: + s.append(c) + else: + for c in pattern: + if c in _ALNUM: + s.append(c) + elif c == u"\x00": + s.append(u"\\000") + else: + s.append(u"\\") + s.append(c) + + return u"".join(s) + else: + 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 "".join(s) + +# -------------------------------------------------------------------- +# Internals. + +import _regex_core +import sys +if sys.version_info < (2, 6): + from Python25 import _regex +elif sys.version_info < (2, 7): + from Python26 import _regex +else: + from Python27 import _regex +from threading import RLock as _RLock +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 = {} + +# Maximum size of the cache. +_MAXCACHE = 500 +_MAXREPCACHE = 500 + +def _compile(pattern, flags=0, kwargs={}): + "Compiles a regular expression to a PatternObject." + 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") + + 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) + 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("can't 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 + + caught_exception = None + global_flags = flags + + while True: + 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(str(caught_exception)) + + if not source.at_end(): + raise error("trailing characters in pattern at position %d" % 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) + + # Should we print the parsed pattern? + if flags & DEBUG: + parsed.dump(indent=0, reverse=reverse) + + # Fix the group references. + parsed.fix_groups(reverse, False) + + # 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, _MAXCACHE) + finally: + _cache_lock.release() + + args_needed = frozenset(args_needed) + + # Store this regular expression and named list. + pattern_key = (pattern, type(pattern), flags, args_needed, DEFAULT_VERSION) + _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/test_regex.py b/lib/regex/test_regex.py new file mode 100644 index 00000000..55b14c4d --- /dev/null +++ b/lib/regex/test_regex.py @@ -0,0 +1,3230 @@ +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( + "{0} not raised".format(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 = "" + FLAGS_WITH_COMPILED_PAT = "can't process flags argument with a compiled pattern" + INVALID_GROUP_REF = "invalid group reference" + MISSING_GT = "missing >" + BAD_GROUP_NAME = "bad group name" + MISSING_LT = "missing <" + UNKNOWN_GROUP_I = "unknown group" + UNKNOWN_GROUP = "unknown group" + BAD_ESCAPE = "bad escape" + BAD_OCTAL_ESCAPE = "bad octal escape" + BAD_SET = "bad set" + STR_PAT_ON_BYTES = "can't use a string pattern on a bytes-like object" + BYTES_PAT_ON_STR = "can't use a bytes pattern on a string-like object" + STR_PAT_BYTES_TEMPL = "expected str instance, bytes found" + BYTES_PAT_STR_TEMPL = "expected bytes instance, str found" + BYTES_PAT_UNI_FLAG = "can't use UNICODE flag with a bytes pattern" + MIXED_FLAGS = "ASCII, LOCALE and UNICODE flags are mutually incompatible" + MISSING_RPAREN = "missing \\)" # Need to escape parenthesis for unittest. + TRAILING_CHARS = "trailing characters in pattern" + BAD_CHAR_RANGE = "bad character range" + NOTHING_TO_REPEAT = "nothing to repeat" + OPEN_GROUP = "can't refer to an open group" + DUPLICATE_GROUP = "duplicate group" + CANT_TURN_OFF = "bad inline flags: can't 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('(?Px)', r'\g\g', 'xx'), 'xxxx') + self.assertEqual(regex.sub('(?Px)', r'\g\g<1>', 'xx'), 'xxxx') + self.assertEqual(regex.sub('(?Px)', r'\g\g', 'xx'), + 'xxxx') + self.assertEqual(regex.sub('(?Px)', 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'(?Px)', 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))"))), + 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('(?Px)', r'\gx)', r'\g<', 'xx')) + self.assertRaisesRegex(regex.error, self.MISSING_LT, lambda: + regex.sub('(?Px)', r'\g', 'xx')) + self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda: + regex.sub('(?Px)', r'\g', 'xx')) + self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda: + regex.sub('(?Px)', r'\g<1a1>', 'xx')) + self.assertRaisesRegex(IndexError, self.UNKNOWN_GROUP_I, lambda: + regex.sub('(?Px)', r'\g', '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('(?Px)|(?Py)', r'\g', 'xx'), '') + self.assertEqual(regex.sub('(?Px)|(?Py)', r'\2', 'xx'), '') + + # The old behaviour was to raise it as an IndexError. + self.assertRaisesRegex(regex.error, self.BAD_GROUP_NAME, lambda: + regex.sub('(?Px)', 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.{0,5}?TEST)\)", + "(MY TEST)"), ["MY TEST"]) + self.assertEqual(regex.findall(r"\((?P.{0,3}?TEST)\)", + "(MY TEST)"), ["MY TEST"]) + self.assertEqual(regex.findall(r"\((?P.{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('(?:(?Pa)|(?Pb))(?Pc)?') + 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('(?Pa)(?Pb)?((?(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('(?Pfirst) (?Psecond)', + 'first second').groupdict(), {'first': 'first', 'second': 'second'}) + + def test_expand(self): + self.assertEqual(regex.match("(?Pfirst) (?Psecond)", + "first second").expand(r"\2 \1 \g \g"), + '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)(?Pa)(?Pb)").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(?Pdef)') + 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(?ne", u"affine", + options=[u"\N{LATIN SMALL LIGATURE FFI}"]).span(), (0, 6)) + self.assertEqual(regex.search(ur"(?fi)a\Lne", + 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.UNKNOWN_GROUP, 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'(?Pa)(?Pb)?b','ab').lastgroup, + 'a') + self.assertEqual(regex.match("(?Pa(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'(?\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\w)', 'x') + m1 = regex.match(r'(?\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)\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(?[ \t]+\r*$)|(?P(?<=[^\n])\Z)') + self.assertEqual(pat.subn(lambda m: '<' + m.lastgroup + '>', + 'foobar '), ('foobar', 1)) + self.assertEqual([m.group() for m in pat.finditer('foobar ')], [' ', + '']) + pat = regex.compile(r'(?mV1)(?P[ \t]+\r*$)|(?P(?<=[^\n])\Z)') + self.assertEqual(pat.subn(lambda m: '<' + m.lastgroup + '>', + 'foobar '), ('foobar', 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)|(?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)(?:(?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)|(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)|(?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)|(?b))(c)", "ac").groups(), + ('a', 'c')) + + self.assertEqual(regex.match(r"(?|(?a)|(?b))(c)", "bc").groups(), + ('b', 'c')) + + self.assertEqual(regex.match(r"(?|(?a)(?b)|(?c)(?d))(e)", + "abe").groups(), ('a', 'b', 'e')) + self.assertEqual(regex.match(r"(?|(?a)(?b)|(?c)(?d))(e)", + "cde").groups(), ('d', 'c', 'e')) + self.assertEqual(regex.match(r"(?|(?a)(?b)|(?c)(d))(e)", + "abe").groups(), ('a', 'b', 'e')) + self.assertEqual(regex.match(r"(?|(?a)(?b)|(?c)(d))(e)", + "cde").groups(), ('d', 'c', 'e')) + self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(d))(e)", + "abe").groups(), ('a', 'b', 'e')) + self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(d))(e)", + "cde").groups(), ('c', 'd', 'e')) + + # Hg issue 87. + self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(?d))(e)", + "abe").groups(), ("a", "b", "e")) + self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(?d))(e)", + "abe").capturesdict(), {"a": ["a"], "b": ["b"]}) + self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(?d))(e)", + "cde").groups(), ("d", None, "e")) + self.assertEqual(regex.match(r"(?|(?a)(?b)|(c)(?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. + ('(?Pa)', '', '', regex.error, self.BAD_GROUP_NAME), # Begins with a digit. + ('(?Pa)', '', '', regex.error, self.BAD_GROUP_NAME), # Begins with an illegal char. + ('(?Pa)', '', '', regex.error, self.BAD_GROUP_NAME), # Begins with an illegal char. + + # Same tests, for the ?P= form. + ('(?Pa)(?P=foo_123', 'aa', '', regex.error, + self.MISSING_RPAREN), + ('(?Pa)(?P=1)', 'aa', '', regex.error, + self.BAD_GROUP_NAME), + ('(?Pa)(?P=!)', 'aa', '', regex.error, + self.BAD_GROUP_NAME), + ('(?Pa)(?P=foo_124)', 'aa', '', regex.error, + self.UNKNOWN_GROUP), # Backref to undefined group. + + ('(?Pa)', 'a', '1', repr('a')), + ('(?Pa)(?P=foo_123)', 'aa', '1', repr('a')), + + # Mal-formed \g in pattern treated as literal for compatibility. + (r'(?a)\ga)\g<1>', 'aa', '1', repr('a')), + (r'(?a)\g', 'aa', '', repr(None)), + (r'(?a)\g', 'aa', '', regex.error, + self.UNKNOWN_GROUP), # Backref to undefined group. + + ('(?a)', 'a', '1', repr('a')), + (r'(?a)\g', 'aa', '1', repr('a')), + + # Test octal escapes. + ('\\1', 'a', '', regex.error, self.UNKNOWN_GROUP), # 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. + ('(?Paaa)a', 'aaaa', '', regex.error, self.BAD_GROUP_NAME), + ('(?Paaa)a', 'aaaa', '0,id', repr(('aaaa', 'aaa'))), + ('(?Paa)(?P=id)', 'aaaa', '0,id', repr(('aaaa', 'aa'))), + ('(?Paa)(?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.UNKNOWN_GROUP), + (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.NOTHING_TO_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.UNKNOWN_GROUP), + ('(?i)((((((((((a))))))))))\\41', '', '', regex.error, + self.UNKNOWN_GROUP), + + ('(((((((((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.NOTHING_TO_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 -. + ('(?]*?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]*?)(?(.){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\L444", u"333one444", + bar=options).group(), u"333one444") + self.assertEqual(regex.match(ur"(?i)333\L444", u"333TWO444", + bar=options).group(), u"333TWO444") + self.assertEqual(regex.match(ur"333\L444", u"333four444", + bar=options), None) + + options = ["one", "two", "three"] + self.assertEqual(regex.match(r"333\L444", "333one444", + bar=options).group(), "333one444") + self.assertEqual(regex.match(r"(?i)333\L444", "333TWO444", + bar=options).group(), "333TWO444") + self.assertEqual(regex.match(r"333\L444", "333four444", + bar=options), None) + + self.assertEqual(repr(type(regex.compile(r"3\L4\L+5", + bar=["one", "two", "three"]))), self.PATTERN_CLASS) + + self.assertEqual(regex.findall(r"^\L", "solid QWERT", + options=set(['good', 'brilliant', '+s\\ol[i}d'])), []) + self.assertEqual(regex.findall(r"^\L", "+solid QWERT", + options=set(['good', 'brilliant', '+solid'])), ['+solid']) + + options = [u"STRASSE"] + self.assertEqual(regex.match(ur"(?fiu)\L", + 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", + 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", u"STRASSE", + words=options).span(), (0, 7)) + + options = ["kit"] + self.assertEqual(regex.search(ur"(?iu)\L", u"SKITS", + words=options).span(), (1, 4)) + self.assertEqual(regex.search(ur"(?iu)\L", + 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=[]).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), ((26, 33), + (26, 33))) + + # 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{e<=1}\b", + " book cot dog desk ", words="cat dog".split()), ["cot", "dog"]) + self.assertEqual(regex.findall(r"\b\L{e<=1}\b", + " book dog cot desk ", words="cat dog".split()), [" dog", "cot"]) + self.assertEqual(regex.findall(r"(?e)\b\L{e<=1}\b", + " book dog cot desk ", words="cat dog".split()), ["dog", "cot"]) + self.assertEqual(regex.findall(r"(?r)\b\L{e<=1}\b", + " book cot dog desk ", words="cat dog".split()), ["dog ", "cot"]) + self.assertEqual(regex.findall(r"(?er)\b\L{e<=1}\b", + " book cot dog desk ", words="cat dog".split()), ["dog", "cot"]) + self.assertEqual(regex.findall(r"(?r)\b\L{e<=1}\b", + " book dog cot desk ", words="cat dog".split()), ["cot", "dog"]) + self.assertEqual(regex.findall(ur"\b\L{e<=1}\b", + u" book cot dog desk ", words=u"cat dog".split()), [u"cot", u"dog"]) + self.assertEqual(regex.findall(ur"\b\L{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{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{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{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{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[^()]+)|(?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('')), True) + self.assertEqual(bool(rgx.search('')), False) + self.assertEqual(bool(rgx.search('')), True) + self.assertEqual(bool(rgx.search('')), False) + self.assertEqual(bool(rgx.search('')), False) + + self.assertEqual(bool(rgx.search('')), False) + self.assertEqual(bool(rgx.search('')), 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')), False) + self.assertEqual(bool(rgx.search('foo')), False) + + self.assertEqual(bool(rgx.search('foo')), True) + self.assertEqual(bool(rgx.search('foo')), True) + self.assertEqual(bool(rgx.search('')), 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"(?\w+) (?\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"(?\w+) (?\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("^((?>\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', + 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))*\))', + '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){1a(?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, + '^nothing to repeat at position 3$', lambda: regex.compile(r'.???')) + + # Hg issue 97. + self.assertEquals(regex.escape(u'foo!?'), u'foo\\!\\?') + self.assertEquals(regex.escape(u'foo!?', special_only=True), + u'foo!\\?') + + self.assertEquals(regex.escape('foo!?'), 'foo\\!\\?') + self.assertEquals(regex.escape('foo!?', special_only=True), 'foo!\\?') + + # Hg issue 100. + self.assertEquals(regex.search('^([^z]*(?:WWWi|W))?$', + 'WWWi').groups(), ('WWWi', )) + self.assertEquals(regex.search('^([^z]*(?:WWWi|w))?$', + 'WWWi').groups(), ('WWWi', )) + self.assertEquals(regex.search('^([^z]*?(?:WWWi|W))?$', + 'WWWi').groups(), ('WWWi', )) + + # Hg issue 101. + pat = regex.compile(r'xxx', flags=regex.FULLCASE | regex.UNICODE) + self.assertEquals([x.group() for x in pat.finditer('yxxx')], ['xxx']) + self.assertEquals(pat.findall('yxxx'), ['xxx']) + + raw = 'yxxx' + self.assertEquals([x.group() for x in pat.finditer(raw)], ['xxx']) + self.assertEquals(pat.findall(raw), ['xxx']) + + pat = regex.compile(r'xxx', flags=regex.FULLCASE | regex.IGNORECASE | + regex.UNICODE) + self.assertEquals([x.group() for x in pat.finditer('yxxx')], ['xxx']) + self.assertEquals(pat.findall('yxxx'), ['xxx']) + + raw = 'yxxx' + self.assertEquals([x.group() for x in pat.finditer(raw)], ['xxx']) + self.assertEquals(pat.findall(raw), ['xxx']) + + # Hg issue 106. + self.assertEquals(regex.sub('(?V0).*', 'x', 'test'), 'x') + self.assertEquals(regex.sub('(?V1).*', 'x', 'test'), 'xx') + + self.assertEquals(regex.sub('(?V0).*?', '|', 'test'), '|t|e|s|t|') + self.assertEquals(regex.sub('(?V1).*?', '|', 'test'), '|||||||||') + + # Hg issue 112. + self.assertEquals(regex.sub(r'^(@)\n(?!.*?@)(.*)', + r'\1\n==========\n\2', '@\n', flags=regex.DOTALL), '@\n==========\n') + + # Hg issue 109. + self.assertEquals(regex.match(r'(?:cats|cat){e<=1}', + 'caz').fuzzy_counts, (1, 0, 0)) + self.assertEquals(regex.match(r'(?e)(?:cats|cat){e<=1}', + 'caz').fuzzy_counts, (1, 0, 0)) + self.assertEquals(regex.match(r'(?b)(?:cats|cat){e<=1}', + 'caz').fuzzy_counts, (1, 0, 0)) + + self.assertEquals(regex.match(r'(?:cat){e<=1}', 'caz').fuzzy_counts, + (1, 0, 0)) + self.assertEquals(regex.match(r'(?e)(?:cat){e<=1}', + 'caz').fuzzy_counts, (1, 0, 0)) + self.assertEquals(regex.match(r'(?b)(?:cat){e<=1}', + 'caz').fuzzy_counts, (1, 0, 0)) + + self.assertEquals(regex.match(r'(?:cats){e<=2}', 'c ats').fuzzy_counts, + (1, 1, 0)) + self.assertEquals(regex.match(r'(?e)(?:cats){e<=2}', + 'c ats').fuzzy_counts, (0, 1, 0)) + self.assertEquals(regex.match(r'(?b)(?:cats){e<=2}', + 'c ats').fuzzy_counts, (0, 1, 0)) + + self.assertEquals(regex.match(r'(?:cats){e<=2}', + 'c a ts').fuzzy_counts, (0, 2, 0)) + self.assertEquals(regex.match(r'(?e)(?:cats){e<=2}', + 'c a ts').fuzzy_counts, (0, 2, 0)) + self.assertEquals(regex.match(r'(?b)(?:cats){e<=2}', + 'c a ts').fuzzy_counts, (0, 2, 0)) + + self.assertEquals(regex.match(r'(?:cats){e<=1}', + 'c ats').fuzzy_counts, (0, 1, 0)) + self.assertEquals(regex.match(r'(?e)(?:cats){e<=1}', + 'c ats').fuzzy_counts, (0, 1, 0)) + self.assertEquals(regex.match(r'(?b)(?:cats){e<=1}', + 'c ats').fuzzy_counts, (0, 1, 0)) + +if not hasattr(str, "format"): + # Strings don't have the .format method (below Python 2.6). + del RegexTests.test_format + +def test_main(): + run_unittest(RegexTests) + +if __name__ == "__main__": + test_main() diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index cd36951a..bfa0cf8c 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -16,35 +16,33 @@ # You should have received a copy of the GNU General Public License # along with SickRage. If not, see . +import re import datetime import os.path -import re import threading import regexes -import time import sickbeard -from sickbeard import logger, helpers, scene_numbering, db -from sickbeard.exceptions import EpisodeNotFoundByAbsoluteNumberException +from sickbeard import logger, helpers, scene_numbering +from regex import regex from dateutil import parser nameparser_lock = threading.Lock() - class NameParser(object): ALL_REGEX = 0 NORMAL_REGEX = 1 SPORTS_REGEX = 2 ANIME_REGEX = 3 - def __init__(self, file_name=True, show=None, useIndexers=False): + def __init__(self, file_name=True, showObj=None, epObj=None, useIndexers=False, convert=False): regexMode = self.ALL_REGEX - if show and show.is_anime: + if showObj and showObj.is_anime: regexMode = self.ANIME_REGEX - elif show and show.is_sports: + elif showObj and showObj.is_sports: regexMode = self.SPORTS_REGEX - elif show and not show.is_anime and not show.is_sports: + elif showObj and not showObj.is_anime and not showObj.is_sports: regexMode = self.NORMAL_REGEX self.file_name = file_name @@ -53,7 +51,9 @@ class NameParser(object): self._compile_regexes(self.regexMode) self.showList = sickbeard.showList self.useIndexers = useIndexers - self.show = show + self.showObj = showObj + self.epObj = epObj + self.convert = convert def clean_series_name(self, series_name): """Cleans up series name by removing any . and _ @@ -85,7 +85,7 @@ class NameParser(object): uncompiled_regex = [regexes.anime_regexes, regexes.sports_regexs, regexes.normal_regexes] elif regexMode == self.NORMAL_REGEX: - logger.log(u"Using NORMAL regexs", logger.DEBUG) + logger.log(u"Using NORMAL reqgexs", logger.DEBUG) uncompiled_regex = [regexes.normal_regexes] elif regexMode == self.SPORTS_REGEX: @@ -101,125 +101,120 @@ class NameParser(object): uncompiled_regex = [regexes.normal_regexes] for regexItem in uncompiled_regex: - for regex_type, regex in regexItem.items(): - try: - self.compiled_regexes[regex_type] - except: - self.compiled_regexes[regex_type] = {} - - for (cur_pattern_name, cur_pattern) in regex: + for regex_type, regex_pattern in regexItem.items(): + for (cur_pattern_name, cur_pattern) in regex_pattern: try: - cur_regex = re.compile(cur_pattern, re.VERBOSE | re.IGNORECASE) - except re.error, errormsg: + cur_regex = regex.compile(cur_pattern, regex.V1 | regex.VERBOSE | regex.IGNORECASE | regex.BESTMATCH) + except regex.error, errormsg: logger.log(u"WARNING: Invalid episode_pattern, %s. %s" % (errormsg, cur_pattern)) else: - self.compiled_regexes[regex_type].update({cur_pattern_name: cur_regex}) + self.compiled_regexes[(regex_type,cur_pattern_name)] = cur_regex def _parse_string(self, name): if not name: return - for cur_regex_type, cur_regexes in self.compiled_regexes.items(): - for cur_regex_name, cur_regex in cur_regexes.items(): - match = cur_regex.match(name) + result = ParseResult(name) + for (cur_regex_type, cur_regex_name), cur_regex in self.compiled_regexes.items(): + match = cur_regex.fullmatch(name) - if not match: + if not match: + continue + + result.which_regex = [cur_regex_name] + + named_groups = match.groupdict().keys() + + if 'series_name' in named_groups: + result.series_name = match.group('series_name') + if result.series_name: + result.series_name = self.clean_series_name(result.series_name) + else:continue + + if 'season_num' in named_groups: + tmp_season = int(match.group('season_num')) + if cur_regex_name == 'bare' and tmp_season in (19, 20): continue + result.season_number = tmp_season - result = ParseResult(name) - result.which_regex = [cur_regex_name] + if 'ep_num' in named_groups: + ep_num = self._convert_number(match.group('ep_num')) + if 'extra_ep_num' in named_groups and match.group('extra_ep_num'): + result.episode_numbers = range(ep_num, self._convert_number(match.group('extra_ep_num')) + 1) + else: + result.episode_numbers = [ep_num] - named_groups = match.groupdict().keys() + if 'ep_ab_num' in named_groups: + ep_ab_num = self._convert_number(match.group('ep_ab_num')) + if 'extra_ab_ep_num' in named_groups and match.group('extra_ab_ep_num'): + result.ab_episode_numbers = range(ep_ab_num, + self._convert_number(match.group('extra_ab_ep_num')) + 1) + else: + result.ab_episode_numbers = [ep_ab_num] - if 'series_name' in named_groups: - result.series_name = match.group('series_name') - if result.series_name: - result.series_name = self.clean_series_name(result.series_name) + if 'sports_event_id' in named_groups: + sports_event_id = match.group('sports_event_id') + if sports_event_id: + result.sports_event_id = int(match.group('sports_event_id')) - cur_show = helpers.get_show_by_name(result.series_name, useIndexer=self.useIndexers) - if not cur_show: - continue - - # if we have a show object to compare against then do so else return the result anyways - if self.show: - if self.show.indexerid != cur_show.indexerid: - logger.log( - u"I expected an episode of the show " + self.show.name + " but the parser thinks its the show " + cur_show.name + ". I will continue thinking its " + self.show.name, - logger.WARNING) - continue - - result.show = cur_show - - if 'season_num' in named_groups: - tmp_season = int(match.group('season_num')) - if cur_regex_name == 'bare' and tmp_season in (19, 20): - continue - result.season_number = tmp_season - - if 'ep_num' in named_groups: - ep_num = self._convert_number(match.group('ep_num')) - if 'extra_ep_num' in named_groups and match.group('extra_ep_num'): - result.episode_numbers = range(ep_num, self._convert_number(match.group('extra_ep_num')) + 1) - else: - result.episode_numbers = [ep_num] - - if 'ep_ab_num' in named_groups: - ep_ab_num = self._convert_number(match.group('ep_ab_num')) - if 'extra_ab_ep_num' in named_groups and match.group('extra_ab_ep_num'): - result.ab_episode_numbers = range(ep_ab_num, - self._convert_number(match.group('extra_ab_ep_num')) + 1) - else: - result.ab_episode_numbers = [ep_ab_num] - - if 'sports_event_id' in named_groups: - sports_event_id = match.group('sports_event_id') - if sports_event_id: - result.sports_event_id = int(match.group('sports_event_id')) - - if 'sports_event_name' in named_groups: - result.sports_event_name = match.group('sports_event_name') - if result.sports_event_name: - result.sports_event_name = self.clean_series_name(result.sports_event_name) - - if 'sports_event_date' in named_groups: - sports_event_date = match.group('sports_event_date') - if sports_event_date: - try: - result.sports_event_date = parser.parse(sports_event_date, fuzzy=True).date() - except: - continue - - if 'air_year' in named_groups and 'air_month' in named_groups and 'air_day' in named_groups: - year = int(match.group('air_year')) - month = int(match.group('air_month')) - day = int(match.group('air_day')) + if 'sports_event_name' in named_groups: + result.sports_event_name = match.group('sports_event_name') + if result.sports_event_name: + result.sports_event_name = self.clean_series_name(result.sports_event_name) + if 'sports_event_date' in named_groups: + sports_event_date = match.group('sports_event_date') + if sports_event_date: try: - dtStr = '%s-%s-%s' % (year, month, day) - result.air_date = datetime.datetime.strptime(dtStr, "%Y-%m-%d").date() + result.sports_event_date = parser.parse(sports_event_date, fuzzy=True).date() except: continue - if 'extra_info' in named_groups: - tmp_extra_info = match.group('extra_info') + if 'air_year' in named_groups and 'air_month' in named_groups and 'air_day' in named_groups: + year = int(match.group('air_year')) + month = int(match.group('air_month')) + day = int(match.group('air_day')) - # Show.S04.Special or Show.S05.Part.2.Extras is almost certainly not every episode in the season - if tmp_extra_info and cur_regex_name == 'season_only' and re.search( - r'([. _-]|^)(special|extra)s?\w*([. _-]|$)', tmp_extra_info, re.I): - continue - result.extra_info = tmp_extra_info + try: + dtStr = '%s-%s-%s' % (year, month, day) + result.air_date = datetime.datetime.strptime(dtStr, "%Y-%m-%d").date() + except: + continue - if 'release_group' in named_groups: - result.release_group = match.group('release_group') + if 'extra_info' in named_groups: + tmp_extra_info = match.group('extra_info') - if result.show and result.show.is_anime and cur_regex_type in ['anime', 'normal']: - return result - elif result.show and result.show.is_sports and cur_regex_type == 'sports': - return result - elif cur_regex_type == 'normal': - return result + # Show.S04.Special or Show.S05.Part.2.Extras is almost certainly not every episode in the season + if tmp_extra_info and cur_regex_name == 'season_only' and regex.search( + r'([. _-]|^)(special|extra)s?\w*([. _-]|$)', tmp_extra_info, regex.I): + continue + result.extra_info = tmp_extra_info - return None + if 'release_group' in named_groups: + result.release_group = match.group('release_group') + + cur_show = helpers.get_show_by_name(result.series_name, useIndexer=self.useIndexers) + if cur_show: + if self.showObj: + if self.showObj.indexerid != cur_show.indexerid: + logger.log( + u"I expected an episode of the show " + self.showObj.name + " but the parser thinks its the show " + cur_show.name + ". I will continue thinking its " + self.showObj.name, + logger.WARNING) + return + + result.show = cur_show + + if not result.show: + continue + + # Natch found! + break + + + if self.convert: + result = result.convert() + + return result def _combine_results(self, first, second, attr): # if the first doesn't exist then return the second or nothing @@ -291,7 +286,7 @@ class NameParser(object): # break it into parts if there are any (dirname, file name, extension) dir_name, file_name = os.path.split(name) - ext_match = re.match('(.*)\.\w{3,4}$', file_name) + ext_match = regex.match('(.*)\.\w{3,4}$', file_name) if ext_match and self.file_name: base_file_name = ext_match.group(1) else: @@ -364,7 +359,8 @@ class ParseResult(object): release_group=None, air_date=None, ab_episode_numbers=None, - show=None + show=None, + score=None ): self.original_name = original_name @@ -392,6 +388,7 @@ class ParseResult(object): self.which_regex = None self.show = show + self.score = score def __eq__(self, other): if not other: @@ -419,6 +416,8 @@ class ParseResult(object): return False if self.show != other.show: return False + if self.score != other.score: + return False return True @@ -479,7 +478,7 @@ class ParseResult(object): new_episode_numbers.append(e) new_season_numbers.append(s) - # need to do a quick sanity check here. It's possible that we now have episodes + # need to do a quick sanity check heregex. It's possible that we now have episodes # from more than one season (by tvdb numbering), and this is just too much # for sickbeard, so we'd need to flag it. new_season_numbers = list(set(new_season_numbers)) # remove duplicates @@ -546,17 +545,7 @@ class NameParserCache(object): logger.log("Using cached parse result for: " + name, logger.DEBUG) return self._previous_parsed[name] - name_parser_cache = NameParserCache() - class InvalidNameException(Exception): - "The given name is not valid" - - -class MultipleSceneShowResults(Exception): - pass - - -class MultipleSceneEpisodeResults(Exception): - pass + "The given name is not valid" \ No newline at end of file diff --git a/sickbeard/naming.py b/sickbeard/naming.py index 1b0deceb..59692da9 100644 --- a/sickbeard/naming.py +++ b/sickbeard/naming.py @@ -56,6 +56,31 @@ class TVShow(): self.anime = 0 self.scene = 0 + def _is_anime(self): + if (self.anime > 0): + return True + else: + return False + + is_anime = property(_is_anime) + + def _is_sports(self): + if (self.sports > 0): + return True + else: + return False + + is_sports = property(_is_sports) + + def _is_scene(self): + if (self.scene > 0): + return True + else: + return False + + is_scene = property(_is_scene) + + class TVEpisode(tv.TVEpisode): def __init__(self, season, episode, absolute_number, name): self.relatedEps = [] @@ -139,9 +164,7 @@ def check_valid_sports_naming(pattern=None): return valid def validate_name(pattern, multi=None, file_only=False, abd=False, sports=False): - ep = _generate_sample_ep(multi, abd, sports) - - parser = NameParser(True) + ep = generate_sample_ep(multi, abd, sports) new_name = ep.formatted_filename(pattern, multi) + '.ext' new_path = ep.formatted_dir(pattern, multi) @@ -154,9 +177,11 @@ def validate_name(pattern, multi=None, file_only=False, abd=False, sports=False) logger.log(u"Trying to parse " + new_name, logger.DEBUG) + parser = NameParser(True) + try: result = parser.parse(new_name) - except InvalidNameException, e : + except Exception, e: logger.log(u"Unable to parse " + new_name + ", not valid", logger.DEBUG) return False @@ -177,7 +202,7 @@ def validate_name(pattern, multi=None, file_only=False, abd=False, sports=False) return True -def _generate_sample_ep(multi=None, abd=False, sports=False, anime=False): +def generate_sample_ep(multi=None, abd=False, sports=False, anime=False): # make a fake episode object ep = TVEpisode(2, 3, 3, "Ep Name") @@ -215,6 +240,6 @@ def _generate_sample_ep(multi=None, abd=False, sports=False, anime=False): def test_name(pattern, multi=None, abd=False, sports=False, anime=False): - ep = _generate_sample_ep(multi, abd, sports, anime) + ep = generate_sample_ep(multi, abd, sports, anime) return {'name': ep.formatted_filename(pattern, multi), 'dir': ep.formatted_dir(pattern, multi)} \ No newline at end of file diff --git a/sickbeard/properFinder.py b/sickbeard/properFinder.py index cbdcf32d..208975e3 100644 --- a/sickbeard/properFinder.py +++ b/sickbeard/properFinder.py @@ -119,7 +119,7 @@ class ProperFinder(): try: myParser = NameParser(False) - parse_result = myParser.parse(curProper.name).convert() + parse_result = myParser.parse(curProper.name) except InvalidNameException: logger.log(u"Unable to parse the filename " + curProper.name + " into a valid episode", logger.DEBUG) continue @@ -138,7 +138,7 @@ class ProperFinder(): showObj = parse_result.show logger.log( - u"Successful match! Result " + parse_result.series_name + " matched to show " + showObj.name, + u"Successful match! Result " + parse_result.original_name + " matched to show " + showObj.name, logger.DEBUG) # set the indexerid in the db to the show's indexerid diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index ab80bafd..24d5c15a 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -278,8 +278,8 @@ class GenericProvider: # parse the file name try: - myParser = NameParser(False, show=show, useIndexers=manualSearch) - parse_result = myParser.parse(title).convert() + myParser = NameParser(False, showObj=show, epObj=ep_obj, convert=True) + parse_result = myParser.parse(title) except InvalidNameException: logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING) continue diff --git a/sickbeard/tv.py b/sickbeard/tv.py index eeb9ed00..c9890efd 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -1895,6 +1895,26 @@ class TVEpisode(object): else: return ek.ek(os.path.join, self.show.location, self.location) + def createStrings(self, pattern=None): + patterns = [ + '%S.N.S%SE%0E', + '%S.N.S%0SE%E', + '%S.N.S%SE%E', + '%S.N.S%0SE%0E', + '%SN S%SE%0E', + '%SN S%0SE%E', + '%SN S%SE%E', + '%SN S%0SE%0E' + + ] + + strings = [] + if not pattern: + for p in patterns: + strings += [self._format_pattern(p)] + return strings + return self._format_pattern(pattern) + def prettyName(self): """ Returns the name of this episode in a "pretty" human-readable format. Used for logging @@ -1903,16 +1923,12 @@ class TVEpisode(object): Returns: A string representing the episode's name and season/ep numbers """ - if self.show.is_anime and not self.show.is_scene: - return self._format_pattern('%SN - %A - %EN') - elif self.show.is_anime and self.show.is_scene: - return self._format_pattern('%SN - %XA - %EN') - elif self.show.is_scene: - return self._format_pattern('%SN - %XSx%0XE - %EN') + if self.show.anime and not self.show.scene: + return self._format_pattern('%SN - %AB - %EN') elif self.show.air_by_date: return self._format_pattern('%SN - %AD - %EN') - else: - return self._format_pattern('%SN - %Sx%0E - %EN') + + return self._format_pattern('%SN - %Sx%0E - %EN') def _ep_name(self): """ @@ -1980,9 +1996,8 @@ class TVEpisode(object): if not name: return '' - np = NameParser(name) - try: + np = NameParser(name) parse_result = np.parse(name) except InvalidNameException, e: logger.log(u"Unable to get parse release_group: " + ex(e), logger.DEBUG) @@ -2017,7 +2032,7 @@ class TVEpisode(object): '%0XS': '%02d' % self.scene_season, '%XE': str(self.scene_episode), '%0XE': '%02d' % self.scene_episode, - '%A': '%(#)03d' % {'#': self.absolute_number}, + '%AB': '%(#)03d' % {'#': self.absolute_number}, '%XA': '%(#)03d' % {'#': self.scene_absolute_number}, '%RN': release_name(self.release_name), '%RG': release_group(self.release_name),