From 0b985834eea5429e35705111368acae7500a3562 Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Sun, 18 May 2014 00:35:49 +0200 Subject: [PATCH 01/82] Changing filename in Show overview: Complete filename is on hover only, to save space --- gui/slick/css/default.css | 5 +++-- gui/slick/interfaces/default/displayShow.tmpl | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gui/slick/css/default.css b/gui/slick/css/default.css index abff4f01..e4e21804 100644 --- a/gui/slick/css/default.css +++ b/gui/slick/css/default.css @@ -445,7 +445,8 @@ input:not(.btn){margin-right:6px;margin-top:5px;padding-top:4px;padding-bottom:4 } .sickbeardTable td.filename { -width: 30%; +width: 10%; +text-align: center; } @@ -1871,4 +1872,4 @@ pre { background: white; width: 270px; height: 220px; -} \ No newline at end of file +} diff --git a/gui/slick/interfaces/default/displayShow.tmpl b/gui/slick/interfaces/default/displayShow.tmpl index d6e3e8be..93f72bb3 100644 --- a/gui/slick/interfaces/default/displayShow.tmpl +++ b/gui/slick/interfaces/default/displayShow.tmpl @@ -278,7 +278,11 @@ #elif $epLoc and (not $epLoc.lower().startswith($show._location.lower()) or not $show._location): #set $epLoc = os.path.basename($epLoc) #end if +#if $epLoc != "" and $epLoc != None: +[details] +#else $epLoc +#end if #if $sickbeard.USE_SUBTITLES and $show.subtitles: From cf1d88343d897d1a00e63d0b89b4c55376343fbb Mon Sep 17 00:00:00 2001 From: JackDandy Date: Fri, 23 May 2014 16:20:44 +0100 Subject: [PATCH 02/82] Add feature to General Config to display fuzzy dates instead of absolute dates. Add feature to General Config to trim the leading number "0" shown on hour of day and date of month. Affects UI dates on the Coming Episodes, Display Show, Manage > Backlog Overview, Home and History pages. Widen the General Config tab widths and tweak, format and align some texts. The many 'test date' variations in the General Config -> "Date and Time" drop down are useless during the month of May as both short and long styles are the same. Change the 'test date' to January 1 of the next year so short and long month styles are distinguishable. --- .../interfaces/default/comingEpisodes.tmpl | 16 +- .../interfaces/default/config_general.tmpl | 88 +++++++--- gui/slick/interfaces/default/displayShow.tmpl | 20 ++- gui/slick/interfaces/default/history.tmpl | 15 +- gui/slick/interfaces/default/home.tmpl | 13 +- gui/slick/interfaces/default/inc_top.tmpl | 7 +- .../default/manage_backlogOverview.tmpl | 14 +- gui/slick/js/fuzzyMoment.js | 164 ++++++++++++++++++ gui/slick/js/moment/moment.min.js | 6 + sickbeard/__init__.py | 8 +- sickbeard/webserve.py | 6 +- 11 files changed, 319 insertions(+), 38 deletions(-) create mode 100644 gui/slick/js/fuzzyMoment.js create mode 100644 gui/slick/js/moment/moment.min.js diff --git a/gui/slick/interfaces/default/comingEpisodes.tmpl b/gui/slick/interfaces/default/comingEpisodes.tmpl index 0d754156..f62df8d2 100644 --- a/gui/slick/interfaces/default/comingEpisodes.tmpl +++ b/gui/slick/interfaces/default/comingEpisodes.tmpl @@ -107,6 +107,17 @@ \$('#sbRoot').ajaxEpSearch(); + #set $fuzzydate = 'airdate' + #if $sickbeard.FUZZY_DATING: + fuzzyMoment({ + containerClass : '.${fuzzydate}', + dateHasTime : true, + dateFormat : '${sickbeard.DATE_PRESET}', + timeFormat : '${sickbeard.TIME_PRESET}', + trimZero : #if $sickbeard.TRIM_ZERO then "true" else "false"# + }); + #end if + }); //--> @@ -146,7 +157,8 @@ - $sbdatetime.sbdatetime.sbfdatetime($cur_result["localtime"]).decode($sickbeard.SYS_ENCODING)$time.mktime($cur_result["localtime"].timetuple()) + ## forced to use a div to wrap airdate, the column sort went crazy with a span +
$sbdatetime.sbdatetime.sbfdatetime($cur_result["localtime"]).decode($sickbeard.SYS_ENCODING)
$time.mktime($cur_result["localtime"].timetuple()) $cur_result["show_name"] #if int($cur_result["paused"]): [paused] @@ -212,7 +224,7 @@ #set $show_div = "ep_listing listing_default" #if $sort == "show": -

+

#end if #for $cur_result in $sql_results: diff --git a/gui/slick/interfaces/default/config_general.tmpl b/gui/slick/interfaces/default/config_general.tmpl index 82128d6d..a96c2367 100644 --- a/gui/slick/interfaces/default/config_general.tmpl +++ b/gui/slick/interfaces/default/config_general.tmpl @@ -48,7 +48,7 @@

Some options may require a manual restart to take effect.

-
+
@@ -124,7 +124,7 @@
-
+
+
@@ -288,7 +296,7 @@ @@ -318,11 +326,11 @@ @@ -330,7 +338,7 @@ @@ -359,16 +367,32 @@

Date and Time

-
+
+ +
+ + +
+ +
+ + +
+
+ Anime +
+ +

+
+
Subtitles
diff --git a/sickbeard/blackandwhitelist.py b/sickbeard/blackandwhitelist.py new file mode 100644 index 00000000..e0252f33 --- /dev/null +++ b/sickbeard/blackandwhitelist.py @@ -0,0 +1,210 @@ +# Author: Dennis Lutter +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see . + +from sickbeard import db, logger + +class BlackAndWhiteList(object): + _tableBlack = "blacklist" + _tableWhite = "whitelist" + blackList = [] + whiteList = [] + blackDict = {} + whiteDict = {} + + last_black_valid_result = None + last_white_valid_result = None + + def __init__(self, show_id): + if not show_id: + raise BlackWhitelistNoShowIDException() + self.show_id = show_id + + self.myDB = db.DBConnection() + self.refresh() + + def refresh(self): + logger.log(u"Building black and white list for " + str(self.show_id), logger.DEBUG) + + (self.blackList, self.blackDict) = self.load_blacklist() + (self.whiteList, self.whiteDict) = self.load_whitelist() + + def load_blacklist(self): + return self._load_list(self._tableBlack) + + def load_whitelist(self): + return self._load_list(self._tableWhite) + + def get_black_keywords_for(self, range): + if range in self.blackDict: + return self.blackDict[range] + else: + return [] + + def get_white_keywords_for(self, range): + if range in self.whiteDict: + return self.whiteDict[range] + else: + return [] + + def set_black_keywords(self, range, values): + self._del_all_black_keywords() + self._add_keywords(self._tableBlack, range, values) + + def set_white_keywords(self, range, values): + self._del_all_white_keywords() + self._add_keywords(self._tableWhite, range, values) + + def set_black_keywords_for(self, range, values): + self._del_all_black_keywords_for(range) + self._add_keywords(self._tableBlack, range, values) + + def set_white_keywords_for(self, range, values): + self._del_all_white_keywords_for(range) + self._add_keywords(self._tableWhite, range, values) + + def add_black_keyword(self, range, value): + self._add_keywords(self._tableBlack, range, [value]) + + def add_white_keyword(self, range, value): + self._add_keywords(self._tableWhite, range, [value]) + + def get_last_result_msg(self): + blackResult = whiteResult = "Untested" + if self.last_black_valid_result == True: + blackResult = "Valid" + elif self.last_black_valid_result == False: + blackResult = "Invalid" + + if self.last_white_valid_result == True: + whiteResult = "Valid" + elif self.last_white_valid_result == False: + whiteResult = "Invalid" + + return "Blacklist: " + blackResult + ", Whitelist: " + whiteResult + + def _add_keywords(self, table, range, values): + for value in values: + self.myDB.action("INSERT INTO " + table + " (show_id, range , keyword) VALUES (?,?,?)", [self.show_id, range, value]) + self.refresh() + + def _del_all_black_keywords(self): + self._del_all_keywords(self._tableBlack) + + def _del_all_white_keywords(self): + self._del_all_keywords(self._tableWhite) + + def _del_all_black_keywords_for(self, range): + self._del_all_keywords_for(self._tableBlack, range) + + def _del_all_white_keywords_for(self, range): + self._del_all_keywords_for(self._tableWhite, range) + + def _del_all_keywords(self, table): + logger.log(u"Deleting all " + table + " keywords for " + str(self.show_id), logger.DEBUG) + self.myDB.action("DELETE FROM " + table + " WHERE show_id = ?", [self.show_id]) + self.refresh() + + def _del_all_keywords_for(self, table, range): + logger.log(u"Deleting all " + range + " " + table + " keywords for " + str(self.show_id), logger.DEBUG) + self.myDB.action("DELETE FROM " + table + " WHERE show_id = ? and range = ?", [self.show_id, range]) + self.refresh() + + def _load_list(self, table): + sqlResults = self.myDB.select("SELECT range,keyword FROM " + table + " WHERE show_id = ? ", [self.show_id]) + if not sqlResults or not len(sqlResults): + return ([], {}) + + list, dict = self._build_keyword_dict(sqlResults) + logger.log("BWL: " + str(self.show_id) + " loaded keywords from " + table + ": " + str(dict), logger.DEBUG) + return list, dict + + def _build_keyword_dict(self, sql_result): + list = [] + dict = {} + for row in sql_result: + list.append(row["keyword"]) + if row["range"] in dict: + dict[row["range"]].append(row["keyword"]) + else: + dict[row["range"]] = [row["keyword"]] + + return (list, dict) + + def is_valid_for_black(self, haystack): + logger.log(u"BWL: " + str(self.show_id) + " is valid black", logger.DEBUG) + result = self._is_valid_for(self.blackDict, False, haystack) + self.last_black_valid_result = result + return result + + def is_valid_for_white(self, haystack): + logger.log(u"BWL: " + str(self.show_id) + " is valid white", logger.DEBUG) + result = self._is_valid_for(self.whiteDict, True, haystack) + self.last_white_valid_result = result + return result + + def is_valid(self, haystack): + return self.is_valid_for_black(haystack) and self.is_valid_for_white(haystack) + + def _is_valid_for(self, list, mood, haystack): + if not len(list): + return True + + results = [] + for range in list: + for keyword in list[range]: + string = None + if range == "global": + string = haystack.name + elif range in haystack.__dict__: + string = haystack.__dict__[range] + elif not range in haystack.__dict__: + results.append((not mood)) + else: + results.append(False) + + if string: + results.append(self._is_keyword_in_string(string, keyword) == mood) + + # black: mood = False + # white: mood = True + if mood in results: + return mood + else: + return (not mood) + + def _is_keyword_in_string(self, fromPost, fromBWList): + """ + will return true if fromBWList is found in fromPost + for now a basic find is used + """ + fromPost = fromPost.lower() + fromBWList = fromBWList.lower() + logger.log(u"BWL: " + str(self.show_id) + " comparing fromPost: " + fromPost + " vs fromBWlist: " + fromBWList, logger.DEBUG) + return (fromPost.find(fromBWList) >= 0) + +class BlackWhiteKeyword(object): + range = "" + value = [] + + def __init__(self, range, values): + self.range = range # "global" or a parser group + self.value = values # a list of values may contain only one item (still a list) + + +class BlackWhitelistNoShowIDException(Exception): + "No show_id was given" diff --git a/sickbeard/databases/mainDB.py b/sickbeard/databases/mainDB.py index 5db76ca0..61af0ee8 100644 --- a/sickbeard/databases/mainDB.py +++ b/sickbeard/databases/mainDB.py @@ -27,7 +27,7 @@ from sickbeard import encodingKludge as ek from sickbeard.name_parser.parser import NameParser, InvalidNameException MIN_DB_VERSION = 9 # oldest db version we support migrating from -MAX_DB_VERSION = 34 +MAX_DB_VERSION = 36 class MainSanityCheck(db.DBSanityCheck): def check(self): @@ -834,3 +834,30 @@ class AddSceneAbsoluteNumbering(AddAbsoluteNumbering): self.addColumn("scene_numbering", "scene_absolute_number", "NUMERIC", "0") self.incDBVersion() + +class AddAnimeBlacklistWhitelist(AddSceneAbsoluteNumbering): + + def test(self): + return self.checkDBVersion() >= 35 + + def execute(self): + backupDatabase(35) + + ql = [] + ql.append(["CREATE TABLE blacklist (show_id INTEGER, range TEXT, keyword TEXT)"]) + ql.append(["CREATE TABLE whitelist (show_id INTEGER, range TEXT, keyword TEXT)"]) + self.connection.mass_action(ql) + + self.incDBVersion() + +class AddSceneAbsoluteNumbering(AddAnimeBlacklistWhitelist): + def test(self): + return self.checkDBVersion() >= 36 + + def execute(self): + backupDatabase(36) + + logger.log(u"Adding column scene_absolute_number to tv_episodes") + self.addColumn("tv_episodes", "scene_absolute_number", "NUMERIC", "0") + + self.incDBVersion() diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py index 953916ce..a84cdd8d 100644 --- a/sickbeard/helpers.py +++ b/sickbeard/helpers.py @@ -680,7 +680,6 @@ def is_anime_in_show_list(): def update_anime_support(): sickbeard.ANIMESUPPORT = is_anime_in_show_list() - def get_all_episodes_from_absolute_number(show, indexer_id, absolute_numbers): if len(absolute_numbers) == 0: raise EpisodeNotFoundByAbsoluteNumberException() diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 5c6198cb..8ac49561 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -24,7 +24,7 @@ import regexes import time import sickbeard -from sickbeard import logger, helpers, scene_numbering +from sickbeard import logger, helpers, scene_numbering, db from sickbeard.exceptions import EpisodeNotFoundByAbsoluteNumberException from dateutil import parser @@ -53,6 +53,7 @@ class NameParser(object): self._compile_regexes(self.regexMode) self.showList = sickbeard.showList self.useIndexers = useIndexers + self.show = show def clean_series_name(self, series_name): """Cleans up series name by removing any . and _ @@ -194,7 +195,12 @@ class NameParser(object): if 'release_group' in named_groups: result.release_group = match.group('release_group') - show = helpers.get_show_by_name(result.series_name, useIndexer=self.useIndexers) + # determin show object for correct regex matching + if not self.show: + show = helpers.get_show_by_name(result.series_name, useIndexer=self.useIndexers) + else: + show = self.show + if show and show.is_anime and cur_regex_type in ['anime', 'normal']: result.show = show return result @@ -336,6 +342,140 @@ class NameParser(object): return final_result + def scene2indexer(self, show, scene_name, season, episodes, absolute_numbers): + if not show: return self # need show object + + # TODO: check if adb and make scene2indexer useable with correct numbers + out_season = None + out_episodes = [] + out_absolute_numbers = [] + + # is the scene name a special season ? + # TODO: define if we get scene seasons or indexer seasons ... for now they are mostly the same ... and i will use them as scene seasons + _possible_seasons = sickbeard.scene_exceptions.get_scene_exception_by_name_multiple(scene_name) + # filter possible_seasons + possible_seasons = [] + for cur_scene_indexer_id, cur_scene_season in _possible_seasons: + if cur_scene_indexer_id and str(cur_scene_indexer_id) != str(show.indexerid): + logger.log("Indexer ID mismatch: " + str(show.indexerid) + " now: " + str(cur_scene_indexer_id), + logger.ERROR) + raise MultipleSceneShowResults("indexerid mismatch") + # don't add season -1 since this is a generic name and not a real season... or if we get None + # if this was the only result possible_seasons will stay empty and the next parts will look in the general matter + if cur_scene_season == -1 or cur_scene_season == None: + continue + possible_seasons.append(cur_scene_season) + # if not possible_seasons: # no special season name was used or we could not find it + logger.log( + "possible seasons for '" + scene_name + "' (" + str(show.indexerid) + ") are " + str(possible_seasons), + logger.DEBUG) + + # lets just get a db connection we will need it anyway + cacheDB = db.DBConnection('cache.db') + # should we use absolute_numbers -> anime or season, episodes -> normal show + if show.is_anime: + logger.log( + u"'" + show.name + "' is an anime i will scene convert the absolute numbers " + str(absolute_numbers), + logger.DEBUG) + if possible_seasons: + # check if we have a scene_absolute_number in the possible seasons + for cur_possible_season in possible_seasons: + # and for all absolute numbers + for cur_ab_number in absolute_numbers: + namesSQlResult = cacheDB.select( + "SELECT season, episode, absolute_number FROM xem_numbering WHERE indexer_id = ? and scene_season = ? and scene_absolute_number = ?", + [show.indexerid, cur_possible_season, cur_ab_number]) + if len(namesSQlResult) > 1: + logger.log( + "Multiple episodes for a absolute number and season. check XEM numbering", + logger.ERROR) + raise MultipleSceneEpisodeResults("Multiple episodes for a absolute number and season") + elif len(namesSQlResult) == 0: + break # break out of current absolute_numbers -> next season ... this is not a good sign + # if we are here we found ONE episode for this season absolute number + # logger.log(u"I found matching episode: " + namesSQlResult[0]['name'], logger.DEBUG) + out_episodes.append(int(namesSQlResult[0]['episode'])) + out_absolute_numbers.append(int(namesSQlResult[0]['absolute_number'])) + out_season = int(namesSQlResult[0][ + 'season']) # note this will always use the last season we got ... this will be a problem on double episodes that break the season barrier + if out_season: # if we found a episode in the cur_possible_season we dont need / want to look at the other season possibilities + break + else: # no possible seasons from the scene names lets look at this more generic + for cur_ab_number in absolute_numbers: + namesSQlResult = cacheDB.select( + "SELECT season, episode, absolute_number FROM xem_numbering WHERE indexer_id = ? and scene_absolute_number = ?", + [show.indexerid, cur_ab_number]) + if len(namesSQlResult) > 1: + logger.log( + "Multiple episodes for a absolute number. this might happend because we are missing a scene name for this season. xem lacking behind ?", + logger.ERROR) + raise MultipleSceneEpisodeResults("Multiple episodes for a absolute number") + elif len(namesSQlResult) == 0: + continue + # if we are here we found ONE episode for this season absolute number + # logger.log(u"I found matching episode: " + namesSQlResult[0]['name'], logger.DEBUG) + out_episodes.append(int(namesSQlResult[0]['episode'])) + out_absolute_numbers.append(int(namesSQlResult[0]['absolute_number'])) + out_season = int(namesSQlResult[0][ + 'season']) # note this will always use the last season we got ... this will be a problem on double episodes that break the season barrier + if not out_season: # we did not find anything in the loops ? damit there is no episode + logger.log("No episode found for these scene numbers. asuming indexer numbers", logger.DEBUG) + # we still have to convert the absolute number to sxxexx ... but that is done not here + else: + logger.log(u"'" + show.name + "' is a normal show i will scene convert the season and episodes " + str( + season) + "x" + str(episodes), logger.DEBUG) + out_absolute_numbers = None + if possible_seasons: + # check if we have a scene_absolute_number in the possible seasons + for cur_possible_season in possible_seasons: + # and for all episode + for cur_episode in episodes: + namesSQlResult = cacheDB.select( + "SELECT season, episode FROM xem_numbering WHERE indexer_id = ? and scene_season = ? and scene_episode = ?", + [show.indexerid, cur_possible_season, cur_episode]) + if len(namesSQlResult) > 1: + logger.log( + "Multiple episodes for season episode number combination. this should not be check xem configuration", + logger.ERROR) + raise MultipleSceneEpisodeResults("Multiple episodes for season episode number combination") + elif len(namesSQlResult) == 0: + break # break out of current episode -> next season ... this is not a good sign + # if we are here we found ONE episode for this season absolute number + # logger.log(u"I found matching episode: " + namesSQlResult[0]['name'], logger.DEBUG) + out_episodes.append(int(namesSQlResult[0]['episode'])) + out_season = int(namesSQlResult[0][ + 'season']) # note this will always use the last season we got ... this will be a problem on double episodes that break the season barrier + if out_season: # if we found a episode in the cur_possible_season we dont need / want to look at the other posibilites + break + else: # no possible seasons from the scene names lets look at this more generic + for cur_episode in episodes: + namesSQlResult = cacheDB.select( + "SELECT season, episode FROM xem_numbering WHERE indexer_id = ? and scene_episode = ? and scene_season = ?", + [show.indexerid, cur_episode, season]) + if len(namesSQlResult) > 1: + logger.log( + "Multiple episodes for season episode number combination. this might happend because we are missing a scene name for this season. xem lacking behind ?", + logger.ERROR) + raise MultipleSceneEpisodeResults("Multiple episodes for season episode number combination") + elif len(namesSQlResult) == 0: + continue + # if we are here we found ONE episode for this season absolute number + # logger.log(u"I found matching episode: " + namesSQlResult[0]['name'], logger.DEBUG) + out_episodes.append(int(namesSQlResult[0]['episode'])) + out_season = int(namesSQlResult[0][ + 'season']) # note this will always use the last season we got ... this will be a problem on double episodes that break the season barrier + # this is only done for normal shows + if not out_season: # we did not find anything in the loops ? darn there is no episode + logger.log("No episode found for these scene numbers. assuming these are valid indexer numbers", + logger.DEBUG) + out_season = season + out_episodes = episodes + out_absolute_numbers = absolute_numbers + + # okay that was easy we found the correct season and episode numbers + return (out_season, out_episodes, out_absolute_numbers) + + class ParseResult(object): def __init__(self, original_name, @@ -454,7 +594,8 @@ class ParseResult(object): if len(self.ab_episode_numbers): abNo = self.ab_episode_numbers[i] - (s, e, a) = scene_numbering.get_indexer_numbering(self.show.indexerid, self.show.indexer, self.season_number, + (s, e, a) = scene_numbering.get_indexer_numbering(self.show.indexerid, self.show.indexer, + self.season_number, epNo, abNo) new_episode_numbers.append(e) new_season_numbers.append(s) @@ -530,3 +671,11 @@ name_parser_cache = NameParserCache() class InvalidNameException(Exception): "The given name is not valid" + + +class MultipleSceneShowResults(Exception): + pass + + +class MultipleSceneEpisodeResults(Exception): + pass diff --git a/sickbeard/providers/btn.py b/sickbeard/providers/btn.py index d176857f..f0711858 100644 --- a/sickbeard/providers/btn.py +++ b/sickbeard/providers/btn.py @@ -39,6 +39,7 @@ class BTNProvider(generic.TorrentProvider): generic.TorrentProvider.__init__(self, "BTN") self.supportsBacklog = True + self.supportsAbsoluteNumbering = True self.enabled = False self.api_key = None @@ -211,13 +212,14 @@ class BTNProvider(generic.TorrentProvider): # Search for entire seasons: no need to do special things for air by date shows whole_season_params = current_params.copy() - partial_season_params = current_params.copy() # Search for entire seasons: no need to do special things for air by date shows whole_season_params['category'] = 'Season' if ep_obj.show.air_by_date or ep_obj.show.sports: # Search for the year of the air by date show whole_season_params['name'] = str(ep_obj.airdate).split('-')[0] + elif ep_obj.show.is_anime: + whole_season_params['name'] = "%d" % ep_obj.scene_absolute_number else: whole_season_params['name'] = 'Season ' + str(ep_obj.scene_season) @@ -232,9 +234,9 @@ class BTNProvider(generic.TorrentProvider): search_params = {'category': 'Episode'} - if self.show.indexer == 1: + if self.show.indexer == 1 and not self.show.is_anime: search_params['tvdb'] = self.show.indexerid - elif self.show.indexer == 2: + elif self.show.indexer == 2 and not self.show.is_anime: search_params['tvrage'] = self.show.indexerid else: search_params['series'] = sanitizeSceneName(self.show.name) @@ -251,6 +253,8 @@ class BTNProvider(generic.TorrentProvider): # BTN uses dots in dates, we just search for the date since that # combined with the series identifier should result in just one episode search_params['name'] = date_str.replace('-', '.') + elif self.show.is_anime: + search_params['name'] = "%i" % int(ep_obj.scene_absolute_number) else: # Do a general name search for the episode, formatted like SXXEYY search_params['name'] = "S%02dE%02d" % (ep_obj.scene_season, ep_obj.scene_episode) diff --git a/sickbeard/providers/fanzub.py b/sickbeard/providers/fanzub.py index 9dec722a..03d18470 100644 --- a/sickbeard/providers/fanzub.py +++ b/sickbeard/providers/fanzub.py @@ -17,6 +17,7 @@ # along with Sick Beard. If not, see . import urllib +import datetime import sickbeard import generic @@ -36,6 +37,7 @@ class Fanzub(generic.NZBProvider): self.supportsBacklog = False self.supportsAbsoluteNumbering = True + self.anime_only = True self.enabled = False @@ -101,24 +103,21 @@ class Fanzub(generic.NZBProvider): results = [] for i in [2, 3, 4]: # we will look for a version 2, 3 and 4 - """ - because of this the proper search failed !! - well more precisly because _doSearch does not accept a dict rather then a string - params = { - "q":"v"+str(i).encode('utf-8') - } - """ - for curResult in self._doSearch("v" + str(i)): + for item in self._doSearch("v" + str(i)): - match = re.search('(\w{3}, \d{1,2} \w{3} \d{4} \d\d:\d\d:\d\d) [\+\-]\d{4}', curResult.findtext('pubDate')) - if not match: + (title, url) = self._get_title_and_url(item) + + if item.has_key('published_parsed') and item['published_parsed']: + result_date = item.published_parsed + if result_date: + result_date = datetime.datetime(*result_date[0:6]) + else: + logger.log(u"Unable to figure out the date for entry " + title + ", skipping it") continue - dateString = match.group(1) - resultDate = parseDate(dateString).replace(tzinfo=None) - - if date == None or resultDate > date: - results.append(classes.Proper(curResult.findtext('title'), curResult.findtext('link'), resultDate)) + if not date or result_date > date: + search_result = classes.Proper(title, url, result_date) + results.append(search_result) return results @@ -145,7 +144,7 @@ class FanzubCache(tvcache.TVCache): return self.getRSSFeed(rss_url) - def _checkAuth(self, data): - return self.provider._checkAuthFromData(data) + def _checkItemAuth(self, title, url): + return True provider = Fanzub() diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index fac98108..ded53756 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -55,11 +55,12 @@ class GenericProvider: self.supportsBacklog = False self.supportsAbsoluteNumbering = False + self.anime_only = False self.search_mode = None self.search_fallback = False self.backlog_only = False - + self.cache = tvcache.TVCache(self) self.session = requests.session() @@ -254,7 +255,7 @@ class GenericProvider: u"Incomplete Indexer <-> Scene mapping detected for " + epObj.prettyName() + ", skipping search!") continue - #cacheResult = self.cache.searchCache([epObj], manualSearch) + # cacheResult = self.cache.searchCache([epObj], manualSearch) #if len(cacheResult): # results.update({epObj.episode:cacheResult[epObj]}) # continue @@ -275,7 +276,7 @@ class GenericProvider: searchItems[epObj] = itemList # if we have cached results return them. - #if len(results): + # if len(results): # return results for ep_obj in searchItems: @@ -323,7 +324,7 @@ class GenericProvider: continue if (parse_result.air_by_date and parse_result.air_date != ep_obj.airdate) or ( - parse_result.sports and parse_result.sports_event_date != ep_obj.airdate): + parse_result.sports and parse_result.sports_event_date != ep_obj.airdate): logger.log("Episode " + title + " didn't air on " + str(ep_obj.airdate) + ", skipping it", logger.DEBUG) continue diff --git a/sickbeard/providers/nyaatorrents.py b/sickbeard/providers/nyaatorrents.py index a4529075..793ead15 100644 --- a/sickbeard/providers/nyaatorrents.py +++ b/sickbeard/providers/nyaatorrents.py @@ -37,7 +37,7 @@ class NyaaProvider(generic.TorrentProvider): self.supportsBacklog = True self.supportsAbsoluteNumbering = True - + self.anime_only = True self.enabled = False self.ratio = None @@ -60,9 +60,7 @@ class NyaaProvider(generic.TorrentProvider): return generic.TorrentProvider.findSearchResults(self, show, season, episodes, search_mode, manualSearch) def _get_season_search_strings(self, ep_obj): - names = [] - names.extend(show_name_helpers.makeSceneShowSearchStrings(self.show)) - return names + return show_name_helpers.makeSceneShowSearchStrings(self.show) def _get_episode_search_strings(self, ep_obj, add_string=''): return self._get_season_search_strings(ep_obj) diff --git a/sickbeard/scene_numbering.py b/sickbeard/scene_numbering.py index 5d58aa1a..aa9a9692 100644 --- a/sickbeard/scene_numbering.py +++ b/sickbeard/scene_numbering.py @@ -68,7 +68,6 @@ def get_scene_numbering(indexer_id, indexer, season, episode, absolute_number=No return xem_result return (season, episode, absolute_number) - def find_scene_numbering(indexer_id, indexer, season, episode, absolute_number=None): """ Same as get_scene_numbering(), but returns None if scene numbering is not set @@ -400,7 +399,6 @@ def get_xem_numbering_for_season(indexer_id, indexer, season): return result - def fix_scene_numbering(): ql = [] @@ -436,3 +434,40 @@ def fix_scene_numbering(): if ql: myDB.mass_action(ql) + +def get_ep_mapping(epObj, parse_result): + # scores + indexer_numbering = 0 + scene_numbering = 0 + absolute_numbering = 0 + + _possible_seasons = sickbeard.scene_exceptions.get_scene_exception_by_name_multiple(parse_result.series_name) + + # indexer numbering + if epObj.season == parse_result.season_number: + indexer_numbering += 1 + elif epObj.episode in parse_result.episode_numbers: + indexer_numbering += 1 + + # scene numbering + if epObj.scene_season == parse_result.season_number: + scene_numbering += 1 + elif epObj.scene_episode in parse_result.episode_numbers: + scene_numbering += 1 + + # absolute numbering + if epObj.show.is_anime and parse_result.is_anime: + + if epObj.absolute_number in parse_result.ab_episode_numbers: + absolute_numbering +=1 + elif epObj.scene_absolute_number in parse_result.ab_episode_numbers: + absolute_numbering += 1 + + if indexer_numbering == 2: + print "indexer numbering" + elif scene_numbering == 2: + print "scene numbering" + elif absolute_numbering == 1: + print "indexer numbering" + else: + print "could not determin numbering" \ No newline at end of file diff --git a/sickbeard/search.py b/sickbeard/search.py index 4c2b7b86..0e9f9a84 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -42,7 +42,7 @@ from sickbeard import providers from sickbeard import failed_history from sickbeard.exceptions import ex from sickbeard.providers.generic import GenericProvider, tvcache - +from sickbeard.blackandwhitelist import BlackAndWhiteList def _downloadResult(result): """ @@ -197,11 +197,23 @@ def filter_release_name(name, filter_words): def pickBestResult(results, show, quality_list=None): logger.log(u"Picking the best result out of " + str([x.name for x in results]), logger.DEBUG) + # build the black And white list + bwl = None + if show: + bwl = BlackAndWhiteList(show.indexerid) + else: + logger.log("Could not create black and white list no show was given", logger.DEBUG) + # find the best result for the current episode bestResult = None for cur_result in results: logger.log("Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) + if bwl: + if not bwl.is_valid(cur_result): + logger.log(cur_result.name+" does not match the blacklist or the whitelist, rejecting it. Result: " + bwl.get_last_result_msg(), logger.MESSAGE) + continue + if quality_list and cur_result.quality not in quality_list: logger.log(cur_result.name + " is a quality we know we don't want, rejecting it", logger.DEBUG) continue @@ -254,12 +266,18 @@ def isFinalResult(result): show_obj = result.episodes[0].show + bwl = BlackAndWhiteList(show_obj.indexerid) + any_qualities, best_qualities = Quality.splitQuality(show_obj.quality) # if there is a redownload that's higher than this then we definitely need to keep looking if best_qualities and result.quality < max(best_qualities): return False + # if it does not match the shows black and white list its no good + elif not bwl.is_valid(result): + return False + # if there's no redownload that's higher (above) and this is the highest initial download then we're good elif any_qualities and result.quality in any_qualities: return True @@ -317,7 +335,7 @@ def filterSearchResults(show, season, results): return foundResults -def searchForNeededEpisodes(episodes): +def searchForNeededEpisodes(show, episodes): foundResults = {} didSearch = False @@ -328,6 +346,10 @@ def searchForNeededEpisodes(episodes): for curProviderCount, curProvider in enumerate(providers): threading.currentThread().name = origThreadName + " :: [" + curProvider.name + "]" + if curProvider.anime_only and not show.is_anime: + logger.log(u"" + str(show.name) + " is not an anime skiping ...") + continue + try: logger.log(u"Updating RSS cache ...") curProvider.cache.updateCache() @@ -382,9 +404,10 @@ def searchProviders(show, season, episodes, manualSearch=False): # check if we want to search for season packs instead of just season/episode seasonSearch = False - seasonEps = show.getAllEpisodes(season) - if len(seasonEps) == len(episodes): - seasonSearch = True + if not manualSearch: + seasonEps = show.getAllEpisodes(season) + if len(seasonEps) == len(episodes): + seasonSearch = True providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive()] @@ -399,6 +422,10 @@ def searchProviders(show, season, episodes, manualSearch=False): foundResults.setdefault(provider.name, {}) searchCount = 0 + if provider.anime_only and not show.is_anime: + logger.log(u"" + str(show.name) + " is not an anime skiping ...") + continue + search_mode = 'eponly' if seasonSearch and provider.search_mode == 'sponly': search_mode = provider.search_mode diff --git a/sickbeard/search_queue.py b/sickbeard/search_queue.py index 8857f4a6..d932bd0b 100644 --- a/sickbeard/search_queue.py +++ b/sickbeard/search_queue.py @@ -97,7 +97,7 @@ class DailySearchQueueItem(generic_queue.QueueItem): generic_queue.QueueItem.execute(self) logger.log("Beginning daily search for [" + self.show.name + "]") - foundResults = search.searchForNeededEpisodes(self.segment) + foundResults = search.searchForNeededEpisodes(self.show, self.segment) # reset thread back to original name threading.currentThread().name = self.thread_name diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py index 54f705ee..5e245dc5 100644 --- a/sickbeard/show_queue.py +++ b/sickbeard/show_queue.py @@ -351,6 +351,16 @@ class QueueItemAdd(ShowQueueItem): logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) + # before we parse local files lets update exceptions + sickbeard.scene_exceptions.retrieve_exceptions() + + # and get scene numbers + logger.log(u"Attempting to load scene numbers", logger.DEBUG) + if self.show.loadEpisodeSceneNumbers(): + logger.log(u"loading scene numbers successfull", logger.DEBUG) + else: + logger.log(u"loading scene numbers NOT successfull or no scene numbers available", logger.DEBUG) + try: self.show.loadEpisodesFromDir() except Exception, e: @@ -538,8 +548,13 @@ class QueueItemUpdate(ShowQueueItem): except exceptions.EpisodeDeletedException: pass - sickbeard.showQueueScheduler.action.refreshShow(self.show, True) #@UndefinedVariable + logger.log(u"Attempting to load scene numbers", logger.DEBUG) + if self.show.loadEpisodeSceneNumbers(): + logger.log(u"loading scene numbers successfull", logger.DEBUG) + else: + logger.log(u"loading scene numbers NOT successfull or no scene numbers available", logger.DEBUG) + sickbeard.showQueueScheduler.action.refreshShow(self.show, True) class QueueItemForceUpdate(QueueItemUpdate): def __init__(self, show=None): diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 6c1f9dc8..2a83b6b4 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -52,6 +52,7 @@ from common import DOWNLOADED, SNATCHED, SNATCHED_PROPER, SNATCHED_BEST, ARCHIVE from common import NAMING_DUPLICATE, NAMING_EXTEND, NAMING_LIMITED_EXTEND, NAMING_SEPARATED_REPEAT, \ NAMING_LIMITED_EXTEND_E_PREFIXED + class TVShow(object): def __init__(self, indexer, indexerid, lang=""): @@ -96,17 +97,19 @@ class TVShow(object): self.loadFromDB() def _is_anime(self): - if(self.anime > 0): + if (self.anime > 0): return True else: return False + is_anime = property(_is_anime) def _is_sports(self): - if(self.sports > 0): + if (self.sports > 0): return True else: return False + is_sports = property(_is_sports) def _getLocation(self): @@ -197,14 +200,25 @@ class TVShow(object): if len(sqlResults) == 1: episode = int(sqlResults[0]["episode"]) season = int(sqlResults[0]["season"]) - logger.log("Found episode by absolute_number:"+str(absolute_number)+" which is "+str(season)+"x"+str(episode), logger.DEBUG) + logger.log( + "Found episode by absolute_number:" + str(absolute_number) + " which is " + str(season) + "x" + str( + episode), logger.DEBUG) elif len(sqlResults) > 1: - logger.log("Multiple entries for absolute number: "+str(absolute_number)+" in show: "+self.name+" found ", logger.ERROR) + logger.log("Multiple entries for absolute number: " + str( + absolute_number) + " in show: " + self.name + " found ", logger.ERROR) return None else: - logger.log("No entries for absolute number: "+str(absolute_number)+" in show: "+self.name+" found.", logger.DEBUG) + logger.log( + "No entries for absolute number: " + str(absolute_number) + " in show: " + self.name + " found.", + logger.DEBUG) return None + def createCurSeasonDict(): + if not season in self.episodes: + self.episodes[season] = {} + + createCurSeasonDict() + if not episode in self.episodes[season] or self.episodes[season][episode] == None: if noCreate: return None @@ -221,7 +235,6 @@ class TVShow(object): self.episodes[season][episode] = ep epObj = self.episodes[season][episode] - epObj.convertToSceneNumbering() return epObj @@ -264,7 +277,7 @@ class TVShow(object): # in the first year after ended (last airdate), update every 30 days # in the first year after ended (last airdate), update every 30 days if (update_date - last_airdate) < datetime.timedelta(days=450) and ( - update_date - last_update_indexer) > datetime.timedelta(days=30): + update_date - last_update_indexer) > datetime.timedelta(days=30): return True return False @@ -519,6 +532,33 @@ class TVShow(object): return scannedEps + def loadEpisodeSceneNumbers(self): + epList = self.loadEpisodesFromDB() + + sql_l = [] + for curSeason in epList: + for curEp in epList[curSeason]: + epObj = self.getEpisode(curSeason, curEp) + + with epObj.lock: + (epObj.scene_season, epObj.scene_episode, epObj.scene_absolute_number) = \ + sickbeard.scene_numbering.get_scene_numbering(self.indexerid, self.indexer, epObj.season, + epObj.episode, epObj.absolute_number) + logger.log( + str(self.indexerid) + ": adding scene numbering. Indexer: " + str(epObj.season) + "x" + str( + epObj.episode) + "| Scene: " + str(epObj.scene_season) + "x" + str(epObj.scene_episode), + logger.DEBUG) + + # mass add to database + if epObj.dirty: + sql_l.append(epObj.get_sql()) + + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) + + return True + def getImages(self, fanart=None, poster=None): fanart_result = poster_result = banner_result = False season_posters_result = season_banners_result = season_all_poster_result = season_all_banner_result = False @@ -765,7 +805,7 @@ class TVShow(object): if not self.imdbid: self.imdbid = sqlResults[0]["imdb_id"] - #Get IMDb_info from database + # Get IMDb_info from database sqlResults = myDB.select("SELECT * FROM imdb_info WHERE indexer_id = ?", [self.indexerid]) if len(sqlResults) == 0: @@ -851,7 +891,7 @@ class TVShow(object): else: imdb_info[key] = imdbTv.get(key.replace('_', ' ')) - #Filter only the value + # Filter only the value if imdb_info['runtimes']: imdb_info['runtimes'] = re.search('\d+', imdb_info['runtimes']).group(0) else: @@ -862,13 +902,13 @@ class TVShow(object): else: imdb_info['akas'] = '' - #Join all genres in a string + # Join all genres in a string if imdb_info['genres']: imdb_info['genres'] = '|'.join(imdb_info['genres']) else: imdb_info['genres'] = '' - #Get only the production country certificate if any + # Get only the production country certificate if any if imdb_info['certificates'] and imdb_info['countries']: dct = {} try: @@ -889,7 +929,7 @@ class TVShow(object): imdb_info['last_update'] = datetime.date.today().toordinal() - #Rename dict keys without spaces for DB upsert + # Rename dict keys without spaces for DB upsert self.imdb_info = dict( (k.replace(' ', '_'), k(v) if hasattr(v, 'keys') else v) for k, v in imdb_info.items()) logger.log(str(self.indexerid) + u": Obtained info from IMDb ->" + str(self.imdb_info), logger.DEBUG) @@ -980,7 +1020,8 @@ class TVShow(object): # if it used to have a file associated with it and it doesn't anymore then set it to IGNORED if curEp.location and curEp.status in Quality.DOWNLOADED: logger.log(str(self.indexerid) + u": Location for " + str(season) + "x" + str( - episode) + " doesn't exist, removing it and changing our status to IGNORED", logger.DEBUG) + episode) + " doesn't exist, removing it and changing our status to IGNORED", + logger.DEBUG) curEp.status = IGNORED curEp.subtitles = list() curEp.subtitles_searchcount = 0 @@ -1008,19 +1049,20 @@ class TVShow(object): hr = (12 + hr, hr)[None is airs.group(3)] min = int((airs.group(2), min)[None is airs.group(2)]) airtime = datetime.time(hr, min) - + airdatetime = datetime.datetime.combine(ep_obj.airdate, airtime) filemtime = datetime.datetime.fromtimestamp(os.path.getmtime(ep_obj.location)) if filemtime != airdatetime: import time + airdatetime = airdatetime.timetuple() if self.touch(ep_obj.location, time.mktime(airdatetime)): logger.log(str(self.indexerid) + u": Changed modify date of " + os.path.basename(ep_obj.location) - + " to show air date " + time.strftime("%b %d,%Y (%H:%M)", airdatetime)) + + " to show air date " + time.strftime("%b %d,%Y (%H:%M)", airdatetime)) - def touch(self, fname, atime = None): + def touch(self, fname, atime=None): if None != atime: try: @@ -1034,7 +1076,7 @@ class TVShow(object): return False def downloadSubtitles(self, force=False): - #TODO: Add support for force option + # TODO: Add support for force option if not ek.ek(os.path.isdir, self._location): logger.log(str(self.indexerid) + ": Show dir doesn't exist, can't download subtitles", logger.DEBUG) return @@ -1224,8 +1266,8 @@ class TVEpisode(object): self._season = season self._episode = episode self._absolute_number = 0 - self._scene_season = season - self._scene_episode = episode + self._scene_season = 0 + self._scene_episode = 0 self._scene_absolute_number = 0 self._description = "" self._subtitles = list() @@ -1274,7 +1316,7 @@ class TVEpisode(object): status = property(lambda self: self._status, dirty_setter("_status")) indexer = property(lambda self: self._indexer, dirty_setter("_indexer")) indexerid = property(lambda self: self._indexerid, dirty_setter("_indexerid")) - #location = property(lambda self: self._location, dirty_setter("_location")) + # location = property(lambda self: self._location, dirty_setter("_location")) file_size = property(lambda self: self._file_size, dirty_setter("_file_size")) release_name = property(lambda self: self._release_name, dirty_setter("_release_name")) is_proper = property(lambda self: self._is_proper, dirty_setter("_is_proper")) @@ -1282,7 +1324,7 @@ class TVEpisode(object): def _set_location(self, new_location): logger.log(u"Setter sets location to " + new_location, logger.DEBUG) - #self._location = newLocation + # self._location = newLocation dirty_setter("_location")(self, new_location) if new_location and ek.ek(os.path.isfile, new_location): @@ -1297,7 +1339,7 @@ class TVEpisode(object): self.subtitles = subtitles.subtitlesLanguages(self.location) def downloadSubtitles(self, force=False): - #TODO: Add support for force option + # TODO: Add support for force option if not ek.ek(os.path.isfile, self.location): logger.log( str(self.show.indexerid) + ": Episode file doesn't exist, can't download subtitles for episode " + str( @@ -1337,7 +1379,7 @@ class TVEpisode(object): return self.refreshSubtitles() - self.subtitles_searchcount = self.subtitles_searchcount + 1 if self.subtitles_searchcount else 1 #added the if because sometime it raise an error + self.subtitles_searchcount = self.subtitles_searchcount + 1 if self.subtitles_searchcount else 1 # added the if because sometime it raise an error self.subtitles_lastsearch = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.saveToDB() @@ -1434,7 +1476,7 @@ class TVEpisode(object): self.episode) + " not found in the database", logger.DEBUG) return False else: - #NAMEIT logger.log(u"AAAAA from" + str(self.season)+"x"+str(self.episode) + " -" + self.name + " to " + str(sqlResults[0]["name"])) + # NAMEIT logger.log(u"AAAAA from" + str(self.season)+"x"+str(self.episode) + " -" + self.name + " to " + str(sqlResults[0]["name"])) if sqlResults[0]["name"]: self.name = sqlResults[0]["name"] @@ -1449,7 +1491,7 @@ class TVEpisode(object): self.subtitles_searchcount = sqlResults[0]["subtitles_searchcount"] self.subtitles_lastsearch = sqlResults[0]["subtitles_lastsearch"] self.airdate = datetime.date.fromordinal(int(sqlResults[0]["airdate"])) - #logger.log(u"1 Status changes from " + str(self.status) + " to " + str(sqlResults[0]["status"]), logger.DEBUG) + # logger.log(u"1 Status changes from " + str(self.status) + " to " + str(sqlResults[0]["status"]), logger.DEBUG) self.status = int(sqlResults[0]["status"]) # don't overwrite my location @@ -1463,12 +1505,31 @@ class TVEpisode(object): self.indexerid = int(sqlResults[0]["indexerid"]) self.indexer = int(sqlResults[0]["indexer"]) + # does one now a better way to test for NULL in the db field ? + if sqlResults[0]["scene_season"]: + self.scene_season = int(sqlResults[0]["scene_season"]) + + if sqlResults[0]["scene_episode"]: + self.scene_episode = int(sqlResults[0]["scene_episode"]) + + if sqlResults[0]["scene_absolute_number"]: + self.scene_absolute_number = int(sqlResults[0]["scene_absolute_number"]) + if sqlResults[0]["release_name"] is not None: self.release_name = sqlResults[0]["release_name"] if sqlResults[0]["is_proper"]: self.is_proper = int(sqlResults[0]["is_proper"]) + if self.scene_season == 0 or self.scene_episode == 0 or self.scene_absolute_number == 0: + (self.scene_season, self.scene_episode, self.scene_absolute_number) = \ + sickbeard.scene_numbering.get_scene_numbering( + self.show.indexerid, + self.show.indexer, + self.season, + self.episode, + self.absolute_number) + self.dirty = False return True @@ -1534,11 +1595,14 @@ class TVEpisode(object): return False if myEp["absolute_number"] == None or myEp["absolute_number"] == "": - logger.log(u"This episode ("+self.show.name+" - "+str(season)+"x"+str(episode)+") has no absolute number on " + sickbeard.indexerApi( + logger.log(u"This episode (" + self.show.name + " - " + str(season) + "x" + str( + episode) + ") has no absolute number on " + sickbeard.indexerApi( self.indexer).name , logger.DEBUG) else: - logger.log(str(self.show.indexerid) + ": The absolute_number for " + str(season) + "x" + str(episode)+" is : "+myEp["absolute_number"], logger.DEBUG) + logger.log( + str(self.show.indexerid) + ": The absolute_number for " + str(season) + "x" + str(episode) + " is : " + + myEp["absolute_number"], logger.DEBUG) self.absolute_number = int(myEp["absolute_number"]) self.name = getattr(myEp, 'episodename', "") @@ -1563,7 +1627,7 @@ class TVEpisode(object): self.deleteEpisode() return False - #early conversion to int so that episode doesn't get marked dirty + # early conversion to int so that episode doesn't get marked dirty self.indexerid = getattr(myEp, 'id', None) if self.indexerid is None: logger.log(u"Failed to retrieve ID from " + sickbeard.indexerApi(self.indexer).name, logger.ERROR) @@ -1571,7 +1635,7 @@ class TVEpisode(object): self.deleteEpisode() return False - #don't update show status if show dir is missing, unless missing show dirs are created during post-processing + # don't update show status if show dir is missing, unless missing show dirs are created during post-processing if not ek.ek(os.path.isdir, self.show._location) and not sickbeard.CREATE_MISSING_SHOW_DIRS: logger.log( u"The show dir is missing, not bothering to change the episode statuses since it'd probably be invalid") @@ -1653,7 +1717,7 @@ class TVEpisode(object): showXML = etree.ElementTree(file=nfoFile) except (SyntaxError, ValueError), e: logger.log(u"Error loading the NFO, backing up the NFO and skipping for now: " + ex(e), - logger.ERROR) #TODO: figure out what's wrong and fix it + logger.ERROR) # TODO: figure out what's wrong and fix it try: ek.ek(os.rename, nfoFile, nfoFile + ".old") except Exception, e: @@ -1777,12 +1841,13 @@ class TVEpisode(object): # use a custom update/insert method to get the data into the DB return [ - "INSERT OR REPLACE INTO tv_episodes (episode_id, indexerid, indexer, name, description, subtitles, subtitles_searchcount, subtitles_lastsearch, airdate, hasnfo, hastbn, status, location, file_size, release_name, is_proper, showid, season, episode, absolute_number) VALUES " - "((SELECT episode_id FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", + "INSERT OR REPLACE INTO tv_episodes (episode_id, indexerid, indexer, name, description, subtitles, subtitles_searchcount, subtitles_lastsearch, airdate, hasnfo, hastbn, status, location, file_size, release_name, is_proper, showid, season, episode, scene_season, scene_episode, absolute_number, scene_absolute_number) VALUES " + "((SELECT episode_id FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", [self.show.indexerid, self.season, self.episode, self.indexerid, self.indexer, self.name, self.description, ",".join([sub for sub in self.subtitles]), self.subtitles_searchcount, self.subtitles_lastsearch, self.airdate.toordinal(), self.hasnfo, self.hastbn, self.status, self.location, self.file_size, - self.release_name, self.is_proper, self.show.indexerid, self.season, self.episode, self.absolute_number]] + self.release_name, self.is_proper, self.show.indexerid, self.season, self.episode, self.scene_season, + self.scene_episode, self.absolute_number, self.scene_absolute_number]] def saveToDB(self, forceSave=False): """ @@ -1817,8 +1882,11 @@ class TVEpisode(object): "file_size": self.file_size, "release_name": self.release_name, "is_proper": self.is_proper, - "absolute_number": self.absolute_number - } + "scene_season": self.scene_season, + "scene_episode": self.scene_episode, + "absolute_number": self.absolute_number, + "scene_absolute_number": self.scene_absolute_number + } controlValueDict = {"showid": self.show.indexerid, "season": self.season, "episode": self.episode} @@ -1840,16 +1908,7 @@ class TVEpisode(object): Returns: A string representing the episode's name and season/ep numbers """ - return self._format_pattern('%SN - %Sx%0E - %EN') - - def prettySceneName(self): - """ - Returns the name of this episode in a "pretty" human-readable format. Used for logging - and notifications and such. - - Returns: A string representing the episode's name and season/ep numbers - """ - return self._format_pattern('%SN - %XSx%0XE - %EN') + return self._format_pattern('Indexer#:[%SN - %Sx%0E - %EN] | Scene#:[%SN - %XSx%0XE - %EN]') def _ep_name(self): """ @@ -1954,7 +2013,7 @@ class TVEpisode(object): '%0XS': '%02d' % self.scene_season, '%XE': str(self.scene_episode), '%0XE': '%02d' % self.scene_episode, - '%AN': '%03d' % self.absolute_number, + '%AN': '%(#)03d' % {'#': self.absolute_number}, '%RN': release_name(self.release_name), '%RG': release_group(self.release_name), '%AD': str(self.airdate).replace('-', ' '), @@ -2004,6 +2063,9 @@ class TVEpisode(object): if self.show.air_by_date or self.show.sports: result_name = result_name.replace('%RN', '%S.N.%A.D.%E.N-SiCKRAGE') result_name = result_name.replace('%rn', '%s.n.%A.D.%e.n-sickrage') + elif self.show.is_anime: + result_name = result_name.replace('%RN', '%S.N.%AN.%E.N-SiCKRAGE') + result_name = result_name.replace('%rn', '%s.n.%an.%e.n-sickrage') else: result_name = result_name.replace('%RN', '%S.N.S%0SE%0E.%E.N-SiCKRAGE') result_name = result_name.replace('%rn', '%s.n.s%0se%0e.%e.n-sickrage') @@ -2099,8 +2161,8 @@ class TVEpisode(object): # fill out the template for this piece and then insert this piece into the actual pattern cur_name_group_result = re.sub('(?i)(?x)' + regex_used, regex_replacement, cur_name_group) - #cur_name_group_result = cur_name_group.replace(ep_format, ep_string) - #logger.log(u"found "+ep_format+" as the ep pattern using "+regex_used+" and replaced it with "+regex_replacement+" to result in "+cur_name_group_result+" from "+cur_name_group, logger.DEBUG) + # cur_name_group_result = cur_name_group.replace(ep_format, ep_string) + # logger.log(u"found "+ep_format+" as the ep pattern using "+regex_used+" and replaced it with "+regex_replacement+" to result in "+cur_name_group_result+" from "+cur_name_group, logger.DEBUG) result_name = result_name.replace(cur_name_group, cur_name_group_result) result_name = self._format_string(result_name, replace_map) @@ -2202,7 +2264,8 @@ class TVEpisode(object): self.location) if self.show.subtitles and sickbeard.SUBTITLES_DIR != '': - related_subs = postProcessor.PostProcessor(self.location).list_associated_files(sickbeard.SUBTITLES_DIR, subtitles_only=True) + related_subs = postProcessor.PostProcessor(self.location).list_associated_files(sickbeard.SUBTITLES_DIR, + subtitles_only=True) absolute_proper_subs_path = ek.ek(os.path.join, sickbeard.SUBTITLES_DIR, self.formatted_filename()) logger.log(u"Files associated to " + self.location + ": " + str(related_files), logger.DEBUG) @@ -2218,7 +2281,8 @@ class TVEpisode(object): logger.log(str(self.indexerid) + u": Unable to rename file " + cur_related_file, logger.ERROR) for cur_related_sub in related_subs: - cur_result = helpers.rename_ep_file(cur_related_sub, absolute_proper_subs_path,absolute_current_path_no_ext_length) + cur_result = helpers.rename_ep_file(cur_related_sub, absolute_proper_subs_path, + absolute_current_path_no_ext_length) if not cur_result: logger.log(str(self.indexerid) + u": Unable to rename file " + cur_related_sub, logger.ERROR) @@ -2240,15 +2304,17 @@ class TVEpisode(object): relEp.saveToDB() def convertToSceneNumbering(self): - (self.scene_season, self.scene_episode, self.scene_absolute_number) = sickbeard.scene_numbering.get_scene_numbering(self.show.indexerid, - self.show.indexer, - self.season, - self.episode, - self.absolute_number) + (self.scene_season, self.scene_episode, + self.scene_absolute_number) = sickbeard.scene_numbering.get_scene_numbering(self.show.indexerid, + self.show.indexer, + self.season, + self.episode, + self.absolute_number) def convertToIndexerNumbering(self): - (self.season, self.episode, self.absolute_number) = sickbeard.scene_numbering.get_indexer_numbering(self.show.indexerid, - self.show.indexer, - self.scene_season, - self.scene_episode, - self.scene_absolute_number) + (self.season, self.episode, self.absolute_number) = sickbeard.scene_numbering.get_indexer_numbering( + self.show.indexerid, + self.show.indexer, + self.scene_season, + self.scene_episode, + self.scene_absolute_number) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index a6cdbe0b..8409abe1 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -60,6 +60,8 @@ from sickbeard.scene_exceptions import get_scene_exceptions from sickbeard.scene_numbering import get_scene_numbering, set_scene_numbering, get_scene_numbering_for_show, \ get_xem_numbering_for_show +from sickbeard.blackandwhitelist import BlackAndWhiteList + from lib.dateutil import tz from lib.unrar2 import RarFile, RarInfo @@ -3042,6 +3044,8 @@ class Home: else: t.sortedShowLists = [["Shows",sorted(sickbeard.showList, lambda x, y: cmp(titler(x.name), titler(y.name)))]] + t.bwl = BlackAndWhiteList(showObj.indexerid) + t.epCounts = epCounts t.epCats = epCats @@ -3077,7 +3081,7 @@ class Home: def editShow(self, show=None, location=None, anyQualities=[], bestQualities=[], exceptions_list=[], flatten_folders=None, paused=None, directCall=False, air_by_date=None, sports=None, dvdorder=None, indexerLang=None, subtitles=None, archive_firstmatch=None, rls_ignore_words=None, - rls_require_words=None, anime=None): + rls_require_words=None, anime=None, blackWords=None, whiteWords=None, blacklist=None, whitelist=None): if show is None: errString = "Invalid show ID: " + str(show) @@ -3101,7 +3105,24 @@ class Home: t = PageTemplate(file="editShow.tmpl") t.submenu = HomeMenu() + bwl = BlackAndWhiteList(showObj.indexerid) + t.whiteWords = "" + if "global" in bwl.whiteDict: + t.whiteWords = ", ".join(bwl.whiteDict["global"]) + t.blackWords = "" + if "global" in bwl.blackDict: + t.blackWords = ", ".join(bwl.blackDict["global"]) + if showObj.is_anime: + + t.whitelist = [] + if bwl.whiteDict.has_key("release_group"): + t.whitelist = bwl.whiteDict["release_group"] + + t.blacklist = [] + if bwl.blackDict.has_key("release_group"): + t.blacklist = bwl.blackDict["release_group"] + t.groups = [] if helpers.set_up_anidb_connection(): anime = adba.Anime(sickbeard.ADBA_CONNECTION, name=showObj.name) @@ -3151,6 +3172,55 @@ class Home: else: do_update_exceptions = True + bwl = BlackAndWhiteList(showObj.indexerid) + if whitelist: + whitelist = whitelist.split(",") + shortWhiteList = [] + if helpers.set_up_anidb_connection(): + for groupName in whitelist: + group = sickbeard.ADBA_CONNECTION.group(gname=groupName) + for line in group.datalines: + if line["shortname"]: + shortWhiteList.append(line["shortname"]) + else: + if not groupName in shortWhiteList: + shortWhiteList.append(groupName) + else: + shortWhiteList = whitelist + bwl.set_white_keywords_for("release_group", shortWhiteList) + else: + bwl.set_white_keywords_for("release_group", []) + + if blacklist: + blacklist = blacklist.split(",") + shortBlacklist = [] + if helpers.set_up_anidb_connection(): + for groupName in blacklist: + group = sickbeard.ADBA_CONNECTION.group(gname=groupName) + for line in group.datalines: + if line["shortname"]: + shortBlacklist.append(line["shortname"]) + else: + if not groupName in shortBlacklist: + shortBlacklist.append(groupName) + else: + shortBlacklist = blacklist + bwl.set_black_keywords_for("release_group", shortBlacklist) + else: + bwl.set_black_keywords_for("release_group", []) + + if whiteWords: + whiteWords = [x.strip() for x in whiteWords.split(",")] + bwl.set_white_keywords_for("global", whiteWords) + else: + bwl.set_white_keywords_for("global", []) + + if blackWords: + blackWords = [x.strip() for x in blackWords.split(",")] + bwl.set_black_keywords_for("global", blackWords) + else: + bwl.set_black_keywords_for("global", []) + errors = [] with showObj.lock: newQuality = Quality.combineQualities(map(int, anyQualities), map(int, bestQualities)) From 370c6d6f73371105315453418dec67abd03b5f13 Mon Sep 17 00:00:00 2001 From: Nicholas Herring Date: Wed, 28 May 2014 15:35:56 +0000 Subject: [PATCH 17/82] Fixed infinite loop in lib/rtorrent This code works when there is only one torrent in rtorrent. As soon as there are multiple torrents, this just spins on the same torrent IF the first torrent isn't the one it is looking for. In general this function just brute forces the server as I expect it is written for a local SCGI endpoint. (Side note, this was my second attempt to do this, since I didn't fork properly when I stated: https://github.com/echel0n/SickRage/pull/585) --- lib/rtorrent/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rtorrent/__init__.py b/lib/rtorrent/__init__.py index 93aeb3b3..290ef115 100644 --- a/lib/rtorrent/__init__.py +++ b/lib/rtorrent/__init__.py @@ -216,7 +216,7 @@ class RTorrent: while i < MAX_RETRIES: for torrent in self.get_torrents(): if torrent.info_hash != info_hash: - break + continue time.sleep(1) i += 1 From e009641804ae375a5c8c101109b8a294f959a5ac Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 28 May 2014 14:13:29 -0700 Subject: [PATCH 18/82] SickRage now stores the XEM scene data to the main DB under tv_episodes for faster lookups and better linkages with epiosde objects, insures we have scene data on hand when we want it! Adding functions to lookup scene season and ep info via scene absolute numbers. We now try and create a show object from parsed release info before we consider it a valid parsed result to insure we even have the show in our show list, also used to validate anime releases. Misc bug fixes here and there. --- lib/adba/aniDBAbstracter.py | 2 +- lib/adba/aniDBcommands.py | 627 +++++++++++++++++--------------- lib/adba/aniDBmaper.py | 4 +- sickbeard/databases/cache_db.py | 28 +- sickbeard/databases/mainDB.py | 15 +- sickbeard/metadata/generic.py | 64 ++-- sickbeard/name_parser/parser.py | 244 ++++--------- sickbeard/providers/btn.py | 15 +- sickbeard/providers/generic.py | 1 - sickbeard/scene_numbering.py | 383 ++++++++++++------- sickbeard/search.py | 12 +- sickbeard/show_name_helpers.py | 25 +- sickbeard/show_queue.py | 13 - sickbeard/tv.py | 68 +--- 14 files changed, 732 insertions(+), 769 deletions(-) diff --git a/lib/adba/aniDBAbstracter.py b/lib/adba/aniDBAbstracter.py index 278a8010..f56b9fdc 100644 --- a/lib/adba/aniDBAbstracter.py +++ b/lib/adba/aniDBAbstracter.py @@ -103,7 +103,7 @@ class aniDBabstractObject(object): class Anime(aniDBabstractObject): - def __init__(self, aniDB, name=None, aid=None, tvdbid=None, tvrageid=None, paramsA=None, autoCorrectName=False, load=False): + def __init__(self, aniDB, name=None, aid=None, tvdbid=None, paramsA=None, autoCorrectName=False, load=False): self.maper = AniDBMaper() self.tvDBMap = TvDBMap() diff --git a/lib/adba/aniDBcommands.py b/lib/adba/aniDBcommands.py index 52ade52c..190234bf 100644 --- a/lib/adba/aniDBcommands.py +++ b/lib/adba/aniDBcommands.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +# !/usr/bin/env python # # This file is part of aDBa. # @@ -19,370 +19,429 @@ from threading import Lock from aniDBresponses import * from aniDBerrors import * -class Command: - queue={None:None} - def __init__(self,command,**parameters): - self.command=command - self.parameters=parameters - self.raw=self.flatten(command,parameters) - self.mode=None - self.callback=None - self.waiter=Lock() - self.waiter.acquire() - - def __repr__(self): - return "Command(%s,%s) %s\n%s\n"%(repr(self.tag),repr(self.command),repr(self.parameters),self.raw_data()) - - def authorize(self,mode,tag,session,callback): - self.mode=mode - self.callback=callback - self.tag=tag - self.session=session - - self.parameters['tag']=tag - self.parameters['s']=session - - def handle(self,resp): - self.resp=resp - if self.mode==1: - self.waiter.release() - elif self.mode==2: - self.callback(resp) - - def wait_response(self): - self.waiter.acquire() - - def flatten(self,command,parameters): - tmp=[] - for key,value in parameters.iteritems(): - if value==None: - continue - tmp.append("%s=%s"%(self.escape(key),self.escape(value))) - return ' '.join([command,'&'.join(tmp)]) - - def escape(self,data): - return str(data).replace('&','&') - - def raw_data(self): - self.raw=self.flatten(self.command,self.parameters) - return self.raw - - def cached(self,interface,database): - return None - - def cache(self,interface,database): - pass - +class Command: + queue = {None: None} + + def __init__(self, command, **parameters): + self.command = command + self.parameters = parameters + self.raw = self.flatten(command, parameters) + + self.mode = None + self.callback = None + self.waiter = Lock() + self.waiter.acquire() + + def __repr__(self): + return "Command(%s,%s) %s\n%s\n" % (repr(self.tag), repr(self.command), repr(self.parameters), self.raw_data()) + + def authorize(self, mode, tag, session, callback): + self.mode = mode + self.callback = callback + self.tag = tag + self.session = session + + self.parameters['tag'] = tag + self.parameters['s'] = session + + def handle(self, resp): + self.resp = resp + if self.mode == 1: + self.waiter.release() + elif self.mode == 2: + self.callback(resp) + + def wait_response(self): + self.waiter.acquire() + + def flatten(self, command, parameters): + tmp = [] + for key, value in parameters.iteritems(): + if value == None: + continue + tmp.append("%s=%s" % (self.escape(key), self.escape(value))) + return ' '.join([command, '&'.join(tmp)]) + + def escape(self, data): + return str(data).replace('&', '&') + + def raw_data(self): + self.raw = self.flatten(self.command, self.parameters) + return self.raw + + def cached(self, interface, database): + return None + + def cache(self, interface, database): + pass + + #first run class AuthCommand(Command): - def __init__(self,username,password,protover,client,clientver,nat=None,comp=None,enc=None,mtu=None): - parameters={'user':username,'pass':password,'protover':protover,'client':client,'clientver':clientver,'nat':nat,'comp':comp,'enc':enc,'mtu':mtu} - Command.__init__(self,'AUTH',**parameters) + def __init__(self, username, password, protover, client, clientver, nat=None, comp=None, enc=None, mtu=None): + parameters = {'user': username, 'pass': password, 'protover': protover, 'client': client, + 'clientver': clientver, 'nat': nat, 'comp': comp, 'enc': enc, 'mtu': mtu} + Command.__init__(self, 'AUTH', **parameters) + class LogoutCommand(Command): - def __init__(self): - Command.__init__(self,'LOGOUT') + def __init__(self): + Command.__init__(self, 'LOGOUT') + #third run (at the same time as second) class PushCommand(Command): - def __init__(self,notify,msg,buddy=None): - parameters={'notify':notify,'msg':msg,'buddy':buddy} - Command.__init__(self,'PUSH',**parameters) + def __init__(self, notify, msg, buddy=None): + parameters = {'notify': notify, 'msg': msg, 'buddy': buddy} + Command.__init__(self, 'PUSH', **parameters) + class PushAckCommand(Command): - def __init__(self,nid): - parameters={'nid':nid} - Command.__init__(self,'PUSHACK',**parameters) + def __init__(self, nid): + parameters = {'nid': nid} + Command.__init__(self, 'PUSHACK', **parameters) + class NotifyAddCommand(Command): - def __init__(self,aid=None,gid=None,type=None,priority=None): - if not (aid or gid) or (aid and gid): - raise AniDBIncorrectParameterError,"You must provide aid OR gid for NOTIFICATIONADD command" - parameters={'aid':aid,"gid":gid,"type":type,"priority":priority} - Command.__init__(self,'NOTIFICATIONADD',**parameters) - + def __init__(self, aid=None, gid=None, type=None, priority=None): + if not (aid or gid) or (aid and gid): + raise AniDBIncorrectParameterError, "You must provide aid OR gid for NOTIFICATIONADD command" + parameters = {'aid': aid, "gid": gid, "type": type, "priority": priority} + Command.__init__(self, 'NOTIFICATIONADD', **parameters) + + class NotifyCommand(Command): - def __init__(self,buddy=None): - parameters={'buddy':buddy} - Command.__init__(self,'NOTIFY',**parameters) + def __init__(self, buddy=None): + parameters = {'buddy': buddy} + Command.__init__(self, 'NOTIFY', **parameters) + class NotifyListCommand(Command): - def __init__(self): - Command.__init__(self,'NOTIFYLIST') + def __init__(self): + Command.__init__(self, 'NOTIFYLIST') + class NotifyGetCommand(Command): - def __init__(self,type,id): - parameters={'type':type,'id':id} - Command.__init__(self,'NOTIFYGET',**parameters) + def __init__(self, type, id): + parameters = {'type': type, 'id': id} + Command.__init__(self, 'NOTIFYGET', **parameters) + class NotifyAckCommand(Command): - def __init__(self,type,id): - parameters={'type':type,'id':id} - Command.__init__(self,'NOTIFYACK',**parameters) + def __init__(self, type, id): + parameters = {'type': type, 'id': id} + Command.__init__(self, 'NOTIFYACK', **parameters) + class BuddyAddCommand(Command): - def __init__(self,uid=None,uname=None): - if not (uid or uname) or (uid and uname): - raise AniDBIncorrectParameterError,"You must provide for BUDDYADD command" - parameters={'uid':uid,'uname':uname.lower()} - Command.__init__(self,'BUDDYADD',**parameters) + def __init__(self, uid=None, uname=None): + if not (uid or uname) or (uid and uname): + raise AniDBIncorrectParameterError, "You must provide for BUDDYADD command" + parameters = {'uid': uid, 'uname': uname.lower()} + Command.__init__(self, 'BUDDYADD', **parameters) + class BuddyDelCommand(Command): - def __init__(self,uid): - parameters={'uid':uid} - Command.__init__(self,'BUDDYDEL',**parameters) + def __init__(self, uid): + parameters = {'uid': uid} + Command.__init__(self, 'BUDDYDEL', **parameters) + class BuddyAcceptCommand(Command): - def __init__(self,uid): - parameters={'uid':uid} - Command.__init__(self,'BUDDYACCEPT',**parameters) + def __init__(self, uid): + parameters = {'uid': uid} + Command.__init__(self, 'BUDDYACCEPT', **parameters) + class BuddyDenyCommand(Command): - def __init__(self,uid): - parameters={'uid':uid} - Command.__init__(self,'BUDDYDENY',**parameters) + def __init__(self, uid): + parameters = {'uid': uid} + Command.__init__(self, 'BUDDYDENY', **parameters) + class BuddyListCommand(Command): - def __init__(self,startat): - parameters={'startat':startat} - Command.__init__(self,'BUDDYLIST',**parameters) + def __init__(self, startat): + parameters = {'startat': startat} + Command.__init__(self, 'BUDDYLIST', **parameters) + class BuddyStateCommand(Command): - def __init__(self,startat): - parameters={'startat':startat} - Command.__init__(self,'BUDDYSTATE',**parameters) + def __init__(self, startat): + parameters = {'startat': startat} + Command.__init__(self, 'BUDDYSTATE', **parameters) + #first run class AnimeCommand(Command): - def __init__(self,aid=None,aname=None,amask=None): - if not (aid or aname): - raise AniDBIncorrectParameterError,"You must provide for ANIME command" - parameters={'aid':aid,'aname':aname,'amask':amask} - Command.__init__(self,'ANIME',**parameters) + def __init__(self, aid=None, aname=None, amask=None): + if not (aid or aname): + raise AniDBIncorrectParameterError, "You must provide for ANIME command" + parameters = {'aid': aid, 'aname': aname, 'amask': amask} + Command.__init__(self, 'ANIME', **parameters) + class EpisodeCommand(Command): - def __init__(self,eid=None,aid=None,aname=None,epno=None): - if not (eid or ((aname or aid) and epno)) or (aname and aid) or (eid and (aname or aid or epno)): - raise AniDBIncorrectParameterError,"You must provide for EPISODE command" - parameters={'eid':eid,'aid':aid,'aname':aname,'epno':epno} - Command.__init__(self,'EPISODE',**parameters) + def __init__(self, eid=None, aid=None, aname=None, epno=None): + if not (eid or ((aname or aid) and epno)) or (aname and aid) or (eid and (aname or aid or epno)): + raise AniDBIncorrectParameterError, "You must provide for EPISODE command" + parameters = {'eid': eid, 'aid': aid, 'aname': aname, 'epno': epno} + Command.__init__(self, 'EPISODE', **parameters) + class FileCommand(Command): - def __init__(self,fid=None,size=None,ed2k=None,aid=None,aname=None,gid=None,gname=None,epno=None,fmask=None,amask=None): - if not (fid or (size and ed2k) or ((aid or aname) and (gid or gname) and epno)) or (fid and (size or ed2k or aid or aname or gid or gname or epno)) or ((size and ed2k) and (fid or aid or aname or gid or gname or epno)) or (((aid or aname) and (gid or gname) and epno) and (fid or size or ed2k)) or (aid and aname) or (gid and gname): - raise AniDBIncorrectParameterError,"You must provide for FILE command" - parameters={'fid':fid,'size':size,'ed2k':ed2k,'aid':aid,'aname':aname,'gid':gid,'gname':gname,'epno':epno,'fmask':fmask,'amask':amask} - Command.__init__(self,'FILE',**parameters) + def __init__(self, fid=None, size=None, ed2k=None, aid=None, aname=None, gid=None, gname=None, epno=None, + fmask=None, amask=None): + if not (fid or (size and ed2k) or ((aid or aname) and (gid or gname) and epno)) or ( + fid and (size or ed2k or aid or aname or gid or gname or epno)) or ( + (size and ed2k) and (fid or aid or aname or gid or gname or epno)) or ( + ((aid or aname) and (gid or gname) and epno) and (fid or size or ed2k)) or (aid and aname) or ( + gid and gname): + raise AniDBIncorrectParameterError, "You must provide for FILE command" + parameters = {'fid': fid, 'size': size, 'ed2k': ed2k, 'aid': aid, 'aname': aname, 'gid': gid, 'gname': gname, + 'epno': epno, 'fmask': fmask, 'amask': amask} + Command.__init__(self, 'FILE', **parameters) + class GroupCommand(Command): - def __init__(self,gid=None,gname=None): - if not (gid or gname) or (gid and gname): - raise AniDBIncorrectParameterError,"You must provide for GROUP command" - parameters={'gid':gid,'gname':gname} - Command.__init__(self,'GROUP',**parameters) + def __init__(self, gid=None, gname=None): + if not (gid or gname) or (gid and gname): + raise AniDBIncorrectParameterError, "You must provide for GROUP command" + parameters = {'gid': gid, 'gname': gname} + Command.__init__(self, 'GROUP', **parameters) + class GroupstatusCommand(Command): - def __init__(self,aid=None,status=None): - if not aid: - raise AniDBIncorrectParameterError,"You must provide aid for GROUPSTATUS command" - parameters={'aid':aid,'status':status} - Command.__init__(self,'GROUPSTATUS',**parameters) + def __init__(self, aid=None, status=None): + if not aid: + raise AniDBIncorrectParameterError, "You must provide aid for GROUPSTATUS command" + parameters = {'aid': aid, 'status': status} + Command.__init__(self, 'GROUPSTATUS', **parameters) + class ProducerCommand(Command): - def __init__(self,pid=None,pname=None): - if not (pid or pname) or (pid and pname): - raise AniDBIncorrectParameterError,"You must provide for PRODUCER command" - parameters={'pid':pid,'pname':pname} - Command.__init__(self,'PRODUCER',**parameters) - - def cached(self,intr,db): - pid=self.parameters['pid'] - pname=self.parameters['pname'] - - codes=('pid', 'name', 'shortname', 'othername', 'type', 'pic', 'url') - names=','.join([code for code in codes if code!='']) - ruleholder=(pid and 'pid=%s' or '(name=%s OR shortname=%s OR othername=%s)') - rulevalues=(pid and [pid] or [pname,pname,pname]) - - rows=db.select('ptb',names,ruleholder+" AND status&8",*rulevalues) - - if len(rows)>1: - raise AniDBInternalError,"It shouldn't be possible for database to return more than 1 line for PRODUCER cache" - elif not len(rows): - return None - else: - resp=ProducerResponse(self,None,'245','CACHED PRODUCER',[list(rows[0])]) - resp.parse() - return resp - - def cache(self,intr,db): - if self.resp.rescode!='245' or self.cached(intr,db): - return + def __init__(self, pid=None, pname=None): + if not (pid or pname) or (pid and pname): + raise AniDBIncorrectParameterError, "You must provide for PRODUCER command" + parameters = {'pid': pid, 'pname': pname} + Command.__init__(self, 'PRODUCER', **parameters) - codes=('pid', 'name', 'shortname', 'othername', 'type', 'pic', 'url') - if len(db.select('ptb','pid','pid=%s',self.resp.datalines[0]['pid'])): - sets='status=status|15,'+','.join([code+'=%s' for code in codes if code!='']) - values=[self.resp.datalines[0][code] for code in codes if code!='']+[self.resp.datalines[0]['pid']] + def cached(self, intr, db): + pid = self.parameters['pid'] + pname = self.parameters['pname'] + + codes = ('pid', 'name', 'shortname', 'othername', 'type', 'pic', 'url') + names = ','.join([code for code in codes if code != '']) + ruleholder = (pid and 'pid=%s' or '(name=%s OR shortname=%s OR othername=%s)') + rulevalues = (pid and [pid] or [pname, pname, pname]) + + rows = db.select('ptb', names, ruleholder + " AND status&8", *rulevalues) + + if len(rows) > 1: + raise AniDBInternalError, "It shouldn't be possible for database to return more than 1 line for PRODUCER cache" + elif not len(rows): + return None + else: + resp = ProducerResponse(self, None, '245', 'CACHED PRODUCER', [list(rows[0])]) + resp.parse() + return resp + + def cache(self, intr, db): + if self.resp.rescode != '245' or self.cached(intr, db): + return + + codes = ('pid', 'name', 'shortname', 'othername', 'type', 'pic', 'url') + if len(db.select('ptb', 'pid', 'pid=%s', self.resp.datalines[0]['pid'])): + sets = 'status=status|15,' + ','.join([code + '=%s' for code in codes if code != '']) + values = [self.resp.datalines[0][code] for code in codes if code != ''] + [self.resp.datalines[0]['pid']] + + db.update('ptb', sets, 'pid=%s', *values) + else: + names = 'status,' + ','.join([code for code in codes if code != '']) + valueholders = '0,' + ','.join(['%s' for code in codes if code != '']) + values = [self.resp.datalines[0][code] for code in codes if code != ''] + + db.insert('ptb', names, valueholders, *values) - db.update('ptb',sets,'pid=%s',*values) - else: - names='status,'+','.join([code for code in codes if code!='']) - valueholders='0,'+','.join(['%s'for code in codes if code!='']) - values=[self.resp.datalines[0][code] for code in codes if code!=''] - - db.insert('ptb',names,valueholders,*values) class MyListCommand(Command): - def __init__(self,lid=None,fid=None,size=None,ed2k=None,aid=None,aname=None,gid=None,gname=None,epno=None): - if not (lid or fid or (size and ed2k) or (aid or aname)) or (lid and (fid or size or ed2k or aid or aname or gid or gname or epno)) or (fid and (lid or size or ed2k or aid or aname or gid or gname or epno)) or ((size and ed2k) and (lid or fid or aid or aname or gid or gname or epno)) or ((aid or aname) and (lid or fid or size or ed2k)) or (aid and aname) or (gid and gname): - raise AniDBIncorrectParameterError,"You must provide for MYLIST command" - parameters={'lid':lid,'fid':fid,'size':size,'ed2k':ed2k,'aid':aid,'aname':aname,'gid':gid,'gname':gname,'epno':epno} - Command.__init__(self,'MYLIST',**parameters) + def __init__(self, lid=None, fid=None, size=None, ed2k=None, aid=None, aname=None, gid=None, gname=None, epno=None): + if not (lid or fid or (size and ed2k) or (aid or aname)) or ( + lid and (fid or size or ed2k or aid or aname or gid or gname or epno)) or ( + fid and (lid or size or ed2k or aid or aname or gid or gname or epno)) or ( + (size and ed2k) and (lid or fid or aid or aname or gid or gname or epno)) or ( + (aid or aname) and (lid or fid or size or ed2k)) or (aid and aname) or (gid and gname): + raise AniDBIncorrectParameterError, "You must provide for MYLIST command" + parameters = {'lid': lid, 'fid': fid, 'size': size, 'ed2k': ed2k, 'aid': aid, 'aname': aname, 'gid': gid, + 'gname': gname, 'epno': epno} + Command.__init__(self, 'MYLIST', **parameters) - def cached(self,intr,db): - lid=self.parameters['lid'] - fid=self.parameters['fid'] - size=self.parameters['size'] - ed2k=self.parameters['ed2k'] - aid=self.parameters['aid'] - aname=self.parameters['aname'] - gid=self.parameters['gid'] - gname=self.parameters['gname'] - epno=self.parameters['epno'] + def cached(self, intr, db): + lid = self.parameters['lid'] + fid = self.parameters['fid'] + size = self.parameters['size'] + ed2k = self.parameters['ed2k'] + aid = self.parameters['aid'] + aname = self.parameters['aname'] + gid = self.parameters['gid'] + gname = self.parameters['gname'] + epno = self.parameters['epno'] - names=','.join([code for code in MylistResponse(None,None,None,None,[]).codetail if code!='']) - - if lid: - ruleholder="lid=%s" - rulevalues=[lid] - elif fid or size or ed2k: - resp=intr.file(fid=fid,size=size,ed2k=ed2k) - if resp.rescode!='220': - resp=NoSuchMylistResponse(self,None,'321','NO SUCH ENTRY (FILE NOT FOUND)',[]) - resp.parse() - return resp - fid=resp.datalines[0]['fid'] - - ruleholder="fid=%s" - rulevalues=[fid] - else: - resp=intr.anime(aid=aid,aname=aname) - if resp.rescode!='230': - resp=NoSuchFileResponse(self,None,'321','NO SUCH ENTRY (ANIME NOT FOUND)',[]) - resp.parse() - return resp - aid=resp.datalines[0]['aid'] + names = ','.join([code for code in MylistResponse(None, None, None, None, []).codetail if code != '']) - resp=intr.group(gid=gid,gname=gname) - if resp.rescode!='250': - resp=NoSuchFileResponse(self,None,'321','NO SUCH ENTRY (GROUP NOT FOUND)',[]) - resp.parse() - return resp - gid=resp.datalines[0]['gid'] + if lid: + ruleholder = "lid=%s" + rulevalues = [lid] + elif fid or size or ed2k: + resp = intr.file(fid=fid, size=size, ed2k=ed2k) + if resp.rescode != '220': + resp = NoSuchMylistResponse(self, None, '321', 'NO SUCH ENTRY (FILE NOT FOUND)', []) + resp.parse() + return resp + fid = resp.datalines[0]['fid'] - resp=intr.episode(aid=aid,epno=epno) - if resp.rescode!='240': - resp=NoSuchFileResponse(self,None,'321','NO SUCH ENTRY (EPISODE NOT FOUND)',[]) - resp.parse() - return resp - eid=resp.datalines[0]['eid'] + ruleholder = "fid=%s" + rulevalues = [fid] + else: + resp = intr.anime(aid=aid, aname=aname) + if resp.rescode != '230': + resp = NoSuchFileResponse(self, None, '321', 'NO SUCH ENTRY (ANIME NOT FOUND)', []) + resp.parse() + return resp + aid = resp.datalines[0]['aid'] - ruleholder="aid=%s AND eid=%s AND gid=%s" - rulevalues=[aid,eid,gid] + resp = intr.group(gid=gid, gname=gname) + if resp.rescode != '250': + resp = NoSuchFileResponse(self, None, '321', 'NO SUCH ENTRY (GROUP NOT FOUND)', []) + resp.parse() + return resp + gid = resp.datalines[0]['gid'] - rows=db.select('ltb',names,ruleholder+" AND status&8",*rulevalues) + resp = intr.episode(aid=aid, epno=epno) + if resp.rescode != '240': + resp = NoSuchFileResponse(self, None, '321', 'NO SUCH ENTRY (EPISODE NOT FOUND)', []) + resp.parse() + return resp + eid = resp.datalines[0]['eid'] - if len(rows)>1: - #resp=MultipleFilesFoundResponse(self,None,'322','CACHED MULTIPLE FILES FOUND',/*get fids from rows, not gonna do this as you haven't got a real cache out of these..*/) - return None - elif not len(rows): - return None - else: - resp=MylistResponse(self,None,'221','CACHED MYLIST',[list(rows[0])]) - resp.parse() - return resp - - def cache(self,intr,db): - if self.resp.rescode!='221' or self.cached(intr,db): - return + ruleholder = "aid=%s AND eid=%s AND gid=%s" + rulevalues = [aid, eid, gid] - codes=MylistResponse(None,None,None,None,[]).codetail - if len(db.select('ltb','lid','lid=%s',self.resp.datalines[0]['lid'])): - sets='status=status|15,'+','.join([code+'=%s' for code in codes if code!='']) - values=[self.resp.datalines[0][code] for code in codes if code!='']+[self.resp.datalines[0]['lid']] + rows = db.select('ltb', names, ruleholder + " AND status&8", *rulevalues) - db.update('ltb',sets,'lid=%s',*values) - else: - names='status,'+','.join([code for code in codes if code!='']) - valueholders='15,'+','.join(['%s' for code in codes if code!='']) - values=[self.resp.datalines[0][code] for code in codes if code!=''] + if len(rows) > 1: + #resp=MultipleFilesFoundResponse(self,None,'322','CACHED MULTIPLE FILES FOUND',/*get fids from rows, not gonna do this as you haven't got a real cache out of these..*/) + return None + elif not len(rows): + return None + else: + resp = MylistResponse(self, None, '221', 'CACHED MYLIST', [list(rows[0])]) + resp.parse() + return resp + + def cache(self, intr, db): + if self.resp.rescode != '221' or self.cached(intr, db): + return + + codes = MylistResponse(None, None, None, None, []).codetail + if len(db.select('ltb', 'lid', 'lid=%s', self.resp.datalines[0]['lid'])): + sets = 'status=status|15,' + ','.join([code + '=%s' for code in codes if code != '']) + values = [self.resp.datalines[0][code] for code in codes if code != ''] + [self.resp.datalines[0]['lid']] + + db.update('ltb', sets, 'lid=%s', *values) + else: + names = 'status,' + ','.join([code for code in codes if code != '']) + valueholders = '15,' + ','.join(['%s' for code in codes if code != '']) + values = [self.resp.datalines[0][code] for code in codes if code != ''] + + db.insert('ltb', names, valueholders, *values) - db.insert('ltb',names,valueholders,*values) class MyListAddCommand(Command): - def __init__(self,lid=None,fid=None,size=None,ed2k=None,aid=None,aname=None,gid=None,gname=None,epno=None,edit=None,state=None,viewed=None,source=None,storage=None,other=None): - if not (lid or fid or (size and ed2k) or ((aid or aname) and (gid or gname))) or (lid and (fid or size or ed2k or aid or aname or gid or gname or epno)) or (fid and (lid or size or ed2k or aid or aname or gid or gname or epno)) or ((size and ed2k) and (lid or fid or aid or aname or gid or gname or epno)) or (((aid or aname) and (gid or gname)) and (lid or fid or size or ed2k)) or (aid and aname) or (gid and gname) or (lid and not edit): - raise AniDBIncorrectParameterError,"You must provide for MYLISTADD command" - parameters={'lid':lid,'fid':fid,'size':size,'ed2k':ed2k,'aid':aid,'aname':aname,'gid':gid,'gname':gname,'epno':epno,'edit':edit,'state':state,'viewed':viewed,'source':source,'storage':storage,'other':other} - Command.__init__(self,'MYLISTADD',**parameters) + def __init__(self, lid=None, fid=None, size=None, ed2k=None, aid=None, aname=None, gid=None, gname=None, epno=None, + edit=None, state=None, viewed=None, source=None, storage=None, other=None): + if not (lid or fid or (size and ed2k) or ((aid or aname) and (gid or gname))) or ( + lid and (fid or size or ed2k or aid or aname or gid or gname or epno)) or ( + fid and (lid or size or ed2k or aid or aname or gid or gname or epno)) or ( + (size and ed2k) and (lid or fid or aid or aname or gid or gname or epno)) or ( + ((aid or aname) and (gid or gname)) and (lid or fid or size or ed2k)) or (aid and aname) or ( + gid and gname) or (lid and not edit): + raise AniDBIncorrectParameterError, "You must provide for MYLISTADD command" + parameters = {'lid': lid, 'fid': fid, 'size': size, 'ed2k': ed2k, 'aid': aid, 'aname': aname, 'gid': gid, + 'gname': gname, 'epno': epno, 'edit': edit, 'state': state, 'viewed': viewed, 'source': source, + 'storage': storage, 'other': other} + Command.__init__(self, 'MYLISTADD', **parameters) + class MyListDelCommand(Command): - def __init__(self,lid=None,fid=None,aid=None,aname=None,gid=None,gname=None,epno=None): - if not (lid or fid or ((aid or aname) and (gid or gname) and epno)) or (lid and (fid or aid or aname or gid or gname or epno)) or (fid and (lid or aid or aname or gid or gname or epno)) or (((aid or aname) and (gid or gname) and epno) and (lid or fid)) or (aid and aname) or (gid and gname): - raise AniDBIncorrectParameterError,"You must provide for MYLISTDEL command" - parameters={'lid':lid,'fid':fid,'aid':aid,'aname':aname,'gid':gid,'gname':gname,'epno':epno} - Command.__init__(self,'MYLISTDEL',**parameters) + def __init__(self, lid=None, fid=None, aid=None, aname=None, gid=None, gname=None, epno=None): + if not (lid or fid or ((aid or aname) and (gid or gname) and epno)) or ( + lid and (fid or aid or aname or gid or gname or epno)) or ( + fid and (lid or aid or aname or gid or gname or epno)) or ( + ((aid or aname) and (gid or gname) and epno) and (lid or fid)) or (aid and aname) or (gid and gname): + raise AniDBIncorrectParameterError, "You must provide for MYLISTDEL command" + parameters = {'lid': lid, 'fid': fid, 'aid': aid, 'aname': aname, 'gid': gid, 'gname': gname, 'epno': epno} + Command.__init__(self, 'MYLISTDEL', **parameters) + class MyListStatsCommand(Command): - def __init__(self): - Command.__init__(self,'MYLISTSTATS') + def __init__(self): + Command.__init__(self, 'MYLISTSTATS') + class VoteCommand(Command): - def __init__(self,type,id=None,name=None,value=None,epno=None): - if not (id or name) or (id and name): - raise AniDBIncorrectParameterError,"You must provide <(id|name)> for VOTE command" - parameters={'type':type,'id':id,'name':name,'value':value,'epno':epno} - Command.__init__(self,'VOTE',**parameters) + def __init__(self, type, id=None, name=None, value=None, epno=None): + if not (id or name) or (id and name): + raise AniDBIncorrectParameterError, "You must provide <(id|name)> for VOTE command" + parameters = {'type': type, 'id': id, 'name': name, 'value': value, 'epno': epno} + Command.__init__(self, 'VOTE', **parameters) + class RandomAnimeCommand(Command): - def __init__(self,type): - parameters={'type':type} - Command.__init__(self,'RANDOMANIME',**parameters) + def __init__(self, type): + parameters = {'type': type} + Command.__init__(self, 'RANDOMANIME', **parameters) + class PingCommand(Command): - def __init__(self): - Command.__init__(self,'PING') + def __init__(self): + Command.__init__(self, 'PING') + #second run class EncryptCommand(Command): - def __init__(self,user,apipassword,type): - self.apipassword=apipassword - parameters={'user':user.lower(),'type':type} - Command.__init__(self,'ENCRYPT',**parameters) + def __init__(self, user, apipassword, type): + self.apipassword = apipassword + parameters = {'user': user.lower(), 'type': type} + Command.__init__(self, 'ENCRYPT', **parameters) + class EncodingCommand(Command): - def __init__(self,name): - parameters={'name':type} - Command.__init__(self,'ENCODING',**parameters) + def __init__(self, name): + parameters = {'name': type} + Command.__init__(self, 'ENCODING', **parameters) + class SendMsgCommand(Command): - def __init__(self,to,title,body): - if len(title)>50 or len(body)>900: - raise AniDBIncorrectParameterError,"Title must not be longer than 50 chars and body must not be longer than 900 chars for SENDMSG command" - parameters={'to':to.lower(),'title':title,'body':body} - Command.__init__(self,'SENDMSG',**parameters) + def __init__(self, to, title, body): + if len(title) > 50 or len(body) > 900: + raise AniDBIncorrectParameterError, "Title must not be longer than 50 chars and body must not be longer than 900 chars for SENDMSG command" + parameters = {'to': to.lower(), 'title': title, 'body': body} + Command.__init__(self, 'SENDMSG', **parameters) + class UserCommand(Command): - def __init__(self,user): - parameters={'user':user} - Command.__init__(self,'USER',**parameters) + def __init__(self, user): + parameters = {'user': user} + Command.__init__(self, 'USER', **parameters) + class UptimeCommand(Command): - def __init__(self): - Command.__init__(self,'UPTIME') + def __init__(self): + Command.__init__(self, 'UPTIME') + class VersionCommand(Command): - def __init__(self): - Command.__init__(self,'VERSION') + def __init__(self): + Command.__init__(self, 'VERSION') diff --git a/lib/adba/aniDBmaper.py b/lib/adba/aniDBmaper.py index fb131a6d..08deccbe 100644 --- a/lib/adba/aniDBmaper.py +++ b/lib/adba/aniDBmaper.py @@ -22,11 +22,11 @@ class AniDBMaper: def getAnimeBitsA(self,amask): map = self.getAnimeMapA() - return self._getBitChain(map,amask); + return self._getBitChain(map,amask) def getAnimeCodesA(self,aBitChain): amap = self.getAnimeMapA() - return self._getCodes(amap,aBitChain); + return self._getCodes(amap,aBitChain) def getFileBitsF(self,fmask): diff --git a/sickbeard/databases/cache_db.py b/sickbeard/databases/cache_db.py index 700cff01..606a6a54 100644 --- a/sickbeard/databases/cache_db.py +++ b/sickbeard/databases/cache_db.py @@ -46,7 +46,6 @@ class AddSceneExceptions(InitialSchema): self.connection.action( "CREATE TABLE scene_exceptions (exception_id INTEGER PRIMARY KEY, indexer_id INTEGER KEY, show_name TEXT)") - class AddSceneNameCache(AddSceneExceptions): def test(self): return self.hasTable("scene_names") @@ -62,38 +61,13 @@ class AddNetworkTimezones(AddSceneNameCache): def execute(self): self.connection.action("CREATE TABLE network_timezones (network_name TEXT PRIMARY KEY, timezone TEXT)") - -class AddXemNumbering(AddNetworkTimezones): - def test(self): - return self.hasTable("xem_numbering") - - def execute(self): - self.connection.action( - "CREATE TABLE xem_numbering (indexer TEXT, indexer_id INTEGER, season INTEGER, episode INTEGER, absolute_number INTEGER, scene_season INTEGER, scene_episode INTEGER, scene_absolute_number INTEGER, PRIMARY KEY (indexer_id, scene_season, scene_episode))") - -class AddXemRefresh(AddXemNumbering): - def test(self): - return self.hasTable("xem_refresh") - - def execute(self): - self.connection.action( - "CREATE TABLE xem_refresh (indexer TEXT, indexer_id INTEGER PRIMARY KEY, last_refreshed INTEGER)") - -class AddLastSearch(AddXemRefresh): +class AddLastSearch(AddNetworkTimezones): def test(self): return self.hasTable("lastSearch") def execute(self): self.connection.action("CREATE TABLE lastSearch (provider TEXT, time NUMERIC)") -class AddAbsoluteNumbering(AddLastSearch): - def test(self): - return self.hasColumn("xem_numbering", "absolute_number") - - def execute(self): - self.addColumn("xem_numbering", "absolute_number", "NUMERIC", "0") - self.addColumn("xem_numbering", "scene_absolute_number", "NUMERIC", "0") - class AddSceneExceptionsSeasons(AddSceneNameCache): def test(self): return self.hasColumn("scene_exceptions", "season") diff --git a/sickbeard/databases/mainDB.py b/sickbeard/databases/mainDB.py index 61af0ee8..120651c1 100644 --- a/sickbeard/databases/mainDB.py +++ b/sickbeard/databases/mainDB.py @@ -27,7 +27,7 @@ from sickbeard import encodingKludge as ek from sickbeard.name_parser.parser import NameParser, InvalidNameException MIN_DB_VERSION = 9 # oldest db version we support migrating from -MAX_DB_VERSION = 36 +MAX_DB_VERSION = 37 class MainSanityCheck(db.DBSanityCheck): def check(self): @@ -861,3 +861,16 @@ class AddSceneAbsoluteNumbering(AddAnimeBlacklistWhitelist): self.addColumn("tv_episodes", "scene_absolute_number", "NUMERIC", "0") self.incDBVersion() + +class AddXemRefresh(AddSceneAbsoluteNumbering): + def test(self): + return self.checkDBVersion() >= 37 + + def execute(self): + backupDatabase(37) + + logger.log(u"Creating table xem_refresh") + self.connection.action( + "CREATE TABLE xem_refresh (indexer TEXT, indexer_id INTEGER PRIMARY KEY, last_refreshed INTEGER)") + + self.incDBVersion() \ No newline at end of file diff --git a/sickbeard/metadata/generic.py b/sickbeard/metadata/generic.py index 9d6476f7..277cfaeb 100644 --- a/sickbeard/metadata/generic.py +++ b/sickbeard/metadata/generic.py @@ -784,9 +784,9 @@ class GenericMetadata(): if image_url is None: for show_name in set(allPossibleShowNames(show_obj)): if image_type in ('poster', 'poster_thumb'): - image_url = self._retrieve_show_images_from_tmdb(show_name, poster=True) + image_url = self._retrieve_show_images_from_tmdb(show_obj, poster=True) elif image_type == 'fanart': - image_url = self._retrieve_show_images_from_tmdb(show_name, backdrop=True) + image_url = self._retrieve_show_images_from_tmdb(show_obj, backdrop=True) if image_url: break @@ -964,11 +964,11 @@ class GenericMetadata(): return (indexer_id, name, indexer) - def _retrieve_show_images_from_tmdb(self, name, id=None, backdrop=False, poster=False): - tmdb = TMDB(sickbeard.TMDB_API_KEY) - result = None + def _retrieve_show_images_from_tmdb(self, show, backdrop=False, poster=False): + tmdb_id = None # get TMDB configuration info + tmdb = TMDB(sickbeard.TMDB_API_KEY) config = tmdb.Configuration() response = config.info() base_url = response['images']['base_url'] @@ -980,38 +980,28 @@ class GenericMetadata(): max_size = max(sizes, key=size_str_to_int) try: - if id is None: - search = tmdb.Search() - response = search.collection({'query': name}) - id = response['results'][0]['id'] + search = tmdb.Search() + for result in search.collection({'query': show.name}) + search.tv({'query': show.name}): + tmdb_id = result['id'] + external_ids = tmdb.TV(tmdb_id).external_ids() + if show.indexerid in [external_ids['tvdb_id'], external_ids['tvrage_id']]: + break - result = tmdb.Collections(id) + if tmdb_id: + images = tmdb.Collections(tmdb_id).images() + if len(images) > 0: + # get backdrop urls + if backdrop: + rel_path = images['backdrops'][0]['file_path'] + url = "{0}{1}{2}".format(base_url, max_size, rel_path) + return url + + # get poster urls + if poster: + rel_path = images['posters'][0]['file_path'] + url = "{0}{1}{2}".format(base_url, max_size, rel_path) + return url except: - try: - if id is None: - search = tmdb.Search() - response = search.tv({'query': name}) - id = response['results'][0]['id'] + pass - result = tmdb.TV(id) - except: - pass - - if result is None: - return None - - images = result.images() - if len(images) > 0: - # get backdrop urls - if backdrop: - rel_path = images['backdrops'][0]['file_path'] - url = "{0}{1}{2}".format(base_url, max_size, rel_path) - return url - - # get poster urls - if poster: - rel_path = images['posters'][0]['file_path'] - url = "{0}{1}{2}".format(base_url, max_size, rel_path) - return url - - return None + logger.log(u"Could not find any posters or background for " + show.name, logger.DEBUG) \ No newline at end of file diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 8ac49561..eea5b0fd 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -116,7 +116,10 @@ class NameParser(object): self.compiled_regexes[regex_type].update({cur_pattern_name: cur_regex}) def _parse_string(self, name): - for cur_regex_type, cur_regexes in self.compiled_regexes.items() if name else []: + 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) @@ -133,6 +136,15 @@ class NameParser(object): if result.series_name: result.series_name = self.clean_series_name(result.series_name) + cur_show = helpers.get_show_by_name(result.series_name, useIndexer=self.useIndexers) + if self.show and cur_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) + else: + result.show = self.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): @@ -195,20 +207,11 @@ class NameParser(object): if 'release_group' in named_groups: result.release_group = match.group('release_group') - # determin show object for correct regex matching - if not self.show: - show = helpers.get_show_by_name(result.series_name, useIndexer=self.useIndexers) - else: - show = self.show - - if show and show.is_anime and cur_regex_type in ['anime', 'normal']: - result.show = show + if result.show and result.show.is_anime and cur_regex_type in ['anime', 'normal']: return result - elif show and show.is_sports and cur_regex_type == 'sports': - result.show = show + elif result.show and result.show.is_sports and cur_regex_type == 'sports': return result elif cur_regex_type == 'normal': - result.show = show if show else None return result return None @@ -241,25 +244,38 @@ class NameParser(object): obj = unicode(obj, encoding) return obj - def _convert_number(self, number): + def _convert_number(self, org_number): + """ + Convert org_number into an integer + org_number: integer or representation of a number: string or unicode + Try force converting to int first, on error try converting from Roman numerals + returns integer or 0 + """ try: - return int(number) + # try forcing to int + if org_number: + number = int(org_number) + else: + number = 0 + except: - numeral_map = zip( - (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1), - ('M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I') + # on error try converting from Roman numerals + roman_to_int_map = (('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100), + ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), + ('IX', 9), ('V', 5), ('IV', 4), ('I', 1) ) - n = unicode(number).upper() + roman_numeral = str(org_number).upper() + number = 0 + index = 0 - i = result = 0 - for integer, numeral in numeral_map: - while n[i:i + len(numeral)] == numeral: - result += integer - i += len(numeral) + for numeral, integer in roman_to_int_map: + while roman_numeral[index:index + len(numeral)] == numeral: + number += integer + index += len(numeral) - return result + return number def parse(self, name, cache_result=True): name = self._unicodify(name) @@ -319,18 +335,6 @@ class NameParser(object): final_result.which_regex += dir_name_result.which_regex final_result.show = self._combine_results(file_name_result, dir_name_result, 'show') - if final_result.show and final_result.show.is_anime and final_result.is_anime: # only need to to do another conversion if the scene2tvdb didn work - logger.log("Getting season and episodes from absolute numbers", logger.DEBUG) - try: - _actual_season, _actual_episodes = helpers.get_all_episodes_from_absolute_number(final_result.show, - None, - final_result.ab_episode_numbers) - except EpisodeNotFoundByAbsoluteNumberException: - logger.log(str(final_result.show.indexerid) + ": Indexer object absolute number " + str( - final_result.ab_episode_numbers) + " is incomplete, cant determin season and episode numbers") - else: - final_result.season = _actual_season - final_result.episodes = _actual_episodes # if there's no useful info in it then raise an exception if final_result.season_number == None and not final_result.episode_numbers and final_result.air_date == None and not final_result.series_name: @@ -341,141 +345,6 @@ class NameParser(object): return final_result - - def scene2indexer(self, show, scene_name, season, episodes, absolute_numbers): - if not show: return self # need show object - - # TODO: check if adb and make scene2indexer useable with correct numbers - out_season = None - out_episodes = [] - out_absolute_numbers = [] - - # is the scene name a special season ? - # TODO: define if we get scene seasons or indexer seasons ... for now they are mostly the same ... and i will use them as scene seasons - _possible_seasons = sickbeard.scene_exceptions.get_scene_exception_by_name_multiple(scene_name) - # filter possible_seasons - possible_seasons = [] - for cur_scene_indexer_id, cur_scene_season in _possible_seasons: - if cur_scene_indexer_id and str(cur_scene_indexer_id) != str(show.indexerid): - logger.log("Indexer ID mismatch: " + str(show.indexerid) + " now: " + str(cur_scene_indexer_id), - logger.ERROR) - raise MultipleSceneShowResults("indexerid mismatch") - # don't add season -1 since this is a generic name and not a real season... or if we get None - # if this was the only result possible_seasons will stay empty and the next parts will look in the general matter - if cur_scene_season == -1 or cur_scene_season == None: - continue - possible_seasons.append(cur_scene_season) - # if not possible_seasons: # no special season name was used or we could not find it - logger.log( - "possible seasons for '" + scene_name + "' (" + str(show.indexerid) + ") are " + str(possible_seasons), - logger.DEBUG) - - # lets just get a db connection we will need it anyway - cacheDB = db.DBConnection('cache.db') - # should we use absolute_numbers -> anime or season, episodes -> normal show - if show.is_anime: - logger.log( - u"'" + show.name + "' is an anime i will scene convert the absolute numbers " + str(absolute_numbers), - logger.DEBUG) - if possible_seasons: - # check if we have a scene_absolute_number in the possible seasons - for cur_possible_season in possible_seasons: - # and for all absolute numbers - for cur_ab_number in absolute_numbers: - namesSQlResult = cacheDB.select( - "SELECT season, episode, absolute_number FROM xem_numbering WHERE indexer_id = ? and scene_season = ? and scene_absolute_number = ?", - [show.indexerid, cur_possible_season, cur_ab_number]) - if len(namesSQlResult) > 1: - logger.log( - "Multiple episodes for a absolute number and season. check XEM numbering", - logger.ERROR) - raise MultipleSceneEpisodeResults("Multiple episodes for a absolute number and season") - elif len(namesSQlResult) == 0: - break # break out of current absolute_numbers -> next season ... this is not a good sign - # if we are here we found ONE episode for this season absolute number - # logger.log(u"I found matching episode: " + namesSQlResult[0]['name'], logger.DEBUG) - out_episodes.append(int(namesSQlResult[0]['episode'])) - out_absolute_numbers.append(int(namesSQlResult[0]['absolute_number'])) - out_season = int(namesSQlResult[0][ - 'season']) # note this will always use the last season we got ... this will be a problem on double episodes that break the season barrier - if out_season: # if we found a episode in the cur_possible_season we dont need / want to look at the other season possibilities - break - else: # no possible seasons from the scene names lets look at this more generic - for cur_ab_number in absolute_numbers: - namesSQlResult = cacheDB.select( - "SELECT season, episode, absolute_number FROM xem_numbering WHERE indexer_id = ? and scene_absolute_number = ?", - [show.indexerid, cur_ab_number]) - if len(namesSQlResult) > 1: - logger.log( - "Multiple episodes for a absolute number. this might happend because we are missing a scene name for this season. xem lacking behind ?", - logger.ERROR) - raise MultipleSceneEpisodeResults("Multiple episodes for a absolute number") - elif len(namesSQlResult) == 0: - continue - # if we are here we found ONE episode for this season absolute number - # logger.log(u"I found matching episode: " + namesSQlResult[0]['name'], logger.DEBUG) - out_episodes.append(int(namesSQlResult[0]['episode'])) - out_absolute_numbers.append(int(namesSQlResult[0]['absolute_number'])) - out_season = int(namesSQlResult[0][ - 'season']) # note this will always use the last season we got ... this will be a problem on double episodes that break the season barrier - if not out_season: # we did not find anything in the loops ? damit there is no episode - logger.log("No episode found for these scene numbers. asuming indexer numbers", logger.DEBUG) - # we still have to convert the absolute number to sxxexx ... but that is done not here - else: - logger.log(u"'" + show.name + "' is a normal show i will scene convert the season and episodes " + str( - season) + "x" + str(episodes), logger.DEBUG) - out_absolute_numbers = None - if possible_seasons: - # check if we have a scene_absolute_number in the possible seasons - for cur_possible_season in possible_seasons: - # and for all episode - for cur_episode in episodes: - namesSQlResult = cacheDB.select( - "SELECT season, episode FROM xem_numbering WHERE indexer_id = ? and scene_season = ? and scene_episode = ?", - [show.indexerid, cur_possible_season, cur_episode]) - if len(namesSQlResult) > 1: - logger.log( - "Multiple episodes for season episode number combination. this should not be check xem configuration", - logger.ERROR) - raise MultipleSceneEpisodeResults("Multiple episodes for season episode number combination") - elif len(namesSQlResult) == 0: - break # break out of current episode -> next season ... this is not a good sign - # if we are here we found ONE episode for this season absolute number - # logger.log(u"I found matching episode: " + namesSQlResult[0]['name'], logger.DEBUG) - out_episodes.append(int(namesSQlResult[0]['episode'])) - out_season = int(namesSQlResult[0][ - 'season']) # note this will always use the last season we got ... this will be a problem on double episodes that break the season barrier - if out_season: # if we found a episode in the cur_possible_season we dont need / want to look at the other posibilites - break - else: # no possible seasons from the scene names lets look at this more generic - for cur_episode in episodes: - namesSQlResult = cacheDB.select( - "SELECT season, episode FROM xem_numbering WHERE indexer_id = ? and scene_episode = ? and scene_season = ?", - [show.indexerid, cur_episode, season]) - if len(namesSQlResult) > 1: - logger.log( - "Multiple episodes for season episode number combination. this might happend because we are missing a scene name for this season. xem lacking behind ?", - logger.ERROR) - raise MultipleSceneEpisodeResults("Multiple episodes for season episode number combination") - elif len(namesSQlResult) == 0: - continue - # if we are here we found ONE episode for this season absolute number - # logger.log(u"I found matching episode: " + namesSQlResult[0]['name'], logger.DEBUG) - out_episodes.append(int(namesSQlResult[0]['episode'])) - out_season = int(namesSQlResult[0][ - 'season']) # note this will always use the last season we got ... this will be a problem on double episodes that break the season barrier - # this is only done for normal shows - if not out_season: # we did not find anything in the loops ? darn there is no episode - logger.log("No episode found for these scene numbers. assuming these are valid indexer numbers", - logger.DEBUG) - out_season = season - out_episodes = episodes - out_absolute_numbers = absolute_numbers - - # okay that was easy we found the correct season and episode numbers - return (out_season, out_episodes, out_absolute_numbers) - - class ParseResult(object): def __init__(self, original_name, @@ -581,25 +450,34 @@ class ParseResult(object): def convert(self): if not self.show: return self # need show object - if not self.season_number: return self # can't work without a season - if not len(self.episode_numbers): return self # need at least one episode if self.air_by_date or self.sports: return self # scene numbering does not apply to air-by-date + # check if show is anime + if self.show.is_anime and not (len(self.episode_numbers) or self.season_number) and not len(self.ab_episode_numbers): + return self # can't work without a season + elif not self.show._is_anime and not (len(self.episode_numbers) or self.season_number): + return self + new_episode_numbers = [] new_season_numbers = [] new_absolute_numbers = [] - for i, epNo in enumerate(self.episode_numbers): - abNo = None - if len(self.ab_episode_numbers): - abNo = self.ab_episode_numbers[i] + if len(self.ab_episode_numbers) and not len(self.episode_numbers): + for epAbNo in self.ab_episode_numbers: + (s, e, a) = scene_numbering.get_absolute_numbering(self.show.indexerid, self.show.indexer, epAbNo) - (s, e, a) = scene_numbering.get_indexer_numbering(self.show.indexerid, self.show.indexer, - self.season_number, - epNo, abNo) - new_episode_numbers.append(e) - new_season_numbers.append(s) - new_absolute_numbers.append(a) + if (s or e or a): + new_episode_numbers.append(e) + new_season_numbers.append(s) + new_absolute_numbers.append(a) + else: + for epNo in self.episode_numbers: + (s, e, a) = scene_numbering.get_indexer_numbering(self.show.indexerid, self.show.indexer, + self.season_number, + epNo, None) + new_episode_numbers.append(e) + new_season_numbers.append(s) + new_absolute_numbers.append(a) # need to do a quick sanity check here. It's possible that we now have episodes # from more than one season (by tvdb numbering), and this is just too much diff --git a/sickbeard/providers/btn.py b/sickbeard/providers/btn.py index f0711858..aadae43d 100644 --- a/sickbeard/providers/btn.py +++ b/sickbeard/providers/btn.py @@ -47,7 +47,7 @@ class BTNProvider(generic.TorrentProvider): self.cache = BTNCache(self) - self.url = "http://broadcasthe.net" + self.url = "http://api.btnapps.net" def isEnabled(self): return self.enabled @@ -134,7 +134,7 @@ class BTNProvider(generic.TorrentProvider): def _api_call(self, apikey, params={}, results_per_page=1000, offset=0): - server = jsonrpclib.Server('http://api.btnapps.net') + server = jsonrpclib.Server(self.url) parsedJSON = {} try: @@ -219,7 +219,8 @@ class BTNProvider(generic.TorrentProvider): # Search for the year of the air by date show whole_season_params['name'] = str(ep_obj.airdate).split('-')[0] elif ep_obj.show.is_anime: - whole_season_params['name'] = "%d" % ep_obj.scene_absolute_number + whole_season_params['name'] = 'S' + str(ep_obj.scene_season) + #whole_season_params['name'] = "%d" % ep_obj.scene_absolute_number else: whole_season_params['name'] = 'Season ' + str(ep_obj.scene_season) @@ -234,9 +235,9 @@ class BTNProvider(generic.TorrentProvider): search_params = {'category': 'Episode'} - if self.show.indexer == 1 and not self.show.is_anime: + if self.show.indexer == 1: search_params['tvdb'] = self.show.indexerid - elif self.show.indexer == 2 and not self.show.is_anime: + elif self.show.indexer == 2: search_params['tvrage'] = self.show.indexerid else: search_params['series'] = sanitizeSceneName(self.show.name) @@ -253,9 +254,7 @@ class BTNProvider(generic.TorrentProvider): # BTN uses dots in dates, we just search for the date since that # combined with the series identifier should result in just one episode search_params['name'] = date_str.replace('-', '.') - elif self.show.is_anime: - search_params['name'] = "%i" % int(ep_obj.scene_absolute_number) - else: + elif not self.show.is_anime: # Do a general name search for the episode, formatted like SXXEYY search_params['name'] = "S%02dE%02d" % (ep_obj.scene_season, ep_obj.scene_episode) diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index ded53756..d947b67e 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -68,7 +68,6 @@ class GenericProvider: self.session.headers.update({ 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36'}) - def getID(self): return GenericProvider.makeID(self.name) diff --git a/sickbeard/scene_numbering.py b/sickbeard/scene_numbering.py index aa9a9692..53da505a 100644 --- a/sickbeard/scene_numbering.py +++ b/sickbeard/scene_numbering.py @@ -23,6 +23,9 @@ import time import traceback +import sickbeard + +from lib.tmdb_api import TMDB try: import json @@ -110,6 +113,28 @@ def get_indexer_numbering(indexer_id, indexer, sceneSeason, sceneEpisode, sceneA return get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode, sceneAbsoluteNumber) return (sceneSeason, sceneEpisode, sceneAbsoluteNumber) +def get_absolute_numbering(indexer_id, indexer, sceneAbsoluteNumber, fallback_to_xem=True): + """ + Returns a tuple, (season, episode, absolute_number) with the TVDB and TVRAGE numbering for (sceneAbsoluteNumber) + (this works like the reverse of get_absolute_numbering) + """ + if indexer_id is None or sceneAbsoluteNumber is None: + return (None, None, None) + + indexer_id = int(indexer_id) + indexer = int(indexer) + + myDB = db.DBConnection() + + rows = myDB.select( + "SELECT season, episode, absolute_number FROM scene_numbering WHERE indexer = ? and indexer_id = ? and scene_absolute_number = ?", + [indexer, indexer_id, sceneAbsoluteNumber]) + if rows: + return (int(rows[0]["season"]), int(rows[0]["episode"]), int(rows[0]["absolute_number"])) + else: + if fallback_to_xem: + return get_indexer_numbering_for_xem(indexer_id, indexer, sceneAbsoluteNumber) + return (None, None, None) def get_scene_numbering_for_show(indexer_id, indexer): """ @@ -137,10 +162,7 @@ def get_scene_numbering_for_show(indexer_id, indexer): scene_episode = int(row['scene_episode']) scene_absolute_number = int(row['scene_absolute_number']) - try: - result[(season, episode)] - except: - result[(season, episode)] = (scene_season, scene_episode, scene_absolute_number) + result[(season, episode)] = (scene_season, scene_episode, scene_absolute_number) return result @@ -191,25 +213,17 @@ def find_xem_numbering(indexer_id, indexer, season, episode, absolute_number): indexer_id = int(indexer_id) indexer = int(indexer) - if _xem_refresh_needed(indexer_id, indexer): - _xem_refresh(indexer_id, indexer) + if xem_refresh_needed(indexer_id, indexer): + xem_refresh(indexer_id, indexer) - cacheDB = db.DBConnection('cache.db') + myDB = db.DBConnection() - rows = cacheDB.select( - "SELECT scene_season, scene_episode, scene_absolute_number FROM xem_numbering WHERE indexer = ? and indexer_id = ? and season = ? and episode = ?", + rows = myDB.select( + "SELECT scene_season, scene_episode, scene_absolute_number FROM tv_episodes WHERE indexer = ? and showid = ? and season = ? and episode = ?", [indexer, indexer_id, season, episode]) if rows: return (int(rows[0]["scene_season"]), int(rows[0]["scene_episode"]), int(rows[0]["scene_absolute_number"])) - elif cacheDB.select( - "SELECT * FROM xem_numbering WHERE indexer = ? and indexer_id = ?", - [indexer, indexer_id]): - - return (0, 0, 0) - else: - return None - def get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode, sceneAbsoluteNumber): """ @@ -226,19 +240,48 @@ def get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode indexer_id = int(indexer_id) indexer = int(indexer) - if _xem_refresh_needed(indexer_id, indexer): - _xem_refresh(indexer_id, indexer) - cacheDB = db.DBConnection('cache.db') - rows = cacheDB.select( - "SELECT season, episode, absolute_number FROM xem_numbering WHERE indexer = ? and indexer_id = ? and scene_season = ? and scene_episode = ?", + if xem_refresh_needed(indexer_id, indexer): + xem_refresh(indexer_id, indexer) + + myDB = db.DBConnection() + + rows = myDB.select( + "SELECT season, episode, absolute_number FROM tv_episodes WHERE indexer = ? and showid = ? and scene_season = ? and scene_episode = ?", [indexer, indexer_id, sceneSeason, sceneEpisode]) if rows: return (int(rows[0]["season"]), int(rows[0]["episode"]), int(rows[0]["absolute_number"])) - else: - return (sceneSeason, sceneEpisode, sceneAbsoluteNumber) + return (sceneSeason, sceneEpisode, sceneAbsoluteNumber) -def _xem_refresh_needed(indexer_id, indexer): +def get_absolute_numbering_for_xem(indexer_id, indexer, sceneAbsoluteNumber): + """ + Reverse of find_xem_numbering: lookup a tvdb season and episode using scene numbering + + @param indexer_id: int + @param sceneSeason: int + @param sceneEpisode: int + @return: (int, int) a tuple of (season, episode) + """ + if indexer_id is None or sceneAbsoluteNumber is None: + return None + + indexer_id = int(indexer_id) + indexer = int(indexer) + + if xem_refresh_needed(indexer_id, indexer): + xem_refresh(indexer_id, indexer) + + myDB = db.DBConnection() + + rows = myDB.select( + "SELECT season, episode, absolute_number FROM tv_episodes WHERE indexer = ? and showid = ? and scene_absolute_number = ?", + [indexer, indexer_id, sceneAbsoluteNumber]) + if rows: + return (int(rows[0]["season"]), int(rows[0]["episode"]), int(rows[0]["absolute_number"])) + + return (None, None, None) + +def xem_refresh_needed(indexer_id, indexer): """ Is a refresh needed on a show? @@ -251,8 +294,8 @@ def _xem_refresh_needed(indexer_id, indexer): indexer_id = int(indexer_id) indexer = int(indexer) - cacheDB = db.DBConnection('cache.db') - rows = cacheDB.select("SELECT last_refreshed FROM xem_refresh WHERE indexer = ? and indexer_id = ?", + myDB = db.DBConnection() + rows = myDB.select("SELECT last_refreshed FROM xem_refresh WHERE indexer = ? and indexer_id = ?", [indexer, indexer_id]) if rows: return time.time() > (int(rows[0]['last_refreshed']) + MAX_XEM_AGE_SECS) @@ -260,7 +303,7 @@ def _xem_refresh_needed(indexer_id, indexer): return True -def _xem_refresh(indexer_id, indexer): +def xem_refresh(indexer_id, indexer): """ Refresh data from xem for a tv show @@ -290,35 +333,34 @@ def _xem_refresh(indexer_id, indexer): return None result = data - cacheDB = db.DBConnection('cache.db') + myDB = db.DBConnection() ql = [] if result: ql.append(["INSERT OR REPLACE INTO xem_refresh (indexer, indexer_id, last_refreshed) VALUES (?,?,?)", [indexer, indexer_id, time.time()]]) if 'success' in result['result']: - ql.append(["DELETE FROM xem_numbering where indexer = ? and indexer_id = ?", [indexer, indexer_id]]) for entry in result['data']: if 'scene' in entry: ql.append([ - "INSERT OR IGNORE INTO xem_numbering (indexer, indexer_id, season, episode, absolute_number, scene_season, scene_episode, scene_absolute_number) VALUES (?,?,?,?,?,?,?,?)", - [indexer, indexer_id, - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'], - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode'], - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['absolute'], - entry['scene']['season'], + "UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?", + [entry['scene']['season'], entry['scene']['episode'], - entry['scene']['absolute']]]) + entry['scene']['absolute'], + indexer_id, + entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'], + entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode'] + ]]) if 'scene_2' in entry: # for doubles ql.append([ - "INSERT OR IGNORE INTO xem_numbering (indexer, indexer_id, season, episode, absolute_number, scene_season, scene_episode, scene_absolute_number) VALUES (?,?,?,?,?,?,?,?)", - [indexer, indexer_id, - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'], - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode'], - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['absolute'], - entry['scene_2']['season'], + "UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?", + [entry['scene_2']['season'], entry['scene_2']['episode'], - entry['scene_2']['absolute']]]) + entry['scene_2']['absolute'], + indexer_id, + entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'], + entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode'] + ]]) else: logger.log(u'Failed to get XEM scene data for show %s from %s because "%s"' % ( indexer_id, sickbeard.indexerApi(indexer).name, result['message']), logger.DEBUG) @@ -332,8 +374,10 @@ def _xem_refresh(indexer_id, indexer): return None if ql: - cacheDB.mass_action(ql) + myDB.mass_action(ql) + # fix xem scene numbering issues + #fix_xem_numbering(indexer_id, indexer) def get_xem_numbering_for_show(indexer_id, indexer): """ @@ -347,127 +391,186 @@ def get_xem_numbering_for_show(indexer_id, indexer): indexer_id = int(indexer_id) indexer = int(indexer) - if _xem_refresh_needed(indexer_id, indexer): - _xem_refresh(indexer_id, indexer) + if xem_refresh_needed(indexer_id, indexer): + xem_refresh(indexer_id, indexer) - cacheDB = db.DBConnection('cache.db') + myDB = db.DBConnection() - rows = cacheDB.select( - 'SELECT season, episode, absolute_number, scene_season, scene_episode, scene_absolute_number FROM xem_numbering WHERE indexer = ? and indexer_id = ? ORDER BY season, episode', + rows = myDB.select( + 'SELECT season, episode, absolute_number, scene_season, scene_episode, scene_absolute_number FROM tv_episodes WHERE indexer = ? and showid = ? ORDER BY season, episode', [indexer, indexer_id]) result = {} for row in rows: - season = int(row['season']) - episode = int(row['episode']) - scene_season = int(row['scene_season']) - scene_episode = int(row['scene_episode']) - scene_absolute_number = int(row['scene_absolute_number']) + season = int(row['season'] or 0) + episode = int(row['episode'] or 0) + scene_season = int(row['scene_season'] or 0) + scene_episode = int(row['scene_episode'] or 0) + scene_absolute_number = int(row['scene_absolute_number'] or 0) result[(season, episode)] = (scene_season, scene_episode, scene_absolute_number) return result - -def get_xem_numbering_for_season(indexer_id, indexer, season): +def fix_xem_numbering(indexer_id, indexer): """ Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings for an entire show. Both the keys and values of the dict are tuples. - Will be empty if there are no scene numbers set + Will be empty if there are no scene numbers set in xem """ - if indexer_id is None or season is None: + if indexer_id is None: return {} indexer_id = int(indexer_id) indexer = int(indexer) - if _xem_refresh_needed(indexer_id, indexer): - _xem_refresh(indexer_id, indexer) - - cacheDB = db.DBConnection('cache.db') - - rows = cacheDB.select( - 'SELECT season, scene_season FROM xem_numbering WHERE indexer = ? and indexer_id = ? AND season = ? ORDER BY season', - [indexer, indexer_id, season]) - - result = {} - if rows: - for row in rows: - result.setdefault(int(row['season']), []).append(int(row['scene_season'])) - else: - result.setdefault(int(season), []).append(int(season)) - - return result - -def fix_scene_numbering(): - ql = [] + # query = [{ + # "name": self.show.name, + # "seasons": [{ + # "episodes": [{ + # "episode_number": None, + # "name": None + # }], + # "season_number": None, + # }], + # "/tv/tv_program/number_of_seasons": [], + # "/tv/tv_program/number_of_episodes": [], + # "/tv/tv_program/thetvdb_id": [], + # "/tv/tv_program/tvrage_id": [], + # "type": "/tv/tv_program", + # }] + # + # + # url = 'https://www.googleapis.com/freebase/v1/mqlread' + # api_key = "AIzaSyCCHNp4dhVHxJYzbLiCE4y4a1rgTnX4fDE" + # params = { + # 'query': json.dumps(query), + # 'key': api_key + # } + # + # + # def get_from_api(url, params=None): + # """Build request and return results + # """ + # import xmltodict + # + # response = requests.get(url, params=params) + # if response.status_code == 200: + # try: + # return response.json() + # except ValueError: + # return xmltodict.parse(response.text)['Data'] + # + # # Get query results + # tmp = get_from_api(url, params=params)['result'] myDB = db.DBConnection() - sqlResults = myDB.select( - "SELECT showid, indexerid, indexer, episode_id, season, episode FROM tv_episodes WHERE scene_season = -1 OR scene_episode = -1") + rows = myDB.select( + 'SELECT season, episode, absolute_number, scene_season, scene_episode, scene_absolute_number FROM tv_episodes WHERE indexer = ? and showid = ?', + [indexer, indexer_id]) - for epResult in sqlResults: - indexerid = int(epResult["showid"]) - indexer = int(epResult["indexer"]) - season = int(epResult["season"]) - episode = int(epResult["episode"]) - absolute_number = int(epResult["absolute_number"]) + last_absolute_number = None + last_scene_season = None + last_scene_episode = None + last_scene_absolute_number = None - logger.log( - u"Repairing any scene numbering issues for showid: " + str(epResult["showid"]) + u" season: " + str( - epResult["season"]) + u" episode: " + str(epResult["episode"]), logger.DEBUG) + update_absolute_number = False + update_scene_season = False + update_scene_episode = False + update_scene_absolute_number = False - scene_season, scene_episode, scene_absolute_number = sickbeard.scene_numbering.get_scene_numbering(indexerid, - indexer, - season, - episode, - absolute_number) + logger.log( + u'Fixing any XEM scene mapping issues for show %s on %s' % (indexer_id, sickbeard.indexerApi(indexer).name,), + logger.DEBUG) - ql.append( - ["UPDATE tv_episodes SET scene_season = ? WHERE indexerid = ?", [scene_season, epResult["indexerid"]]]) - ql.append( - ["UPDATE tv_episodes SET scene_episode = ? WHERE indexerid = ?", [scene_episode, epResult["indexerid"]]]) - ql.append( - ["UPDATE tv_episodes SET scene_absolute_number = ? WHERE indexerid = ?", - [scene_absolute_number, epResult["indexerid"]]]) + ql = [] + for row in rows: + season = int(row['season']) + episode = int(row['episode']) + + if not int(row['scene_season']) and last_scene_season: + scene_season = last_scene_season + 1 + update_scene_season = True + else: + scene_season = int(row['scene_season']) + if last_scene_season and scene_season < last_scene_season: + scene_season = last_scene_season + 1 + update_scene_season = True + + if not int(row['scene_episode']) and last_scene_episode: + scene_episode = last_scene_episode + 1 + update_scene_episode = True + else: + scene_episode = int(row['scene_episode']) + if last_scene_episode and scene_episode < last_scene_episode: + scene_episode = last_scene_episode + 1 + update_scene_episode = True + + # check for unset values and correct them + if not int(row['absolute_number']) and last_absolute_number: + absolute_number = last_absolute_number + 1 + update_absolute_number = True + else: + absolute_number = int(row['absolute_number']) + if last_absolute_number and absolute_number < last_absolute_number: + absolute_number = last_absolute_number + 1 + update_absolute_number = True + + if not int(row['scene_absolute_number']) and last_scene_absolute_number: + scene_absolute_number = last_scene_absolute_number + 1 + update_scene_absolute_number = True + else: + scene_absolute_number = int(row['scene_absolute_number']) + if last_scene_absolute_number and scene_absolute_number < last_scene_absolute_number: + scene_absolute_number = last_scene_absolute_number + 1 + update_scene_absolute_number = True + + # store values for lookup on next iteration + last_absolute_number = absolute_number + last_scene_season = scene_season + last_scene_episode = scene_episode + last_scene_absolute_number = scene_absolute_number + + if update_absolute_number: + ql.append([ + "UPDATE tv_episodes SET absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?", + [absolute_number, + indexer_id, + season, + episode + ]]) + update_absolute_number = False + + if update_scene_season: + ql.append([ + "UPDATE tv_episodes SET scene_season = ? WHERE showid = ? AND season = ? AND episode = ?", + [scene_season, + indexer_id, + season, + episode + ]]) + update_scene_season = False + + if update_scene_episode: + ql.append([ + "UPDATE tv_episodes SET scene_episode = ? WHERE showid = ? AND season = ? AND episode = ?", + [scene_episode, + indexer_id, + season, + episode + ]]) + update_scene_episode = False + + if update_scene_absolute_number: + ql.append([ + "UPDATE tv_episodes SET scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?", + [scene_absolute_number, + indexer_id, + season, + episode + ]]) + update_scene_absolute_number = False if ql: - myDB.mass_action(ql) - -def get_ep_mapping(epObj, parse_result): - # scores - indexer_numbering = 0 - scene_numbering = 0 - absolute_numbering = 0 - - _possible_seasons = sickbeard.scene_exceptions.get_scene_exception_by_name_multiple(parse_result.series_name) - - # indexer numbering - if epObj.season == parse_result.season_number: - indexer_numbering += 1 - elif epObj.episode in parse_result.episode_numbers: - indexer_numbering += 1 - - # scene numbering - if epObj.scene_season == parse_result.season_number: - scene_numbering += 1 - elif epObj.scene_episode in parse_result.episode_numbers: - scene_numbering += 1 - - # absolute numbering - if epObj.show.is_anime and parse_result.is_anime: - - if epObj.absolute_number in parse_result.ab_episode_numbers: - absolute_numbering +=1 - elif epObj.scene_absolute_number in parse_result.ab_episode_numbers: - absolute_numbering += 1 - - if indexer_numbering == 2: - print "indexer numbering" - elif scene_numbering == 2: - print "scene numbering" - elif absolute_numbering == 1: - print "indexer numbering" - else: - print "could not determin numbering" \ No newline at end of file + myDB.mass_action(ql) \ No newline at end of file diff --git a/sickbeard/search.py b/sickbeard/search.py index 0e9f9a84..8ca15682 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -344,12 +344,12 @@ def searchForNeededEpisodes(show, episodes): origThreadName = threading.currentThread().name providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive() and not x.backlog_only] for curProviderCount, curProvider in enumerate(providers): - threading.currentThread().name = origThreadName + " :: [" + curProvider.name + "]" - if curProvider.anime_only and not show.is_anime: logger.log(u"" + str(show.name) + " is not an anime skiping ...") continue + threading.currentThread().name = origThreadName + " :: [" + curProvider.name + "]" + try: logger.log(u"Updating RSS cache ...") curProvider.cache.updateCache() @@ -418,14 +418,14 @@ def searchProviders(show, season, episodes, manualSearch=False): origThreadName = threading.currentThread().name for providerNum, provider in enumerate(providers): - threading.currentThread().name = origThreadName + " :: [" + provider.name + "]" - foundResults.setdefault(provider.name, {}) - searchCount = 0 - if provider.anime_only and not show.is_anime: logger.log(u"" + str(show.name) + " is not an anime skiping ...") continue + threading.currentThread().name = origThreadName + " :: [" + provider.name + "]" + foundResults.setdefault(provider.name, {}) + searchCount = 0 + search_mode = 'eponly' if seasonSearch and provider.search_mode == 'sponly': search_mode = provider.search_mode diff --git a/sickbeard/show_name_helpers.py b/sickbeard/show_name_helpers.py index 49de785c..172c017d 100644 --- a/sickbeard/show_name_helpers.py +++ b/sickbeard/show_name_helpers.py @@ -30,6 +30,7 @@ from sickbeard import db from sickbeard import encodingKludge as ek from name_parser.parser import NameParser, InvalidNameException from lib.unidecode import unidecode +from sickbeard.blackandwhitelist import BlackAndWhiteList resultFilters = ["sub(bed|ed|pack|s)", "(dk|fin|heb|kor|nor|nordic|pl|swe)sub(bed|ed|s)?", "(dir|sample|sub|nfo)fix", "sample", "(dvd)?extras", @@ -58,7 +59,8 @@ def filterBadReleases(name): filters = [re.compile('(^|[\W_])%s($|[\W_])' % filter.strip(), re.I) for filter in resultFilters] for regfilter in filters: if regfilter.search(name): - logger.log(u"Invalid scene release: " + name + " contains pattern: " + regfilter.pattern + ", ignoring it", logger.DEBUG) + logger.log(u"Invalid scene release: " + name + " contains pattern: " + regfilter.pattern + ", ignoring it", + logger.DEBUG) return False return True @@ -135,7 +137,8 @@ def makeSceneSeasonSearchString(show, ep_obj, extraSearchType=None): # if we need a better one then add it to the list of episodes to fetch if (curStatus in ( - common.DOWNLOADED, common.SNATCHED) and curQuality < highestBestQuality) or curStatus == common.WANTED: + common.DOWNLOADED, + common.SNATCHED) and curQuality < highestBestQuality) or curStatus == common.WANTED: ab_number = episode.scene_absolute_number if ab_number > 0: seasonStrings.append("%d" % ab_number) @@ -148,6 +151,7 @@ def makeSceneSeasonSearchString(show, ep_obj, extraSearchType=None): numseasons = int(numseasonsSQlResult[0][0]) seasonStrings = ["S%02d" % int(ep_obj.scene_season)] + bwl = BlackAndWhiteList(show.indexerid) showNames = set(makeSceneShowSearchStrings(show, ep_obj.scene_season)) toReturn = [] @@ -162,7 +166,12 @@ def makeSceneSeasonSearchString(show, ep_obj, extraSearchType=None): # for providers that don't allow multiple searches in one request we only search for Sxx style stuff else: for cur_season in seasonStrings: - toReturn.append(curShow + "." + cur_season) + if len(bwl.whiteList) > 0: + for keyword in bwl.whiteList: + toReturn.append(keyword + '.' + curShow+ "." + cur_season) + else: + toReturn.append(curShow + "." + cur_season) + return toReturn @@ -188,13 +197,18 @@ def makeSceneSearchString(show, ep_obj): if numseasons == 1 and not ep_obj.show.is_anime: epStrings = [''] + bwl = BlackAndWhiteList(ep_obj.show.indexerid) showNames = set(makeSceneShowSearchStrings(show, ep_obj.scene_season)) toReturn = [] for curShow in showNames: for curEpString in epStrings: - toReturn.append(curShow + '.' + curEpString) + if len(bwl.whiteList) > 0: + for keyword in bwl.whiteList: + toReturn.append(keyword + '.' + curShow + '.' + curEpString) + else: + toReturn.append(curShow + '.' + curEpString) return toReturn @@ -228,7 +242,8 @@ def isGoodResult(name, show, log=True, season=-1): return True if log: - logger.log(u"Provider gave result " + name + " but that doesn't seem like a valid result for " + show.name + " so I'm ignoring it") + logger.log( + u"Provider gave result " + name + " but that doesn't seem like a valid result for " + show.name + " so I'm ignoring it") return False diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py index 5e245dc5..6fc46bcc 100644 --- a/sickbeard/show_queue.py +++ b/sickbeard/show_queue.py @@ -354,13 +354,6 @@ class QueueItemAdd(ShowQueueItem): # before we parse local files lets update exceptions sickbeard.scene_exceptions.retrieve_exceptions() - # and get scene numbers - logger.log(u"Attempting to load scene numbers", logger.DEBUG) - if self.show.loadEpisodeSceneNumbers(): - logger.log(u"loading scene numbers successfull", logger.DEBUG) - else: - logger.log(u"loading scene numbers NOT successfull or no scene numbers available", logger.DEBUG) - try: self.show.loadEpisodesFromDir() except Exception, e: @@ -548,12 +541,6 @@ class QueueItemUpdate(ShowQueueItem): except exceptions.EpisodeDeletedException: pass - logger.log(u"Attempting to load scene numbers", logger.DEBUG) - if self.show.loadEpisodeSceneNumbers(): - logger.log(u"loading scene numbers successfull", logger.DEBUG) - else: - logger.log(u"loading scene numbers NOT successfull or no scene numbers available", logger.DEBUG) - sickbeard.showQueueScheduler.action.refreshShow(self.show, True) class QueueItemForceUpdate(QueueItemUpdate): diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 2a83b6b4..0064ee24 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -17,6 +17,7 @@ # along with SickRage. If not, see . from __future__ import with_statement +import json import os.path import datetime @@ -24,6 +25,7 @@ import threading import re import glob import traceback +import requests import sickbeard @@ -186,6 +188,10 @@ class TVShow(object): def getEpisode(self, season, episode, file=None, noCreate=False, absolute_number=None): + # Load XEM data to DB for show + if sickbeard.scene_numbering.xem_refresh_needed(self.indexerid, self.indexer): + sickbeard.scene_numbering.xem_refresh(self.indexerid, self.indexer) + if not season in self.episodes: self.episodes[season] = {} @@ -213,12 +219,6 @@ class TVShow(object): logger.DEBUG) return None - def createCurSeasonDict(): - if not season in self.episodes: - self.episodes[season] = {} - - createCurSeasonDict() - if not episode in self.episodes[season] or self.episodes[season][episode] == None: if noCreate: return None @@ -274,7 +274,6 @@ class TVShow(object): last_update_indexer = datetime.date.fromordinal(self.last_update_indexer) - # in the first year after ended (last airdate), update every 30 days # in the first year after ended (last airdate), update every 30 days if (update_date - last_airdate) < datetime.timedelta(days=450) and ( update_date - last_update_indexer) > datetime.timedelta(days=30): @@ -532,33 +531,6 @@ class TVShow(object): return scannedEps - def loadEpisodeSceneNumbers(self): - epList = self.loadEpisodesFromDB() - - sql_l = [] - for curSeason in epList: - for curEp in epList[curSeason]: - epObj = self.getEpisode(curSeason, curEp) - - with epObj.lock: - (epObj.scene_season, epObj.scene_episode, epObj.scene_absolute_number) = \ - sickbeard.scene_numbering.get_scene_numbering(self.indexerid, self.indexer, epObj.season, - epObj.episode, epObj.absolute_number) - logger.log( - str(self.indexerid) + ": adding scene numbering. Indexer: " + str(epObj.season) + "x" + str( - epObj.episode) + "| Scene: " + str(epObj.scene_season) + "x" + str(epObj.scene_episode), - logger.DEBUG) - - # mass add to database - if epObj.dirty: - sql_l.append(epObj.get_sql()) - - if len(sql_l) > 0: - myDB = db.DBConnection() - myDB.mass_action(sql_l) - - return True - def getImages(self, fanart=None, poster=None): fanart_result = poster_result = banner_result = False season_posters_result = season_banners_result = season_all_poster_result = season_all_banner_result = False @@ -1460,7 +1432,6 @@ class TVEpisode(object): "Couldn't find episode " + str(season) + "x" + str(episode)) def loadFromDB(self, season, episode): - logger.log( str(self.show.indexerid) + u": Loading episode details from DB for episode " + str(season) + "x" + str( episode), logger.DEBUG) @@ -1521,15 +1492,6 @@ class TVEpisode(object): if sqlResults[0]["is_proper"]: self.is_proper = int(sqlResults[0]["is_proper"]) - if self.scene_season == 0 or self.scene_episode == 0 or self.scene_absolute_number == 0: - (self.scene_season, self.scene_episode, self.scene_absolute_number) = \ - sickbeard.scene_numbering.get_scene_numbering( - self.show.indexerid, - self.show.indexer, - self.season, - self.episode, - self.absolute_number) - self.dirty = False return True @@ -2301,20 +2263,4 @@ class TVEpisode(object): with self.lock: self.saveToDB() for relEp in self.relatedEps: - relEp.saveToDB() - - def convertToSceneNumbering(self): - (self.scene_season, self.scene_episode, - self.scene_absolute_number) = sickbeard.scene_numbering.get_scene_numbering(self.show.indexerid, - self.show.indexer, - self.season, - self.episode, - self.absolute_number) - - def convertToIndexerNumbering(self): - (self.season, self.episode, self.absolute_number) = sickbeard.scene_numbering.get_indexer_numbering( - self.show.indexerid, - self.show.indexer, - self.scene_season, - self.scene_episode, - self.scene_absolute_number) + relEp.saveToDB() \ No newline at end of file From 894e53333006efaabc0595d8ee6845b8aaf95f2d Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Thu, 29 May 2014 00:24:52 +0200 Subject: [PATCH 19/82] Got AniDB? --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c2a423f1..3166d374 100644 --- a/readme.md +++ b/readme.md @@ -29,7 +29,7 @@ FEATURES: - DVD Order numbering for returning the results in DVD order instead of Air-By-Date order. - Improved Failed handling code for both NZB and Torrent downloads. - DupeKey/DupeScore for NZBGet 12+ -- Searches both TheTVDB.com and TVRage.com for shows, seasons, episodes +- Searches both TheTVDB.com, TVRage.com and AniDB.net for shows, seasons, episodes - Importing of existing video files now allows you to choose which indexer you wish to have SickBeard download its show info from. - Your tvshow.nfo files are now tagged with a indexer key so that SickBeard can easily tell if the shows info comes from TheTVDB or TVRage. - Failed download handling has been improved now for both NZB and Torrents. From 0e34c8c4b32afeb1ea85ad96f5f80e12d7e9251b Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Thu, 29 May 2014 02:30:38 +0200 Subject: [PATCH 20/82] Backport from https://github.com/thezoggy/Sick-Beard, applied to our branch General cleanups in notifiers. * Cleaned up notifier ui page wording so they follow similar pattern. * Better exception handling for pyTivo and NMJ * Cleaned up logging entries, trying to standardize on what level we report and verbiage (not using contractions, prune out duplicate/excessive entries) --- .../default/config_notifications.tmpl | 23 +++++++------- sickbeard/notifiers/__init__.py | 4 +-- sickbeard/notifiers/boxcar.py | 13 ++++---- sickbeard/notifiers/growl.py | 13 ++++---- sickbeard/notifiers/libnotify.py | 6 ++-- sickbeard/notifiers/nma.py | 10 +++---- sickbeard/notifiers/nmj.py | 30 ++++++++++++++----- sickbeard/notifiers/nmjv2.py | 12 ++++---- sickbeard/notifiers/plex.py | 2 +- sickbeard/notifiers/prowl.py | 8 ++--- sickbeard/notifiers/pushover.py | 14 ++++----- sickbeard/notifiers/pytivo.py | 14 +++++---- sickbeard/notifiers/synoindex.py | 8 ++--- sickbeard/notifiers/tweet.py | 24 +++++++-------- sickbeard/notifiers/xbmc.py | 4 +-- 15 files changed, 97 insertions(+), 88 deletions(-) diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl index 3e99a027..a67adfbb 100644 --- a/gui/slick/interfaces/default/config_notifications.tmpl +++ b/gui/slick/interfaces/default/config_notifications.tmpl @@ -19,9 +19,9 @@
@@ -381,7 +381,8 @@
-

Synology Indexer

+

Synology

+

The Synology DiskStation NAS.

Synology Indexer is the daemon running on the Synology NAS to build its media database.

@@ -390,7 +391,7 @@
diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index d73c579d..99ece634 100644 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -42,7 +42,7 @@ import emailnotify from sickbeard.common import * -# home theater +# home theater / nas xbmc_notifier = xbmc.XBMCNotifier() plex_notifier = plex.PLEXNotifier() nmj_notifier = nmj.NMJNotifier() @@ -60,7 +60,7 @@ boxcar2_notifier = boxcar2.Boxcar2Notifier() nma_notifier = nma.NMA_Notifier() pushalot_notifier = pushalot.PushalotNotifier() pushbullet_notifier = pushbullet.PushbulletNotifier() -# online +# social twitter_notifier = tweet.TwitterNotifier() trakt_notifier = trakt.TraktNotifier() email_notifier = emailnotify.EmailNotifier() diff --git a/sickbeard/notifiers/boxcar.py b/sickbeard/notifiers/boxcar.py index 26feda26..3787e344 100644 --- a/sickbeard/notifiers/boxcar.py +++ b/sickbeard/notifiers/boxcar.py @@ -30,8 +30,8 @@ API_URL = "https://boxcar.io/devices/providers/fWc4sgSmpcN6JujtBmR6/notification class BoxcarNotifier: - def test_notify(self, email, title="Test"): - return self._sendBoxcar("This is a test notification from SickRage", title, email) + def test_notify(self, boxcar_username): + return self._notify("This is a test notification from Sick Beard", "Test", boxcar_username, force=True) def _sendBoxcar(self, msg, title, email, subscribe=False): """ @@ -73,7 +73,7 @@ class BoxcarNotifier: except urllib2.HTTPError, e: # if we get an error back that doesn't have an error code then who knows what's really happening if not hasattr(e, 'code'): - logger.log("Boxcar notification failed." + ex(e), logger.ERROR) + logger.log("Boxcar notification failed. Error code: " + ex(e), logger.ERROR) return False else: logger.log("Boxcar notification failed. Error code: " + str(e.code), logger.WARNING) @@ -104,10 +104,10 @@ class BoxcarNotifier: # If you receive an HTTP status code of 400, it is because you failed to send the proper parameters elif e.code == 400: - logger.log("Wrong data send to boxcar", logger.ERROR) + logger.log("Wrong data sent to boxcar", logger.ERROR) return False - logger.log("Boxcar notification successful.", logger.DEBUG) + logger.log("Boxcar notification successful.", logger.MESSAGE) return True def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]): @@ -143,8 +143,7 @@ class BoxcarNotifier: logger.log("Sending notification for " + message, logger.DEBUG) - self._sendBoxcar(message, title, username) - return True + return self._sendBoxcar(message, title, username) notifier = BoxcarNotifier diff --git a/sickbeard/notifiers/growl.py b/sickbeard/notifiers/growl.py index aeda68f6..a40141a0 100644 --- a/sickbeard/notifiers/growl.py +++ b/sickbeard/notifiers/growl.py @@ -127,7 +127,7 @@ class GrowlNotifier: for pc in growlHosts: opts['host'] = pc[0] opts['port'] = pc[1] - logger.log(u"Sending growl to " + opts['host'] + ":" + str(opts['port']) + ": " + message) + logger.log(u"GROWL: Sending message '" + message + "' to " + opts['host'] + ":" + str(opts['port']), logger.DEBUG) try: if self._send_growl(opts, message): return True @@ -136,8 +136,8 @@ class GrowlNotifier: return self._send_growl(opts, message) else: return False - except socket.error, e: - logger.log(u"Unable to send growl to " + opts['host'] + ":" + str(opts['port']) + ": " + ex(e)) + except Exception, e: + logger.log(u"GROWL: Unable to send growl to " + opts['host'] + ":" + str(opts['port']) + " - " + ex(e), logger.WARNING) return False def _sendRegistration(self, host=None, password=None, name='SickRage Notification'): @@ -179,10 +179,9 @@ class GrowlNotifier: try: return self._send(opts['host'], opts['port'], register.encode(), opts['debug']) - except socket.error, e: - logger.log( - u"Unable to send growl to " + opts['host'] + ":" + str(opts['port']) + ": " + str(e).decode('utf-8')) + except Exception, e: + logger.log(u"GROWL: Unable to send growl to " + opts['host'] + ":" + str(opts['port']) + " - " + ex(e), logger.WARNING) return False -notifier = GrowlNotifier \ No newline at end of file +notifier = GrowlNotifier diff --git a/sickbeard/notifiers/libnotify.py b/sickbeard/notifiers/libnotify.py index 94273320..2b39db72 100644 --- a/sickbeard/notifiers/libnotify.py +++ b/sickbeard/notifiers/libnotify.py @@ -67,15 +67,15 @@ class LibnotifyNotifier: try: import pynotify except ImportError: - logger.log(u"Unable to import pynotify. libnotify notifications won't work.") + logger.log(u"Unable to import pynotify. libnotify notifications won't work.", logger.ERROR) return False try: import gobject except ImportError: - logger.log(u"Unable to import gobject. We can't catch a GError in display.") + logger.log(u"Unable to import gobject. We can't catch a GError in display.", logger.ERROR) return False if not pynotify.init('SickRage'): - logger.log(u"Initialization of pynotify failed. libnotify notifications won't work.") + logger.log(u"Initialization of pynotify failed. libnotify notifications won't work.", logger.ERROR) return False self.pynotify = pynotify self.gobject = gobject diff --git a/sickbeard/notifiers/nma.py b/sickbeard/notifiers/nma.py index 0ce06a6d..1593e468 100644 --- a/sickbeard/notifiers/nma.py +++ b/sickbeard/notifiers/nma.py @@ -26,7 +26,7 @@ class NMA_Notifier: def _sendNMA(self, nma_api=None, nma_priority=None, event=None, message=None, force=False): - title = 'Sick-Beard' + title = 'SickRage' if not sickbeard.USE_NMA and not force: return False @@ -37,10 +37,6 @@ class NMA_Notifier: if nma_priority == None: nma_priority = sickbeard.NMA_PRIORITY - logger.log(u"NMA title: " + title, logger.DEBUG) - logger.log(u"NMA event: " + event, logger.DEBUG) - logger.log(u"NMA message: " + message, logger.DEBUG) - batch = False p = pynma.PyNMA() @@ -49,13 +45,15 @@ class NMA_Notifier: if len(keys) > 1: batch = True + logger.log("NMA: Sending notice with details: event=\"%s\", message=\"%s\", priority=%s, batch=%s" % (event, message, nma_priority, batch), logger.DEBUG) response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) if not response[nma_api][u'code'] == u'200': logger.log(u'Could not send notification to NotifyMyAndroid', logger.ERROR) return False else: + logger.log(u"NMA: Notification sent to NotifyMyAndroid", logger.MESSAGE) return True -notifier = NMA_Notifier \ No newline at end of file +notifier = NMA_Notifier diff --git a/sickbeard/notifiers/nmj.py b/sickbeard/notifiers/nmj.py index 459942c4..75746ef5 100644 --- a/sickbeard/notifiers/nmj.py +++ b/sickbeard/notifiers/nmj.py @@ -22,6 +22,7 @@ import telnetlib import re from sickbeard import logger +from sickbeard.exceptions import ex try: import xml.etree.cElementTree as etree @@ -44,7 +45,7 @@ class NMJNotifier: try: terminal = telnetlib.Telnet(host) except Exception: - logger.log(u"Warning: unable to get a telnet session to %s" % (host), logger.ERROR) + logger.log(u"Warning: unable to get a telnet session to %s" % (host), logger.WARNING) return False # tell the terminal to output the necessary info to the screen so we can search it later @@ -66,7 +67,7 @@ class NMJNotifier: logger.log(u"Found NMJ database %s on device %s" % (database, device), logger.DEBUG) sickbeard.NMJ_DATABASE = database else: - logger.log(u"Could not get current NMJ database on %s, NMJ is probably not running!" % (host), logger.ERROR) + logger.log(u"Could not get current NMJ database on %s, NMJ is probably not running!" % (host), logger.WARNING) return False # if the device is a remote host then try to parse the mounting URL and save it to the config @@ -79,7 +80,7 @@ class NMJNotifier: sickbeard.NMJ_MOUNT = mount else: logger.log(u"Detected a network share on the Popcorn Hour, but could not get the mounting url", - logger.DEBUG) + logger.WARNING) return False return True @@ -117,7 +118,13 @@ class NMJNotifier: logger.log(u"Try to mount network drive via url: %s" % (mount), logger.DEBUG) handle = urllib2.urlopen(req) except IOError, e: - logger.log(u"Warning: Couldn't contact popcorn hour on host %s: %s" % (host, e)) + if hasattr(e, 'reason'): + logger.log(u"NMJ: Could not contact Popcorn Hour on host %s: %s" % (host, e.reason), logger.WARNING) + elif hasattr(e, 'code'): + logger.log(u"NMJ: Problem with Popcorn Hour on host %s: %s" % (host, e.code), logger.WARNING) + return False + except Exception, e: + logger.log(u"NMJ: Unknown exception: " + ex(e), logger.ERROR) return False # build up the request URL and parameters @@ -126,7 +133,8 @@ class NMJNotifier: "arg0": "scanner_start", "arg1": database, "arg2": "background", - "arg3": ""} + "arg3": "" + } params = urllib.urlencode(params) updateUrl = UPDATE_URL % {"host": host, "params": params} @@ -137,7 +145,13 @@ class NMJNotifier: handle = urllib2.urlopen(req) response = handle.read() except IOError, e: - logger.log(u"Warning: Couldn't contact Popcorn Hour on host %s: %s" % (host, e)) + if hasattr(e, 'reason'): + logger.log(u"NMJ: Could not contact Popcorn Hour on host %s: %s" % (host, e.reason), logger.WARNING) + elif hasattr(e, 'code'): + logger.log(u"NMJ: Problem with Popcorn Hour on host %s: %s" % (host, e.code), logger.WARNING) + return False + except Exception, e: + logger.log(u"NMJ: Unknown exception: " + ex(e), logger.ERROR) return False # try to parse the resulting XML @@ -150,10 +164,10 @@ class NMJNotifier: # if the result was a number then consider that an error if int(result) > 0: - logger.log(u"Popcorn Hour returned an errorcode: %s" % (result)) + logger.log(u"Popcorn Hour returned an errorcode: %s" % (result), logger.ERROR) return False else: - logger.log(u"NMJ started background scan") + logger.log(u"NMJ started background scan", logger.MESSAGE) return True def _notifyNMJ(self, host=None, database=None, mount=None, force=False): diff --git a/sickbeard/notifiers/nmjv2.py b/sickbeard/notifiers/nmjv2.py index 355a4193..6b9b53f8 100644 --- a/sickbeard/notifiers/nmjv2.py +++ b/sickbeard/notifiers/nmjv2.py @@ -87,7 +87,7 @@ class NMJv2Notifier: return True except IOError, e: - logger.log(u"Warning: Couldn't contact popcorn hour on host %s: %s" % (host, e)) + logger.log(u"Warning: Couldn't contact popcorn hour on host %s: %s" % (host, e), logger.WARNING) return False return False @@ -105,7 +105,7 @@ class NMJv2Notifier: #if a host is provided then attempt to open a handle to that URL try: url_scandir = "http://" + host + ":8008/metadata_database?arg0=update_scandir&arg1=" + sickbeard.NMJv2_DATABASE + "&arg2=&arg3=update_all" - logger.log(u"NMJ scan update command send to host: %s" % (host)) + logger.log(u"NMJ scan update command sent to host: %s" % (host), logger.DEBUG) url_updatedb = "http://" + host + ":8008/metadata_database?arg0=scanner_start&arg1=" + sickbeard.NMJv2_DATABASE + "&arg2=background&arg3=" logger.log(u"Try to mount network drive via url: %s" % (host), logger.DEBUG) prereq = urllib2.Request(url_scandir) @@ -116,7 +116,7 @@ class NMJv2Notifier: handle2 = urllib2.urlopen(req) response2 = handle2.read() except IOError, e: - logger.log(u"Warning: Couldn't contact popcorn hour on host %s: %s" % (host, e)) + logger.log(u"Warning: Couldn't contact popcorn hour on host %s: %s" % (host, e), logger.WARNING) return False try: et = etree.fromstring(response1) @@ -142,15 +142,15 @@ class NMJv2Notifier: "Read only file system"] if int(result1) > 0: index = error_codes.index(result1) - logger.log(u"Popcorn Hour returned an error: %s" % (error_messages[index])) + logger.log(u"Popcorn Hour returned an error: %s" % (error_messages[index]), logger.ERROR) return False else: if int(result2) > 0: index = error_codes.index(result2) - logger.log(u"Popcorn Hour returned an error: %s" % (error_messages[index])) + logger.log(u"Popcorn Hour returned an error: %s" % (error_messages[index]), logger.ERROR) return False else: - logger.log(u"NMJv2 started background scan") + logger.log(u"NMJv2 started background scan", logger.MESSAGE) return True def _notifyNMJ(self, host=None, force=False): diff --git a/sickbeard/notifiers/plex.py b/sickbeard/notifiers/plex.py index 8047ab54..1e5cbb62 100644 --- a/sickbeard/notifiers/plex.py +++ b/sickbeard/notifiers/plex.py @@ -82,7 +82,7 @@ class PLEXNotifier(XBMCNotifier): if sickbeard.USE_PLEX and sickbeard.PLEX_UPDATE_LIBRARY: if not sickbeard.PLEX_SERVER_HOST: - logger.log(u"No Plex Server host specified, check your settings", logger.DEBUG) + logger.log(u"No Plex Media Server host specified, check your settings", logger.DEBUG) return False logger.log(u"Updating library for the Plex Media Server host: " + sickbeard.PLEX_SERVER_HOST, diff --git a/sickbeard/notifiers/prowl.py b/sickbeard/notifiers/prowl.py index 026a975c..ce2ecbad 100644 --- a/sickbeard/notifiers/prowl.py +++ b/sickbeard/notifiers/prowl.py @@ -65,11 +65,7 @@ class ProwlNotifier: title = "SickRage" - logger.log(u"Prowl title: " + title, logger.DEBUG) - logger.log(u"Prowl event: " + event, logger.DEBUG) - logger.log(u"Prowl message: " + message, logger.DEBUG) - logger.log(u"Prowl api: " + prowl_api, logger.DEBUG) - logger.log(u"Prowl priority: " + prowl_priority, logger.DEBUG) + logger.log("PROWL: Sending notice with details: event=\"%s\", message=\"%s\", priority=%s, api=%s" % (event, message, prowl_priority, prowl_api), logger.DEBUG) http_handler = HTTPSConnection("api.prowlapp.com") @@ -91,7 +87,7 @@ class ProwlNotifier: request_status = response.status if request_status == 200: - logger.log(u"Prowl notifications sent.", logger.DEBUG) + logger.log(u"Prowl notifications sent.", logger.MESSAGE) return True elif request_status == 401: logger.log(u"Prowl auth failed: %s" % response.reason, logger.ERROR) diff --git a/sickbeard/notifiers/pushover.py b/sickbeard/notifiers/pushover.py index 8fd5f468..ac0aabad 100644 --- a/sickbeard/notifiers/pushover.py +++ b/sickbeard/notifiers/pushover.py @@ -33,7 +33,7 @@ API_KEY = "awKfdt263PLaEWV9RXuSn4c46qoAyA" class PushoverNotifier: def test_notify(self, userKey=None): - return self._sendPushover("This is a test notification from SickRage", 'Test', userKey) + return self._notifyPushover("This is a test notification from SickRage", 'Test', userKey, force=True) def _sendPushover(self, msg, title, userKey=None): """ @@ -74,7 +74,7 @@ class PushoverNotifier: logger.log("Pushover notification failed." + ex(e), logger.ERROR) return False else: - logger.log("Pushover notification failed. Error code: " + str(e.code), logger.WARNING) + logger.log("Pushover notification failed. Error code: " + str(e.code), logger.ERROR) # HTTP status 404 if the provided email address isn't a Pushover user. if e.code == 404: @@ -98,7 +98,7 @@ class PushoverNotifier: logger.log("Wrong data sent to pushover", logger.ERROR) return False - logger.log("Pushover notification successful.", logger.DEBUG) + logger.log("Pushover notification successful.", logger.MESSAGE) return True def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]): @@ -114,24 +114,24 @@ class PushoverNotifier: if sickbeard.PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD: self._notifyPushover(title, ep_name + ": " + lang) - def _notifyPushover(self, title, message, userKey=None): + def _notifyPushover(self, title, message, userKey=None, force=False): """ Sends a pushover notification based on the provided info or SB config title: The title of the notification to send message: The message string to send userKey: The userKey to send the notification to + force: Enforce sending, for instance for testing """ - if not sickbeard.USE_PUSHOVER: + if not sickbeard.USE_PUSHOVER and not force: logger.log("Notification for Pushover not enabled, skipping this notification", logger.DEBUG) return False logger.log("Sending notification for " + message, logger.DEBUG) # self._sendPushover(message, title, userKey) - self._sendPushover(message, title) - return True + return self._sendPushover(message, title) notifier = PushoverNotifier diff --git a/sickbeard/notifiers/pytivo.py b/sickbeard/notifiers/pytivo.py index 1ae3ac8f..0afbab93 100644 --- a/sickbeard/notifiers/pytivo.py +++ b/sickbeard/notifiers/pytivo.py @@ -23,6 +23,7 @@ from urllib import urlencode from urllib2 import Request, urlopen, HTTPError from sickbeard import logger +from sickbeard.exceptions import ex from sickbeard import encodingKludge as ek @@ -81,7 +82,7 @@ class pyTivoNotifier: requestUrl = "http://" + host + "/TiVoConnect?" + urlencode( {'Command': 'Push', 'Container': container, 'File': file, 'tsn': tsn}) - logger.log(u"pyTivo notification: Requesting " + requestUrl) + logger.log(u"pyTivo notification: Requesting " + requestUrl, logger.DEBUG) request = Request(requestUrl) @@ -89,13 +90,14 @@ class pyTivoNotifier: response = urlopen(request) #@UnusedVariable except HTTPError , e: if hasattr(e, 'reason'): - logger.log(u"pyTivo notification: Error, failed to reach a server") - logger.log(u"'Error reason: " + e.reason) + logger.log(u"pyTivo notification: Error, failed to reach a server - " + e.reason, logger.ERROR) return False elif hasattr(e, 'code'): - logger.log(u"pyTivo notification: Error, the server couldn't fulfill the request") - logger.log(u"Error code: " + e.code) - return False + logger.log(u"pyTivo notification: Error, the server couldn't fulfill the request - ", + e.code, logger.ERROR) + return False + except Exception, e: + logger.log(u"PYTIVO: Unknown exception: " + ex(e), logger.ERROR) + return False else: logger.log(u"pyTivo notification: Successfully requested transfer of file") return True diff --git a/sickbeard/notifiers/synoindex.py b/sickbeard/notifiers/synoindex.py index dd78e1d2..96ff111f 100644 --- a/sickbeard/notifiers/synoindex.py +++ b/sickbeard/notifiers/synoindex.py @@ -48,7 +48,7 @@ class synoIndexNotifier: if sickbeard.USE_SYNOINDEX: synoindex_cmd = ['/usr/syno/bin/synoindex', '-N', ek.ek(os.path.abspath, new_path), ek.ek(os.path.abspath, old_path)] - logger.log(u"Executing command " + str(synoindex_cmd)) + logger.log(u"Executing command " + str(synoindex_cmd), logger.DEBUG) logger.log(u"Absolute path to command: " + ek.ek(os.path.abspath, synoindex_cmd[0]), logger.DEBUG) try: p = subprocess.Popen(synoindex_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, @@ -56,7 +56,7 @@ class synoIndexNotifier: out, err = p.communicate() #@UnusedVariable logger.log(u"Script result: " + str(out), logger.DEBUG) except OSError, e: - logger.log(u"Unable to run synoindex: " + ex(e)) + logger.log(u"Unable to run synoindex: " + ex(e), logger.ERROR) def deleteFolder(self, cur_path): self.makeObject('-D', cur_path) @@ -73,7 +73,7 @@ class synoIndexNotifier: def makeObject(self, cmd_arg, cur_path): if sickbeard.USE_SYNOINDEX: synoindex_cmd = ['/usr/syno/bin/synoindex', cmd_arg, ek.ek(os.path.abspath, cur_path)] - logger.log(u"Executing command " + str(synoindex_cmd)) + logger.log(u"Executing command " + str(synoindex_cmd), logger.DEBUG) logger.log(u"Absolute path to command: " + ek.ek(os.path.abspath, synoindex_cmd[0]), logger.DEBUG) try: p = subprocess.Popen(synoindex_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, @@ -81,7 +81,7 @@ class synoIndexNotifier: out, err = p.communicate() #@UnusedVariable logger.log(u"Script result: " + str(out), logger.DEBUG) except OSError, e: - logger.log(u"Unable to run synoindex: " + ex(e)) + logger.log(u"Unable to run synoindex: " + ex(e), logger.ERROR) notifier = synoIndexNotifier diff --git a/sickbeard/notifiers/tweet.py b/sickbeard/notifiers/tweet.py index aaa6fe2a..e010f7c0 100644 --- a/sickbeard/notifiers/tweet.py +++ b/sickbeard/notifiers/tweet.py @@ -61,12 +61,12 @@ class TwitterNotifier: oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) oauth_client = oauth.Client(oauth_consumer) - logger.log('Requesting temp token from Twitter') + logger.log('Requesting temp token from Twitter', logger.DEBUG) resp, content = oauth_client.request(self.REQUEST_TOKEN_URL, 'GET') if resp['status'] != '200': - logger.log('Invalid respond from Twitter requesting temp token: %s' % resp['status']) + logger.log('Invalid response from Twitter requesting temp token: %s' % resp['status'], logger.ERROR) else: request_token = dict(parse_qsl(content)) @@ -85,26 +85,26 @@ class TwitterNotifier: token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret']) token.set_verifier(key) - logger.log('Generating and signing request for an access token using key ' + key) + logger.log('Generating and signing request for an access token using key ' + key, logger.DEBUG) signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1() #@UnusedVariable oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) - logger.log('oauth_consumer: ' + str(oauth_consumer)) + logger.log('oauth_consumer: ' + str(oauth_consumer), logger.DEBUG) oauth_client = oauth.Client(oauth_consumer, token) - logger.log('oauth_client: ' + str(oauth_client)) + logger.log('oauth_client: ' + str(oauth_client), logger.DEBUG) resp, content = oauth_client.request(self.ACCESS_TOKEN_URL, method='POST', body='oauth_verifier=%s' % key) - logger.log('resp, content: ' + str(resp) + ',' + str(content)) + logger.log('resp, content: ' + str(resp) + ',' + str(content), logger.DEBUG) access_token = dict(parse_qsl(content)) - logger.log('access_token: ' + str(access_token)) + logger.log('access_token: ' + str(access_token), logger.DEBUG) - logger.log('resp[status] = ' + str(resp['status'])) + logger.log('resp[status] = ' + str(resp['status']), logger.DEBUG) if resp['status'] != '200': logger.log('The request for a token with did not succeed: ' + str(resp['status']), logger.ERROR) return False else: - logger.log('Your Twitter Access Token key: %s' % access_token['oauth_token']) - logger.log('Access Token secret: %s' % access_token['oauth_token_secret']) + logger.log('Your Twitter Access Token key: %s' % access_token['oauth_token'], logger.DEBUG) + logger.log('Access Token secret: %s' % access_token['oauth_token_secret'], logger.DEBUG) sickbeard.TWITTER_USERNAME = access_token['oauth_token'] sickbeard.TWITTER_PASSWORD = access_token['oauth_token_secret'] return True @@ -117,7 +117,7 @@ class TwitterNotifier: access_token_key = sickbeard.TWITTER_USERNAME access_token_secret = sickbeard.TWITTER_PASSWORD - logger.log(u"Sending tweet: " + message) + logger.log(u"Sending tweet: " + message, logger.DEBUG) api = twitter.Api(username, password, access_token_key, access_token_secret) @@ -138,4 +138,4 @@ class TwitterNotifier: return self._send_tweet(prefix + ": " + message) -notifier = TwitterNotifier \ No newline at end of file +notifier = TwitterNotifier diff --git a/sickbeard/notifiers/xbmc.py b/sickbeard/notifiers/xbmc.py index 34d2be50..95084be3 100644 --- a/sickbeard/notifiers/xbmc.py +++ b/sickbeard/notifiers/xbmc.py @@ -66,7 +66,7 @@ class XBMCNotifier: 3 | (pre Eden) 4 | v11 (Eden) 5 | (pre Frodo) - 6 | v12 (Frodo) + 6 | v12 (Frodo) / v13 (Gotham) """ @@ -327,7 +327,7 @@ class XBMCNotifier: time.sleep(5) # do a full update if requested else: - logger.log(u"Doing Full Library XBMC update on host: " + host, logger.DEBUG) + logger.log(u"Doing Full Library XBMC update on host: " + host, logger.MESSAGE) updateCommand = {'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video)'} request = self._send_to_xbmc(updateCommand, host) From 7bf12460bef6cf6964d0fca19c9d57696a6fc57f Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Thu, 29 May 2014 02:44:00 +0200 Subject: [PATCH 21/82] PEP8 cleanups --- sickbeard/name_parser/parser.py | 6 +++--- sickbeard/tv.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index eea5b0fd..098231ad 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -58,15 +58,15 @@ class NameParser(object): def clean_series_name(self, series_name): """Cleans up series name by removing any . and _ characters, along with any trailing hyphens. - + Is basically equivalent to replacing all _ and . with a space, but handles decimal numbers in string, for example: - + >>> cleanRegexedSeriesName("an.example.1.0.test") 'an example 1.0 test' >>> cleanRegexedSeriesName("an_example_1.0_test") 'an example 1.0 test' - + Stolen from dbr's tvnamer """ diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 0064ee24..93d9cfa4 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -2263,4 +2263,4 @@ class TVEpisode(object): with self.lock: self.saveToDB() for relEp in self.relatedEps: - relEp.saveToDB() \ No newline at end of file + relEp.saveToDB() From 98f839bc91d390ad86743a1462f51e310ef0a5cc Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Thu, 29 May 2014 03:07:32 +0200 Subject: [PATCH 22/82] Backporting from midgetspy. This is https://github.com/Sp1l/Sick-Beard/commit/3d130af6183697d3c984cc28aeccb41a8496d6a5 * Add datadir option (separate app from data) * Add webroot option (for proxied setups) * Remove wget dependency --- init.freebsd | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/init.freebsd b/init.freebsd index 6f5b8204..fdc17987 100644 --- a/init.freebsd +++ b/init.freebsd @@ -17,6 +17,8 @@ # Default: /usr/local/sickbeard # sickbeard_chdir: Change to this directory before running SickRage. # Default is same as sickbeard_dir. +# sickbeard_datadir: Data directory for Sick Beard (DB, Logs, config) +# Default is same as sickbeard_chdir # sickbeard_pid: The name of the pidfile to create. # Default is sickbeard.pid in sickbeard_dir. # sickbeard_host: The hostname or IP SickRage is listening on @@ -27,6 +29,8 @@ # Default is an empty string (no username) # sickbeard_web_password: Password to authenticate to the SickRage web interface # Default is an empty string (no password) +# sickbeard_webroot: Set to value of web_root in config (for proxies etc) +# Default is an empty string (if set must start with a "/") PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin" . /etc/rc.subr @@ -40,13 +44,13 @@ load_rc_config ${name} : ${sickbeard_user:="_sabnzbd"} : ${sickbeard_dir:="/usr/local/sickbeard"} : ${sickbeard_chdir:="${sickbeard_dir}"} +: ${sickbeard_datadir:="${sickbeard_chdir}"} : ${sickbeard_pid:="${sickbeard_dir}/sickbeard.pid"} : ${sickbeard_host:="127.0.0.1"} : ${sickbeard_port:="8081"} : ${sickbeard_web_user:=""} : ${sickbeard_web_password:=""} - -WGET="/usr/local/bin/wget" # You need wget for this script to safely shutdown SickRage. +: ${sickbeard_webroot:=""} status_cmd="${name}_status" stop_cmd="${name}_stop" @@ -54,11 +58,9 @@ stop_cmd="${name}_stop" command="/usr/sbin/daemon" command_args="-f -p ${sickbeard_pid} python ${sickbeard_dir}/SickBeard.py --quiet --nolaunch" -# Check for wget and refuse to start without it. -if [ ! -x "${WGET}" ]; then - warn "Sickbeard not started: You need wget to safely shut down SickRage." - exit 1 -fi +# Add datadir to the command if set +[ ! -z "${sickbeard_datadir}" ] && \ + command_args="${command_args} --datadir ${sickbeard_datadir}" # Ensure user is root when running this script. if [ `id -u` != "0" ]; then @@ -77,7 +79,12 @@ verify_sickbeard_pid() { sickbeard_stop() { echo "Stopping $name" verify_sickbeard_pid - ${WGET} -O - -q --user=${sickbeard_web_user} --password=${sickbeard_web_password} "http://${sickbeard_host}:${sickbeard_port}/home/shutdown/" >/dev/null + sickbeard_url="${sickbeard_host}:${sickbeard_port}" + [ ! -z "${sickbeard_web_user}" ] && \ + sickbeard_url="${sickbeard_web_user}:${sickbeard_web_password}@${sickbeard_url}" + [ ! -z "${sickbeard_webroot}" ] && \ + sickbeard_url="${sickbeard_url}${sickbeard_webroot}" + fetch -o - -q "http://${sickbeard_url}/home/shutdown/?pid=${pid}" >/dev/null if [ -n "${pid}" ]; then wait_for_pids ${pid} echo "Stopped" @@ -89,4 +96,3 @@ sickbeard_status() { } run_rc_command "$1" - From 690b904b980c019723724ca8c849ed1b76988571 Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Thu, 29 May 2014 03:12:47 +0200 Subject: [PATCH 23/82] Make UI look better on iOS --- gui/slick/interfaces/default/inc_top.tmpl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gui/slick/interfaces/default/inc_top.tmpl b/gui/slick/interfaces/default/inc_top.tmpl index b7bc1c18..5015d8a3 100644 --- a/gui/slick/interfaces/default/inc_top.tmpl +++ b/gui/slick/interfaces/default/inc_top.tmpl @@ -15,6 +15,10 @@ + + + + From 764cf6e62e6054f81e7b0b30294d8f6a82ed3efa Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Thu, 29 May 2014 03:17:43 +0200 Subject: [PATCH 24/82] Change process title for more clarity when running multiple python progs --- SickBeard.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/SickBeard.py b/SickBeard.py index b6cc16b3..e5a36cc7 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -180,6 +180,16 @@ def main(): # Need console logging for SickBeard.py and SickBeard-console.exe consoleLogging = (not hasattr(sys, "frozen")) or (sickbeard.MY_NAME.lower().find('-console') > 0) + # Attempt to rename the process for easier debugging + try: + from setproctitle import setproctitle + except ImportError: + if consoleLogging: + sys.stderr.write(u"setproctitle module is not available.\n") + setproctitle = lambda t: None + + setproctitle(sickbeard.MY_NAME) + # Rename the main thread threading.currentThread().name = "MAIN" From 2dcd26e69c94daa4b23cdc8497c1876f5d799a27 Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 28 May 2014 22:40:12 -0700 Subject: [PATCH 25/82] Update imdbpy libs to v5.0 Fixed invalid indexer id issues for TVRage shows. Fixed issues for getting posters and backdrops for TVRage shows. We now convert XML straight to a dict object for Indexer APIs, improved overall performance api's Fixed issues with TVRage shows and displaying genre's properly. --- lib/imdb/__init__.py | 49 +- lib/imdb/imdbpy.cfg | 6 +- lib/imdb/linguistics.py | 6 +- lib/imdb/locale/generatepot.py | 2 +- lib/imdb/locale/imdbpy-ar.po | 1303 ++++++++++++++++ lib/imdb/locale/imdbpy-bg.po | 1303 ++++++++++++++++ lib/imdb/locale/imdbpy-de.po | 1303 ++++++++++++++++ lib/imdb/locale/imdbpy-es.po | 1304 +++++++++++++++++ lib/imdb/locale/imdbpy-fr.po | 1304 +++++++++++++++++ lib/imdb/locale/msgfmt.py | 2 +- lib/imdb/locale/rebuildmo.py | 2 +- lib/imdb/parser/http/__init__.py | 51 +- lib/imdb/parser/http/movieParser.py | 126 +- lib/imdb/parser/http/personParser.py | 32 +- lib/imdb/parser/http/searchCharacterParser.py | 8 +- lib/imdb/parser/http/searchCompanyParser.py | 6 +- lib/imdb/parser/http/searchMovieParser.py | 31 +- lib/imdb/parser/http/searchPersonParser.py | 8 +- lib/imdb/parser/http/utils.py | 2 +- lib/imdb/parser/mobile/__init__.py | 44 +- lib/imdb/parser/sql/__init__.py | 30 +- lib/imdb/parser/sql/alchemyadapter.py | 7 +- lib/imdb/parser/sql/cutils.so | Bin 28469 -> 0 bytes lib/imdb/parser/sql/objectadapter.py | 4 + lib/imdb/utils.py | 78 +- lib/tvdb_api/tvdb_api.py | 170 ++- lib/tvrage_api/tvrage_api.py | 306 ++-- lib/xmltodict.py | 359 +++++ sickbeard/metadata/generic.py | 41 +- sickbeard/tv.py | 12 +- 30 files changed, 7446 insertions(+), 453 deletions(-) create mode 100644 lib/imdb/locale/imdbpy-ar.po create mode 100644 lib/imdb/locale/imdbpy-bg.po create mode 100644 lib/imdb/locale/imdbpy-de.po create mode 100644 lib/imdb/locale/imdbpy-es.po create mode 100644 lib/imdb/locale/imdbpy-fr.po delete mode 100644 lib/imdb/parser/sql/cutils.so create mode 100644 lib/xmltodict.py diff --git a/lib/imdb/__init__.py b/lib/imdb/__init__.py index f93482da..0cdc9650 100644 --- a/lib/imdb/__init__.py +++ b/lib/imdb/__init__.py @@ -6,7 +6,7 @@ a person from the IMDb database. It can fetch data through different media (e.g.: the IMDb web pages, a SQL database, etc.) -Copyright 2004-2012 Davide Alberani +Copyright 2004-2014 Davide Alberani This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA __all__ = ['IMDb', 'IMDbError', 'Movie', 'Person', 'Character', 'Company', 'available_access_systems'] -__version__ = VERSION = '4.9' +__version__ = VERSION = '5.0' # Import compatibility module (importing it is enough). import _compat @@ -160,6 +160,7 @@ def IMDb(accessSystem=None, *arguments, **keywords): kwds.update(keywords) keywords = kwds except Exception, e: + import logging logging.getLogger('imdbpy').warn('Unable to read configuration' \ ' file; complete error: %s' % e) # It just LOOKS LIKE a bad habit: we tried to read config @@ -303,7 +304,7 @@ class IMDbBase: # http://akas.imdb.com/keyword/%s/ imdbURL_keyword_main=imdbURL_base + 'keyword/%s/' # http://akas.imdb.com/chart/top - imdbURL_top250=imdbURL_base + 'chart/top', + imdbURL_top250=imdbURL_base + 'chart/top' # http://akas.imdb.com/chart/bottom imdbURL_bottom100=imdbURL_base + 'chart/bottom' # http://akas.imdb.com/find?%s @@ -824,22 +825,23 @@ class IMDbBase: # subclass, somewhere under the imdb.parser package. raise NotImplementedError('override this method') - def _searchIMDb(self, kind, ton): + def _searchIMDb(self, kind, ton, title_kind=None): """Search the IMDb akas server for the given title or name.""" # The Exact Primary search system has gone AWOL, so we resort # to the mobile search. :-/ if not ton: return None + ton = ton.strip('"') aSystem = IMDb('mobile') if kind == 'tt': searchFunct = aSystem.search_movie - check = 'long imdb canonical title' + check = 'long imdb title' elif kind == 'nm': searchFunct = aSystem.search_person - check = 'long imdb canonical name' + check = 'long imdb name' elif kind == 'char': searchFunct = aSystem.search_character - check = 'long imdb canonical name' + check = 'long imdb name' elif kind == 'co': # XXX: are [COUNTRY] codes included in the results? searchFunct = aSystem.search_company @@ -852,24 +854,42 @@ class IMDbBase: # exact match. if len(searchRes) == 1: return searchRes[0].getID() + title_only_matches = [] for item in searchRes: # Return the first perfect match. - if item[check] == ton: - return item.getID() + if item[check].strip('"') == ton: + # For titles do additional check for kind + if kind != 'tt' or title_kind == item['kind']: + return item.getID() + elif kind == 'tt': + title_only_matches.append(item.getID()) + # imdbpy2sql.py could detected wrong type, so if no title and kind + # matches found - collect all results with title only match + # Return list of IDs if multiple matches (can happen when searching + # titles with no title_kind specified) + # Example: DB: Band of Brothers "tv series" vs "tv mini-series" + if title_only_matches: + if len(title_only_matches) == 1: + return title_only_matches[0] + else: + return title_only_matches return None - def title2imdbID(self, title): + def title2imdbID(self, title, kind=None): """Translate a movie title (in the plain text data files format) to an imdbID. Try an Exact Primary Title search on IMDb; - return None if it's unable to get the imdbID.""" - return self._searchIMDb('tt', title) + return None if it's unable to get the imdbID; + Always specify kind: movie, tv series, video game etc. or search can + return list of IDs if multiple matches found + """ + return self._searchIMDb('tt', title, kind) def name2imdbID(self, name): """Translate a person name in an imdbID. Try an Exact Primary Name search on IMDb; return None if it's unable to get the imdbID.""" - return self._searchIMDb('tt', name) + return self._searchIMDb('nm', name) def character2imdbID(self, name): """Translate a character name in an imdbID. @@ -896,7 +916,8 @@ class IMDbBase: imdbID = aSystem.get_imdbMovieID(mop.movieID) else: imdbID = aSystem.title2imdbID(build_title(mop, canonical=0, - ptdf=1)) + ptdf=0, appendKind=False), + mop['kind']) elif isinstance(mop, Person.Person): if mop.personID is not None: imdbID = aSystem.get_imdbPersonID(mop.personID) diff --git a/lib/imdb/imdbpy.cfg b/lib/imdb/imdbpy.cfg index 407fdacc..a40970d3 100644 --- a/lib/imdb/imdbpy.cfg +++ b/lib/imdb/imdbpy.cfg @@ -29,7 +29,7 @@ [imdbpy] ## Default. -accessSystem = mobile +accessSystem = http ## Optional (options common to every data access system): # Activate adult searches (on, by default). @@ -37,7 +37,7 @@ accessSystem = mobile # Number of results for searches (20 by default). #results = 20 # Re-raise all caught exceptions (off, by default). -reraiseExceptions = on +#reraiseExceptions = off ## Optional (options common to http and mobile data access systems): # Proxy used to access the network. If it requires authentication, @@ -69,7 +69,7 @@ reraiseExceptions = on ## Set the threshold for logging messages. # Can be one of "debug", "info", "warning", "error", "critical" (default: # "warning"). -loggingLevel = info +#loggingLevel = debug ## Path to a configuration file for the logging facility; # see: http://docs.python.org/library/logging.html#configuring-logging diff --git a/lib/imdb/linguistics.py b/lib/imdb/linguistics.py index da8829fd..d53597b2 100644 --- a/lib/imdb/linguistics.py +++ b/lib/imdb/linguistics.py @@ -64,8 +64,10 @@ LANG_ARTICLES = { 'English': ('the', 'a', 'an'), 'Italian': ('la', 'le', "l'", 'il', 'i', 'un', 'una', 'gli', 'lo', "un'", 'uno'), - 'Spanish': ('la', 'le', 'el', 'les', 'un', 'los', 'una', 'uno', 'unos', - 'unas'), + 'Spanish': ('la', 'lo', 'el', 'las', 'un', 'los', 'una', 'al', 'del', + 'unos', 'unas', 'uno'), + 'French': ('le', "l'", 'la', 'les', 'un', 'une', 'des', 'au', 'du', '\xc3\xa0 la', + 'de la', 'aux'), 'Portuguese': ('a', 'as', 'o', 'os', 'um', 'uns', 'uma', 'umas'), 'Turkish': (), # Some languages doesn't have articles. } diff --git a/lib/imdb/locale/generatepot.py b/lib/imdb/locale/generatepot.py index 99b68144..282f7d41 100644 --- a/lib/imdb/locale/generatepot.py +++ b/lib/imdb/locale/generatepot.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python """ generatepot.py script. diff --git a/lib/imdb/locale/imdbpy-ar.po b/lib/imdb/locale/imdbpy-ar.po new file mode 100644 index 00000000..31489dbc --- /dev/null +++ b/lib/imdb/locale/imdbpy-ar.po @@ -0,0 +1,1303 @@ +# Gettext message file for imdbpy +# Translators: +# RainDropR , 2013 +msgid "" +msgstr "" +"Project-Id-Version: IMDbPY\n" +"POT-Creation-Date: 2010-03-18 14:35+0000\n" +"PO-Revision-Date: 2013-11-20 11:07+0000\n" +"Last-Translator: RainDropR \n" +"Language-Team: Arabic (http://www.transifex.com/projects/p/imdbpy/language/ar/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Domain: imdbpy\n" +"Language: ar\n" +"Language-Code: en\n" +"Language-Name: English\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"Preferred-Encodings: utf-8\n" + +# Default: Actor +msgid "actor" +msgstr "ممثل" + +# Default: Actress +msgid "actress" +msgstr "ممثلة" + +# Default: Adaption +msgid "adaption" +msgstr "إقتباس" + +# Default: Additional information +msgid "additional-information" +msgstr "معلومات إضافية" + +# Default: Admissions +msgid "admissions" +msgstr "" + +# Default: Agent address +msgid "agent-address" +msgstr "" + +# Default: Airing +msgid "airing" +msgstr "" + +# Default: Akas +msgid "akas" +msgstr "" + +# Default: Akas from release info +msgid "akas-from-release-info" +msgstr "" + +# Default: All products +msgid "all-products" +msgstr "" + +# Default: Alternate language version of +msgid "alternate-language-version-of" +msgstr "" + +# Default: Alternate versions +msgid "alternate-versions" +msgstr "" + +# Default: Amazon reviews +msgid "amazon-reviews" +msgstr "" + +# Default: Analog left +msgid "analog-left" +msgstr "" + +# Default: Analog right +msgid "analog-right" +msgstr "" + +# Default: Animation department +msgid "animation-department" +msgstr "" + +# Default: Archive footage +msgid "archive-footage" +msgstr "" + +# Default: Arithmetic mean +msgid "arithmetic-mean" +msgstr "" + +# Default: Art department +msgid "art-department" +msgstr "" + +# Default: Art direction +msgid "art-direction" +msgstr "" + +# Default: Art director +msgid "art-director" +msgstr "" + +# Default: Article +msgid "article" +msgstr "مقال" + +# Default: Asin +msgid "asin" +msgstr "" + +# Default: Aspect ratio +msgid "aspect-ratio" +msgstr "" + +# Default: Assigner +msgid "assigner" +msgstr "" + +# Default: Assistant director +msgid "assistant-director" +msgstr "" + +# Default: Auctions +msgid "auctions" +msgstr "" + +# Default: Audio noise +msgid "audio-noise" +msgstr "" + +# Default: Audio quality +msgid "audio-quality" +msgstr "جودة الصوت" + +# Default: Award +msgid "award" +msgstr "جائزة" + +# Default: Awards +msgid "awards" +msgstr "جوائز" + +# Default: Biographical movies +msgid "biographical-movies" +msgstr "" + +# Default: Biography +msgid "biography" +msgstr "" + +# Default: Biography print +msgid "biography-print" +msgstr "" + +# Default: Birth date +msgid "birth-date" +msgstr "تاريخ الميلاد" + +# Default: Birth name +msgid "birth-name" +msgstr "" + +# Default: Birth notes +msgid "birth-notes" +msgstr "" + +# Default: Body +msgid "body" +msgstr "جسد" + +# Default: Book +msgid "book" +msgstr "كتاب" + +# Default: Books +msgid "books" +msgstr "كتب" + +# Default: Bottom 100 rank +msgid "bottom-100-rank" +msgstr "" + +# Default: Budget +msgid "budget" +msgstr "" + +# Default: Business +msgid "business" +msgstr "" + +# Default: By arrangement with +msgid "by-arrangement-with" +msgstr "" + +# Default: Camera +msgid "camera" +msgstr "كاميرا" + +# Default: Camera and electrical department +msgid "camera-and-electrical-department" +msgstr "" + +# Default: Canonical episode title +msgid "canonical-episode-title" +msgstr "" + +# Default: Canonical name +msgid "canonical-name" +msgstr "" + +# Default: Canonical series title +msgid "canonical-series-title" +msgstr "" + +# Default: Canonical title +msgid "canonical-title" +msgstr "" + +# Default: Cast +msgid "cast" +msgstr "" + +# Default: Casting department +msgid "casting-department" +msgstr "" + +# Default: Casting director +msgid "casting-director" +msgstr "" + +# Default: Catalog number +msgid "catalog-number" +msgstr "" + +# Default: Category +msgid "category" +msgstr "فئة" + +# Default: Certificate +msgid "certificate" +msgstr "شهادة" + +# Default: Certificates +msgid "certificates" +msgstr "شهادات" + +# Default: Certification +msgid "certification" +msgstr "" + +# Default: Channel +msgid "channel" +msgstr "قناة" + +# Default: Character +msgid "character" +msgstr "شخصية" + +# Default: Cinematographer +msgid "cinematographer" +msgstr "" + +# Default: Cinematographic process +msgid "cinematographic-process" +msgstr "" + +# Default: Close captions teletext ld g +msgid "close-captions-teletext-ld-g" +msgstr "" + +# Default: Color info +msgid "color-info" +msgstr "" + +# Default: Color information +msgid "color-information" +msgstr "" + +# Default: Color rendition +msgid "color-rendition" +msgstr "" + +# Default: Company +msgid "company" +msgstr "شركة" + +# Default: Complete cast +msgid "complete-cast" +msgstr "" + +# Default: Complete crew +msgid "complete-crew" +msgstr "" + +# Default: Composer +msgid "composer" +msgstr "مؤلف" + +# Default: Connections +msgid "connections" +msgstr "" + +# Default: Contrast +msgid "contrast" +msgstr "" + +# Default: Copyright holder +msgid "copyright-holder" +msgstr "" + +# Default: Costume department +msgid "costume-department" +msgstr "" + +# Default: Costume designer +msgid "costume-designer" +msgstr "" + +# Default: Countries +msgid "countries" +msgstr "بلدان" + +# Default: Country +msgid "country" +msgstr "بلد" + +# Default: Courtesy of +msgid "courtesy-of" +msgstr "" + +# Default: Cover +msgid "cover" +msgstr "" + +# Default: Cover url +msgid "cover-url" +msgstr "" + +# Default: Crazy credits +msgid "crazy-credits" +msgstr "" + +# Default: Creator +msgid "creator" +msgstr "" + +# Default: Current role +msgid "current-role" +msgstr "" + +# Default: Database +msgid "database" +msgstr "قاعدة البيانات" + +# Default: Date +msgid "date" +msgstr "تاريخ" + +# Default: Death date +msgid "death-date" +msgstr "" + +# Default: Death notes +msgid "death-notes" +msgstr "" + +# Default: Demographic +msgid "demographic" +msgstr "ديموغرافي" + +# Default: Description +msgid "description" +msgstr "وصف" + +# Default: Dialogue intellegibility +msgid "dialogue-intellegibility" +msgstr "" + +# Default: Digital sound +msgid "digital-sound" +msgstr "" + +# Default: Director +msgid "director" +msgstr "مخرج" + +# Default: Disc format +msgid "disc-format" +msgstr "" + +# Default: Disc size +msgid "disc-size" +msgstr "" + +# Default: Distributors +msgid "distributors" +msgstr "موزعون" + +# Default: Dvd +msgid "dvd" +msgstr "dvd" + +# Default: Dvd features +msgid "dvd-features" +msgstr "" + +# Default: Dvd format +msgid "dvd-format" +msgstr "" + +# Default: Dvds +msgid "dvds" +msgstr "" + +# Default: Dynamic range +msgid "dynamic-range" +msgstr "" + +# Default: Edited from +msgid "edited-from" +msgstr "" + +# Default: Edited into +msgid "edited-into" +msgstr "" + +# Default: Editor +msgid "editor" +msgstr "محرر" + +# Default: Editorial department +msgid "editorial-department" +msgstr "" + +# Default: Episode +msgid "episode" +msgstr "حلقة" + +# Default: Episode of +msgid "episode-of" +msgstr "" + +# Default: Episode title +msgid "episode-title" +msgstr "" + +# Default: Episodes +msgid "episodes" +msgstr "حلقات" + +# Default: Episodes rating +msgid "episodes-rating" +msgstr "" + +# Default: Essays +msgid "essays" +msgstr "" + +# Default: External reviews +msgid "external-reviews" +msgstr "" + +# Default: Faqs +msgid "faqs" +msgstr "" + +# Default: Feature +msgid "feature" +msgstr "" + +# Default: Featured in +msgid "featured-in" +msgstr "" + +# Default: Features +msgid "features" +msgstr "" + +# Default: Film negative format +msgid "film-negative-format" +msgstr "" + +# Default: Filming dates +msgid "filming-dates" +msgstr "" + +# Default: Filmography +msgid "filmography" +msgstr "" + +# Default: Followed by +msgid "followed-by" +msgstr "" + +# Default: Follows +msgid "follows" +msgstr "" + +# Default: For +msgid "for" +msgstr "ل" + +# Default: Frequency response +msgid "frequency-response" +msgstr "" + +# Default: From +msgid "from" +msgstr "من" + +# Default: Full article link +msgid "full-article-link" +msgstr "" + +# Default: Full size cover url +msgid "full-size-cover-url" +msgstr "" + +# Default: Full size headshot +msgid "full-size-headshot" +msgstr "" + +# Default: Genres +msgid "genres" +msgstr "أنواع" + +# Default: Goofs +msgid "goofs" +msgstr "" + +# Default: Gross +msgid "gross" +msgstr "" + +# Default: Group genre +msgid "group-genre" +msgstr "" + +# Default: Headshot +msgid "headshot" +msgstr "" + +# Default: Height +msgid "height" +msgstr "" + +# Default: Imdbindex +msgid "imdbindex" +msgstr "" + +# Default: In development +msgid "in-development" +msgstr "" + +# Default: Interview +msgid "interview" +msgstr "حوار" + +# Default: Interviews +msgid "interviews" +msgstr "" + +# Default: Introduction +msgid "introduction" +msgstr "مقدمة" + +# Default: Item +msgid "item" +msgstr "" + +# Default: Keywords +msgid "keywords" +msgstr "" + +# Default: Kind +msgid "kind" +msgstr "" + +# Default: Label +msgid "label" +msgstr "" + +# Default: Laboratory +msgid "laboratory" +msgstr "مختبر" + +# Default: Language +msgid "language" +msgstr "لغة" + +# Default: Languages +msgid "languages" +msgstr "لغات" + +# Default: Laserdisc +msgid "laserdisc" +msgstr "" + +# Default: Laserdisc title +msgid "laserdisc-title" +msgstr "" + +# Default: Length +msgid "length" +msgstr "" + +# Default: Line +msgid "line" +msgstr "" + +# Default: Link +msgid "link" +msgstr "رابط" + +# Default: Link text +msgid "link-text" +msgstr "" + +# Default: Literature +msgid "literature" +msgstr "" + +# Default: Locations +msgid "locations" +msgstr "مواقع" + +# Default: Long imdb canonical name +msgid "long-imdb-canonical-name" +msgstr "" + +# Default: Long imdb canonical title +msgid "long-imdb-canonical-title" +msgstr "" + +# Default: Long imdb episode title +msgid "long-imdb-episode-title" +msgstr "" + +# Default: Long imdb name +msgid "long-imdb-name" +msgstr "" + +# Default: Long imdb title +msgid "long-imdb-title" +msgstr "" + +# Default: Magazine cover photo +msgid "magazine-cover-photo" +msgstr "" + +# Default: Make up +msgid "make-up" +msgstr "" + +# Default: Master format +msgid "master-format" +msgstr "" + +# Default: Median +msgid "median" +msgstr "" + +# Default: Merchandising links +msgid "merchandising-links" +msgstr "" + +# Default: Mini biography +msgid "mini-biography" +msgstr "" + +# Default: Misc links +msgid "misc-links" +msgstr "" + +# Default: Miscellaneous companies +msgid "miscellaneous-companies" +msgstr "" + +# Default: Miscellaneous crew +msgid "miscellaneous-crew" +msgstr "" + +# Default: Movie +msgid "movie" +msgstr "فيلم" + +# Default: Mpaa +msgid "mpaa" +msgstr "" + +# Default: Music department +msgid "music-department" +msgstr "" + +# Default: Name +msgid "name" +msgstr "إسم" + +# Default: News +msgid "news" +msgstr "أخبار" + +# Default: Newsgroup reviews +msgid "newsgroup-reviews" +msgstr "" + +# Default: Nick names +msgid "nick-names" +msgstr "" + +# Default: Notes +msgid "notes" +msgstr "" + +# Default: Novel +msgid "novel" +msgstr "رواية" + +# Default: Number +msgid "number" +msgstr "رقم" + +# Default: Number of chapter stops +msgid "number-of-chapter-stops" +msgstr "" + +# Default: Number of episodes +msgid "number-of-episodes" +msgstr "" + +# Default: Number of seasons +msgid "number-of-seasons" +msgstr "" + +# Default: Number of sides +msgid "number-of-sides" +msgstr "" + +# Default: Number of votes +msgid "number-of-votes" +msgstr "" + +# Default: Official retail price +msgid "official-retail-price" +msgstr "" + +# Default: Official sites +msgid "official-sites" +msgstr "" + +# Default: Opening weekend +msgid "opening-weekend" +msgstr "" + +# Default: Original air date +msgid "original-air-date" +msgstr "" + +# Default: Original music +msgid "original-music" +msgstr "" + +# Default: Original title +msgid "original-title" +msgstr "" + +# Default: Other literature +msgid "other-literature" +msgstr "" + +# Default: Other works +msgid "other-works" +msgstr "" + +# Default: Parents guide +msgid "parents-guide" +msgstr "" + +# Default: Performed by +msgid "performed-by" +msgstr "" + +# Default: Person +msgid "person" +msgstr "شخص" + +# Default: Photo sites +msgid "photo-sites" +msgstr "" + +# Default: Pictorial +msgid "pictorial" +msgstr "" + +# Default: Picture format +msgid "picture-format" +msgstr "" + +# Default: Plot +msgid "plot" +msgstr "حبكة" + +# Default: Plot outline +msgid "plot-outline" +msgstr "" + +# Default: Portrayed in +msgid "portrayed-in" +msgstr "" + +# Default: Pressing plant +msgid "pressing-plant" +msgstr "" + +# Default: Printed film format +msgid "printed-film-format" +msgstr "" + +# Default: Printed media reviews +msgid "printed-media-reviews" +msgstr "" + +# Default: Producer +msgid "producer" +msgstr "منتج" + +# Default: Production companies +msgid "production-companies" +msgstr "" + +# Default: Production country +msgid "production-country" +msgstr "" + +# Default: Production dates +msgid "production-dates" +msgstr "" + +# Default: Production design +msgid "production-design" +msgstr "" + +# Default: Production designer +msgid "production-designer" +msgstr "" + +# Default: Production manager +msgid "production-manager" +msgstr "" + +# Default: Production process protocol +msgid "production-process-protocol" +msgstr "" + +# Default: Quality of source +msgid "quality-of-source" +msgstr "" + +# Default: Quality program +msgid "quality-program" +msgstr "" + +# Default: Quote +msgid "quote" +msgstr "مقتبس" + +# Default: Quotes +msgid "quotes" +msgstr "مقتبسات" + +# Default: Rating +msgid "rating" +msgstr "تقييم" + +# Default: Recommendations +msgid "recommendations" +msgstr "" + +# Default: Referenced in +msgid "referenced-in" +msgstr "" + +# Default: References +msgid "references" +msgstr "" + +# Default: Region +msgid "region" +msgstr "" + +# Default: Release country +msgid "release-country" +msgstr "" + +# Default: Release date +msgid "release-date" +msgstr "" + +# Default: Release dates +msgid "release-dates" +msgstr "" + +# Default: Remade as +msgid "remade-as" +msgstr "" + +# Default: Remake of +msgid "remake-of" +msgstr "" + +# Default: Rentals +msgid "rentals" +msgstr "" + +# Default: Result +msgid "result" +msgstr "نتيجة" + +# Default: Review +msgid "review" +msgstr "" + +# Default: Review author +msgid "review-author" +msgstr "" + +# Default: Review kind +msgid "review-kind" +msgstr "" + +# Default: Runtime +msgid "runtime" +msgstr "" + +# Default: Runtimes +msgid "runtimes" +msgstr "" + +# Default: Salary history +msgid "salary-history" +msgstr "" + +# Default: Screenplay teleplay +msgid "screenplay-teleplay" +msgstr "" + +# Default: Season +msgid "season" +msgstr "موسم" + +# Default: Second unit director or assistant director +msgid "second-unit-director-or-assistant-director" +msgstr "" + +# Default: Self +msgid "self" +msgstr "" + +# Default: Series animation department +msgid "series-animation-department" +msgstr "" + +# Default: Series art department +msgid "series-art-department" +msgstr "" + +# Default: Series assistant directors +msgid "series-assistant-directors" +msgstr "" + +# Default: Series camera department +msgid "series-camera-department" +msgstr "" + +# Default: Series casting department +msgid "series-casting-department" +msgstr "" + +# Default: Series cinematographers +msgid "series-cinematographers" +msgstr "" + +# Default: Series costume department +msgid "series-costume-department" +msgstr "" + +# Default: Series editorial department +msgid "series-editorial-department" +msgstr "" + +# Default: Series editors +msgid "series-editors" +msgstr "" + +# Default: Series make up department +msgid "series-make-up-department" +msgstr "" + +# Default: Series miscellaneous +msgid "series-miscellaneous" +msgstr "" + +# Default: Series music department +msgid "series-music-department" +msgstr "" + +# Default: Series producers +msgid "series-producers" +msgstr "" + +# Default: Series production designers +msgid "series-production-designers" +msgstr "" + +# Default: Series production managers +msgid "series-production-managers" +msgstr "" + +# Default: Series sound department +msgid "series-sound-department" +msgstr "" + +# Default: Series special effects department +msgid "series-special-effects-department" +msgstr "" + +# Default: Series stunts +msgid "series-stunts" +msgstr "" + +# Default: Series title +msgid "series-title" +msgstr "" + +# Default: Series transportation department +msgid "series-transportation-department" +msgstr "" + +# Default: Series visual effects department +msgid "series-visual-effects-department" +msgstr "" + +# Default: Series writers +msgid "series-writers" +msgstr "" + +# Default: Series years +msgid "series-years" +msgstr "" + +# Default: Set decoration +msgid "set-decoration" +msgstr "" + +# Default: Sharpness +msgid "sharpness" +msgstr "" + +# Default: Similar to +msgid "similar-to" +msgstr "" + +# Default: Smart canonical episode title +msgid "smart-canonical-episode-title" +msgstr "" + +# Default: Smart canonical series title +msgid "smart-canonical-series-title" +msgstr "" + +# Default: Smart canonical title +msgid "smart-canonical-title" +msgstr "" + +# Default: Smart long imdb canonical title +msgid "smart-long-imdb-canonical-title" +msgstr "" + +# Default: Sound clips +msgid "sound-clips" +msgstr "" + +# Default: Sound crew +msgid "sound-crew" +msgstr "" + +# Default: Sound encoding +msgid "sound-encoding" +msgstr "" + +# Default: Sound mix +msgid "sound-mix" +msgstr "" + +# Default: Soundtrack +msgid "soundtrack" +msgstr "" + +# Default: Spaciality +msgid "spaciality" +msgstr "إختصاص" + +# Default: Special effects +msgid "special-effects" +msgstr "" + +# Default: Special effects companies +msgid "special-effects-companies" +msgstr "" + +# Default: Special effects department +msgid "special-effects-department" +msgstr "" + +# Default: Spin off +msgid "spin-off" +msgstr "" + +# Default: Spin off from +msgid "spin-off-from" +msgstr "" + +# Default: Spoofed in +msgid "spoofed-in" +msgstr "" + +# Default: Spoofs +msgid "spoofs" +msgstr "" + +# Default: Spouse +msgid "spouse" +msgstr "زوج" + +# Default: Status of availablility +msgid "status-of-availablility" +msgstr "" + +# Default: Studio +msgid "studio" +msgstr "استوديو" + +# Default: Studios +msgid "studios" +msgstr "استوديوهات" + +# Default: Stunt performer +msgid "stunt-performer" +msgstr "" + +# Default: Stunts +msgid "stunts" +msgstr "" + +# Default: Subtitles +msgid "subtitles" +msgstr "" + +# Default: Supplement +msgid "supplement" +msgstr "" + +# Default: Supplements +msgid "supplements" +msgstr "" + +# Default: Synopsis +msgid "synopsis" +msgstr "" + +# Default: Taglines +msgid "taglines" +msgstr "" + +# Default: Tech info +msgid "tech-info" +msgstr "" + +# Default: Thanks +msgid "thanks" +msgstr "بفضل" + +# Default: Time +msgid "time" +msgstr "وقت" + +# Default: Title +msgid "title" +msgstr "عنوان" + +# Default: Titles in this product +msgid "titles-in-this-product" +msgstr "" + +# Default: To +msgid "to" +msgstr "إلى" + +# Default: Top 250 rank +msgid "top-250-rank" +msgstr "" + +# Default: Trade mark +msgid "trade-mark" +msgstr "" + +# Default: Transportation department +msgid "transportation-department" +msgstr "" + +# Default: Trivia +msgid "trivia" +msgstr "" + +# Default: Tv +msgid "tv" +msgstr "تلفزيون" + +# Default: Under license from +msgid "under-license-from" +msgstr "" + +# Default: Unknown link +msgid "unknown-link" +msgstr "" + +# Default: Upc +msgid "upc" +msgstr "upc" + +# Default: Version of +msgid "version-of" +msgstr "" + +# Default: Vhs +msgid "vhs" +msgstr "vhs" + +# Default: Video +msgid "video" +msgstr "فيديو" + +# Default: Video artifacts +msgid "video-artifacts" +msgstr "" + +# Default: Video clips +msgid "video-clips" +msgstr "" + +# Default: Video noise +msgid "video-noise" +msgstr "" + +# Default: Video quality +msgid "video-quality" +msgstr "" + +# Default: Video standard +msgid "video-standard" +msgstr "" + +# Default: Visual effects +msgid "visual-effects" +msgstr "" + +# Default: Votes +msgid "votes" +msgstr "أصوات" + +# Default: Votes distribution +msgid "votes-distribution" +msgstr "" + +# Default: Weekend gross +msgid "weekend-gross" +msgstr "" + +# Default: Where now +msgid "where-now" +msgstr "" + +# Default: With +msgid "with" +msgstr "مع" + +# Default: Writer +msgid "writer" +msgstr "كاتب" + +# Default: Written by +msgid "written-by" +msgstr "" + +# Default: Year +msgid "year" +msgstr "سنة" + +# Default: Zshops +msgid "zshops" +msgstr "" diff --git a/lib/imdb/locale/imdbpy-bg.po b/lib/imdb/locale/imdbpy-bg.po new file mode 100644 index 00000000..41c4ce6a --- /dev/null +++ b/lib/imdb/locale/imdbpy-bg.po @@ -0,0 +1,1303 @@ +# Gettext message file for imdbpy +# Translators: +# Niko Kovach , 2014 +msgid "" +msgstr "" +"Project-Id-Version: IMDbPY\n" +"POT-Creation-Date: 2010-03-18 14:35+0000\n" +"PO-Revision-Date: 2014-03-16 10:46+0000\n" +"Last-Translator: Niko Kovach \n" +"Language-Team: Bulgarian (http://www.transifex.com/projects/p/imdbpy/language/bg/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Domain: imdbpy\n" +"Language: bg\n" +"Language-Code: en\n" +"Language-Name: English\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Preferred-Encodings: utf-8\n" + +# Default: Actor +msgid "actor" +msgstr "актьор" + +# Default: Actress +msgid "actress" +msgstr "актриса" + +# Default: Adaption +msgid "adaption" +msgstr "адаптация" + +# Default: Additional information +msgid "additional-information" +msgstr "допълнителна информация" + +# Default: Admissions +msgid "admissions" +msgstr "" + +# Default: Agent address +msgid "agent-address" +msgstr "" + +# Default: Airing +msgid "airing" +msgstr "" + +# Default: Akas +msgid "akas" +msgstr "" + +# Default: Akas from release info +msgid "akas-from-release-info" +msgstr "" + +# Default: All products +msgid "all-products" +msgstr "всички продукти" + +# Default: Alternate language version of +msgid "alternate-language-version-of" +msgstr "" + +# Default: Alternate versions +msgid "alternate-versions" +msgstr "" + +# Default: Amazon reviews +msgid "amazon-reviews" +msgstr "" + +# Default: Analog left +msgid "analog-left" +msgstr "" + +# Default: Analog right +msgid "analog-right" +msgstr "" + +# Default: Animation department +msgid "animation-department" +msgstr "" + +# Default: Archive footage +msgid "archive-footage" +msgstr "" + +# Default: Arithmetic mean +msgid "arithmetic-mean" +msgstr "" + +# Default: Art department +msgid "art-department" +msgstr "" + +# Default: Art direction +msgid "art-direction" +msgstr "" + +# Default: Art director +msgid "art-director" +msgstr "арт директор" + +# Default: Article +msgid "article" +msgstr "" + +# Default: Asin +msgid "asin" +msgstr "" + +# Default: Aspect ratio +msgid "aspect-ratio" +msgstr "" + +# Default: Assigner +msgid "assigner" +msgstr "" + +# Default: Assistant director +msgid "assistant-director" +msgstr "" + +# Default: Auctions +msgid "auctions" +msgstr "" + +# Default: Audio noise +msgid "audio-noise" +msgstr "" + +# Default: Audio quality +msgid "audio-quality" +msgstr "" + +# Default: Award +msgid "award" +msgstr "награда" + +# Default: Awards +msgid "awards" +msgstr "награди" + +# Default: Biographical movies +msgid "biographical-movies" +msgstr "" + +# Default: Biography +msgid "biography" +msgstr "биография" + +# Default: Biography print +msgid "biography-print" +msgstr "" + +# Default: Birth date +msgid "birth-date" +msgstr "рождена дата" + +# Default: Birth name +msgid "birth-name" +msgstr "" + +# Default: Birth notes +msgid "birth-notes" +msgstr "" + +# Default: Body +msgid "body" +msgstr "" + +# Default: Book +msgid "book" +msgstr "книга" + +# Default: Books +msgid "books" +msgstr "книги" + +# Default: Bottom 100 rank +msgid "bottom-100-rank" +msgstr "" + +# Default: Budget +msgid "budget" +msgstr "бюджет" + +# Default: Business +msgid "business" +msgstr "" + +# Default: By arrangement with +msgid "by-arrangement-with" +msgstr "" + +# Default: Camera +msgid "camera" +msgstr "камера" + +# Default: Camera and electrical department +msgid "camera-and-electrical-department" +msgstr "" + +# Default: Canonical episode title +msgid "canonical-episode-title" +msgstr "" + +# Default: Canonical name +msgid "canonical-name" +msgstr "" + +# Default: Canonical series title +msgid "canonical-series-title" +msgstr "" + +# Default: Canonical title +msgid "canonical-title" +msgstr "" + +# Default: Cast +msgid "cast" +msgstr "" + +# Default: Casting department +msgid "casting-department" +msgstr "" + +# Default: Casting director +msgid "casting-director" +msgstr "кастинг директор" + +# Default: Catalog number +msgid "catalog-number" +msgstr "" + +# Default: Category +msgid "category" +msgstr "категория" + +# Default: Certificate +msgid "certificate" +msgstr "сертификат" + +# Default: Certificates +msgid "certificates" +msgstr "сертификати" + +# Default: Certification +msgid "certification" +msgstr "сертифициране" + +# Default: Channel +msgid "channel" +msgstr "канал" + +# Default: Character +msgid "character" +msgstr "характер" + +# Default: Cinematographer +msgid "cinematographer" +msgstr "кинематограф" + +# Default: Cinematographic process +msgid "cinematographic-process" +msgstr "" + +# Default: Close captions teletext ld g +msgid "close-captions-teletext-ld-g" +msgstr "" + +# Default: Color info +msgid "color-info" +msgstr "" + +# Default: Color information +msgid "color-information" +msgstr "" + +# Default: Color rendition +msgid "color-rendition" +msgstr "" + +# Default: Company +msgid "company" +msgstr "компания" + +# Default: Complete cast +msgid "complete-cast" +msgstr "" + +# Default: Complete crew +msgid "complete-crew" +msgstr "" + +# Default: Composer +msgid "composer" +msgstr "композитор" + +# Default: Connections +msgid "connections" +msgstr "връзки" + +# Default: Contrast +msgid "contrast" +msgstr "контраст" + +# Default: Copyright holder +msgid "copyright-holder" +msgstr "" + +# Default: Costume department +msgid "costume-department" +msgstr "" + +# Default: Costume designer +msgid "costume-designer" +msgstr "" + +# Default: Countries +msgid "countries" +msgstr "страни" + +# Default: Country +msgid "country" +msgstr "страна" + +# Default: Courtesy of +msgid "courtesy-of" +msgstr "" + +# Default: Cover +msgid "cover" +msgstr "" + +# Default: Cover url +msgid "cover-url" +msgstr "" + +# Default: Crazy credits +msgid "crazy-credits" +msgstr "" + +# Default: Creator +msgid "creator" +msgstr "създател" + +# Default: Current role +msgid "current-role" +msgstr "" + +# Default: Database +msgid "database" +msgstr "база данни" + +# Default: Date +msgid "date" +msgstr "дата" + +# Default: Death date +msgid "death-date" +msgstr "дата на смъртта" + +# Default: Death notes +msgid "death-notes" +msgstr "" + +# Default: Demographic +msgid "demographic" +msgstr "" + +# Default: Description +msgid "description" +msgstr "описание" + +# Default: Dialogue intellegibility +msgid "dialogue-intellegibility" +msgstr "" + +# Default: Digital sound +msgid "digital-sound" +msgstr "" + +# Default: Director +msgid "director" +msgstr "директор" + +# Default: Disc format +msgid "disc-format" +msgstr "формат на диска" + +# Default: Disc size +msgid "disc-size" +msgstr "размер на диска" + +# Default: Distributors +msgid "distributors" +msgstr "дистрибутори" + +# Default: Dvd +msgid "dvd" +msgstr "dvd" + +# Default: Dvd features +msgid "dvd-features" +msgstr "dvd характеристики" + +# Default: Dvd format +msgid "dvd-format" +msgstr "dvd формат" + +# Default: Dvds +msgid "dvds" +msgstr "dvd-та" + +# Default: Dynamic range +msgid "dynamic-range" +msgstr "динамичен обхват" + +# Default: Edited from +msgid "edited-from" +msgstr "" + +# Default: Edited into +msgid "edited-into" +msgstr "" + +# Default: Editor +msgid "editor" +msgstr "редактор" + +# Default: Editorial department +msgid "editorial-department" +msgstr "" + +# Default: Episode +msgid "episode" +msgstr "епизод" + +# Default: Episode of +msgid "episode-of" +msgstr "епизод от" + +# Default: Episode title +msgid "episode-title" +msgstr "име на епизода" + +# Default: Episodes +msgid "episodes" +msgstr "епизоди" + +# Default: Episodes rating +msgid "episodes-rating" +msgstr "рейтинг на епизодите" + +# Default: Essays +msgid "essays" +msgstr "" + +# Default: External reviews +msgid "external-reviews" +msgstr "външни рецензии" + +# Default: Faqs +msgid "faqs" +msgstr "" + +# Default: Feature +msgid "feature" +msgstr "" + +# Default: Featured in +msgid "featured-in" +msgstr "" + +# Default: Features +msgid "features" +msgstr "" + +# Default: Film negative format +msgid "film-negative-format" +msgstr "" + +# Default: Filming dates +msgid "filming-dates" +msgstr "" + +# Default: Filmography +msgid "filmography" +msgstr "филмография" + +# Default: Followed by +msgid "followed-by" +msgstr "последван от" + +# Default: Follows +msgid "follows" +msgstr "последователи" + +# Default: For +msgid "for" +msgstr "" + +# Default: Frequency response +msgid "frequency-response" +msgstr "" + +# Default: From +msgid "from" +msgstr "" + +# Default: Full article link +msgid "full-article-link" +msgstr "" + +# Default: Full size cover url +msgid "full-size-cover-url" +msgstr "" + +# Default: Full size headshot +msgid "full-size-headshot" +msgstr "" + +# Default: Genres +msgid "genres" +msgstr "жанрове" + +# Default: Goofs +msgid "goofs" +msgstr "" + +# Default: Gross +msgid "gross" +msgstr "" + +# Default: Group genre +msgid "group-genre" +msgstr "" + +# Default: Headshot +msgid "headshot" +msgstr "" + +# Default: Height +msgid "height" +msgstr "" + +# Default: Imdbindex +msgid "imdbindex" +msgstr "imdb индекс" + +# Default: In development +msgid "in-development" +msgstr "" + +# Default: Interview +msgid "interview" +msgstr "интервю" + +# Default: Interviews +msgid "interviews" +msgstr "интервюта" + +# Default: Introduction +msgid "introduction" +msgstr "въведение" + +# Default: Item +msgid "item" +msgstr "елемент" + +# Default: Keywords +msgid "keywords" +msgstr "ключови думи" + +# Default: Kind +msgid "kind" +msgstr "" + +# Default: Label +msgid "label" +msgstr "етикет" + +# Default: Laboratory +msgid "laboratory" +msgstr "лаборатория" + +# Default: Language +msgid "language" +msgstr "език" + +# Default: Languages +msgid "languages" +msgstr "езици" + +# Default: Laserdisc +msgid "laserdisc" +msgstr "лазерен диск" + +# Default: Laserdisc title +msgid "laserdisc-title" +msgstr "име на лазерения диск" + +# Default: Length +msgid "length" +msgstr "продължителност" + +# Default: Line +msgid "line" +msgstr "" + +# Default: Link +msgid "link" +msgstr "връзка" + +# Default: Link text +msgid "link-text" +msgstr "текст за връзката" + +# Default: Literature +msgid "literature" +msgstr "литература" + +# Default: Locations +msgid "locations" +msgstr "местоположения" + +# Default: Long imdb canonical name +msgid "long-imdb-canonical-name" +msgstr "" + +# Default: Long imdb canonical title +msgid "long-imdb-canonical-title" +msgstr "" + +# Default: Long imdb episode title +msgid "long-imdb-episode-title" +msgstr "" + +# Default: Long imdb name +msgid "long-imdb-name" +msgstr "" + +# Default: Long imdb title +msgid "long-imdb-title" +msgstr "" + +# Default: Magazine cover photo +msgid "magazine-cover-photo" +msgstr "" + +# Default: Make up +msgid "make-up" +msgstr "" + +# Default: Master format +msgid "master-format" +msgstr "" + +# Default: Median +msgid "median" +msgstr "" + +# Default: Merchandising links +msgid "merchandising-links" +msgstr "" + +# Default: Mini biography +msgid "mini-biography" +msgstr "" + +# Default: Misc links +msgid "misc-links" +msgstr "" + +# Default: Miscellaneous companies +msgid "miscellaneous-companies" +msgstr "" + +# Default: Miscellaneous crew +msgid "miscellaneous-crew" +msgstr "" + +# Default: Movie +msgid "movie" +msgstr "филм" + +# Default: Mpaa +msgid "mpaa" +msgstr "mpaa" + +# Default: Music department +msgid "music-department" +msgstr "музикален департамент" + +# Default: Name +msgid "name" +msgstr "име" + +# Default: News +msgid "news" +msgstr "новини" + +# Default: Newsgroup reviews +msgid "newsgroup-reviews" +msgstr "" + +# Default: Nick names +msgid "nick-names" +msgstr "" + +# Default: Notes +msgid "notes" +msgstr "бележки" + +# Default: Novel +msgid "novel" +msgstr "роман" + +# Default: Number +msgid "number" +msgstr "номер" + +# Default: Number of chapter stops +msgid "number-of-chapter-stops" +msgstr "" + +# Default: Number of episodes +msgid "number-of-episodes" +msgstr "" + +# Default: Number of seasons +msgid "number-of-seasons" +msgstr "" + +# Default: Number of sides +msgid "number-of-sides" +msgstr "" + +# Default: Number of votes +msgid "number-of-votes" +msgstr "" + +# Default: Official retail price +msgid "official-retail-price" +msgstr "" + +# Default: Official sites +msgid "official-sites" +msgstr "официалени сайтове" + +# Default: Opening weekend +msgid "opening-weekend" +msgstr "" + +# Default: Original air date +msgid "original-air-date" +msgstr "" + +# Default: Original music +msgid "original-music" +msgstr "" + +# Default: Original title +msgid "original-title" +msgstr "" + +# Default: Other literature +msgid "other-literature" +msgstr "" + +# Default: Other works +msgid "other-works" +msgstr "" + +# Default: Parents guide +msgid "parents-guide" +msgstr "" + +# Default: Performed by +msgid "performed-by" +msgstr "" + +# Default: Person +msgid "person" +msgstr "персона" + +# Default: Photo sites +msgid "photo-sites" +msgstr "" + +# Default: Pictorial +msgid "pictorial" +msgstr "" + +# Default: Picture format +msgid "picture-format" +msgstr "" + +# Default: Plot +msgid "plot" +msgstr "" + +# Default: Plot outline +msgid "plot-outline" +msgstr "" + +# Default: Portrayed in +msgid "portrayed-in" +msgstr "" + +# Default: Pressing plant +msgid "pressing-plant" +msgstr "" + +# Default: Printed film format +msgid "printed-film-format" +msgstr "" + +# Default: Printed media reviews +msgid "printed-media-reviews" +msgstr "" + +# Default: Producer +msgid "producer" +msgstr "продуцент" + +# Default: Production companies +msgid "production-companies" +msgstr "производствени компании" + +# Default: Production country +msgid "production-country" +msgstr "производствена страна" + +# Default: Production dates +msgid "production-dates" +msgstr "" + +# Default: Production design +msgid "production-design" +msgstr "" + +# Default: Production designer +msgid "production-designer" +msgstr "" + +# Default: Production manager +msgid "production-manager" +msgstr "" + +# Default: Production process protocol +msgid "production-process-protocol" +msgstr "" + +# Default: Quality of source +msgid "quality-of-source" +msgstr "" + +# Default: Quality program +msgid "quality-program" +msgstr "" + +# Default: Quote +msgid "quote" +msgstr "цитат" + +# Default: Quotes +msgid "quotes" +msgstr "цитати" + +# Default: Rating +msgid "rating" +msgstr "рейтинг" + +# Default: Recommendations +msgid "recommendations" +msgstr "препоръки" + +# Default: Referenced in +msgid "referenced-in" +msgstr "" + +# Default: References +msgid "references" +msgstr "референции" + +# Default: Region +msgid "region" +msgstr "регион" + +# Default: Release country +msgid "release-country" +msgstr "" + +# Default: Release date +msgid "release-date" +msgstr "" + +# Default: Release dates +msgid "release-dates" +msgstr "" + +# Default: Remade as +msgid "remade-as" +msgstr "" + +# Default: Remake of +msgid "remake-of" +msgstr "" + +# Default: Rentals +msgid "rentals" +msgstr "" + +# Default: Result +msgid "result" +msgstr "резултат" + +# Default: Review +msgid "review" +msgstr "рецензия" + +# Default: Review author +msgid "review-author" +msgstr "автор на рецензията" + +# Default: Review kind +msgid "review-kind" +msgstr "" + +# Default: Runtime +msgid "runtime" +msgstr "времетраене" + +# Default: Runtimes +msgid "runtimes" +msgstr "" + +# Default: Salary history +msgid "salary-history" +msgstr "" + +# Default: Screenplay teleplay +msgid "screenplay-teleplay" +msgstr "" + +# Default: Season +msgid "season" +msgstr "сезон" + +# Default: Second unit director or assistant director +msgid "second-unit-director-or-assistant-director" +msgstr "" + +# Default: Self +msgid "self" +msgstr "" + +# Default: Series animation department +msgid "series-animation-department" +msgstr "" + +# Default: Series art department +msgid "series-art-department" +msgstr "" + +# Default: Series assistant directors +msgid "series-assistant-directors" +msgstr "" + +# Default: Series camera department +msgid "series-camera-department" +msgstr "" + +# Default: Series casting department +msgid "series-casting-department" +msgstr "" + +# Default: Series cinematographers +msgid "series-cinematographers" +msgstr "" + +# Default: Series costume department +msgid "series-costume-department" +msgstr "" + +# Default: Series editorial department +msgid "series-editorial-department" +msgstr "" + +# Default: Series editors +msgid "series-editors" +msgstr "" + +# Default: Series make up department +msgid "series-make-up-department" +msgstr "" + +# Default: Series miscellaneous +msgid "series-miscellaneous" +msgstr "" + +# Default: Series music department +msgid "series-music-department" +msgstr "" + +# Default: Series producers +msgid "series-producers" +msgstr "" + +# Default: Series production designers +msgid "series-production-designers" +msgstr "" + +# Default: Series production managers +msgid "series-production-managers" +msgstr "" + +# Default: Series sound department +msgid "series-sound-department" +msgstr "" + +# Default: Series special effects department +msgid "series-special-effects-department" +msgstr "" + +# Default: Series stunts +msgid "series-stunts" +msgstr "" + +# Default: Series title +msgid "series-title" +msgstr "име на серията" + +# Default: Series transportation department +msgid "series-transportation-department" +msgstr "" + +# Default: Series visual effects department +msgid "series-visual-effects-department" +msgstr "" + +# Default: Series writers +msgid "series-writers" +msgstr "" + +# Default: Series years +msgid "series-years" +msgstr "" + +# Default: Set decoration +msgid "set-decoration" +msgstr "" + +# Default: Sharpness +msgid "sharpness" +msgstr "" + +# Default: Similar to +msgid "similar-to" +msgstr "" + +# Default: Smart canonical episode title +msgid "smart-canonical-episode-title" +msgstr "" + +# Default: Smart canonical series title +msgid "smart-canonical-series-title" +msgstr "" + +# Default: Smart canonical title +msgid "smart-canonical-title" +msgstr "" + +# Default: Smart long imdb canonical title +msgid "smart-long-imdb-canonical-title" +msgstr "" + +# Default: Sound clips +msgid "sound-clips" +msgstr "" + +# Default: Sound crew +msgid "sound-crew" +msgstr "" + +# Default: Sound encoding +msgid "sound-encoding" +msgstr "" + +# Default: Sound mix +msgid "sound-mix" +msgstr "" + +# Default: Soundtrack +msgid "soundtrack" +msgstr "саундтрак" + +# Default: Spaciality +msgid "spaciality" +msgstr "" + +# Default: Special effects +msgid "special-effects" +msgstr "специални ефекти" + +# Default: Special effects companies +msgid "special-effects-companies" +msgstr "" + +# Default: Special effects department +msgid "special-effects-department" +msgstr "" + +# Default: Spin off +msgid "spin-off" +msgstr "" + +# Default: Spin off from +msgid "spin-off-from" +msgstr "" + +# Default: Spoofed in +msgid "spoofed-in" +msgstr "" + +# Default: Spoofs +msgid "spoofs" +msgstr "" + +# Default: Spouse +msgid "spouse" +msgstr "" + +# Default: Status of availablility +msgid "status-of-availablility" +msgstr "" + +# Default: Studio +msgid "studio" +msgstr "студио" + +# Default: Studios +msgid "studios" +msgstr "студиа" + +# Default: Stunt performer +msgid "stunt-performer" +msgstr "" + +# Default: Stunts +msgid "stunts" +msgstr "" + +# Default: Subtitles +msgid "subtitles" +msgstr "субтитри" + +# Default: Supplement +msgid "supplement" +msgstr "допълнение" + +# Default: Supplements +msgid "supplements" +msgstr "допълнения" + +# Default: Synopsis +msgid "synopsis" +msgstr "синопсис" + +# Default: Taglines +msgid "taglines" +msgstr "подзаглавия" + +# Default: Tech info +msgid "tech-info" +msgstr "" + +# Default: Thanks +msgid "thanks" +msgstr "" + +# Default: Time +msgid "time" +msgstr "време" + +# Default: Title +msgid "title" +msgstr "име" + +# Default: Titles in this product +msgid "titles-in-this-product" +msgstr "" + +# Default: To +msgid "to" +msgstr "" + +# Default: Top 250 rank +msgid "top-250-rank" +msgstr "" + +# Default: Trade mark +msgid "trade-mark" +msgstr "търговска марка" + +# Default: Transportation department +msgid "transportation-department" +msgstr "" + +# Default: Trivia +msgid "trivia" +msgstr "любопитно" + +# Default: Tv +msgid "tv" +msgstr "тв" + +# Default: Under license from +msgid "under-license-from" +msgstr "" + +# Default: Unknown link +msgid "unknown-link" +msgstr "" + +# Default: Upc +msgid "upc" +msgstr "" + +# Default: Version of +msgid "version-of" +msgstr "" + +# Default: Vhs +msgid "vhs" +msgstr "" + +# Default: Video +msgid "video" +msgstr "видео" + +# Default: Video artifacts +msgid "video-artifacts" +msgstr "" + +# Default: Video clips +msgid "video-clips" +msgstr "" + +# Default: Video noise +msgid "video-noise" +msgstr "" + +# Default: Video quality +msgid "video-quality" +msgstr "" + +# Default: Video standard +msgid "video-standard" +msgstr "" + +# Default: Visual effects +msgid "visual-effects" +msgstr "" + +# Default: Votes +msgid "votes" +msgstr "гласа" + +# Default: Votes distribution +msgid "votes-distribution" +msgstr "" + +# Default: Weekend gross +msgid "weekend-gross" +msgstr "" + +# Default: Where now +msgid "where-now" +msgstr "" + +# Default: With +msgid "with" +msgstr "" + +# Default: Writer +msgid "writer" +msgstr "сценарист" + +# Default: Written by +msgid "written-by" +msgstr "" + +# Default: Year +msgid "year" +msgstr "година" + +# Default: Zshops +msgid "zshops" +msgstr "" diff --git a/lib/imdb/locale/imdbpy-de.po b/lib/imdb/locale/imdbpy-de.po new file mode 100644 index 00000000..c0585b92 --- /dev/null +++ b/lib/imdb/locale/imdbpy-de.po @@ -0,0 +1,1303 @@ +# Gettext message file for imdbpy +# Translators: +# Ioan, 2013 +msgid "" +msgstr "" +"Project-Id-Version: IMDbPY\n" +"POT-Creation-Date: 2010-03-18 14:35+0000\n" +"PO-Revision-Date: 2013-11-20 11:07+0000\n" +"Last-Translator: Ioan\n" +"Language-Team: German (http://www.transifex.com/projects/p/imdbpy/language/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Domain: imdbpy\n" +"Language: de\n" +"Language-Code: en\n" +"Language-Name: English\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Preferred-Encodings: utf-8\n" + +# Default: Actor +msgid "actor" +msgstr "" + +# Default: Actress +msgid "actress" +msgstr "" + +# Default: Adaption +msgid "adaption" +msgstr "" + +# Default: Additional information +msgid "additional-information" +msgstr "" + +# Default: Admissions +msgid "admissions" +msgstr "" + +# Default: Agent address +msgid "agent-address" +msgstr "" + +# Default: Airing +msgid "airing" +msgstr "" + +# Default: Akas +msgid "akas" +msgstr "" + +# Default: Akas from release info +msgid "akas-from-release-info" +msgstr "" + +# Default: All products +msgid "all-products" +msgstr "" + +# Default: Alternate language version of +msgid "alternate-language-version-of" +msgstr "" + +# Default: Alternate versions +msgid "alternate-versions" +msgstr "" + +# Default: Amazon reviews +msgid "amazon-reviews" +msgstr "" + +# Default: Analog left +msgid "analog-left" +msgstr "" + +# Default: Analog right +msgid "analog-right" +msgstr "" + +# Default: Animation department +msgid "animation-department" +msgstr "" + +# Default: Archive footage +msgid "archive-footage" +msgstr "" + +# Default: Arithmetic mean +msgid "arithmetic-mean" +msgstr "" + +# Default: Art department +msgid "art-department" +msgstr "" + +# Default: Art direction +msgid "art-direction" +msgstr "" + +# Default: Art director +msgid "art-director" +msgstr "" + +# Default: Article +msgid "article" +msgstr "Artikel" + +# Default: Asin +msgid "asin" +msgstr "" + +# Default: Aspect ratio +msgid "aspect-ratio" +msgstr "" + +# Default: Assigner +msgid "assigner" +msgstr "" + +# Default: Assistant director +msgid "assistant-director" +msgstr "" + +# Default: Auctions +msgid "auctions" +msgstr "" + +# Default: Audio noise +msgid "audio-noise" +msgstr "" + +# Default: Audio quality +msgid "audio-quality" +msgstr "" + +# Default: Award +msgid "award" +msgstr "Auszeichnung" + +# Default: Awards +msgid "awards" +msgstr "Auszeichnungen" + +# Default: Biographical movies +msgid "biographical-movies" +msgstr "" + +# Default: Biography +msgid "biography" +msgstr "Biographie" + +# Default: Biography print +msgid "biography-print" +msgstr "" + +# Default: Birth date +msgid "birth-date" +msgstr "Geburtsdatum" + +# Default: Birth name +msgid "birth-name" +msgstr "Geburtsname" + +# Default: Birth notes +msgid "birth-notes" +msgstr "" + +# Default: Body +msgid "body" +msgstr "" + +# Default: Book +msgid "book" +msgstr "Buch" + +# Default: Books +msgid "books" +msgstr "Bücher" + +# Default: Bottom 100 rank +msgid "bottom-100-rank" +msgstr "" + +# Default: Budget +msgid "budget" +msgstr "Kosten" + +# Default: Business +msgid "business" +msgstr "" + +# Default: By arrangement with +msgid "by-arrangement-with" +msgstr "" + +# Default: Camera +msgid "camera" +msgstr "Kamera" + +# Default: Camera and electrical department +msgid "camera-and-electrical-department" +msgstr "" + +# Default: Canonical episode title +msgid "canonical-episode-title" +msgstr "" + +# Default: Canonical name +msgid "canonical-name" +msgstr "" + +# Default: Canonical series title +msgid "canonical-series-title" +msgstr "" + +# Default: Canonical title +msgid "canonical-title" +msgstr "" + +# Default: Cast +msgid "cast" +msgstr "" + +# Default: Casting department +msgid "casting-department" +msgstr "" + +# Default: Casting director +msgid "casting-director" +msgstr "" + +# Default: Catalog number +msgid "catalog-number" +msgstr "" + +# Default: Category +msgid "category" +msgstr "" + +# Default: Certificate +msgid "certificate" +msgstr "" + +# Default: Certificates +msgid "certificates" +msgstr "" + +# Default: Certification +msgid "certification" +msgstr "" + +# Default: Channel +msgid "channel" +msgstr "" + +# Default: Character +msgid "character" +msgstr "" + +# Default: Cinematographer +msgid "cinematographer" +msgstr "" + +# Default: Cinematographic process +msgid "cinematographic-process" +msgstr "" + +# Default: Close captions teletext ld g +msgid "close-captions-teletext-ld-g" +msgstr "" + +# Default: Color info +msgid "color-info" +msgstr "" + +# Default: Color information +msgid "color-information" +msgstr "" + +# Default: Color rendition +msgid "color-rendition" +msgstr "" + +# Default: Company +msgid "company" +msgstr "" + +# Default: Complete cast +msgid "complete-cast" +msgstr "" + +# Default: Complete crew +msgid "complete-crew" +msgstr "" + +# Default: Composer +msgid "composer" +msgstr "" + +# Default: Connections +msgid "connections" +msgstr "" + +# Default: Contrast +msgid "contrast" +msgstr "" + +# Default: Copyright holder +msgid "copyright-holder" +msgstr "" + +# Default: Costume department +msgid "costume-department" +msgstr "" + +# Default: Costume designer +msgid "costume-designer" +msgstr "" + +# Default: Countries +msgid "countries" +msgstr "Länder" + +# Default: Country +msgid "country" +msgstr "Land" + +# Default: Courtesy of +msgid "courtesy-of" +msgstr "" + +# Default: Cover +msgid "cover" +msgstr "Cover" + +# Default: Cover url +msgid "cover-url" +msgstr "" + +# Default: Crazy credits +msgid "crazy-credits" +msgstr "" + +# Default: Creator +msgid "creator" +msgstr "Ersteller" + +# Default: Current role +msgid "current-role" +msgstr "" + +# Default: Database +msgid "database" +msgstr "Datenbank" + +# Default: Date +msgid "date" +msgstr "Datum" + +# Default: Death date +msgid "death-date" +msgstr "" + +# Default: Death notes +msgid "death-notes" +msgstr "" + +# Default: Demographic +msgid "demographic" +msgstr "" + +# Default: Description +msgid "description" +msgstr "" + +# Default: Dialogue intellegibility +msgid "dialogue-intellegibility" +msgstr "" + +# Default: Digital sound +msgid "digital-sound" +msgstr "" + +# Default: Director +msgid "director" +msgstr "" + +# Default: Disc format +msgid "disc-format" +msgstr "" + +# Default: Disc size +msgid "disc-size" +msgstr "" + +# Default: Distributors +msgid "distributors" +msgstr "" + +# Default: Dvd +msgid "dvd" +msgstr "DVD" + +# Default: Dvd features +msgid "dvd-features" +msgstr "" + +# Default: Dvd format +msgid "dvd-format" +msgstr "" + +# Default: Dvds +msgid "dvds" +msgstr "DVDs" + +# Default: Dynamic range +msgid "dynamic-range" +msgstr "" + +# Default: Edited from +msgid "edited-from" +msgstr "" + +# Default: Edited into +msgid "edited-into" +msgstr "" + +# Default: Editor +msgid "editor" +msgstr "" + +# Default: Editorial department +msgid "editorial-department" +msgstr "" + +# Default: Episode +msgid "episode" +msgstr "Episode" + +# Default: Episode of +msgid "episode-of" +msgstr "" + +# Default: Episode title +msgid "episode-title" +msgstr "Episodentitel" + +# Default: Episodes +msgid "episodes" +msgstr "Episoden" + +# Default: Episodes rating +msgid "episodes-rating" +msgstr "" + +# Default: Essays +msgid "essays" +msgstr "" + +# Default: External reviews +msgid "external-reviews" +msgstr "" + +# Default: Faqs +msgid "faqs" +msgstr "" + +# Default: Feature +msgid "feature" +msgstr "" + +# Default: Featured in +msgid "featured-in" +msgstr "" + +# Default: Features +msgid "features" +msgstr "" + +# Default: Film negative format +msgid "film-negative-format" +msgstr "" + +# Default: Filming dates +msgid "filming-dates" +msgstr "" + +# Default: Filmography +msgid "filmography" +msgstr "" + +# Default: Followed by +msgid "followed-by" +msgstr "" + +# Default: Follows +msgid "follows" +msgstr "" + +# Default: For +msgid "for" +msgstr "" + +# Default: Frequency response +msgid "frequency-response" +msgstr "" + +# Default: From +msgid "from" +msgstr "" + +# Default: Full article link +msgid "full-article-link" +msgstr "" + +# Default: Full size cover url +msgid "full-size-cover-url" +msgstr "" + +# Default: Full size headshot +msgid "full-size-headshot" +msgstr "" + +# Default: Genres +msgid "genres" +msgstr "" + +# Default: Goofs +msgid "goofs" +msgstr "" + +# Default: Gross +msgid "gross" +msgstr "" + +# Default: Group genre +msgid "group-genre" +msgstr "" + +# Default: Headshot +msgid "headshot" +msgstr "" + +# Default: Height +msgid "height" +msgstr "Höhe" + +# Default: Imdbindex +msgid "imdbindex" +msgstr "" + +# Default: In development +msgid "in-development" +msgstr "" + +# Default: Interview +msgid "interview" +msgstr "" + +# Default: Interviews +msgid "interviews" +msgstr "" + +# Default: Introduction +msgid "introduction" +msgstr "" + +# Default: Item +msgid "item" +msgstr "" + +# Default: Keywords +msgid "keywords" +msgstr "Schlüsselwörter" + +# Default: Kind +msgid "kind" +msgstr "" + +# Default: Label +msgid "label" +msgstr "" + +# Default: Laboratory +msgid "laboratory" +msgstr "" + +# Default: Language +msgid "language" +msgstr "Sprache" + +# Default: Languages +msgid "languages" +msgstr "Sprachen" + +# Default: Laserdisc +msgid "laserdisc" +msgstr "" + +# Default: Laserdisc title +msgid "laserdisc-title" +msgstr "" + +# Default: Length +msgid "length" +msgstr "Länge" + +# Default: Line +msgid "line" +msgstr "" + +# Default: Link +msgid "link" +msgstr "Link" + +# Default: Link text +msgid "link-text" +msgstr "" + +# Default: Literature +msgid "literature" +msgstr "Literatur" + +# Default: Locations +msgid "locations" +msgstr "" + +# Default: Long imdb canonical name +msgid "long-imdb-canonical-name" +msgstr "" + +# Default: Long imdb canonical title +msgid "long-imdb-canonical-title" +msgstr "" + +# Default: Long imdb episode title +msgid "long-imdb-episode-title" +msgstr "" + +# Default: Long imdb name +msgid "long-imdb-name" +msgstr "" + +# Default: Long imdb title +msgid "long-imdb-title" +msgstr "" + +# Default: Magazine cover photo +msgid "magazine-cover-photo" +msgstr "" + +# Default: Make up +msgid "make-up" +msgstr "" + +# Default: Master format +msgid "master-format" +msgstr "" + +# Default: Median +msgid "median" +msgstr "" + +# Default: Merchandising links +msgid "merchandising-links" +msgstr "" + +# Default: Mini biography +msgid "mini-biography" +msgstr "" + +# Default: Misc links +msgid "misc-links" +msgstr "" + +# Default: Miscellaneous companies +msgid "miscellaneous-companies" +msgstr "" + +# Default: Miscellaneous crew +msgid "miscellaneous-crew" +msgstr "" + +# Default: Movie +msgid "movie" +msgstr "Film" + +# Default: Mpaa +msgid "mpaa" +msgstr "" + +# Default: Music department +msgid "music-department" +msgstr "" + +# Default: Name +msgid "name" +msgstr "Name" + +# Default: News +msgid "news" +msgstr "Nachrichten" + +# Default: Newsgroup reviews +msgid "newsgroup-reviews" +msgstr "" + +# Default: Nick names +msgid "nick-names" +msgstr "" + +# Default: Notes +msgid "notes" +msgstr "" + +# Default: Novel +msgid "novel" +msgstr "" + +# Default: Number +msgid "number" +msgstr "" + +# Default: Number of chapter stops +msgid "number-of-chapter-stops" +msgstr "" + +# Default: Number of episodes +msgid "number-of-episodes" +msgstr "" + +# Default: Number of seasons +msgid "number-of-seasons" +msgstr "" + +# Default: Number of sides +msgid "number-of-sides" +msgstr "" + +# Default: Number of votes +msgid "number-of-votes" +msgstr "" + +# Default: Official retail price +msgid "official-retail-price" +msgstr "" + +# Default: Official sites +msgid "official-sites" +msgstr "" + +# Default: Opening weekend +msgid "opening-weekend" +msgstr "" + +# Default: Original air date +msgid "original-air-date" +msgstr "" + +# Default: Original music +msgid "original-music" +msgstr "" + +# Default: Original title +msgid "original-title" +msgstr "" + +# Default: Other literature +msgid "other-literature" +msgstr "" + +# Default: Other works +msgid "other-works" +msgstr "" + +# Default: Parents guide +msgid "parents-guide" +msgstr "" + +# Default: Performed by +msgid "performed-by" +msgstr "" + +# Default: Person +msgid "person" +msgstr "" + +# Default: Photo sites +msgid "photo-sites" +msgstr "" + +# Default: Pictorial +msgid "pictorial" +msgstr "" + +# Default: Picture format +msgid "picture-format" +msgstr "" + +# Default: Plot +msgid "plot" +msgstr "Inhalt" + +# Default: Plot outline +msgid "plot-outline" +msgstr "" + +# Default: Portrayed in +msgid "portrayed-in" +msgstr "" + +# Default: Pressing plant +msgid "pressing-plant" +msgstr "" + +# Default: Printed film format +msgid "printed-film-format" +msgstr "" + +# Default: Printed media reviews +msgid "printed-media-reviews" +msgstr "" + +# Default: Producer +msgid "producer" +msgstr "" + +# Default: Production companies +msgid "production-companies" +msgstr "" + +# Default: Production country +msgid "production-country" +msgstr "" + +# Default: Production dates +msgid "production-dates" +msgstr "" + +# Default: Production design +msgid "production-design" +msgstr "" + +# Default: Production designer +msgid "production-designer" +msgstr "" + +# Default: Production manager +msgid "production-manager" +msgstr "" + +# Default: Production process protocol +msgid "production-process-protocol" +msgstr "" + +# Default: Quality of source +msgid "quality-of-source" +msgstr "" + +# Default: Quality program +msgid "quality-program" +msgstr "" + +# Default: Quote +msgid "quote" +msgstr "" + +# Default: Quotes +msgid "quotes" +msgstr "" + +# Default: Rating +msgid "rating" +msgstr "" + +# Default: Recommendations +msgid "recommendations" +msgstr "" + +# Default: Referenced in +msgid "referenced-in" +msgstr "" + +# Default: References +msgid "references" +msgstr "" + +# Default: Region +msgid "region" +msgstr "Region" + +# Default: Release country +msgid "release-country" +msgstr "" + +# Default: Release date +msgid "release-date" +msgstr "" + +# Default: Release dates +msgid "release-dates" +msgstr "" + +# Default: Remade as +msgid "remade-as" +msgstr "" + +# Default: Remake of +msgid "remake-of" +msgstr "" + +# Default: Rentals +msgid "rentals" +msgstr "" + +# Default: Result +msgid "result" +msgstr "" + +# Default: Review +msgid "review" +msgstr "" + +# Default: Review author +msgid "review-author" +msgstr "" + +# Default: Review kind +msgid "review-kind" +msgstr "" + +# Default: Runtime +msgid "runtime" +msgstr "Laufzeit" + +# Default: Runtimes +msgid "runtimes" +msgstr "Laufzeiten" + +# Default: Salary history +msgid "salary-history" +msgstr "" + +# Default: Screenplay teleplay +msgid "screenplay-teleplay" +msgstr "" + +# Default: Season +msgid "season" +msgstr "" + +# Default: Second unit director or assistant director +msgid "second-unit-director-or-assistant-director" +msgstr "" + +# Default: Self +msgid "self" +msgstr "" + +# Default: Series animation department +msgid "series-animation-department" +msgstr "" + +# Default: Series art department +msgid "series-art-department" +msgstr "" + +# Default: Series assistant directors +msgid "series-assistant-directors" +msgstr "" + +# Default: Series camera department +msgid "series-camera-department" +msgstr "" + +# Default: Series casting department +msgid "series-casting-department" +msgstr "" + +# Default: Series cinematographers +msgid "series-cinematographers" +msgstr "" + +# Default: Series costume department +msgid "series-costume-department" +msgstr "" + +# Default: Series editorial department +msgid "series-editorial-department" +msgstr "" + +# Default: Series editors +msgid "series-editors" +msgstr "" + +# Default: Series make up department +msgid "series-make-up-department" +msgstr "" + +# Default: Series miscellaneous +msgid "series-miscellaneous" +msgstr "" + +# Default: Series music department +msgid "series-music-department" +msgstr "" + +# Default: Series producers +msgid "series-producers" +msgstr "" + +# Default: Series production designers +msgid "series-production-designers" +msgstr "" + +# Default: Series production managers +msgid "series-production-managers" +msgstr "" + +# Default: Series sound department +msgid "series-sound-department" +msgstr "" + +# Default: Series special effects department +msgid "series-special-effects-department" +msgstr "" + +# Default: Series stunts +msgid "series-stunts" +msgstr "" + +# Default: Series title +msgid "series-title" +msgstr "" + +# Default: Series transportation department +msgid "series-transportation-department" +msgstr "" + +# Default: Series visual effects department +msgid "series-visual-effects-department" +msgstr "" + +# Default: Series writers +msgid "series-writers" +msgstr "" + +# Default: Series years +msgid "series-years" +msgstr "" + +# Default: Set decoration +msgid "set-decoration" +msgstr "" + +# Default: Sharpness +msgid "sharpness" +msgstr "" + +# Default: Similar to +msgid "similar-to" +msgstr "" + +# Default: Smart canonical episode title +msgid "smart-canonical-episode-title" +msgstr "" + +# Default: Smart canonical series title +msgid "smart-canonical-series-title" +msgstr "" + +# Default: Smart canonical title +msgid "smart-canonical-title" +msgstr "" + +# Default: Smart long imdb canonical title +msgid "smart-long-imdb-canonical-title" +msgstr "" + +# Default: Sound clips +msgid "sound-clips" +msgstr "" + +# Default: Sound crew +msgid "sound-crew" +msgstr "" + +# Default: Sound encoding +msgid "sound-encoding" +msgstr "" + +# Default: Sound mix +msgid "sound-mix" +msgstr "" + +# Default: Soundtrack +msgid "soundtrack" +msgstr "" + +# Default: Spaciality +msgid "spaciality" +msgstr "" + +# Default: Special effects +msgid "special-effects" +msgstr "" + +# Default: Special effects companies +msgid "special-effects-companies" +msgstr "" + +# Default: Special effects department +msgid "special-effects-department" +msgstr "" + +# Default: Spin off +msgid "spin-off" +msgstr "" + +# Default: Spin off from +msgid "spin-off-from" +msgstr "" + +# Default: Spoofed in +msgid "spoofed-in" +msgstr "" + +# Default: Spoofs +msgid "spoofs" +msgstr "" + +# Default: Spouse +msgid "spouse" +msgstr "" + +# Default: Status of availablility +msgid "status-of-availablility" +msgstr "" + +# Default: Studio +msgid "studio" +msgstr "" + +# Default: Studios +msgid "studios" +msgstr "" + +# Default: Stunt performer +msgid "stunt-performer" +msgstr "" + +# Default: Stunts +msgid "stunts" +msgstr "" + +# Default: Subtitles +msgid "subtitles" +msgstr "Untertitel" + +# Default: Supplement +msgid "supplement" +msgstr "" + +# Default: Supplements +msgid "supplements" +msgstr "" + +# Default: Synopsis +msgid "synopsis" +msgstr "" + +# Default: Taglines +msgid "taglines" +msgstr "" + +# Default: Tech info +msgid "tech-info" +msgstr "" + +# Default: Thanks +msgid "thanks" +msgstr "Danke" + +# Default: Time +msgid "time" +msgstr "Zeit" + +# Default: Title +msgid "title" +msgstr "" + +# Default: Titles in this product +msgid "titles-in-this-product" +msgstr "" + +# Default: To +msgid "to" +msgstr "" + +# Default: Top 250 rank +msgid "top-250-rank" +msgstr "" + +# Default: Trade mark +msgid "trade-mark" +msgstr "" + +# Default: Transportation department +msgid "transportation-department" +msgstr "" + +# Default: Trivia +msgid "trivia" +msgstr "" + +# Default: Tv +msgid "tv" +msgstr "TV" + +# Default: Under license from +msgid "under-license-from" +msgstr "" + +# Default: Unknown link +msgid "unknown-link" +msgstr "" + +# Default: Upc +msgid "upc" +msgstr "" + +# Default: Version of +msgid "version-of" +msgstr "" + +# Default: Vhs +msgid "vhs" +msgstr "VHS" + +# Default: Video +msgid "video" +msgstr "Video" + +# Default: Video artifacts +msgid "video-artifacts" +msgstr "" + +# Default: Video clips +msgid "video-clips" +msgstr "" + +# Default: Video noise +msgid "video-noise" +msgstr "" + +# Default: Video quality +msgid "video-quality" +msgstr "" + +# Default: Video standard +msgid "video-standard" +msgstr "" + +# Default: Visual effects +msgid "visual-effects" +msgstr "" + +# Default: Votes +msgid "votes" +msgstr "" + +# Default: Votes distribution +msgid "votes-distribution" +msgstr "" + +# Default: Weekend gross +msgid "weekend-gross" +msgstr "" + +# Default: Where now +msgid "where-now" +msgstr "" + +# Default: With +msgid "with" +msgstr "" + +# Default: Writer +msgid "writer" +msgstr "Schreiber" + +# Default: Written by +msgid "written-by" +msgstr "" + +# Default: Year +msgid "year" +msgstr "Jahr" + +# Default: Zshops +msgid "zshops" +msgstr "" diff --git a/lib/imdb/locale/imdbpy-es.po b/lib/imdb/locale/imdbpy-es.po new file mode 100644 index 00000000..729903df --- /dev/null +++ b/lib/imdb/locale/imdbpy-es.po @@ -0,0 +1,1304 @@ +# Gettext message file for imdbpy +# Translators: +# strel , 2013 +msgid "" +msgstr "" +"Project-Id-Version: IMDbPY\n" +"Report-Msgid-Bugs-To: http://sourceforge.net/tracker/?group_id=105998&atid=642794\n" +"POT-Creation-Date: 2010-03-18 14:35+0000\n" +"PO-Revision-Date: 2013-03-11 17:18+0000\n" +"Last-Translator: strel \n" +"Language-Team: Spanish (http://www.transifex.com/projects/p/imdbpy/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Domain: imdbpy\n" +"Language: es\n" +"Language-Code: en\n" +"Language-Name: English\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Preferred-Encodings: utf-8\n" + +# Default: Actor +msgid "actor" +msgstr "actor" + +# Default: Actress +msgid "actress" +msgstr "actriz" + +# Default: Adaption +msgid "adaption" +msgstr "adaptación" + +# Default: Additional information +msgid "additional-information" +msgstr "información-adicional" + +# Default: Admissions +msgid "admissions" +msgstr "facturación" + +# Default: Agent address +msgid "agent-address" +msgstr "dirección-del-agente" + +# Default: Airing +msgid "airing" +msgstr "estreno-televisivo" + +# Default: Akas +msgid "akas" +msgstr "alias" + +# Default: Akas from release info +msgid "akas-from-release-info" +msgstr "alias-en-los-datos-de-publicación" + +# Default: All products +msgid "all-products" +msgstr "todos-los-productos" + +# Default: Alternate language version of +msgid "alternate-language-version-of" +msgstr "versión-con-distinto-idioma-de" + +# Default: Alternate versions +msgid "alternate-versions" +msgstr "versiones-distintas" + +# Default: Amazon reviews +msgid "amazon-reviews" +msgstr "revisiones-de-amazon" + +# Default: Analog left +msgid "analog-left" +msgstr "izquierda-analógico" + +# Default: Analog right +msgid "analog-right" +msgstr "análogo-derecha" + +# Default: Animation department +msgid "animation-department" +msgstr "departamento-de-animación" + +# Default: Archive footage +msgid "archive-footage" +msgstr "video-de-archivo" + +# Default: Arithmetic mean +msgid "arithmetic-mean" +msgstr "media-aritmética" + +# Default: Art department +msgid "art-department" +msgstr "departamento-artístico" + +# Default: Art direction +msgid "art-direction" +msgstr "dirección-artística" + +# Default: Art director +msgid "art-director" +msgstr "director-artístico" + +# Default: Article +msgid "article" +msgstr "artículo" + +# Default: Asin +msgid "asin" +msgstr "asin" + +# Default: Aspect ratio +msgid "aspect-ratio" +msgstr "relación-de-aspecto" + +# Default: Assigner +msgid "assigner" +msgstr "director" + +# Default: Assistant director +msgid "assistant-director" +msgstr "asistente-de-dirección" + +# Default: Auctions +msgid "auctions" +msgstr "subastas" + +# Default: Audio noise +msgid "audio-noise" +msgstr "audio-ruido" + +# Default: Audio quality +msgid "audio-quality" +msgstr "calidad-del-audio" + +# Default: Award +msgid "award" +msgstr "premio" + +# Default: Awards +msgid "awards" +msgstr "premios" + +# Default: Biographical movies +msgid "biographical-movies" +msgstr "películas-biográficas" + +# Default: Biography +msgid "biography" +msgstr "biografía" + +# Default: Biography print +msgid "biography-print" +msgstr "biografía-impresa" + +# Default: Birth date +msgid "birth-date" +msgstr "fecha-de-nacimiento" + +# Default: Birth name +msgid "birth-name" +msgstr "nombre-de-pila" + +# Default: Birth notes +msgid "birth-notes" +msgstr "notas-de-nacimiento" + +# Default: Body +msgid "body" +msgstr "cuerpo" + +# Default: Book +msgid "book" +msgstr "libro" + +# Default: Books +msgid "books" +msgstr "libros" + +# Default: Bottom 100 rank +msgid "bottom-100-rank" +msgstr "ranking-de-los-últimos-100" + +# Default: Budget +msgid "budget" +msgstr "presupuesto" + +# Default: Business +msgid "business" +msgstr "negocio" + +# Default: By arrangement with +msgid "by-arrangement-with" +msgstr "por-acuerdo-con" + +# Default: Camera +msgid "camera" +msgstr "cámara" + +# Default: Camera and electrical department +msgid "camera-and-electrical-department" +msgstr "departamento-de-cámara-y-eléctrico" + +# Default: Canonical episode title +msgid "canonical-episode-title" +msgstr "título-canónico-de-episodio" + +# Default: Canonical name +msgid "canonical-name" +msgstr "nombre-canónico" + +# Default: Canonical series title +msgid "canonical-series-title" +msgstr "título-canónico-de-serie" + +# Default: Canonical title +msgid "canonical-title" +msgstr "título-canónico" + +# Default: Cast +msgid "cast" +msgstr "selección" + +# Default: Casting department +msgid "casting-department" +msgstr "departamento-de-selección" + +# Default: Casting director +msgid "casting-director" +msgstr "director-de-selección" + +# Default: Catalog number +msgid "catalog-number" +msgstr "número-de-catálogo" + +# Default: Category +msgid "category" +msgstr "categoría" + +# Default: Certificate +msgid "certificate" +msgstr "certificado" + +# Default: Certificates +msgid "certificates" +msgstr "certificados" + +# Default: Certification +msgid "certification" +msgstr "certificación" + +# Default: Channel +msgid "channel" +msgstr "canal" + +# Default: Character +msgid "character" +msgstr "personaje" + +# Default: Cinematographer +msgid "cinematographer" +msgstr "técnico-de-cámara" + +# Default: Cinematographic process +msgid "cinematographic-process" +msgstr "proceso-de-rodaje" + +# Default: Close captions teletext ld g +msgid "close-captions-teletext-ld-g" +msgstr "cerrar-subtítulos-teletexto-ld-g" + +# Default: Color info +msgid "color-info" +msgstr "info-de-color" + +# Default: Color information +msgid "color-information" +msgstr "información-de-color" + +# Default: Color rendition +msgid "color-rendition" +msgstr "fidelidad-de-color" + +# Default: Company +msgid "company" +msgstr "compañía" + +# Default: Complete cast +msgid "complete-cast" +msgstr "selección-completa" + +# Default: Complete crew +msgid "complete-crew" +msgstr "equipo-completo" + +# Default: Composer +msgid "composer" +msgstr "compositor" + +# Default: Connections +msgid "connections" +msgstr "conexiones" + +# Default: Contrast +msgid "contrast" +msgstr "contraste" + +# Default: Copyright holder +msgid "copyright-holder" +msgstr "tenerdor-del-copyright" + +# Default: Costume department +msgid "costume-department" +msgstr "departamento-de-vestuario" + +# Default: Costume designer +msgid "costume-designer" +msgstr "diseñador-de-vestuario" + +# Default: Countries +msgid "countries" +msgstr "países" + +# Default: Country +msgid "country" +msgstr "país" + +# Default: Courtesy of +msgid "courtesy-of" +msgstr "cortesía-de" + +# Default: Cover +msgid "cover" +msgstr "cubierta" + +# Default: Cover url +msgid "cover-url" +msgstr "url-de-la-cubierta" + +# Default: Crazy credits +msgid "crazy-credits" +msgstr "créditos-locos" + +# Default: Creator +msgid "creator" +msgstr "creador" + +# Default: Current role +msgid "current-role" +msgstr "papel-actual" + +# Default: Database +msgid "database" +msgstr "base-de-datos" + +# Default: Date +msgid "date" +msgstr "fecha" + +# Default: Death date +msgid "death-date" +msgstr "fecha-de-fallecimiento" + +# Default: Death notes +msgid "death-notes" +msgstr "notas-de-fallecimiento" + +# Default: Demographic +msgid "demographic" +msgstr "demografía" + +# Default: Description +msgid "description" +msgstr "descripción" + +# Default: Dialogue intellegibility +msgid "dialogue-intellegibility" +msgstr "diálogo-inteligible" + +# Default: Digital sound +msgid "digital-sound" +msgstr "sonido-digital" + +# Default: Director +msgid "director" +msgstr "director" + +# Default: Disc format +msgid "disc-format" +msgstr "formato-de-disco" + +# Default: Disc size +msgid "disc-size" +msgstr "tamaño-de-disco" + +# Default: Distributors +msgid "distributors" +msgstr "distribuidor" + +# Default: Dvd +msgid "dvd" +msgstr "dvd" + +# Default: Dvd features +msgid "dvd-features" +msgstr "características-de-dvd" + +# Default: Dvd format +msgid "dvd-format" +msgstr "formato-de-dvd" + +# Default: Dvds +msgid "dvds" +msgstr "dvds" + +# Default: Dynamic range +msgid "dynamic-range" +msgstr "rango-dinámico" + +# Default: Edited from +msgid "edited-from" +msgstr "editado-desde" + +# Default: Edited into +msgid "edited-into" +msgstr "editado-a" + +# Default: Editor +msgid "editor" +msgstr "editor" + +# Default: Editorial department +msgid "editorial-department" +msgstr "departamento-editorial" + +# Default: Episode +msgid "episode" +msgstr "episodio" + +# Default: Episode of +msgid "episode-of" +msgstr "episodio-de" + +# Default: Episode title +msgid "episode-title" +msgstr "título-del-episodio" + +# Default: Episodes +msgid "episodes" +msgstr "episodios" + +# Default: Episodes rating +msgid "episodes-rating" +msgstr "valoración-de-episodios" + +# Default: Essays +msgid "essays" +msgstr "ensayos" + +# Default: External reviews +msgid "external-reviews" +msgstr "reseñas-externas" + +# Default: Faqs +msgid "faqs" +msgstr "faqs-(preguntas-frecuentes)" + +# Default: Feature +msgid "feature" +msgstr "aparición" + +# Default: Featured in +msgid "featured-in" +msgstr "aparecido-en" + +# Default: Features +msgid "features" +msgstr "apariciones" + +# Default: Film negative format +msgid "film-negative-format" +msgstr "formato-de-negativo-de-película" + +# Default: Filming dates +msgid "filming-dates" +msgstr "fechas-de-filmación" + +# Default: Filmography +msgid "filmography" +msgstr "filmografía" + +# Default: Followed by +msgid "followed-by" +msgstr "seguido-por" + +# Default: Follows +msgid "follows" +msgstr "sigue-a" + +# Default: For +msgid "for" +msgstr "para" + +# Default: Frequency response +msgid "frequency-response" +msgstr "respuesta-de-frecuencia" + +# Default: From +msgid "from" +msgstr "desde" + +# Default: Full article link +msgid "full-article-link" +msgstr "enlace-al-artículo-completo" + +# Default: Full size cover url +msgid "full-size-cover-url" +msgstr "url-a-la-caratula-de-tamaño-completo" + +# Default: Full size headshot +msgid "full-size-headshot" +msgstr "retrato-de-tamaño-completo" + +# Default: Genres +msgid "genres" +msgstr "géneros" + +# Default: Goofs +msgid "goofs" +msgstr "gazapos" + +# Default: Gross +msgid "gross" +msgstr "recaudación-bruta" + +# Default: Group genre +msgid "group-genre" +msgstr "género-del-grupo" + +# Default: Headshot +msgid "headshot" +msgstr "retrato" + +# Default: Height +msgid "height" +msgstr "altura" + +# Default: Imdbindex +msgid "imdbindex" +msgstr "íncide-imdb" + +# Default: In development +msgid "in-development" +msgstr "en-desarrollo" + +# Default: Interview +msgid "interview" +msgstr "entrevista" + +# Default: Interviews +msgid "interviews" +msgstr "entrevistas" + +# Default: Introduction +msgid "introduction" +msgstr "introducción" + +# Default: Item +msgid "item" +msgstr "elemento" + +# Default: Keywords +msgid "keywords" +msgstr "contraseñas" + +# Default: Kind +msgid "kind" +msgstr "clase" + +# Default: Label +msgid "label" +msgstr "etiqueta" + +# Default: Laboratory +msgid "laboratory" +msgstr "laboratorio" + +# Default: Language +msgid "language" +msgstr "idioma" + +# Default: Languages +msgid "languages" +msgstr "idiomas" + +# Default: Laserdisc +msgid "laserdisc" +msgstr "laserdisc" + +# Default: Laserdisc title +msgid "laserdisc-title" +msgstr "título-del-laserdisc" + +# Default: Length +msgid "length" +msgstr "duración" + +# Default: Line +msgid "line" +msgstr "línea" + +# Default: Link +msgid "link" +msgstr "enlace" + +# Default: Link text +msgid "link-text" +msgstr "texto-del-enlace" + +# Default: Literature +msgid "literature" +msgstr "escritos" + +# Default: Locations +msgid "locations" +msgstr "localizaciones" + +# Default: Long imdb canonical name +msgid "long-imdb-canonical-name" +msgstr "nombre-canónico-largo-de-imdb" + +# Default: Long imdb canonical title +msgid "long-imdb-canonical-title" +msgstr "título-canónico-largo-de-imdb" + +# Default: Long imdb episode title +msgid "long-imdb-episode-title" +msgstr "título-largo-de-episodio-de-imdb" + +# Default: Long imdb name +msgid "long-imdb-name" +msgstr "nombre-largo-de-imdb" + +# Default: Long imdb title +msgid "long-imdb-title" +msgstr "título-largo-de-imdb" + +# Default: Magazine cover photo +msgid "magazine-cover-photo" +msgstr "foto-de-cubierta-de-magazine" + +# Default: Make up +msgid "make-up" +msgstr "maquillaje" + +# Default: Master format +msgid "master-format" +msgstr "formato-maestro" + +# Default: Median +msgid "median" +msgstr "mediana" + +# Default: Merchandising links +msgid "merchandising-links" +msgstr "enlaces-de-merchandising" + +# Default: Mini biography +msgid "mini-biography" +msgstr "mini-biografía" + +# Default: Misc links +msgid "misc-links" +msgstr "enlaces-varios" + +# Default: Miscellaneous companies +msgid "miscellaneous-companies" +msgstr "compañías-varias" + +# Default: Miscellaneous crew +msgid "miscellaneous-crew" +msgstr "personal-vario" + +# Default: Movie +msgid "movie" +msgstr "película" + +# Default: Mpaa +msgid "mpaa" +msgstr "mpaa" + +# Default: Music department +msgid "music-department" +msgstr "departamento-musical" + +# Default: Name +msgid "name" +msgstr "nombre" + +# Default: News +msgid "news" +msgstr "noticias" + +# Default: Newsgroup reviews +msgid "newsgroup-reviews" +msgstr "reseñas-de-grupos-de-noticias" + +# Default: Nick names +msgid "nick-names" +msgstr "apodos" + +# Default: Notes +msgid "notes" +msgstr "notas" + +# Default: Novel +msgid "novel" +msgstr "novela" + +# Default: Number +msgid "number" +msgstr "número" + +# Default: Number of chapter stops +msgid "number-of-chapter-stops" +msgstr "número-de-pausas-del-capítulo" + +# Default: Number of episodes +msgid "number-of-episodes" +msgstr "número-de-episodios" + +# Default: Number of seasons +msgid "number-of-seasons" +msgstr "número-de-temporadas" + +# Default: Number of sides +msgid "number-of-sides" +msgstr "número-de-caras" + +# Default: Number of votes +msgid "number-of-votes" +msgstr "número-de-votos" + +# Default: Official retail price +msgid "official-retail-price" +msgstr "precio-minorista-oficial" + +# Default: Official sites +msgid "official-sites" +msgstr "sitios-oficiales" + +# Default: Opening weekend +msgid "opening-weekend" +msgstr "fin-de-semana-inaugural" + +# Default: Original air date +msgid "original-air-date" +msgstr "fecha-de-emisión-original" + +# Default: Original music +msgid "original-music" +msgstr "música-original" + +# Default: Original title +msgid "original-title" +msgstr "título-original" + +# Default: Other literature +msgid "other-literature" +msgstr "otros-escritos" + +# Default: Other works +msgid "other-works" +msgstr "otros-trabajos" + +# Default: Parents guide +msgid "parents-guide" +msgstr "guía-parental" + +# Default: Performed by +msgid "performed-by" +msgstr "interpretado-por" + +# Default: Person +msgid "person" +msgstr "persona" + +# Default: Photo sites +msgid "photo-sites" +msgstr "lugares-fotografiados" + +# Default: Pictorial +msgid "pictorial" +msgstr "reportaje-fotográfico" + +# Default: Picture format +msgid "picture-format" +msgstr "formato-de-fotografía" + +# Default: Plot +msgid "plot" +msgstr "trama" + +# Default: Plot outline +msgid "plot-outline" +msgstr "resumen-de-la-trama" + +# Default: Portrayed in +msgid "portrayed-in" +msgstr "representado-en" + +# Default: Pressing plant +msgid "pressing-plant" +msgstr "fábrica-de-copias" + +# Default: Printed film format +msgid "printed-film-format" +msgstr "formato-de-película-impresa" + +# Default: Printed media reviews +msgid "printed-media-reviews" +msgstr "reseñas-en-medios-escritos" + +# Default: Producer +msgid "producer" +msgstr "productor" + +# Default: Production companies +msgid "production-companies" +msgstr "compañías-de-la-producción" + +# Default: Production country +msgid "production-country" +msgstr "país-de-la-producción" + +# Default: Production dates +msgid "production-dates" +msgstr "fechas-de-producción" + +# Default: Production design +msgid "production-design" +msgstr "diseño-de-producción" + +# Default: Production designer +msgid "production-designer" +msgstr "diseñador-de-producción" + +# Default: Production manager +msgid "production-manager" +msgstr "director-de-producción" + +# Default: Production process protocol +msgid "production-process-protocol" +msgstr "protocolo-de-proceso-de-producción" + +# Default: Quality of source +msgid "quality-of-source" +msgstr "calidad-del-original" + +# Default: Quality program +msgid "quality-program" +msgstr "programa-de-calidad" + +# Default: Quote +msgid "quote" +msgstr "cita" + +# Default: Quotes +msgid "quotes" +msgstr "citas" + +# Default: Rating +msgid "rating" +msgstr "valoración" + +# Default: Recommendations +msgid "recommendations" +msgstr "recomendaciones" + +# Default: Referenced in +msgid "referenced-in" +msgstr "referenciado-en" + +# Default: References +msgid "references" +msgstr "referencias" + +# Default: Region +msgid "region" +msgstr "región" + +# Default: Release country +msgid "release-country" +msgstr "país-de-estreno" + +# Default: Release date +msgid "release-date" +msgstr "fecha-de-estreno" + +# Default: Release dates +msgid "release-dates" +msgstr "fechas-de-estreno" + +# Default: Remade as +msgid "remade-as" +msgstr "reversionado-como" + +# Default: Remake of +msgid "remake-of" +msgstr "refrito-de" + +# Default: Rentals +msgid "rentals" +msgstr "recaudación-por-alquileres" + +# Default: Result +msgid "result" +msgstr "resultado" + +# Default: Review +msgid "review" +msgstr "reseña" + +# Default: Review author +msgid "review-author" +msgstr "autor-de-la-reseña" + +# Default: Review kind +msgid "review-kind" +msgstr "tipo-de-reseña" + +# Default: Runtime +msgid "runtime" +msgstr "duración" + +# Default: Runtimes +msgid "runtimes" +msgstr "duraciones" + +# Default: Salary history +msgid "salary-history" +msgstr "historial-salarial" + +# Default: Screenplay teleplay +msgid "screenplay-teleplay" +msgstr "guiones-cinematrográfico-y-televisivo" + +# Default: Season +msgid "season" +msgstr "temporada" + +# Default: Second unit director or assistant director +msgid "second-unit-director-or-assistant-director" +msgstr "segundo-director-de-unidad-o-asistente-de-dirección" + +# Default: Self +msgid "self" +msgstr "auto" + +# Default: Series animation department +msgid "series-animation-department" +msgstr "departamento-de-animación-de-la-serie" + +# Default: Series art department +msgid "series-art-department" +msgstr "departamento-artístico-de-la-serie" + +# Default: Series assistant directors +msgid "series-assistant-directors" +msgstr "asistentes-de-dirección-de-la-serie" + +# Default: Series camera department +msgid "series-camera-department" +msgstr "departamento-de-cámaras-de-la-serie" + +# Default: Series casting department +msgid "series-casting-department" +msgstr "departamento-de-selección-de-la-serie" + +# Default: Series cinematographers +msgid "series-cinematographers" +msgstr "técnicos-de-cámara-de-la-serie" + +# Default: Series costume department +msgid "series-costume-department" +msgstr "departamento-de-vestuario-de-la-serie" + +# Default: Series editorial department +msgid "series-editorial-department" +msgstr "departamento-editorial-de-la-serie" + +# Default: Series editors +msgid "series-editors" +msgstr "editores-de-la-serie" + +# Default: Series make up department +msgid "series-make-up-department" +msgstr "departamento-de-maquillaje-de-la-serie" + +# Default: Series miscellaneous +msgid "series-miscellaneous" +msgstr "series-varias" + +# Default: Series music department +msgid "series-music-department" +msgstr "departamento-musical-de-la-serie" + +# Default: Series producers +msgid "series-producers" +msgstr "productores-de-la-serie" + +# Default: Series production designers +msgid "series-production-designers" +msgstr "diseñadores-de-producción-de-la-serie" + +# Default: Series production managers +msgid "series-production-managers" +msgstr "directores-de-producción-de-la-serie" + +# Default: Series sound department +msgid "series-sound-department" +msgstr "departamento-de-sonido-de-la-serie" + +# Default: Series special effects department +msgid "series-special-effects-department" +msgstr "departamento-de-efectos-especiales-de-la-serie" + +# Default: Series stunts +msgid "series-stunts" +msgstr "acrobacias-de-la-serie" + +# Default: Series title +msgid "series-title" +msgstr "título" + +# Default: Series transportation department +msgid "series-transportation-department" +msgstr "departamento-de-transporte-de-la-serie" + +# Default: Series visual effects department +msgid "series-visual-effects-department" +msgstr "departamento-de-efectos-visuales-de-la-serie" + +# Default: Series writers +msgid "series-writers" +msgstr "guionistas-de-la-serie" + +# Default: Series years +msgid "series-years" +msgstr "años-de-la-serie" + +# Default: Set decoration +msgid "set-decoration" +msgstr "decoración-del-set" + +# Default: Sharpness +msgid "sharpness" +msgstr "agudeza" + +# Default: Similar to +msgid "similar-to" +msgstr "similar-a" + +# Default: Smart canonical episode title +msgid "smart-canonical-episode-title" +msgstr "título-canónico-inteligente-del-episodio" + +# Default: Smart canonical series title +msgid "smart-canonical-series-title" +msgstr "título-canónico-inteligente-de-la-serie" + +# Default: Smart canonical title +msgid "smart-canonical-title" +msgstr "título-canónico-inteligente" + +# Default: Smart long imdb canonical title +msgid "smart-long-imdb-canonical-title" +msgstr "título-canónico-inteligente-largo-de-imdb" + +# Default: Sound clips +msgid "sound-clips" +msgstr "audio-clips" + +# Default: Sound crew +msgid "sound-crew" +msgstr "equipo-de-audio" + +# Default: Sound encoding +msgid "sound-encoding" +msgstr "compresión-de-audio" + +# Default: Sound mix +msgid "sound-mix" +msgstr "mezcla-de-audio" + +# Default: Soundtrack +msgid "soundtrack" +msgstr "banda-sonora" + +# Default: Spaciality +msgid "spaciality" +msgstr "espacialidad" + +# Default: Special effects +msgid "special-effects" +msgstr "efectos-especiales" + +# Default: Special effects companies +msgid "special-effects-companies" +msgstr "compañías-de-efectos-especiales" + +# Default: Special effects department +msgid "special-effects-department" +msgstr "departamento-de-efectos-especiales" + +# Default: Spin off +msgid "spin-off" +msgstr "secuela" + +# Default: Spin off from +msgid "spin-off-from" +msgstr "secuela-de" + +# Default: Spoofed in +msgid "spoofed-in" +msgstr "paradiado-en" + +# Default: Spoofs +msgid "spoofs" +msgstr "parodias" + +# Default: Spouse +msgid "spouse" +msgstr "esposa" + +# Default: Status of availablility +msgid "status-of-availablility" +msgstr "estado-de-disponibilidad" + +# Default: Studio +msgid "studio" +msgstr "estudio" + +# Default: Studios +msgid "studios" +msgstr "estudios" + +# Default: Stunt performer +msgid "stunt-performer" +msgstr "especialista-de-acrobacias" + +# Default: Stunts +msgid "stunts" +msgstr "acrobacias" + +# Default: Subtitles +msgid "subtitles" +msgstr "subtítulos" + +# Default: Supplement +msgid "supplement" +msgstr "suplemento" + +# Default: Supplements +msgid "supplements" +msgstr "suplementos" + +# Default: Synopsis +msgid "synopsis" +msgstr "sinopsis" + +# Default: Taglines +msgid "taglines" +msgstr "eslogan" + +# Default: Tech info +msgid "tech-info" +msgstr "información-técnica" + +# Default: Thanks +msgid "thanks" +msgstr "gracias" + +# Default: Time +msgid "time" +msgstr "hora" + +# Default: Title +msgid "title" +msgstr "título" + +# Default: Titles in this product +msgid "titles-in-this-product" +msgstr "títulos-en-este-producto" + +# Default: To +msgid "to" +msgstr "a" + +# Default: Top 250 rank +msgid "top-250-rank" +msgstr "primeros-250-de-la-clasificación" + +# Default: Trade mark +msgid "trade-mark" +msgstr "marca-registrada" + +# Default: Transportation department +msgid "transportation-department" +msgstr "departamento-de-transporte" + +# Default: Trivia +msgid "trivia" +msgstr "curiosidades" + +# Default: Tv +msgid "tv" +msgstr "tv" + +# Default: Under license from +msgid "under-license-from" +msgstr "bajo-licencia-de" + +# Default: Unknown link +msgid "unknown-link" +msgstr "enlace-desconocido" + +# Default: Upc +msgid "upc" +msgstr "upc" + +# Default: Version of +msgid "version-of" +msgstr "versión-de" + +# Default: Vhs +msgid "vhs" +msgstr "vhs" + +# Default: Video +msgid "video" +msgstr "vídeo" + +# Default: Video artifacts +msgid "video-artifacts" +msgstr "efectos-de-vídeo" + +# Default: Video clips +msgid "video-clips" +msgstr "vídeo-clips" + +# Default: Video noise +msgid "video-noise" +msgstr "vídeo-ruido" + +# Default: Video quality +msgid "video-quality" +msgstr "calidad-de-vídeo" + +# Default: Video standard +msgid "video-standard" +msgstr "estandar-de-vídeo" + +# Default: Visual effects +msgid "visual-effects" +msgstr "efectos-visuales" + +# Default: Votes +msgid "votes" +msgstr "votos" + +# Default: Votes distribution +msgid "votes-distribution" +msgstr "distribución-de-votos" + +# Default: Weekend gross +msgid "weekend-gross" +msgstr "recaudación-bruta-del-fin-de-semana" + +# Default: Where now +msgid "where-now" +msgstr "dónde-está-ahora" + +# Default: With +msgid "with" +msgstr "con" + +# Default: Writer +msgid "writer" +msgstr "escritor" + +# Default: Written by +msgid "written-by" +msgstr "escrito-por" + +# Default: Year +msgid "year" +msgstr "año" + +# Default: Zshops +msgid "zshops" +msgstr "amazon-zshops" diff --git a/lib/imdb/locale/imdbpy-fr.po b/lib/imdb/locale/imdbpy-fr.po new file mode 100644 index 00000000..c4509c99 --- /dev/null +++ b/lib/imdb/locale/imdbpy-fr.po @@ -0,0 +1,1304 @@ +# Gettext message file for imdbpy +# Translators: +# RainDropR , 2013 +# Stéphane Aulery, 2012 +msgid "" +msgstr "" +"Project-Id-Version: IMDbPY\n" +"POT-Creation-Date: 2010-03-18 14:35+0000\n" +"PO-Revision-Date: 2013-11-20 11:07+0000\n" +"Last-Translator: RainDropR \n" +"Language-Team: French (http://www.transifex.com/projects/p/imdbpy/language/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Domain: imdbpy\n" +"Language: fr\n" +"Language-Code: en\n" +"Language-Name: English\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Preferred-Encodings: utf-8\n" + +# Default: Actor +msgid "actor" +msgstr "acteur" + +# Default: Actress +msgid "actress" +msgstr "actrice" + +# Default: Adaption +msgid "adaption" +msgstr "adaptation" + +# Default: Additional information +msgid "additional-information" +msgstr "" + +# Default: Admissions +msgid "admissions" +msgstr "" + +# Default: Agent address +msgid "agent-address" +msgstr "" + +# Default: Airing +msgid "airing" +msgstr "" + +# Default: Akas +msgid "akas" +msgstr "" + +# Default: Akas from release info +msgid "akas-from-release-info" +msgstr "" + +# Default: All products +msgid "all-products" +msgstr "" + +# Default: Alternate language version of +msgid "alternate-language-version-of" +msgstr "" + +# Default: Alternate versions +msgid "alternate-versions" +msgstr "" + +# Default: Amazon reviews +msgid "amazon-reviews" +msgstr "" + +# Default: Analog left +msgid "analog-left" +msgstr "" + +# Default: Analog right +msgid "analog-right" +msgstr "" + +# Default: Animation department +msgid "animation-department" +msgstr "" + +# Default: Archive footage +msgid "archive-footage" +msgstr "" + +# Default: Arithmetic mean +msgid "arithmetic-mean" +msgstr "" + +# Default: Art department +msgid "art-department" +msgstr "" + +# Default: Art direction +msgid "art-direction" +msgstr "" + +# Default: Art director +msgid "art-director" +msgstr "" + +# Default: Article +msgid "article" +msgstr "article" + +# Default: Asin +msgid "asin" +msgstr "asin" + +# Default: Aspect ratio +msgid "aspect-ratio" +msgstr "" + +# Default: Assigner +msgid "assigner" +msgstr "" + +# Default: Assistant director +msgid "assistant-director" +msgstr "" + +# Default: Auctions +msgid "auctions" +msgstr "" + +# Default: Audio noise +msgid "audio-noise" +msgstr "" + +# Default: Audio quality +msgid "audio-quality" +msgstr "" + +# Default: Award +msgid "award" +msgstr "récompense" + +# Default: Awards +msgid "awards" +msgstr "récompenses" + +# Default: Biographical movies +msgid "biographical-movies" +msgstr "" + +# Default: Biography +msgid "biography" +msgstr "biographie" + +# Default: Biography print +msgid "biography-print" +msgstr "" + +# Default: Birth date +msgid "birth-date" +msgstr "" + +# Default: Birth name +msgid "birth-name" +msgstr "" + +# Default: Birth notes +msgid "birth-notes" +msgstr "" + +# Default: Body +msgid "body" +msgstr "Corps" + +# Default: Book +msgid "book" +msgstr "livre" + +# Default: Books +msgid "books" +msgstr "vres" + +# Default: Bottom 100 rank +msgid "bottom-100-rank" +msgstr "" + +# Default: Budget +msgid "budget" +msgstr "budget" + +# Default: Business +msgid "business" +msgstr "" + +# Default: By arrangement with +msgid "by-arrangement-with" +msgstr "" + +# Default: Camera +msgid "camera" +msgstr "camera" + +# Default: Camera and electrical department +msgid "camera-and-electrical-department" +msgstr "" + +# Default: Canonical episode title +msgid "canonical-episode-title" +msgstr "" + +# Default: Canonical name +msgid "canonical-name" +msgstr "" + +# Default: Canonical series title +msgid "canonical-series-title" +msgstr "" + +# Default: Canonical title +msgid "canonical-title" +msgstr "" + +# Default: Cast +msgid "cast" +msgstr "" + +# Default: Casting department +msgid "casting-department" +msgstr "" + +# Default: Casting director +msgid "casting-director" +msgstr "" + +# Default: Catalog number +msgid "catalog-number" +msgstr "" + +# Default: Category +msgid "category" +msgstr "catégorie" + +# Default: Certificate +msgid "certificate" +msgstr "certificat" + +# Default: Certificates +msgid "certificates" +msgstr "" + +# Default: Certification +msgid "certification" +msgstr "" + +# Default: Channel +msgid "channel" +msgstr "chaîne" + +# Default: Character +msgid "character" +msgstr "" + +# Default: Cinematographer +msgid "cinematographer" +msgstr "" + +# Default: Cinematographic process +msgid "cinematographic-process" +msgstr "" + +# Default: Close captions teletext ld g +msgid "close-captions-teletext-ld-g" +msgstr "" + +# Default: Color info +msgid "color-info" +msgstr "" + +# Default: Color information +msgid "color-information" +msgstr "" + +# Default: Color rendition +msgid "color-rendition" +msgstr "" + +# Default: Company +msgid "company" +msgstr "société" + +# Default: Complete cast +msgid "complete-cast" +msgstr "" + +# Default: Complete crew +msgid "complete-crew" +msgstr "" + +# Default: Composer +msgid "composer" +msgstr "" + +# Default: Connections +msgid "connections" +msgstr "" + +# Default: Contrast +msgid "contrast" +msgstr "" + +# Default: Copyright holder +msgid "copyright-holder" +msgstr "" + +# Default: Costume department +msgid "costume-department" +msgstr "" + +# Default: Costume designer +msgid "costume-designer" +msgstr "" + +# Default: Countries +msgid "countries" +msgstr "pays" + +# Default: Country +msgid "country" +msgstr "pays" + +# Default: Courtesy of +msgid "courtesy-of" +msgstr "" + +# Default: Cover +msgid "cover" +msgstr "couverture" + +# Default: Cover url +msgid "cover-url" +msgstr "" + +# Default: Crazy credits +msgid "crazy-credits" +msgstr "" + +# Default: Creator +msgid "creator" +msgstr "créateur" + +# Default: Current role +msgid "current-role" +msgstr "" + +# Default: Database +msgid "database" +msgstr "base de données" + +# Default: Date +msgid "date" +msgstr "date" + +# Default: Death date +msgid "death-date" +msgstr "" + +# Default: Death notes +msgid "death-notes" +msgstr "" + +# Default: Demographic +msgid "demographic" +msgstr "" + +# Default: Description +msgid "description" +msgstr "description" + +# Default: Dialogue intellegibility +msgid "dialogue-intellegibility" +msgstr "" + +# Default: Digital sound +msgid "digital-sound" +msgstr "" + +# Default: Director +msgid "director" +msgstr "directeur" + +# Default: Disc format +msgid "disc-format" +msgstr "" + +# Default: Disc size +msgid "disc-size" +msgstr "" + +# Default: Distributors +msgid "distributors" +msgstr "distributeurs" + +# Default: Dvd +msgid "dvd" +msgstr "dvd" + +# Default: Dvd features +msgid "dvd-features" +msgstr "" + +# Default: Dvd format +msgid "dvd-format" +msgstr "" + +# Default: Dvds +msgid "dvds" +msgstr "dvds" + +# Default: Dynamic range +msgid "dynamic-range" +msgstr "" + +# Default: Edited from +msgid "edited-from" +msgstr "" + +# Default: Edited into +msgid "edited-into" +msgstr "" + +# Default: Editor +msgid "editor" +msgstr "éditeur" + +# Default: Editorial department +msgid "editorial-department" +msgstr "" + +# Default: Episode +msgid "episode" +msgstr "épisode" + +# Default: Episode of +msgid "episode-of" +msgstr "" + +# Default: Episode title +msgid "episode-title" +msgstr "" + +# Default: Episodes +msgid "episodes" +msgstr "épisodes" + +# Default: Episodes rating +msgid "episodes-rating" +msgstr "" + +# Default: Essays +msgid "essays" +msgstr "" + +# Default: External reviews +msgid "external-reviews" +msgstr "" + +# Default: Faqs +msgid "faqs" +msgstr "faqs" + +# Default: Feature +msgid "feature" +msgstr "Caractéristique" + +# Default: Featured in +msgid "featured-in" +msgstr "" + +# Default: Features +msgid "features" +msgstr "caractéristiques" + +# Default: Film negative format +msgid "film-negative-format" +msgstr "" + +# Default: Filming dates +msgid "filming-dates" +msgstr "" + +# Default: Filmography +msgid "filmography" +msgstr "" + +# Default: Followed by +msgid "followed-by" +msgstr "" + +# Default: Follows +msgid "follows" +msgstr "" + +# Default: For +msgid "for" +msgstr "pour" + +# Default: Frequency response +msgid "frequency-response" +msgstr "" + +# Default: From +msgid "from" +msgstr "de" + +# Default: Full article link +msgid "full-article-link" +msgstr "" + +# Default: Full size cover url +msgid "full-size-cover-url" +msgstr "" + +# Default: Full size headshot +msgid "full-size-headshot" +msgstr "" + +# Default: Genres +msgid "genres" +msgstr "genres" + +# Default: Goofs +msgid "goofs" +msgstr "" + +# Default: Gross +msgid "gross" +msgstr "" + +# Default: Group genre +msgid "group-genre" +msgstr "" + +# Default: Headshot +msgid "headshot" +msgstr "" + +# Default: Height +msgid "height" +msgstr "hauteur" + +# Default: Imdbindex +msgid "imdbindex" +msgstr "" + +# Default: In development +msgid "in-development" +msgstr "" + +# Default: Interview +msgid "interview" +msgstr "interview" + +# Default: Interviews +msgid "interviews" +msgstr "" + +# Default: Introduction +msgid "introduction" +msgstr "introduction" + +# Default: Item +msgid "item" +msgstr "élément" + +# Default: Keywords +msgid "keywords" +msgstr "" + +# Default: Kind +msgid "kind" +msgstr "" + +# Default: Label +msgid "label" +msgstr "" + +# Default: Laboratory +msgid "laboratory" +msgstr "laboratoire" + +# Default: Language +msgid "language" +msgstr "langue" + +# Default: Languages +msgid "languages" +msgstr "langues" + +# Default: Laserdisc +msgid "laserdisc" +msgstr "" + +# Default: Laserdisc title +msgid "laserdisc-title" +msgstr "" + +# Default: Length +msgid "length" +msgstr "" + +# Default: Line +msgid "line" +msgstr "ligne" + +# Default: Link +msgid "link" +msgstr "lien" + +# Default: Link text +msgid "link-text" +msgstr "" + +# Default: Literature +msgid "literature" +msgstr "" + +# Default: Locations +msgid "locations" +msgstr "" + +# Default: Long imdb canonical name +msgid "long-imdb-canonical-name" +msgstr "" + +# Default: Long imdb canonical title +msgid "long-imdb-canonical-title" +msgstr "" + +# Default: Long imdb episode title +msgid "long-imdb-episode-title" +msgstr "" + +# Default: Long imdb name +msgid "long-imdb-name" +msgstr "" + +# Default: Long imdb title +msgid "long-imdb-title" +msgstr "" + +# Default: Magazine cover photo +msgid "magazine-cover-photo" +msgstr "" + +# Default: Make up +msgid "make-up" +msgstr "" + +# Default: Master format +msgid "master-format" +msgstr "" + +# Default: Median +msgid "median" +msgstr "" + +# Default: Merchandising links +msgid "merchandising-links" +msgstr "" + +# Default: Mini biography +msgid "mini-biography" +msgstr "" + +# Default: Misc links +msgid "misc-links" +msgstr "" + +# Default: Miscellaneous companies +msgid "miscellaneous-companies" +msgstr "" + +# Default: Miscellaneous crew +msgid "miscellaneous-crew" +msgstr "" + +# Default: Movie +msgid "movie" +msgstr "film" + +# Default: Mpaa +msgid "mpaa" +msgstr "mpaa" + +# Default: Music department +msgid "music-department" +msgstr "" + +# Default: Name +msgid "name" +msgstr "nom" + +# Default: News +msgid "news" +msgstr "actualisé" + +# Default: Newsgroup reviews +msgid "newsgroup-reviews" +msgstr "" + +# Default: Nick names +msgid "nick-names" +msgstr "" + +# Default: Notes +msgid "notes" +msgstr "notesnouvelle" + +# Default: Novel +msgid "novel" +msgstr "nouvelle" + +# Default: Number +msgid "number" +msgstr "numéro" + +# Default: Number of chapter stops +msgid "number-of-chapter-stops" +msgstr "" + +# Default: Number of episodes +msgid "number-of-episodes" +msgstr "" + +# Default: Number of seasons +msgid "number-of-seasons" +msgstr "" + +# Default: Number of sides +msgid "number-of-sides" +msgstr "" + +# Default: Number of votes +msgid "number-of-votes" +msgstr "" + +# Default: Official retail price +msgid "official-retail-price" +msgstr "" + +# Default: Official sites +msgid "official-sites" +msgstr "" + +# Default: Opening weekend +msgid "opening-weekend" +msgstr "" + +# Default: Original air date +msgid "original-air-date" +msgstr "" + +# Default: Original music +msgid "original-music" +msgstr "" + +# Default: Original title +msgid "original-title" +msgstr "" + +# Default: Other literature +msgid "other-literature" +msgstr "" + +# Default: Other works +msgid "other-works" +msgstr "" + +# Default: Parents guide +msgid "parents-guide" +msgstr "" + +# Default: Performed by +msgid "performed-by" +msgstr "" + +# Default: Person +msgid "person" +msgstr "" + +# Default: Photo sites +msgid "photo-sites" +msgstr "" + +# Default: Pictorial +msgid "pictorial" +msgstr "" + +# Default: Picture format +msgid "picture-format" +msgstr "" + +# Default: Plot +msgid "plot" +msgstr "" + +# Default: Plot outline +msgid "plot-outline" +msgstr "" + +# Default: Portrayed in +msgid "portrayed-in" +msgstr "" + +# Default: Pressing plant +msgid "pressing-plant" +msgstr "" + +# Default: Printed film format +msgid "printed-film-format" +msgstr "" + +# Default: Printed media reviews +msgid "printed-media-reviews" +msgstr "" + +# Default: Producer +msgid "producer" +msgstr "producteur" + +# Default: Production companies +msgid "production-companies" +msgstr "" + +# Default: Production country +msgid "production-country" +msgstr "" + +# Default: Production dates +msgid "production-dates" +msgstr "" + +# Default: Production design +msgid "production-design" +msgstr "" + +# Default: Production designer +msgid "production-designer" +msgstr "" + +# Default: Production manager +msgid "production-manager" +msgstr "" + +# Default: Production process protocol +msgid "production-process-protocol" +msgstr "" + +# Default: Quality of source +msgid "quality-of-source" +msgstr "" + +# Default: Quality program +msgid "quality-program" +msgstr "" + +# Default: Quote +msgid "quote" +msgstr "citation" + +# Default: Quotes +msgid "quotes" +msgstr "citations" + +# Default: Rating +msgid "rating" +msgstr "" + +# Default: Recommendations +msgid "recommendations" +msgstr "" + +# Default: Referenced in +msgid "referenced-in" +msgstr "" + +# Default: References +msgid "references" +msgstr "références" + +# Default: Region +msgid "region" +msgstr "" + +# Default: Release country +msgid "release-country" +msgstr "" + +# Default: Release date +msgid "release-date" +msgstr "" + +# Default: Release dates +msgid "release-dates" +msgstr "" + +# Default: Remade as +msgid "remade-as" +msgstr "" + +# Default: Remake of +msgid "remake-of" +msgstr "" + +# Default: Rentals +msgid "rentals" +msgstr "" + +# Default: Result +msgid "result" +msgstr "résultat" + +# Default: Review +msgid "review" +msgstr "revue" + +# Default: Review author +msgid "review-author" +msgstr "" + +# Default: Review kind +msgid "review-kind" +msgstr "" + +# Default: Runtime +msgid "runtime" +msgstr "" + +# Default: Runtimes +msgid "runtimes" +msgstr "" + +# Default: Salary history +msgid "salary-history" +msgstr "" + +# Default: Screenplay teleplay +msgid "screenplay-teleplay" +msgstr "" + +# Default: Season +msgid "season" +msgstr "saison" + +# Default: Second unit director or assistant director +msgid "second-unit-director-or-assistant-director" +msgstr "" + +# Default: Self +msgid "self" +msgstr "" + +# Default: Series animation department +msgid "series-animation-department" +msgstr "" + +# Default: Series art department +msgid "series-art-department" +msgstr "" + +# Default: Series assistant directors +msgid "series-assistant-directors" +msgstr "" + +# Default: Series camera department +msgid "series-camera-department" +msgstr "" + +# Default: Series casting department +msgid "series-casting-department" +msgstr "" + +# Default: Series cinematographers +msgid "series-cinematographers" +msgstr "" + +# Default: Series costume department +msgid "series-costume-department" +msgstr "" + +# Default: Series editorial department +msgid "series-editorial-department" +msgstr "" + +# Default: Series editors +msgid "series-editors" +msgstr "" + +# Default: Series make up department +msgid "series-make-up-department" +msgstr "" + +# Default: Series miscellaneous +msgid "series-miscellaneous" +msgstr "" + +# Default: Series music department +msgid "series-music-department" +msgstr "" + +# Default: Series producers +msgid "series-producers" +msgstr "" + +# Default: Series production designers +msgid "series-production-designers" +msgstr "" + +# Default: Series production managers +msgid "series-production-managers" +msgstr "" + +# Default: Series sound department +msgid "series-sound-department" +msgstr "" + +# Default: Series special effects department +msgid "series-special-effects-department" +msgstr "" + +# Default: Series stunts +msgid "series-stunts" +msgstr "" + +# Default: Series title +msgid "series-title" +msgstr "" + +# Default: Series transportation department +msgid "series-transportation-department" +msgstr "" + +# Default: Series visual effects department +msgid "series-visual-effects-department" +msgstr "" + +# Default: Series writers +msgid "series-writers" +msgstr "" + +# Default: Series years +msgid "series-years" +msgstr "" + +# Default: Set decoration +msgid "set-decoration" +msgstr "" + +# Default: Sharpness +msgid "sharpness" +msgstr "" + +# Default: Similar to +msgid "similar-to" +msgstr "" + +# Default: Smart canonical episode title +msgid "smart-canonical-episode-title" +msgstr "" + +# Default: Smart canonical series title +msgid "smart-canonical-series-title" +msgstr "" + +# Default: Smart canonical title +msgid "smart-canonical-title" +msgstr "" + +# Default: Smart long imdb canonical title +msgid "smart-long-imdb-canonical-title" +msgstr "" + +# Default: Sound clips +msgid "sound-clips" +msgstr "" + +# Default: Sound crew +msgid "sound-crew" +msgstr "" + +# Default: Sound encoding +msgid "sound-encoding" +msgstr "" + +# Default: Sound mix +msgid "sound-mix" +msgstr "" + +# Default: Soundtrack +msgid "soundtrack" +msgstr "" + +# Default: Spaciality +msgid "spaciality" +msgstr "" + +# Default: Special effects +msgid "special-effects" +msgstr "" + +# Default: Special effects companies +msgid "special-effects-companies" +msgstr "" + +# Default: Special effects department +msgid "special-effects-department" +msgstr "" + +# Default: Spin off +msgid "spin-off" +msgstr "" + +# Default: Spin off from +msgid "spin-off-from" +msgstr "" + +# Default: Spoofed in +msgid "spoofed-in" +msgstr "" + +# Default: Spoofs +msgid "spoofs" +msgstr "" + +# Default: Spouse +msgid "spouse" +msgstr "époux" + +# Default: Status of availablility +msgid "status-of-availablility" +msgstr "" + +# Default: Studio +msgid "studio" +msgstr "studio" + +# Default: Studios +msgid "studios" +msgstr "studios" + +# Default: Stunt performer +msgid "stunt-performer" +msgstr "" + +# Default: Stunts +msgid "stunts" +msgstr "" + +# Default: Subtitles +msgid "subtitles" +msgstr "sous-titres" + +# Default: Supplement +msgid "supplement" +msgstr "bonus" + +# Default: Supplements +msgid "supplements" +msgstr "bonus" + +# Default: Synopsis +msgid "synopsis" +msgstr "synopsis" + +# Default: Taglines +msgid "taglines" +msgstr "" + +# Default: Tech info +msgid "tech-info" +msgstr "" + +# Default: Thanks +msgid "thanks" +msgstr "" + +# Default: Time +msgid "time" +msgstr "temps" + +# Default: Title +msgid "title" +msgstr "titre" + +# Default: Titles in this product +msgid "titles-in-this-product" +msgstr "" + +# Default: To +msgid "to" +msgstr "" + +# Default: Top 250 rank +msgid "top-250-rank" +msgstr "" + +# Default: Trade mark +msgid "trade-mark" +msgstr "" + +# Default: Transportation department +msgid "transportation-department" +msgstr "" + +# Default: Trivia +msgid "trivia" +msgstr "" + +# Default: Tv +msgid "tv" +msgstr "tv" + +# Default: Under license from +msgid "under-license-from" +msgstr "" + +# Default: Unknown link +msgid "unknown-link" +msgstr "" + +# Default: Upc +msgid "upc" +msgstr "upc" + +# Default: Version of +msgid "version-of" +msgstr "" + +# Default: Vhs +msgid "vhs" +msgstr "" + +# Default: Video +msgid "video" +msgstr "video" + +# Default: Video artifacts +msgid "video-artifacts" +msgstr "" + +# Default: Video clips +msgid "video-clips" +msgstr "" + +# Default: Video noise +msgid "video-noise" +msgstr "" + +# Default: Video quality +msgid "video-quality" +msgstr "" + +# Default: Video standard +msgid "video-standard" +msgstr "" + +# Default: Visual effects +msgid "visual-effects" +msgstr "" + +# Default: Votes +msgid "votes" +msgstr "" + +# Default: Votes distribution +msgid "votes-distribution" +msgstr "" + +# Default: Weekend gross +msgid "weekend-gross" +msgstr "" + +# Default: Where now +msgid "where-now" +msgstr "" + +# Default: With +msgid "with" +msgstr "avec" + +# Default: Writer +msgid "writer" +msgstr "auteur" + +# Default: Written by +msgid "written-by" +msgstr "" + +# Default: Year +msgid "year" +msgstr "année" + +# Default: Zshops +msgid "zshops" +msgstr "" diff --git a/lib/imdb/locale/msgfmt.py b/lib/imdb/locale/msgfmt.py index 45f24d64..9e0ab747 100644 --- a/lib/imdb/locale/msgfmt.py +++ b/lib/imdb/locale/msgfmt.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # -*- coding: iso-8859-1 -*- """Generate binary message catalog from textual translation description. diff --git a/lib/imdb/locale/rebuildmo.py b/lib/imdb/locale/rebuildmo.py index f6c01d14..b72a74c3 100644 --- a/lib/imdb/locale/rebuildmo.py +++ b/lib/imdb/locale/rebuildmo.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python """ rebuildmo.py script. diff --git a/lib/imdb/parser/http/__init__.py b/lib/imdb/parser/http/__init__.py index e49e7bb6..16f8518d 100644 --- a/lib/imdb/parser/http/__init__.py +++ b/lib/imdb/parser/http/__init__.py @@ -104,15 +104,24 @@ PY_VERSION = sys.version_info[:2] # The cookies for the "adult" search. # Please don't mess with these account. # Old 'IMDbPY' account. -_old_cookie_id = 'boM2bYxz9MCsOnH9gZ0S9QHs12NWrNdApxsls1Vb5/NGrNdjcHx3dUas10UASoAjVEvhAbGagERgOpNkAPvxdbfKwaV2ikEj9SzXY1WPxABmDKQwdqzwRbM+12NSeJFGUEx3F8as10WwidLzVshDtxaPIbP13NdjVS9UZTYqgTVGrNcT9vyXU1' -_old_cookie_uu = '3M3AXsquTU5Gur/Svik+ewflPm5Rk2ieY3BIPlLjyK3C0Dp9F8UoPgbTyKiGtZp4x1X+uAUGKD7BM2g+dVd8eqEzDErCoYvdcvGLvVLAen1y08hNQtALjVKAe+1hM8g9QbNonlG1/t4S82ieUsBbrSIQbq1yhV6tZ6ArvSbA7rgHc8n5AdReyAmDaJ5Wm/ee3VDoCnGj/LlBs2ieUZNorhHDKK5Q==' -# New 'IMDbPYweb' account. -_cookie_id = 'rH1jNAkjTlNXvHolvBVBsgaPICNZbNdjVjzFwzas9JRmusdjVoqBs/Hs12NR+1WFxEoR9bGKEDUg6sNlADqXwkas12N131Rwdb+UQNGKN8PWrNdjcdqBQVLq8mbGDHP3hqzxhbD692NQi9D0JjpBtRaPIbP1zNdjUOqENQYv1ADWrNcT9vyXU1' -_cookie_uu = 'su4/m8cho4c6HP+W1qgq6wchOmhnF0w+lIWvHjRUPJ6nRA9sccEafjGADJ6hQGrMd4GKqLcz2X4z5+w+M4OIKnRn7FpENH7dxDQu3bQEHyx0ZEyeRFTPHfQEX03XF+yeN1dsPpcXaqjUZAw+lGRfXRQEfz3RIX9IgVEffdBAHw2wQXyf9xdMPrQELw0QNB8dsffsqcdQemjPB0w+moLcPh0JrKrHJ9hjBzdMPpcXTH7XRwwOk=' +_IMDbPY_cookie_id = 'boM2bYxz9MCsOnH9gZ0S9QHs12NWrNdApxsls1Vb5/NGrNdjcHx3dUas10UASoAjVEvhAbGagERgOpNkAPvxdbfKwaV2ikEj9SzXY1WPxABmDKQwdqzwRbM+12NSeJFGUEx3F8as10WwidLzVshDtxaPIbP13NdjVS9UZTYqgTVGrNcT9vyXU1' +_IMDbPY_cookie_uu = '3M3AXsquTU5Gur/Svik+ewflPm5Rk2ieY3BIPlLjyK3C0Dp9F8UoPgbTyKiGtZp4x1X+uAUGKD7BM2g+dVd8eqEzDErCoYvdcvGLvVLAen1y08hNQtALjVKAe+1hM8g9QbNonlG1/t4S82ieUsBbrSIQbq1yhV6tZ6ArvSbA7rgHc8n5AdReyAmDaJ5Wm/ee3VDoCnGj/LlBs2ieUZNorhHDKK5Q==' +# 'imdbpy2010' account. +_imdbpy2010_cookie_id = 'QrCdxVi+L+WgqOLrQJJgBgRRXGInphxiBPU/YXSFDyExMFzCp6YcYgSVXyEUhS/xMID8wqemHGID4DlntwZ49vemP5UXsAxiJ4D6goSmHGIgNT9hMXBaRSF2vMS3phxB0bVfQiQlP1RxdrzhB6YcRHFASyIhQVowwXCKtDSlD2YhgRvxBsCKtGemHBKH9mxSI=' +_imdbpy2010_cookie_uu = 'oiEo2yoJFCA2Zbn/o7Z1LAPIwotAu6QdALv3foDb1x5F/tdrFY63XkSfty4kntS8Y8jkHSDLt3406+d+JThEilPI0mtTaOQdA/t2/iErp22jaLdeVU5ya4PIREpj7HFdpzhEHadcIAngSER50IoHDpD6Bz4Qy3b+UIhE/hBbhz5Q63ceA2hEvhPo5B0FnrL9Q8jkWjDIbA0Au3d+AOtnXoCIRL4Q28c+UOtnXpP4RL4T6OQdA+6ijUCI5B0AW2d+UOtnXpPYRL4T6OQdA8jkTUOYlC0A==' +# old 'IMDbPYweb' account. +_old_IMDbPYweb_cookie_id = 'rH1jNAkjTlNXvHolvBVBsgaPICNZbNdjVjzFwzas9JRmusdjVoqBs/Hs12NR+1WFxEoR9bGKEDUg6sNlADqXwkas12N131Rwdb+UQNGKN8PWrNdjcdqBQVLq8mbGDHP3hqzxhbD692NQi9D0JjpBtRaPIbP1zNdjUOqENQYv1ADWrNcT9vyXU1' +_old_IMDbPYweb_cookie_uu = 'su4/m8cho4c6HP+W1qgq6wchOmhnF0w+lIWvHjRUPJ6nRA9sccEafjGADJ6hQGrMd4GKqLcz2X4z5+w+M4OIKnRn7FpENH7dxDQu3bQEHyx0ZEyeRFTPHfQEX03XF+yeN1dsPpcXaqjUZAw+lGRfXRQEfz3RIX9IgVEffdBAHw2wQXyf9xdMPrQELw0QNB8dsffsqcdQemjPB0w+moLcPh0JrKrHJ9hjBzdMPpcXTH7XRwwOk=' +# old 'IMDbPYweb' account values (as of 2012-12-30) +_IMDbPYweb_cookie_id = 'BCYjtpb46Go0cMHAMewWZEauhwqPL7ASCPpPVNutu6BuayHZd0U6Dk3UAqVlEM8DHLDsSr02RGQn5ff3245-R4A130NAWJ_5yqXx7X-zJey8vQM8JKdv3rTUSEJznJQlojUW1Bije-Q0FXAixs4I0sePWhd_tA41i-9AF2q3lPmaksram6ilMhN9i3IPESW1PMbk' +_IMDbPYweb_cookie_uu = 'BCYttQjEMc-NyUdFUGxThidAnBo7wwalEzj4un9uzf2XoEjtqDhNfrH7bOSuwlRkMEQ11SNyTajl-b9Q-21m4HwYu0e3jXZrjYLXLYzFkrEroCDyUREqaTwPJPSjGtFmvlaVBZEZmsWpaxe18DT5KiygKyGPZKH78Xu4im6ba-Sd31WvbXHzP8KGXPpGjhhVuv7Dcv314HCWkE832Srf9ya-Uv0FdGAmYyLbIAXuxnvpYQd6oZ8-CYkSGLIqcKWdrf5S' +# 'IMDbPY2013' account +_IMDbPY2013_cookie_id = 'BCYmoyqSm2WglmOzG-SrFWSvVpxsTZOB0qEOOqmAwCBxCbaNgKOxd0DTKzUvt7t04Pya5gV2tUrpDmYxrc1Dr54DQj2UXI7QI35__M5-HI2KrbOI3PjDz6M-_U3HG8topMfN64R24tmBixoZhMYXVaEc556lf0Z4gQNJVYRANXvwytP5v1lpfeToRlu9aVJwN4kT' +_IMDbPY2013_cookie_uu = 'BCYquDS8Y2i8R1pJxS4nB77YrhjHHXeOea2Xl9KtZvE6RZKVfMvzTGU4Vl5-yxfPbgRSiFJasyf-hhPuVvXyaHlfeBjNlbFT8hz2HzFFkQ_SxKxq05J51gi7Fv4SaAws1M-i7zmQ1TRunfJqCVIYqPwIs2NO7s4_YDH2ZoISVGLgca8OY2K58HychOZB1oRWHVeAJNhLJMrCWJBuGRLCNnQK5X9tA0dPPntr2Ussy0ouul-N1GQz-8y5vda3JJ_C6xkwmHcA6JrOdOFO_HqMWjVSXuxGEdrXC919JM9H0vooVvKeVgAEJnTh2GiVlUJUoH3c' -# imdbpy2010 account. -#_cookie_id = 'QrCdxVi+L+WgqOLrQJJgBgRRXGInphxiBPU/YXSFDyExMFzCp6YcYgSVXyEUhS/xMID8wqemHGID4DlntwZ49vemP5UXsAxiJ4D6goSmHGIgNT9hMXBaRSF2vMS3phxB0bVfQiQlP1RxdrzhB6YcRHFASyIhQVowwXCKtDSlD2YhgRvxBsCKtGemHBKH9mxSI=' -#_cookie_uu = 'oiEo2yoJFCA2Zbn/o7Z1LAPIwotAu6QdALv3foDb1x5F/tdrFY63XkSfty4kntS8Y8jkHSDLt3406+d+JThEilPI0mtTaOQdA/t2/iErp22jaLdeVU5ya4PIREpj7HFdpzhEHadcIAngSER50IoHDpD6Bz4Qy3b+UIhE/hBbhz5Q63ceA2hEvhPo5B0FnrL9Q8jkWjDIbA0Au3d+AOtnXoCIRL4Q28c+UOtnXpP4RL4T6OQdA+6ijUCI5B0AW2d+UOtnXpPYRL4T6OQdA8jkTUOYlC0A==' +# Currently used account. +_cookie_id = _IMDbPY2013_cookie_id +_cookie_uu = _IMDbPY2013_cookie_uu class _FakeURLOpener(object): @@ -141,9 +150,10 @@ class IMDbURLopener(FancyURLopener): for header in ('User-Agent', 'User-agent', 'user-agent'): self.del_header(header) self.set_header('User-Agent', 'Mozilla/5.0') + self.set_header('Accept-Language', 'en-us,en;q=0.5') # XXX: This class is used also to perform "Exact Primary # [Title|Name]" searches, and so by default the cookie is set. - c_header = 'id=%s; uu=%s' % (_cookie_id, _cookie_uu) + c_header = 'uu=%s; id=%s' % (_cookie_uu, _cookie_id) self.set_header('Cookie', c_header) def get_proxy(self): @@ -199,12 +209,11 @@ class IMDbURLopener(FancyURLopener): server_encode = uopener.info().getparam('charset') # Otherwise, look at the content-type HTML meta tag. if server_encode is None and content: - first_bytes = content[:512] - begin_h = first_bytes.find('text/html; charset=') + begin_h = content.find('text/html; charset=') if begin_h != -1: - end_h = first_bytes[19+begin_h:].find('"') + end_h = content[19+begin_h:].find('"') if end_h != -1: - server_encode = first_bytes[19+begin_h:19+begin_h+end_h] + server_encode = content[19+begin_h:19+begin_h+end_h] if server_encode: try: if lookup(server_encode): @@ -455,16 +464,16 @@ class IMDbHTTPAccessSystem(IMDbBase): results is the maximum number of results to be retrieved.""" if isinstance(ton, unicode): try: - ton = ton.encode('iso8859-1') + ton = ton.encode('utf-8') except Exception, e: try: - ton = ton.encode('utf-8') + ton = ton.encode('iso8859-1') except Exception, e: pass ##params = 'q=%s&%s=on&mx=%s' % (quote_plus(ton), kind, str(results)) - params = 'q=%s;s=%s;mx=%s' % (quote_plus(ton), kind, str(results)) + params = 'q=%s&s=%s&mx=%s' % (quote_plus(ton), kind, str(results)) if kind == 'ep': - params = params.replace('s=ep;', 's=tt;ttype=ep;', 1) + params = params.replace('s=ep&', 's=tt&ttype=ep&', 1) cont = self._retrieve(self.urls['find'] % params) #print 'URL:', imdbURL_find % params if cont.find('Your search returned more than') == -1 or \ @@ -472,7 +481,7 @@ class IMDbHTTPAccessSystem(IMDbBase): return cont # The retrieved page contains no results, because too many # titles or names contain the string we're looking for. - params = 'q=%s;ls=%s;lm=0' % (quote_plus(ton), kind) + params = 'q=%s&ls=%s&lm=0' % (quote_plus(ton), kind) size = 131072 + results * 512 return self._retrieve(self.urls['find'] % params, size=size) @@ -587,6 +596,10 @@ class IMDbHTTPAccessSystem(IMDbBase): cont = self._retrieve(self.urls['movie_main'] % movieID + 'recommendations') return self.mProxy.rec_parser.parse(cont) + def get_movie_critic_reviews(self, movieID): + cont = self._retrieve(self.urls['movie_main'] % movieID + 'criticreviews') + return self.mProxy.criticrev_parser.parse(cont) + def get_movie_external_reviews(self, movieID): cont = self._retrieve(self.urls['movie_main'] % movieID + 'externalreviews') return self.mProxy.externalrev_parser.parse(cont) @@ -754,7 +767,7 @@ class IMDbHTTPAccessSystem(IMDbBase): return self.pProxy.person_keywords_parser.parse(cont) def _search_character(self, name, results): - cont = self._get_search_content('char', name, results) + cont = self._get_search_content('ch', name, results) return self.scProxy.search_character_parser.parse(cont, results=results)['data'] def get_character_main(self, characterID): diff --git a/lib/imdb/parser/http/movieParser.py b/lib/imdb/parser/http/movieParser.py index d05b9e01..a203b0d9 100644 --- a/lib/imdb/parser/http/movieParser.py +++ b/lib/imdb/parser/http/movieParser.py @@ -9,7 +9,7 @@ pages would be: plot summary: http://akas.imdb.com/title/tt0094226/plotsummary ...and so on... -Copyright 2004-2012 Davide Alberani +Copyright 2004-2013 Davide Alberani 2008 H. Turgut Uyar This program is free software; you can redistribute it and/or modify @@ -531,9 +531,6 @@ class DOMHTMLMovieParser(DOMParserBase): def _process_plotsummary(x): """Process a plot (contributed by Rdian06).""" xauthor = x.get('author') - if xauthor: - xauthor = xauthor.replace('{', '<').replace('}', '>').replace('(', - '<').replace(')', '>').strip() xplot = x.get('plot', u'').strip() if xauthor: xplot += u'::%s' % xauthor @@ -555,17 +552,20 @@ class DOMHTMLPlotParser(DOMParserBase): # Notice that recently IMDb started to put the email of the # author only in the link, that we're not collecting, here. extractors = [Extractor(label='plot', - path="//p[@class='plotpar']", - attrs=Attribute(key='plot', - multi=True, - path={'plot': './text()', - 'author': './i/a/text()'}, - postprocess=_process_plotsummary))] + path="//ul[@class='zebraList']//p", + attrs=Attribute(key='plot', + multi=True, + path={'plot': './text()[1]', + 'author': './span/em/a/text()'}, + postprocess=_process_plotsummary))] def _process_award(x): award = {} - award['award'] = x.get('award').strip() + _award = x.get('award') + if _award is not None: + _award = _award.strip() + award['award'] = _award if not award['award']: return {} award['year'] = x.get('year').strip() @@ -709,10 +709,16 @@ class DOMHTMLTaglinesParser(DOMParserBase): result = tparser.parse(taglines_html_string) """ extractors = [Extractor(label='taglines', - path="//div[@id='tn15content']/p", - attrs=Attribute(key='taglines', multi=True, + path='//*[contains(concat(" ", normalize-space(@class), " "), " soda ")]', + attrs=Attribute(key='taglines', + multi=True, path="./text()"))] + def postprocess_data(self, data): + if 'taglines' in data: + data['taglines'] = [tagline.strip() for tagline in data['taglines']] + return data + class DOMHTMLKeywordsParser(DOMParserBase): """Parser for the "keywords" page of a given movie. @@ -785,9 +791,9 @@ class DOMHTMLSoundtrackParser(DOMHTMLAlternateVersionsParser): ] def postprocess_data(self, data): - if 'soundtrack' in data: + if 'alternate versions' in data: nd = [] - for x in data['soundtrack']: + for x in data['alternate versions']: ds = x.split('\n') title = ds[0] if title[0] == '"' and title[-1] == '"': @@ -846,6 +852,13 @@ class DOMHTMLCrazyCreditsParser(DOMParserBase): x.replace('\n', ' ').replace(' ', ' ')))] +def _process_goof(x): + if x['spoiler_category']: + return x['spoiler_category'].strip() + ': SPOILER: ' + x['text'].strip() + else: + return x['category'].strip() + ': ' + x['text'].strip() + + class DOMHTMLGoofsParser(DOMParserBase): """Parser for the "goofs" page of a given movie. The page should be provided as a string, as taken from @@ -858,9 +871,14 @@ class DOMHTMLGoofsParser(DOMParserBase): """ _defGetRefs = True - extractors = [Extractor(label='goofs', path="//ul[@class='trivia']/li", - attrs=Attribute(key='goofs', multi=True, path=".//text()", - postprocess=lambda x: (x or u'').strip()))] + extractors = [Extractor(label='goofs', path="//div[@class='soda odd']", + attrs=Attribute(key='goofs', multi=True, + path={ + 'text':"./text()", + 'category':'./preceding-sibling::h4[1]/text()', + 'spoiler_category': './h4/text()' + }, + postprocess=_process_goof))] class DOMHTMLQuotesParser(DOMParserBase): @@ -876,9 +894,16 @@ class DOMHTMLQuotesParser(DOMParserBase): _defGetRefs = True extractors = [ - Extractor(label='quotes', - path="//div[@class='_imdbpy']", - attrs=Attribute(key='quotes', + Extractor(label='quotes_odd', + path="//div[@class='quote soda odd']", + attrs=Attribute(key='quotes_odd', + multi=True, + path=".//text()", + postprocess=lambda x: x.strip().replace(' \n', + '::').replace('::\n', '::').replace('\n', ' '))), + Extractor(label='quotes_even', + path="//div[@class='quote soda even']", + attrs=Attribute(key='quotes_even', multi=True, path=".//text()", postprocess=lambda x: x.strip().replace(' \n', @@ -886,27 +911,23 @@ class DOMHTMLQuotesParser(DOMParserBase): ] preprocessors = [ - (re.compile('()', re.I), - r'\1
'), - (re.compile('
', re.I), '
'), - (re.compile('
', re.I), '
'), - (re.compile('', re.I|re.S), ''), - # For BeautifulSoup. - (re.compile('', re.I), '
') - ] + (re.compile('
', re.I), '') + ] def preprocess_dom(self, dom): # Remove "link this quote" links. - for qLink in self.xpath(dom, "//p[@class='linksoda']"): + for qLink in self.xpath(dom, "//span[@class='linksoda']"): + qLink.drop_tree() + for qLink in self.xpath(dom, "//div[@class='sharesoda_pre']"): qLink.drop_tree() return dom def postprocess_data(self, data): - if 'quotes' not in data: + quotes = data.get('quotes_odd', []) + data.get('quotes_even', []) + if not quotes: return {} - for idx, quote in enumerate(data['quotes']): - data['quotes'][idx] = quote.split('::') - return data + quotes = [q.split('::') for q in quotes] + return {'quotes': quotes} class DOMHTMLReleaseinfoParser(DOMParserBase): @@ -920,13 +941,13 @@ class DOMHTMLReleaseinfoParser(DOMParserBase): result = rdparser.parse(releaseinfo_html_string) """ extractors = [Extractor(label='release dates', - path="//th[@class='xxxx']/../../tr", + path="//table[@id='release_dates']//tr", attrs=Attribute(key='release dates', multi=True, path={'country': ".//td[1]//text()", 'date': ".//td[2]//text()", 'notes': ".//td[3]//text()"})), Extractor(label='akas', - path="//div[@class='_imdbpy_akas']/table/tr", + path="//table[@id='akas']//tr", attrs=Attribute(key='akas', multi=True, path={'title': "./td[1]/text()", 'countries': "./td[2]/text()"}))] @@ -961,7 +982,7 @@ class DOMHTMLReleaseinfoParser(DOMParserBase): title = (aka.get('title') or '').strip() if not title: continue - countries = (aka.get('countries') or '').split('/') + countries = (aka.get('countries') or '').split(',') if not countries: nakas.append(title) else: @@ -1135,7 +1156,28 @@ def _normalize_href(href): href = '%s%s' % (imdbURL_base, href) return href +class DOMHTMLCriticReviewsParser(DOMParserBase): + """Parser for the "critic reviews" pages of a given movie. + The page should be provided as a string, as taken from + the akas.imdb.com server. The final result will be a + dictionary, with a key for every relevant section. + Example: + osparser = DOMHTMLCriticReviewsParser() + result = osparser.parse(officialsites_html_string) + """ + kind = 'critic reviews' + + extractors = [ + Extractor(label='metascore', + path="//div[@class='metascore_wrap']/div/span", + attrs=Attribute(key='metascore', + path=".//text()")), + Extractor(label='metacritic url', + path="//div[@class='article']/div[@class='see-more']/a", + attrs=Attribute(key='metacritic url', + path="./@href")) ] + class DOMHTMLOfficialsitesParser(DOMParserBase): """Parser for the "official sites", "external reviews", "newsgroup reviews", "miscellaneous links", "sound clips", "video clips" and @@ -1471,6 +1513,14 @@ class DOMHTMLSeasonEpisodesParser(DOMParserBase): try: selected_season = int(selected_season) except: pass nd = {selected_season: {}} + if 'episode -1' in data: + counter = 1 + for episode in data['episode -1']: + while 'episode %d' % counter in data: + counter += 1 + k = 'episode %d' % counter + data[k] = [episode] + del data['episode -1'] for episode_nr, episode in data.iteritems(): if not (episode and episode[0] and episode_nr.startswith('episode ')): @@ -1860,6 +1910,8 @@ _OBJECTS = { 'releasedates_parser': ((DOMHTMLReleaseinfoParser,), None), 'ratings_parser': ((DOMHTMLRatingsParser,), None), 'officialsites_parser': ((DOMHTMLOfficialsitesParser,), None), + 'criticrev_parser': ((DOMHTMLCriticReviewsParser,), + {'kind': 'critic reviews'}), 'externalrev_parser': ((DOMHTMLOfficialsitesParser,), {'kind': 'external reviews'}), 'newsgrouprev_parser': ((DOMHTMLOfficialsitesParser,), diff --git a/lib/imdb/parser/http/personParser.py b/lib/imdb/parser/http/personParser.py index af967210..9261a4da 100644 --- a/lib/imdb/parser/http/personParser.py +++ b/lib/imdb/parser/http/personParser.py @@ -8,7 +8,7 @@ E.g., for "Mel Gibson" the referred pages would be: biography: http://akas.imdb.com/name/nm0000154/bio ...and so on... -Copyright 2004-20101 Davide Alberani +Copyright 2004-2013 Davide Alberani 2008 H. Turgut Uyar This program is free software; you can redistribute it and/or modify @@ -60,6 +60,7 @@ class DOMHTMLMaindetailsParser(DOMParserBase): result = cparser.parse(categorized_html_string) """ _containsObjects = True + _name_imdb_index = re.compile(r'\([IVXLCDM]+\)') _birth_attrs = [Attribute(key='birth date', path='.//time[@itemprop="birthDate"]/@datetime'), @@ -100,6 +101,10 @@ class DOMHTMLMaindetailsParser(DOMParserBase): path=".//text()", postprocess=lambda x: analyze_name(x, canonical=1))), + Extractor(label='name_index', + path="//h1[@class='header']/span[1]", + attrs=Attribute(key='name_index', + path="./text()")), Extractor(label='birth info', path="//div[h4='Born:']", @@ -110,7 +115,7 @@ class DOMHTMLMaindetailsParser(DOMParserBase): attrs=_death_attrs), Extractor(label='headshot', - path="//td[@id='img_primary']/a", + path="//td[@id='img_primary']/div[@class='image']/a", attrs=Attribute(key='headshot', path="./img/@src")), @@ -152,6 +157,11 @@ class DOMHTMLMaindetailsParser(DOMParserBase): for what in 'birth date', 'death date': if what in data and not data[what]: del data[what] + name_index = (data.get('name_index') or '').strip() + if name_index: + if self._name_imdb_index.match(name_index): + data['imdbIndex'] = name_index[1:-1] + del data['name_index'] # XXX: the code below is for backwards compatibility # probably could be removed for key in data.keys(): @@ -220,13 +230,13 @@ class DOMHTMLBioParser(DOMParserBase): attrs=Attribute(key='headshot', path="./img/@src")), Extractor(label='birth info', - path="//div[h5='Date of Birth']", + path="//table[@id='overviewTable']//td[text()='Date of Birth']/following-sibling::td[1]", attrs=_birth_attrs), Extractor(label='death info', - path="//div[h5='Date of Death']", + path="//table[@id='overviewTable']//td[text()='Date of Death']/following-sibling::td[1]", attrs=_death_attrs), Extractor(label='nick names', - path="//div[h5='Nickname']", + path="//table[@id='overviewTable']//td[text()='Nickenames']/following-sibling::td[1]", attrs=Attribute(key='nick names', path="./text()", joiner='|', @@ -234,25 +244,25 @@ class DOMHTMLBioParser(DOMParserBase): '::(', 1) for n in x.split('|') if n.strip()])), Extractor(label='birth name', - path="//div[h5='Birth Name']", + path="//table[@id='overviewTable']//td[text()='Birth Name']/following-sibling::td[1]", attrs=Attribute(key='birth name', path="./text()", postprocess=lambda x: canonicalName(x.strip()))), Extractor(label='height', - path="//div[h5='Height']", + path="//table[@id='overviewTable']//td[text()='Height']/following-sibling::td[1]", attrs=Attribute(key='height', path="./text()", postprocess=lambda x: x.strip())), Extractor(label='mini biography', - path="//div[h5='Mini Biography']", + path="//a[@name='mini_bio']/following-sibling::div[1 = count(preceding-sibling::a[1] | ../a[@name='mini_bio'])]", attrs=Attribute(key='mini biography', multi=True, path={ - 'bio': "./p//text()", - 'by': "./b/following-sibling::a/text()" + 'bio': ".//text()", + 'by': ".//a[@name='ba']//text()" }, postprocess=lambda x: "%s::%s" % \ - (x.get('bio').strip(), + ((x.get('bio') or u'').split('- IMDb Mini Biography By:')[0].strip(), (x.get('by') or u'').strip() or u'Anonymous'))), Extractor(label='spouse', path="//div[h5='Spouse']/table/tr", diff --git a/lib/imdb/parser/http/searchCharacterParser.py b/lib/imdb/parser/http/searchCharacterParser.py index c81ca7e4..5f281fa0 100644 --- a/lib/imdb/parser/http/searchCharacterParser.py +++ b/lib/imdb/parser/http/searchCharacterParser.py @@ -5,9 +5,9 @@ This module provides the HTMLSearchCharacterParser class (and the search_character_parser instance), used to parse the results of a search for a given character. E.g., when searching for the name "Jesse James", the parsed page would be: - http://akas.imdb.com/find?s=Characters;mx=20;q=Jesse+James + http://akas.imdb.com/find?s=ch;mx=20;q=Jesse+James -Copyright 2007-2009 Davide Alberani +Copyright 2007-2012 Davide Alberani 2008 H. Turgut Uyar This program is free software; you can redistribute it and/or modify @@ -42,7 +42,7 @@ class DOMBasicCharacterParser(DOMBasicMovieParser): class DOMHTMLSearchCharacterParser(DOMHTMLSearchMovieParser): _BaseParser = DOMBasicCharacterParser - _notDirectHitTitle = 'imdb search' + _notDirectHitTitle = '<title>find - imdb' _titleBuilder = lambda self, x: build_name(x, canonical=False) _linkPrefix = '/character/ch' @@ -57,7 +57,7 @@ class DOMHTMLSearchCharacterParser(DOMHTMLSearchMovieParser): {'name': x.get('name')} ))] extractors = [Extractor(label='search', - path="//td[3]/a[starts-with(@href, " \ + path="//td[@class='result_text']/a[starts-with(@href, " \ "'/character/ch')]/..", attrs=_attrs)] diff --git a/lib/imdb/parser/http/searchCompanyParser.py b/lib/imdb/parser/http/searchCompanyParser.py index ab666fbc..40ea8a72 100644 --- a/lib/imdb/parser/http/searchCompanyParser.py +++ b/lib/imdb/parser/http/searchCompanyParser.py @@ -7,7 +7,7 @@ for a given company. E.g., when searching for the name "Columbia Pictures", the parsed page would be: http://akas.imdb.com/find?s=co;mx=20;q=Columbia+Pictures -Copyright 2008-2009 Davide Alberani <da@erlug.linux.it> +Copyright 2008-2012 Davide Alberani <da@erlug.linux.it> 2008 H. Turgut Uyar <uyar@tekir.org> This program is free software; you can redistribute it and/or modify @@ -42,7 +42,7 @@ class DOMBasicCompanyParser(DOMBasicMovieParser): class DOMHTMLSearchCompanyParser(DOMHTMLSearchMovieParser): _BaseParser = DOMBasicCompanyParser - _notDirectHitTitle = '<title>imdb company' + _notDirectHitTitle = '<title>find - imdb' _titleBuilder = lambda self, x: build_company_name(x) _linkPrefix = '/company/co' @@ -59,7 +59,7 @@ class DOMHTMLSearchCompanyParser(DOMHTMLSearchMovieParser): or u''), stripNotes=True) ))] extractors = [Extractor(label='search', - path="//td[3]/a[starts-with(@href, " \ + path="//td[@class='result_text']/a[starts-with(@href, " \ "'/company/co')]/..", attrs=_attrs)] diff --git a/lib/imdb/parser/http/searchMovieParser.py b/lib/imdb/parser/http/searchMovieParser.py index 44c78d0c..425fe26a 100644 --- a/lib/imdb/parser/http/searchMovieParser.py +++ b/lib/imdb/parser/http/searchMovieParser.py @@ -8,7 +8,7 @@ E.g., for when searching for the title "the passion", the parsed page would be: http://akas.imdb.com/find?q=the+passion&tt=on&mx=20 -Copyright 2004-2010 Davide Alberani <da@erlug.linux.it> +Copyright 2004-2013 Davide Alberani <da@erlug.linux.it> 2008 H. Turgut Uyar <uyar@tekir.org> This program is free software; you can redistribute it and/or modify @@ -77,7 +77,7 @@ class DOMBasicMovieParser(DOMParserBase): def custom_analyze_title(title): """Remove garbage notes after the (year), (year/imdbIndex) or (year) (TV)""" # XXX: very crappy. :-( - nt = title.split(' ')[0] + nt = title.split(' aka ')[0] if nt: title = nt if not title: @@ -92,7 +92,7 @@ class DOMHTMLSearchMovieParser(DOMParserBase): "new search system" is used, for movies.""" _BaseParser = DOMBasicMovieParser - _notDirectHitTitle = '<title>imdb title' + _notDirectHitTitle = '<title>find - imdb' _titleBuilder = lambda self, x: build_title(x) _linkPrefix = '/title/tt' @@ -101,8 +101,7 @@ class DOMHTMLSearchMovieParser(DOMParserBase): path={ 'link': "./a[1]/@href", 'info': ".//text()", - #'akas': ".//div[@class='_imdbpyAKA']//text()" - 'akas': ".//p[@class='find-aka']//text()" + 'akas': "./i//text()" }, postprocess=lambda x: ( analyze_imdbid(x.get('link') or u''), @@ -110,7 +109,7 @@ class DOMHTMLSearchMovieParser(DOMParserBase): x.get('akas') ))] extractors = [Extractor(label='search', - path="//td[3]/a[starts-with(@href, '/title/tt')]/..", + path="//td[@class='result_text']", attrs=_attrs)] def _init(self): self.url = u'' @@ -119,14 +118,11 @@ class DOMHTMLSearchMovieParser(DOMParserBase): self.url = u'' def preprocess_string(self, html_string): - if self._notDirectHitTitle in html_string[:1024].lower(): + if self._notDirectHitTitle in html_string[:10240].lower(): if self._linkPrefix == '/title/tt': # Only for movies. + # XXX (HTU): does this still apply? html_string = html_string.replace('(TV mini-series)', '(mini)') - html_string = html_string.replace('

', - '

::') - #html_string = _reAKAStitles.sub( - # r'

\1::
\2', html_string) return html_string # Direct hit! dbme = self._BaseParser(useModule=self._useModule) @@ -141,7 +137,7 @@ class DOMHTMLSearchMovieParser(DOMParserBase): title = self._titleBuilder(res[0][1]) if not (link and title): return u'' link = link.replace('http://pro.imdb.com', '') - new_html = '%s' % (link, + new_html = '%s' % (link, title) return new_html @@ -161,11 +157,14 @@ class DOMHTMLSearchMovieParser(DOMParserBase): if not datum[0] and datum[1]: continue if datum[2] is not None: - akas = filter(None, datum[2].split('::')) + #akas = filter(None, datum[2].split('::')) if self._linkPrefix == '/title/tt': - akas = [a.replace('" - ', '::').rstrip() for a in akas] - akas = [a.replace('aka "', '', 1).replace('aka "', - '', 1).lstrip() for a in akas] + # XXX (HTU): couldn't find a result with multiple akas + aka = datum[2] + akas = [aka[1:-1]] # remove the quotes + #akas = [a.replace('" - ', '::').rstrip() for a in akas] + #akas = [a.replace('aka "', '', 1).replace('aka "', + #'', 1).lstrip() for a in akas] datum[1]['akas'] = akas data['data'][idx] = (datum[0], datum[1]) else: diff --git a/lib/imdb/parser/http/searchPersonParser.py b/lib/imdb/parser/http/searchPersonParser.py index 1756efc5..2dd26941 100644 --- a/lib/imdb/parser/http/searchPersonParser.py +++ b/lib/imdb/parser/http/searchPersonParser.py @@ -7,7 +7,7 @@ for a given person. E.g., when searching for the name "Mel Gibson", the parsed page would be: http://akas.imdb.com/find?q=Mel+Gibson&nm=on&mx=20 -Copyright 2004-2010 Davide Alberani +Copyright 2004-2013 Davide Alberani 2008 H. Turgut Uyar This program is free software; you can redistribute it and/or modify @@ -55,7 +55,7 @@ class DOMHTMLSearchPersonParser(DOMHTMLSearchMovieParser): """Parse the html page that the IMDb web server shows when the "new search system" is used, for persons.""" _BaseParser = DOMBasicPersonParser - _notDirectHitTitle = 'imdb name' + _notDirectHitTitle = '<title>find - imdb' _titleBuilder = lambda self, x: build_name(x, canonical=True) _linkPrefix = '/name/nm' @@ -74,11 +74,11 @@ class DOMHTMLSearchPersonParser(DOMHTMLSearchMovieParser): canonical=1), x.get('akas') ))] extractors = [Extractor(label='search', - path="//td[3]/a[starts-with(@href, '/name/nm')]/..", + path="//td[@class='result_text']/a[starts-with(@href, '/name/nm')]/..", attrs=_attrs)] def preprocess_string(self, html_string): - if self._notDirectHitTitle in html_string[:1024].lower(): + if self._notDirectHitTitle in html_string[:10240].lower(): html_string = _reAKASp.sub( r'\1<div class="_imdbpyAKA">\2::</div>\3', html_string) diff --git a/lib/imdb/parser/http/utils.py b/lib/imdb/parser/http/utils.py index f8dbc050..8b4e17e3 100644 --- a/lib/imdb/parser/http/utils.py +++ b/lib/imdb/parser/http/utils.py @@ -340,7 +340,7 @@ def build_movie(txt, movieID=None, roleID=None, status=None, title = title[:nidx].rstrip() if year: year = year.strip() - if title[-1] == ')': + if title[-1:] == ')': fpIdx = title.rfind('(') if fpIdx != -1: if notes: notes = '%s %s' % (title[fpIdx:], notes) diff --git a/lib/imdb/parser/mobile/__init__.py b/lib/imdb/parser/mobile/__init__.py index c391386b..e7ab589d 100644 --- a/lib/imdb/parser/mobile/__init__.py +++ b/lib/imdb/parser/mobile/__init__.py @@ -6,7 +6,7 @@ IMDb's data for mobile systems. the imdb.IMDb function will return an instance of this class when called with the 'accessSystem' argument set to "mobile". -Copyright 2005-2011 Davide Alberani <da@erlug.linux.it> +Copyright 2005-2012 Davide Alberani <da@erlug.linux.it> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -193,7 +193,7 @@ class IMDbMobileAccessSystem(IMDbHTTPAccessSystem): title) return res tl = title[0].lower() - if not tl.startswith('imdb title'): + if not tl.startswith('find - imdb'): # a direct hit! title = _unHtml(title[0]) mid = None @@ -211,7 +211,7 @@ class IMDbMobileAccessSystem(IMDbHTTPAccessSystem): # XXX: this results*3 prevents some recursion errors, but... # it's not exactly understandable (i.e.: why 'results' is # not enough to get all the results?) - lis = _findBetween(cont, 'td valign="top">', '</td>', + lis = _findBetween(cont, 'td class="result_text">', '</td>', maxRes=results*3) for li in lis: akas = re_makas.findall(li) @@ -492,7 +492,7 @@ class IMDbMobileAccessSystem(IMDbHTTPAccessSystem): self._mobile_logger.warn('no title tag searching for name %s', name) return res nl = name[0].lower() - if not nl.startswith('imdb name'): + if not nl.startswith('find - imdb'): # a direct hit! name = _unHtml(name[0]) name = name.replace('- Filmography by type' , '').strip() @@ -506,7 +506,7 @@ class IMDbMobileAccessSystem(IMDbHTTPAccessSystem): return res res[:] = [(str(pid[0]), analyze_name(name, canonical=1))] else: - lis = _findBetween(cont, 'td valign="top">', '</td>', + lis = _findBetween(cont, 'td class="result_text">', '</td>', maxRes=results*3) for li in lis: akas = _findBetween(li, '<em>"', '"</em>') @@ -771,7 +771,7 @@ class IMDbMobileAccessSystem(IMDbHTTPAccessSystem): return {'data': d} def _search_character(self, name, results): - cont = subXMLRefs(self._get_search_content('char', name, results)) + cont = subXMLRefs(self._get_search_content('ch', name, results)) name = _findBetween(cont, '<title>', '', maxRes=1) res = [] if not name: @@ -779,8 +779,7 @@ class IMDbMobileAccessSystem(IMDbHTTPAccessSystem): name) return res nl = name[0].lower() - if not (nl.startswith('imdb search') or nl.startswith('imdb search') \ - or nl.startswith('imdb character')): + if not nl.startswith('find - imdb'): # a direct hit! name = _unHtml(name[0]).replace('(Character)', '').strip() pid = None @@ -793,23 +792,18 @@ class IMDbMobileAccessSystem(IMDbHTTPAccessSystem): return res res[:] = [(str(pid[0]), analyze_name(name))] else: - sects = _findBetween(cont, 'Popular Characters', '', - maxRes=results*3) - sects += _findBetween(cont, 'Characters', '', - maxRes=results*3) - for sect in sects: - lis = _findBetween(sect, '', ' +Copyright 2005-2012 Davide Alberani This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -452,7 +452,12 @@ def get_movie_data(movieID, kindDict, fromAka=0, _table=None): else: if not fromAka: Table = Title else: Table = AkaTitle - m = Table.get(movieID) + try: + m = Table.get(movieID) + except Exception, e: + _aux_logger.warn('Unable to fetch information for movieID %s: %s', movieID, e) + mdict = {} + return mdict mdict = {'title': m.title, 'kind': kindDict[m.kindID], 'year': m.productionYear, 'imdbIndex': m.imdbIndex, 'season': m.seasonNr, 'episode': m.episodeNr} @@ -825,14 +830,14 @@ class IMDbSqlAccessSystem(IMDbBase): imdbID = movie.imdbID if imdbID is not None: return '%07d' % imdbID m_dict = get_movie_data(movie.id, self._kind) - titline = build_title(m_dict, ptdf=1) - imdbID = self.title2imdbID(titline) + titline = build_title(m_dict, ptdf=0) + imdbID = self.title2imdbID(titline, m_dict['kind']) # If the imdbID was retrieved from the web and was not in the # database, update the database (ignoring errors, because it's # possibile that the current user has not update privileges). # There're times when I think I'm a genius; this one of # those times... - if imdbID is not None: + if imdbID is not None and not isinstance(imdbID, list): try: movie.imdbID = int(imdbID) except: pass return imdbID @@ -847,9 +852,9 @@ class IMDbSqlAccessSystem(IMDbBase): imdbID = person.imdbID if imdbID is not None: return '%07d' % imdbID n_dict = {'name': person.name, 'imdbIndex': person.imdbIndex} - namline = build_name(n_dict, canonical=1) + namline = build_name(n_dict, canonical=False) imdbID = self.name2imdbID(namline) - if imdbID is not None: + if imdbID is not None and not isinstance(imdbID, list): try: person.imdbID = int(imdbID) except: pass return imdbID @@ -864,9 +869,9 @@ class IMDbSqlAccessSystem(IMDbBase): imdbID = character.imdbID if imdbID is not None: return '%07d' % imdbID n_dict = {'name': character.name, 'imdbIndex': character.imdbIndex} - namline = build_name(n_dict, canonical=1) + namline = build_name(n_dict, canonical=False) imdbID = self.character2imdbID(namline) - if imdbID is not None: + if imdbID is not None and not isinstance(imdbID, list): try: character.imdbID = int(imdbID) except: pass return imdbID @@ -883,7 +888,7 @@ class IMDbSqlAccessSystem(IMDbBase): n_dict = {'name': company.name, 'country': company.countryCode} namline = build_company_name(n_dict) imdbID = self.company2imdbID(namline) - if imdbID is not None: + if imdbID is not None and not isinstance(imdbID, list): try: company.imdbID = int(imdbID) except: pass return imdbID @@ -1116,8 +1121,9 @@ class IMDbSqlAccessSystem(IMDbBase): if mlinks: for ml in mlinks: lmovieData = get_movie_data(ml[0], self._kind) - m = Movie(movieID=ml[0], data=lmovieData, accessSystem='sql') - ml[0] = m + if lmovieData: + m = Movie(movieID=ml[0], data=lmovieData, accessSystem='sql') + ml[0] = m res['connections'] = {} mlinks[:] = _groupListBy(mlinks, 1) for group in mlinks: diff --git a/lib/imdb/parser/sql/alchemyadapter.py b/lib/imdb/parser/sql/alchemyadapter.py index 9b5c79e4..eb14e76c 100644 --- a/lib/imdb/parser/sql/alchemyadapter.py +++ b/lib/imdb/parser/sql/alchemyadapter.py @@ -466,6 +466,7 @@ class _AlchemyConnection(object): def setConnection(uri, tables, encoding='utf8', debug=False): """Set connection for every table.""" + params = {'encoding': encoding} # FIXME: why on earth MySQL requires an additional parameter, # is well beyond my understanding... if uri.startswith('mysql'): @@ -474,7 +475,11 @@ def setConnection(uri, tables, encoding='utf8', debug=False): else: uri += '?' uri += 'charset=%s' % encoding - params = {'encoding': encoding} + + # On some server configurations, we will need to explictly enable + # loading data from local files + params['local_infile'] = 1 + if debug: params['echo'] = True if uri.startswith('ibm_db'): diff --git a/lib/imdb/parser/sql/cutils.so b/lib/imdb/parser/sql/cutils.so deleted file mode 100644 index 80246ffd19f5f796323f034f03f263b390710a1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28469 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 diff --git a/lib/imdb/parser/sql/objectadapter.py b/lib/imdb/parser/sql/objectadapter.py index 97971042..e102c45f 100644 --- a/lib/imdb/parser/sql/objectadapter.py +++ b/lib/imdb/parser/sql/objectadapter.py @@ -182,6 +182,10 @@ def setConnection(uri, tables, encoding='utf8', debug=False): kw['use_unicode'] = 1 #kw['sqlobject_encoding'] = encoding kw['charset'] = encoding + + # On some server configurations, we will need to explictly enable + # loading data from local files + kw['local_infile'] = 1 conn = connectionForURI(uri, **kw) conn.debug = debug # XXX: doesn't work and a work-around was put in imdbpy2sql.py; diff --git a/lib/imdb/utils.py b/lib/imdb/utils.py index 9c300b08..f468efd4 100644 --- a/lib/imdb/utils.py +++ b/lib/imdb/utils.py @@ -3,7 +3,7 @@ utils module (imdb package). This module provides basic utilities for the imdb package. -Copyright 2004-2012 Davide Alberani +Copyright 2004-2013 Davide Alberani 2009 H. Turgut Uyar This program is free software; you can redistribute it and/or modify @@ -189,10 +189,9 @@ _unicodeArticles = linguistics.toUnicode(_articles) articlesDicts = linguistics.articlesDictsForLang(None) spArticles = linguistics.spArticlesForLang(None) -def canonicalTitle(title, lang=None): +def canonicalTitle(title, lang=None, imdbIndex=None): """Return the title in the canonic format 'Movie Title, The'; - beware that it doesn't handle long imdb titles, but only the - title portion, without year[/imdbIndex] or special markup. + beware that it doesn't handle long imdb titles. The 'lang' argument can be used to specify the language of the title. """ isUnicode = isinstance(title, unicode) @@ -203,15 +202,19 @@ def canonicalTitle(title, lang=None): except IndexError: pass if isUnicode: - _format = u'%s, %s' + _format = u'%s%s, %s' else: - _format = '%s, %s' + _format = '%s%s, %s' ltitle = title.lower() + if imdbIndex: + imdbIndex = ' (%s)' % imdbIndex + else: + imdbIndex = '' spArticles = linguistics.spArticlesForLang(lang) for article in spArticles[isUnicode]: if ltitle.startswith(article): lart = len(article) - title = _format % (title[lart:], title[:lart]) + title = _format % (title[lart:], imdbIndex, title[:lart]) if article[-1] == ' ': title = title[:-1] break @@ -383,18 +386,42 @@ def analyze_title(title, canonical=None, canonicalSeries=None, if title.endswith('(TV)'): kind = u'tv movie' title = title[:-4].rstrip() + elif title.endswith('(TV Movie)'): + kind = u'tv movie' + title = title[:-10].rstrip() elif title.endswith('(V)'): kind = u'video movie' title = title[:-3].rstrip() - elif title.endswith('(video)'): + elif title.lower().endswith('(video)'): kind = u'video movie' title = title[:-7].rstrip() + elif title.endswith('(TV Short)'): + kind = u'tv short' + title = title[:-10].rstrip() + elif title.endswith('(TV Mini-Series)'): + kind = u'tv mini series' + title = title[:-16].rstrip() elif title.endswith('(mini)'): kind = u'tv mini series' title = title[:-6].rstrip() elif title.endswith('(VG)'): kind = u'video game' title = title[:-4].rstrip() + elif title.endswith('(Video Game)'): + kind = u'video game' + title = title[:-12].rstrip() + elif title.endswith('(TV Series)'): + epindex = title.find('(TV Episode) - ') + if epindex >= 0: + # It's an episode of a series. + kind = u'episode' + series_info = analyze_title(title[epindex + 15:]) + result['episode of'] = series_info.get('title') + result['series year'] = series_info.get('year') + title = title[:epindex] + else: + kind = u'tv series' + title = title[:-11].rstrip() # Search for the year and the optional imdbIndex (a roman number). yi = re_year_index.findall(title) if not yi: @@ -430,9 +457,6 @@ def analyze_title(title, canonical=None, canonicalSeries=None, if not kind: kind = u'tv series' title = title[1:-1].strip() - elif title.endswith('(TV series)'): - kind = u'tv series' - title = title[:-11].rstrip() if not title: raise IMDbParserError('invalid title: "%s"' % original_t) if canonical is not None: @@ -489,7 +513,7 @@ def _convertTime(title, fromPTDFtoWEB=1, _emptyString=u''): def build_title(title_dict, canonical=None, canonicalSeries=None, canonicalEpisode=None, ptdf=0, lang=None, _doYear=1, - _emptyString=u''): + _emptyString=u'', appendKind=True): """Given a dictionary that represents a "long" IMDb title, return a string. @@ -511,6 +535,11 @@ def build_title(title_dict, canonical=None, canonicalSeries=None, doYear = 0 if ptdf: doYear = 1 + # XXX: for results coming from the new search page. + if not isinstance(episode_of, (dict, _Container)): + episode_of = {'title': episode_of, 'kind': 'tv series'} + if 'series year' in title_dict: + episode_of['year'] = title_dict['series year'] pre_title = build_title(episode_of, canonical=canonicalSeries, ptdf=0, _doYear=doYear, _emptyString=_emptyString) @@ -545,12 +574,14 @@ def build_title(title_dict, canonical=None, canonicalSeries=None, episode_title += '.%s' % episode episode_title += ')' episode_title = '{%s}' % episode_title - return '%s %s' % (pre_title, episode_title) + return _emptyString + '%s %s' % (_emptyString + pre_title, + _emptyString + episode_title) title = title_dict.get('title', '') + imdbIndex = title_dict.get('imdbIndex', '') if not title: return _emptyString if canonical is not None: if canonical: - title = canonicalTitle(title, lang=lang) + title = canonicalTitle(title, lang=lang, imdbIndex=imdbIndex) else: title = normalizeTitle(title, lang=lang) if pre_title: @@ -558,15 +589,20 @@ def build_title(title_dict, canonical=None, canonicalSeries=None, if kind in (u'tv series', u'tv mini series'): title = '"%s"' % title if _doYear: - imdbIndex = title_dict.get('imdbIndex') - year = title_dict.get('year') or u'????' + year = title_dict.get('year') or '????' if isinstance(_emptyString, str): year = str(year) - title += ' (%s' % year - if imdbIndex: - title += '/%s' % imdbIndex - title += ')' - if kind: + imdbIndex = title_dict.get('imdbIndex') + if not ptdf: + if imdbIndex and (canonical is None or canonical): + title += ' (%s)' % imdbIndex + title += ' (%s)' % year + else: + title += ' (%s' % year + if imdbIndex and (canonical is None or canonical): + title += '/%s' % imdbIndex + title += ')' + if appendKind and kind: if kind == 'tv movie': title += ' (TV)' elif kind == 'video movie': diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py index 36ba497a..150eda7c 100644 --- a/lib/tvdb_api/tvdb_api.py +++ b/lib/tvdb_api/tvdb_api.py @@ -11,6 +11,7 @@ __author__ = "dbr/Ben" __version__ = "1.9" import os +import re import time import getpass import StringIO @@ -18,8 +19,10 @@ import tempfile import warnings import logging import zipfile +import datetime as dt import requests import cachecontrol +import xmltodict try: import xml.etree.cElementTree as ElementTree @@ -31,6 +34,7 @@ try: except ImportError: gzip = None +from lib.dateutil.parser import parse from cachecontrol import caches from tvdb_ui import BaseUI, ConsoleUI @@ -560,44 +564,71 @@ class Tvdb: except requests.Timeout, e: raise tvdb_error("Connection timed out " + str(e.message) + " while loading URL " + str(url)) - if 'application/zip' in resp.headers.get("Content-Type", '') and resp.ok: - try: - # TODO: The zip contains actors.xml and banners.xml, which are currently ignored [GH-20] - log().debug("We recived a zip file unpacking now ...") - zipdata = StringIO.StringIO() - zipdata.write(resp.content) - myzipfile = zipfile.ZipFile(zipdata) - return myzipfile.read('%s.xml' % language) - except zipfile.BadZipfile: - raise tvdb_error("Bad zip file received from thetvdb.com, could not read it") + def process(path, key, value): + key = key.lower() - return resp.content if resp.ok else None + # clean up value and do type changes + if value: + try: + # convert to integer if needed + if value.isdigit(): + value = int(value) + except: + pass + + if key in ['banner', 'fanart', 'poster']: + value = self.config['url_artworkPrefix'] % (value) + else: + value = self._cleanData(value) + + try: + if key == 'firstaired' and value in "0000-00-00": + new_value = str(dt.date.fromordinal(1)) + new_value = re.sub("([-]0{2}){1,}", "", new_value) + fixDate = parse(new_value, fuzzy=True).date() + value = fixDate.strftime("%Y-%m-%d") + elif key == 'firstaired': + value = parse(value, fuzzy=True).date() + value = value.strftime("%Y-%m-%d") + except: + pass + + value = self._cleanData(value) + return (key, value) + + if resp.ok: + if 'application/zip' in resp.headers.get("Content-Type", ''): + try: + # TODO: The zip contains actors.xml and banners.xml, which are currently ignored [GH-20] + log().debug("We recived a zip file unpacking now ...") + zipdata = StringIO.StringIO() + zipdata.write(resp.content) + myzipfile = zipfile.ZipFile(zipdata) + return xmltodict.parse(myzipfile.read('%s.xml' % language), postprocessor=process) + except zipfile.BadZipfile: + raise tvdb_error("Bad zip file received from thetvdb.com, could not read it") + else: + return xmltodict.parse(resp.text.strip(), postprocessor=process) def _getetsrc(self, url, params=None, language=None): """Loads a URL using caching, returns an ElementTree of the source """ - src = self._loadUrl(url, params=params, language=language) try: - # TVDB doesn't sanitize \r (CR) from user input in some fields, - # remove it to avoid errors. Change from SickBeard, from will14m - return ElementTree.fromstring(src.rstrip("\r")) if src else None - except SyntaxError: src = self._loadUrl(url, params=params, language=language) - try: - return ElementTree.fromstring(src.rstrip("\r")) if src else None - except SyntaxError, exceptionmsg: - errormsg = "There was an error with the XML retrieved from thetvdb.com:\n%s" % ( - exceptionmsg + src = [src[item] for item in src][0] + except: + errormsg = "There was an error with the XML retrieved from thetvdb.com:" + + if self.config['cache_enabled']: + errormsg += "\nFirst try emptying the cache folder at..\n%s" % ( + self.config['cache_location'] ) - if self.config['cache_enabled']: - errormsg += "\nFirst try emptying the cache folder at..\n%s" % ( - self.config['cache_location'] - ) + errormsg += "\nIf this does not resolve the issue, please try again later. If the error persists, report a bug on" + errormsg += "\nhttp://dbr.lighthouseapp.com/projects/13342-tvdb_api/overview\n" + raise tvdb_error(errormsg) - errormsg += "\nIf this does not resolve the issue, please try again later. If the error persists, report a bug on" - errormsg += "\nhttp://dbr.lighthouseapp.com/projects/13342-tvdb_api/overview\n" - raise tvdb_error(errormsg) + return src def _setItem(self, sid, seas, ep, attrib, value): """Creates a new episode, creating Show(), Season() and @@ -649,9 +680,8 @@ class Tvdb: log().debug("Searching for show %s" % series) self.config['params_getSeries']['seriesname'] = series seriesEt = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']) - allSeries = list(dict((s.tag.lower(), s.text) for s in x.getchildren()) for x in seriesEt) - return allSeries + return [seriesEt[item] for item in seriesEt][0] def _getSeries(self, series): """This searches TheTVDB.com for the series name, @@ -798,24 +828,13 @@ class Tvdb: self.config['url_seriesInfo'] % (sid, getShowInLanguage) ) - if seriesInfoEt is None: return False - for curInfo in seriesInfoEt.findall("Series")[0]: - tag = curInfo.tag.lower() - value = curInfo.text + # check and make sure we have data to process and that it contains a series name + if seriesInfoEt is None or 'seriesname' not in seriesInfoEt['series']: + return False - if tag == 'seriesname' and value is None: - return False + for k, v in seriesInfoEt['series'].items(): + self._setShowData(sid, k, v) - if value is not None: - if tag == 'id': - value = int(value) - - if tag in ['banner', 'fanart', 'poster']: - value = self.config['url_artworkPrefix'] % (value) - else: - value = self._cleanData(value) - - self._setShowData(sid, tag, value) if seriesSearch: return True @@ -837,63 +856,40 @@ class Tvdb: epsEt = self._getetsrc(url, language=language) - for cur_ep in epsEt.findall("Episode"): - + for cur_ep in epsEt["episode"]: if self.config['dvdorder']: log().debug('Using DVD ordering.') - use_dvd = cur_ep.find('DVD_season').text != None and cur_ep.find('DVD_episodenumber').text != None + use_dvd = cur_ep['dvd_season'] != None and cur_ep['dvd_episodenumber'] != None else: use_dvd = False if use_dvd: - elem_seasnum, elem_epno = cur_ep.find('DVD_season'), cur_ep.find('DVD_episodenumber') + seasnum, epno = cur_ep['dvd_season'], cur_ep['dvd_episodenumber'] else: - elem_seasnum, elem_epno = cur_ep.find('SeasonNumber'), cur_ep.find('EpisodeNumber') - - if elem_seasnum is None or elem_epno is None: + seasnum, epno = cur_ep['seasonnumber'], cur_ep['episodenumber'] + if seasnum is None or epno is None: log().warning("An episode has incomplete season/episode number (season: %r, episode: %r)" % ( - elem_seasnum, elem_epno)) - log().debug( - " ".join( - "%r is %r" % (child.tag, child.text) for child in cur_ep.getchildren())) - # TODO: Should this happen? + seasnum, epno)) continue # Skip to next episode - # float() is because https://github.com/dbr/tvnamer/issues/95 - should probably be fixed in TVDB data - seas_no = int(float(elem_seasnum.text)) - ep_no = int(float(elem_epno.text)) + seas_no = int(float(seasnum)) + ep_no = int(float(epno)) - useDVD = False + for k,v in cur_ep.items(): + k = k.lower() - if (self.config['dvdorder']): - log().debug('DVD Order? Yes') - useDVD = (cur_ep.find('DVD_season').text != None and cur_ep.find('DVD_episodenumber').text != None) - else: - log().debug('DVD Order? No') + if v is not None: + if k == 'id': + v = int(v) - if (useDVD): - log().debug('Use DVD Order? Yes') - seas_no = int(cur_ep.find('DVD_season').text) - ep_no = int(float(cur_ep.find('DVD_episodenumber').text)) - else: - log().debug('Use DVD Order? No') - seas_no = int(cur_ep.find('SeasonNumber').text) - ep_no = int(cur_ep.find('EpisodeNumber').text) - - for cur_item in cur_ep.getchildren(): - tag = cur_item.tag.lower() - value = cur_item.text - if value is not None: - if tag == 'id': - value = int(value) - - if tag == 'filename': - value = self.config['url_artworkPrefix'] % (value) + if k == 'filename': + v = self.config['url_artworkPrefix'] % (v) else: - value = self._cleanData(value) - self._setItem(sid, seas_no, ep_no, tag, value) + v = self._cleanData(v) + + self._setItem(sid, seas_no, ep_no, k, v) return True diff --git a/lib/tvrage_api/tvrage_api.py b/lib/tvrage_api/tvrage_api.py index 08452b42..bad2b5cb 100644 --- a/lib/tvrage_api/tvrage_api.py +++ b/lib/tvrage_api/tvrage_api.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +# !/usr/bin/env python2 #encoding:utf-8 #author:echel0n #project:tvrage_api @@ -24,6 +24,7 @@ import logging import datetime as dt import requests import cachecontrol +import xmltodict try: import xml.etree.cElementTree as ElementTree @@ -35,11 +36,13 @@ from cachecontrol import caches from tvrage_ui import BaseUI from tvrage_exceptions import (tvrage_error, tvrage_userabort, tvrage_shownotfound, - tvrage_seasonnotfound, tvrage_episodenotfound, tvrage_attributenotfound) + tvrage_seasonnotfound, tvrage_episodenotfound, tvrage_attributenotfound) + def log(): return logging.getLogger("tvrage_api") + def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None): """Retry calling the decorated function using an exponential backoff. @@ -83,6 +86,7 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None): return deco_retry + class ShowContainer(dict): """Simple dict that holds a series of Show instances """ @@ -105,13 +109,14 @@ class ShowContainer(dict): _lastgc = time.time() del tbd - + super(ShowContainer, self).__setitem__(key, value) class Show(dict): """Holds a dict of seasons, and show data. """ + def __init__(self): dict.__init__(self) self.data = {} @@ -157,7 +162,7 @@ class Show(dict): raise tvrage_episodenotfound("Could not find any episodes that aired on %s" % date) return ret - def search(self, term = None, key = None): + def search(self, term=None, key=None): """ Search all episodes in show. Can search all data, or a specific key (for example, episodename) @@ -173,7 +178,7 @@ class Show(dict): """ results = [] for cur_season in self.values(): - searchresult = cur_season.search(term = term, key = key) + searchresult = cur_season.search(term=term, key=key) if len(searchresult) != 0: results.extend(searchresult) @@ -181,7 +186,7 @@ class Show(dict): class Season(dict): - def __init__(self, show = None): + def __init__(self, show=None): """The show attribute points to the parent show """ self.show = show @@ -202,13 +207,13 @@ class Season(dict): else: return dict.__getitem__(self, episode_number) - def search(self, term = None, key = None): + def search(self, term=None, key=None): """Search all episodes in season, returns a list of matching Episode instances. """ results = [] for ep in self.values(): - searchresult = ep.search(term = term, key = key) + searchresult = ep.search(term=term, key=key) if searchresult is not None: results.append( searchresult @@ -217,7 +222,7 @@ class Season(dict): class Episode(dict): - def __init__(self, season = None): + def __init__(self, season=None): """The season attribute points to the parent season """ self.season = season @@ -242,7 +247,7 @@ class Episode(dict): except KeyError: raise tvrage_attributenotfound("Cannot find attribute %s" % (repr(key))) - def search(self, term = None, key = None): + def search(self, term=None, key=None): """Search episode data for term, if it matches, return the Episode (self). The key parameter can be used to limit the search to a specific element, for example, episodename. @@ -258,25 +263,27 @@ class Episode(dict): if key is not None and cur_key != key: # Do not search this key continue - if cur_value.find( unicode(term).lower() ) > -1: + if cur_value.find(unicode(term).lower()) > -1: return self + class TVRage: """Create easy-to-use interface to name of season/episode name""" + def __init__(self, - interactive = False, - select_first = False, - debug = False, - cache = True, - banners = False, - actors = False, - custom_ui = None, - language = None, - search_all_languages = False, - apikey = None, - forceConnect=False, - useZip=False, - dvdorder=False): + interactive=False, + select_first=False, + debug=False, + cache=True, + banners=False, + actors=False, + custom_ui=None, + language=None, + search_all_languages=False, + apikey=None, + forceConnect=False, + useZip=False, + dvdorder=False): """ cache (True/False/str/unicode/urllib2 opener): @@ -294,18 +301,18 @@ class TVRage: return an exception immediately. """ - self.shows = ShowContainer() # Holds all Show classes - self.corrections = {} # Holds show-name to show_id mapping - self.sess = requests.session() # HTTP Session + self.shows = ShowContainer() # Holds all Show classes + self.corrections = {} # Holds show-name to show_id mapping + self.sess = requests.session() # HTTP Session self.config = {} if apikey is not None: self.config['apikey'] = apikey else: - self.config['apikey'] = "Uhewg1Rr0o62fvZvUIZt" # tvdb_api's API key + self.config['apikey'] = "Uhewg1Rr0o62fvZvUIZt" # tvdb_api's API key - self.config['debug_enabled'] = debug # show debugging messages + self.config['debug_enabled'] = debug # show debugging messages self.config['custom_ui'] = custom_ui @@ -322,8 +329,8 @@ class TVRage: if self.config['debug_enabled']: warnings.warn("The debug argument to tvrage_api.__init__ will be removed in the next version. " - "To enable debug messages, use the following code before importing: " - "import logging; logging.basicConfig(level=logging.DEBUG)") + "To enable debug messages, use the following code before importing: " + "import logging; logging.basicConfig(level=logging.DEBUG)") logging.basicConfig(level=logging.DEBUG) @@ -331,8 +338,8 @@ class TVRage: # Hard-coded here as it is realtively static, and saves another HTTP request, as # recommended on http://tvrage.com/wiki/index.php/API:languages.xml self.config['valid_languages'] = [ - "da", "fi", "nl", "de", "it", "es", "fr","pl", "hu","el","tr", - "ru","he","ja","pt","zh","cs","sl", "hr","ko","en","sv","no" + "da", "fi", "nl", "de", "it", "es", "fr", "pl", "hu", "el", "tr", + "ru", "he", "ja", "pt", "zh", "cs", "sl", "hr", "ko", "en", "sv", "no" ] # tvrage.com should be based around numeric language codes, @@ -340,9 +347,9 @@ class TVRage: # requires the language ID, thus this mapping is required (mainly # for usage in tvrage_ui - internally tvrage_api will use the language abbreviations) self.config['langabbv_to_id'] = {'el': 20, 'en': 7, 'zh': 27, - 'it': 15, 'cs': 28, 'es': 16, 'ru': 22, 'nl': 13, 'pt': 26, 'no': 9, - 'tr': 21, 'pl': 18, 'fr': 17, 'hr': 31, 'de': 14, 'da': 10, 'fi': 11, - 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, 'sv': 8, 'sl': 30} + 'it': 15, 'cs': 28, 'es': 16, 'ru': 22, 'nl': 13, 'pt': 26, 'no': 9, + 'tr': 21, 'pl': 18, 'fr': 17, 'hr': 31, 'de': 14, 'da': 10, 'fi': 11, + 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, 'sv': 8, 'sl': 30} if language is None: self.config['language'] = 'en' @@ -390,9 +397,9 @@ class TVRage: # get response from TVRage if self.config['cache_enabled']: - resp = self.sess.get(url, cache_auto=True, params=params) + resp = self.sess.get(url.strip(), cache_auto=True, params=params) else: - resp = requests.get(url, params=params) + resp = requests.get(url.strip(), params=params) except requests.HTTPError, e: raise tvrage_error("HTTP error " + str(e.errno) + " while loading URL " + str(url)) @@ -403,81 +410,84 @@ class TVRage: except requests.Timeout, e: raise tvrage_error("Connection timed out " + str(e.message) + " while loading URL " + str(url)) - return resp.content if resp.ok else None + def remap_keys(path, key, value): + name_map = { + 'showid': 'id', + 'showname': 'seriesname', + 'name': 'seriesname', + 'summary': 'overview', + 'started': 'firstaired', + 'genres': 'genre', + 'airtime': 'airs_time', + 'airday': 'airs_dayofweek', + 'image': 'fanart', + 'epnum': 'absolute_number', + 'title': 'episodename', + 'airdate': 'firstaired', + 'screencap': 'filename', + 'seasonnum': 'episodenumber' + } + + try: + key = name_map[key.lower()] + except (ValueError, TypeError, KeyError): + key.lower() + + # clean up value and do type changes + if value: + if isinstance(value, dict): + if key == 'network': + value = value['#text'] + if key == 'genre': + value = value['genre'] + if not isinstance(value, list): + value = [value] + value = '|' + '|'.join(value) + '|' + + try: + # convert to integer if needed + if value.isdigit(): + value = int(value) + except: + pass + + try: + if key == 'firstaired' and value in "0000-00-00": + new_value = str(dt.date.fromordinal(1)) + new_value = re.sub("([-]0{2}){1,}", "", new_value) + fixDate = parse(new_value, fuzzy=True).date() + value = fixDate.strftime("%Y-%m-%d") + elif key == 'firstaired': + value = parse(value, fuzzy=True).date() + value = value.strftime("%Y-%m-%d") + except: + pass + + value = self._cleanData(value) + return (key, value) + + if resp.ok: + return xmltodict.parse(resp.text.strip(), postprocessor=remap_keys) def _getetsrc(self, url, params=None): """Loads a URL using caching, returns an ElementTree of the source """ - reDict = { - 'showid': 'id', - 'showname': 'seriesname', - 'name': 'seriesname', - 'summary': 'overview', - 'started': 'firstaired', - 'genres': 'genre', - 'airtime': 'airs_time', - 'airday': 'airs_dayofweek', - 'image': 'fanart', - 'epnum': 'absolute_number', - 'title': 'episodename', - 'airdate': 'firstaired', - 'screencap': 'filename', - 'seasonnum': 'episodenumber', - } - robj = re.compile('|'.join(reDict.keys())) - src = self._loadUrl(url, params) try: - # TVRAGE doesn't sanitize \r (CR) from user input in some fields, - # remove it to avoid errors. Change from SickBeard, from will14m - xml = ElementTree.fromstring(src.rstrip("\r")) - tree = ElementTree.ElementTree(xml) - for elm in tree.findall('.//*'): - elm.tag = robj.sub(lambda m: reDict[m.group(0)], elm.tag) - - if elm.tag in 'firstaired': - try: - if elm.text in "0000-00-00": - elm.text = str(dt.date.fromordinal(1)) - elm.text = re.sub("([-]0{2}){1,}", "", elm.text) - fixDate = parse(elm.text, fuzzy=True).date() - elm.text = fixDate.strftime("%Y-%m-%d") - except: - pass - return ElementTree.fromstring(ElementTree.tostring(xml)) - except SyntaxError: src = self._loadUrl(url, params) - try: - xml = ElementTree.fromstring(src.rstrip("\r")) - tree = ElementTree.ElementTree(xml) - for elm in tree.findall('.//*'): - elm.tag = robj.sub(lambda m: reDict[m.group(0)], elm.tag) + src = [src[item] for item in src][0] + except: + errormsg = "There was an error with the XML retrieved from tvrage.com" - if elm.tag in 'firstaired' and elm.text: - if elm.text == "0000-00-00": - elm.text = str(dt.date.fromordinal(1)) - try: - #month = strptime(match.group('air_month')[:3],'%b').tm_mon - #day = re.sub("(st|nd|rd|th)", "", match.group('air_day')) - #dtStr = '%s/%s/%s' % (year, month, day) - - fixDate = parse(elm.text, fuzzy=True) - elm.text = fixDate.strftime("%Y-%m-%d") - except: - pass - return ElementTree.fromstring(ElementTree.tostring(xml)) - except SyntaxError, exceptionmsg: - errormsg = "There was an error with the XML retrieved from tvrage.com:\n%s" % ( - exceptionmsg + if self.config['cache_enabled']: + errormsg += "\nFirst try emptying the cache folder at..\n%s" % ( + self.config['cache_location'] ) - if self.config['cache_enabled']: - errormsg += "\nFirst try emptying the cache folder at..\n%s" % ( - self.config['cache_location'] - ) + errormsg += "\nIf this does not resolve the issue, please try again later. If the error persists, report a bug on\n" + raise tvrage_error(errormsg) - errormsg += "\nIf this does not resolve the issue, please try again later. If the error persists, report a bug on\n" - raise tvrage_error(errormsg) + return src def _setItem(self, sid, seas, ep, attrib, value): """Creates a new episode, creating Show(), Season() and @@ -497,9 +507,9 @@ class TVRage: if sid not in self.shows: self.shows[sid] = Show() if seas not in self.shows[sid]: - self.shows[sid][seas] = Season(show = self.shows[sid]) + self.shows[sid][seas] = Season(show=self.shows[sid]) if ep not in self.shows[sid][seas]: - self.shows[sid][seas][ep] = Episode(season = self.shows[sid][seas]) + self.shows[sid][seas][ep] = Episode(season=self.shows[sid][seas]) self.shows[sid][seas][ep][attrib] = value def _setShowData(self, sid, key, value): @@ -529,9 +539,8 @@ class TVRage: log().debug("Searching for show %s" % series) self.config['params_getSeries']['show'] = series seriesEt = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']) - allSeries = list(dict((s.tag.lower(),s.text) for s in x.getchildren()) for x in seriesEt) - return allSeries + return [seriesEt[item] for item in seriesEt][0] def _getSeries(self, series): """This searches tvrage.com for the series name, @@ -547,10 +556,10 @@ class TVRage: if self.config['custom_ui'] is not None: log().debug("Using custom UI %s" % (repr(self.config['custom_ui']))) - ui = self.config['custom_ui'](config = self.config) + ui = self.config['custom_ui'](config=self.config) else: log().debug('Auto-selecting first search result using BaseUI') - ui = BaseUI(config = self.config) + ui = BaseUI(config=self.config) return ui.selectSeries(allSeries) @@ -568,62 +577,49 @@ class TVRage: self.config['params_seriesInfo'] ) - if seriesInfoEt is None: return False - for curInfo in seriesInfoEt: - tag = curInfo.tag.lower() - value = curInfo.text + # check and make sure we have data to process and that it contains a series name + if seriesInfoEt is None or 'seriesname' not in seriesInfoEt: + return False - if tag == 'seriesname' and value is None: - return False + for k, v in seriesInfoEt.items(): + self._setShowData(sid, k, v) - if tag == 'id': - value = int(value) - - if value is not None: - value = self._cleanData(value) - - self._setShowData(sid, tag, value) - if seriesSearch: return True - - try: - # Parse genre data - log().debug('Getting genres of %s' % (sid)) - for genre in seriesInfoEt.find('genres'): - tag = genre.tag.lower() - - value = genre.text - if value is not None: - value = self._cleanData(value) - - self._setShowData(sid, tag, value) - except Exception: - log().debug('No genres for %s' % (sid)) + # series search ends here + if seriesSearch: + return True # Parse episode data log().debug('Getting all episodes of %s' % (sid)) self.config['params_epInfo']['sid'] = sid epsEt = self._getetsrc(self.config['url_epInfo'], self.config['params_epInfo']) - for cur_list in epsEt.findall("Episodelist"): - for cur_seas in cur_list: - try: - seas_no = int(cur_seas.attrib['no']) - for cur_ep in cur_seas: - ep_no = int(cur_ep.find('episodenumber').text) - self._setItem(sid, seas_no, ep_no, 'seasonnumber', seas_no) - for cur_item in cur_ep: - tag = cur_item.tag.lower() - value = cur_item.text - if value is not None: - if tag == 'id': - value = int(value) + for season in epsEt['Episodelist']['Season']: + episodes = season['episode'] + if not isinstance(episodes, list): + episodes = [episodes] - value = self._cleanData(value) + for episode in episodes: + seas_no = int(season['@no']) + ep_no = int(episode['episodenumber']) + self._setItem(sid, seas_no, ep_no, 'seasonnumber', seas_no) - self._setItem(sid, seas_no, ep_no, tag, value) - except: - continue + for k,v in episode.items(): + try: + k = k.lower() + if v is not None: + if k == 'link': + v = v.rsplit('/', 1)[1] + k = 'id' + + if k == 'id': + v = int(v) + + v = self._cleanData(v) + + self._setItem(sid, seas_no, ep_no, k, v) + except: + continue return True def _nameToSid(self, name): @@ -632,7 +628,7 @@ class TVRage: the correct SID. """ if name in self.corrections: - log().debug('Correcting %s to %s' % (name, self.corrections[name]) ) + log().debug('Correcting %s to %s' % (name, self.corrections[name])) return self.corrections[name] else: log().debug('Getting show %s' % (name)) @@ -673,11 +669,13 @@ def main(): grabs an episode name interactively. """ import logging + logging.basicConfig(level=logging.DEBUG) tvrage_instance = TVRage(cache=False) print tvrage_instance['Lost']['seriesname'] print tvrage_instance['Lost'][1][4]['episodename'] + if __name__ == '__main__': main() diff --git a/lib/xmltodict.py b/lib/xmltodict.py new file mode 100644 index 00000000..4fdbb16a --- /dev/null +++ b/lib/xmltodict.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python +"Makes working with XML feel like you are working with JSON" + +from xml.parsers import expat +from xml.sax.saxutils import XMLGenerator +from xml.sax.xmlreader import AttributesImpl +try: # pragma no cover + from cStringIO import StringIO +except ImportError: # pragma no cover + try: + from StringIO import StringIO + except ImportError: + from io import StringIO +try: # pragma no cover + from collections import OrderedDict +except ImportError: # pragma no cover + try: + from ordereddict import OrderedDict + except ImportError: + OrderedDict = dict + +try: # pragma no cover + _basestring = basestring +except NameError: # pragma no cover + _basestring = str +try: # pragma no cover + _unicode = unicode +except NameError: # pragma no cover + _unicode = str + +__author__ = 'Martin Blech' +__version__ = '0.9.0' +__license__ = 'MIT' + + +class ParsingInterrupted(Exception): + pass + + +class _DictSAXHandler(object): + def __init__(self, + item_depth=0, + item_callback=lambda *args: True, + xml_attribs=True, + attr_prefix='@', + cdata_key='#text', + force_cdata=False, + cdata_separator='', + postprocessor=None, + dict_constructor=OrderedDict, + strip_whitespace=True, + namespace_separator=':', + namespaces=None): + self.path = [] + self.stack = [] + self.data = None + self.item = None + self.item_depth = item_depth + self.xml_attribs = xml_attribs + self.item_callback = item_callback + self.attr_prefix = attr_prefix + self.cdata_key = cdata_key + self.force_cdata = force_cdata + self.cdata_separator = cdata_separator + self.postprocessor = postprocessor + self.dict_constructor = dict_constructor + self.strip_whitespace = strip_whitespace + self.namespace_separator = namespace_separator + self.namespaces = namespaces + + def _build_name(self, full_name): + if not self.namespaces: + return full_name + i = full_name.rfind(self.namespace_separator) + if i == -1: + return full_name + namespace, name = full_name[:i], full_name[i+1:] + short_namespace = self.namespaces.get(namespace, namespace) + if not short_namespace: + return name + else: + return self.namespace_separator.join((short_namespace, name)) + + def _attrs_to_dict(self, attrs): + if isinstance(attrs, dict): + return attrs + return self.dict_constructor(zip(attrs[0::2], attrs[1::2])) + + def startElement(self, full_name, attrs): + name = self._build_name(full_name) + attrs = self._attrs_to_dict(attrs) + self.path.append((name, attrs or None)) + if len(self.path) > self.item_depth: + self.stack.append((self.item, self.data)) + if self.xml_attribs: + attrs = self.dict_constructor( + (self.attr_prefix+key, value) + for (key, value) in attrs.items()) + else: + attrs = None + self.item = attrs or None + self.data = None + + def endElement(self, full_name): + name = self._build_name(full_name) + if len(self.path) == self.item_depth: + item = self.item + if item is None: + item = self.data + should_continue = self.item_callback(self.path, item) + if not should_continue: + raise ParsingInterrupted() + if len(self.stack): + item, data = self.item, self.data + self.item, self.data = self.stack.pop() + if self.strip_whitespace and data is not None: + data = data.strip() or None + if data and self.force_cdata and item is None: + item = self.dict_constructor() + if item is not None: + if data: + self.push_data(item, self.cdata_key, data) + self.item = self.push_data(self.item, name, item) + else: + self.item = self.push_data(self.item, name, data) + else: + self.item = self.data = None + self.path.pop() + + def characters(self, data): + if not self.data: + self.data = data + else: + self.data += self.cdata_separator + data + + def push_data(self, item, key, data): + if self.postprocessor is not None: + result = self.postprocessor(self.path, key, data) + if result is None: + return item + key, data = result + if item is None: + item = self.dict_constructor() + try: + value = item[key] + if isinstance(value, list): + value.append(data) + else: + item[key] = [value, data] + except KeyError: + item[key] = data + return item + + +def parse(xml_input, encoding=None, expat=expat, process_namespaces=False, + namespace_separator=':', **kwargs): + """Parse the given XML input and convert it into a dictionary. + + `xml_input` can either be a `string` or a file-like object. + + If `xml_attribs` is `True`, element attributes are put in the dictionary + among regular child elements, using `@` as a prefix to avoid collisions. If + set to `False`, they are just ignored. + + Simple example:: + + >>> import xmltodict + >>> doc = xmltodict.parse(\"\"\" + ... + ... 1 + ... 2 + ... + ... \"\"\") + >>> doc['a']['@prop'] + u'x' + >>> doc['a']['b'] + [u'1', u'2'] + + If `item_depth` is `0`, the function returns a dictionary for the root + element (default behavior). Otherwise, it calls `item_callback` every time + an item at the specified depth is found and returns `None` in the end + (streaming mode). + + The callback function receives two parameters: the `path` from the document + root to the item (name-attribs pairs), and the `item` (dict). If the + callback's return value is false-ish, parsing will be stopped with the + :class:`ParsingInterrupted` exception. + + Streaming example:: + + >>> def handle(path, item): + ... print 'path:%s item:%s' % (path, item) + ... return True + ... + >>> xmltodict.parse(\"\"\" + ... + ... 1 + ... 2 + ... \"\"\", item_depth=2, item_callback=handle) + path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:1 + path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:2 + + The optional argument `postprocessor` is a function that takes `path`, + `key` and `value` as positional arguments and returns a new `(key, value)` + pair where both `key` and `value` may have changed. Usage example:: + + >>> def postprocessor(path, key, value): + ... try: + ... return key + ':int', int(value) + ... except (ValueError, TypeError): + ... return key, value + >>> xmltodict.parse('12x', + ... postprocessor=postprocessor) + OrderedDict([(u'a', OrderedDict([(u'b:int', [1, 2]), (u'b', u'x')]))]) + + You can pass an alternate version of `expat` (such as `defusedexpat`) by + using the `expat` parameter. E.g: + + >>> import defusedexpat + >>> xmltodict.parse('hello', expat=defusedexpat.pyexpat) + OrderedDict([(u'a', u'hello')]) + + """ + handler = _DictSAXHandler(namespace_separator=namespace_separator, + **kwargs) + if isinstance(xml_input, _unicode): + if not encoding: + encoding = 'utf-8' + xml_input = xml_input.encode(encoding) + if not process_namespaces: + namespace_separator = None + parser = expat.ParserCreate( + encoding, + namespace_separator + ) + try: + parser.ordered_attributes = True + except AttributeError: + # Jython's expat does not support ordered_attributes + pass + parser.StartElementHandler = handler.startElement + parser.EndElementHandler = handler.endElement + parser.CharacterDataHandler = handler.characters + parser.buffer_text = True + try: + parser.ParseFile(xml_input) + except (TypeError, AttributeError): + parser.Parse(xml_input, True) + return handler.item + + +def _emit(key, value, content_handler, + attr_prefix='@', + cdata_key='#text', + depth=0, + preprocessor=None, + pretty=False, + newl='\n', + indent='\t'): + if preprocessor is not None: + result = preprocessor(key, value) + if result is None: + return + key, value = result + if not isinstance(value, (list, tuple)): + value = [value] + if depth == 0 and len(value) > 1: + raise ValueError('document with multiple roots') + for v in value: + if v is None: + v = OrderedDict() + elif not isinstance(v, dict): + v = _unicode(v) + if isinstance(v, _basestring): + v = OrderedDict(((cdata_key, v),)) + cdata = None + attrs = OrderedDict() + children = [] + for ik, iv in v.items(): + if ik == cdata_key: + cdata = iv + continue + if ik.startswith(attr_prefix): + attrs[ik[len(attr_prefix):]] = iv + continue + children.append((ik, iv)) + if pretty: + content_handler.ignorableWhitespace(depth * indent) + content_handler.startElement(key, AttributesImpl(attrs)) + if pretty and children: + content_handler.ignorableWhitespace(newl) + for child_key, child_value in children: + _emit(child_key, child_value, content_handler, + attr_prefix, cdata_key, depth+1, preprocessor, + pretty, newl, indent) + if cdata is not None: + content_handler.characters(cdata) + if pretty and children: + content_handler.ignorableWhitespace(depth * indent) + content_handler.endElement(key) + if pretty and depth: + content_handler.ignorableWhitespace(newl) + + +def unparse(input_dict, output=None, encoding='utf-8', full_document=True, + **kwargs): + """Emit an XML document for the given `input_dict` (reverse of `parse`). + + The resulting XML document is returned as a string, but if `output` (a + file-like object) is specified, it is written there instead. + + Dictionary keys prefixed with `attr_prefix` (default=`'@'`) are interpreted + as XML node attributes, whereas keys equal to `cdata_key` + (default=`'#text'`) are treated as character data. + + The `pretty` parameter (default=`False`) enables pretty-printing. In this + mode, lines are terminated with `'\n'` and indented with `'\t'`, but this + can be customized with the `newl` and `indent` parameters. + + """ + ((key, value),) = input_dict.items() + must_return = False + if output is None: + output = StringIO() + must_return = True + content_handler = XMLGenerator(output, encoding) + if full_document: + content_handler.startDocument() + _emit(key, value, content_handler, **kwargs) + if full_document: + content_handler.endDocument() + if must_return: + value = output.getvalue() + try: # pragma no cover + value = value.decode(encoding) + except AttributeError: # pragma no cover + pass + return value + +if __name__ == '__main__': # pragma: no cover + import sys + import marshal + + (item_depth,) = sys.argv[1:] + item_depth = int(item_depth) + + def handle_item(path, item): + marshal.dump((path, item), sys.stdout) + return True + + try: + root = parse(sys.stdin, + item_depth=item_depth, + item_callback=handle_item, + dict_constructor=dict) + if item_depth == 0: + handle_item([], root) + except KeyboardInterrupt: + pass diff --git a/sickbeard/metadata/generic.py b/sickbeard/metadata/generic.py index 277cfaeb..c53fbe32 100644 --- a/sickbeard/metadata/generic.py +++ b/sickbeard/metadata/generic.py @@ -782,14 +782,10 @@ class GenericMetadata(): # Try and get posters and fanart from TMDB if image_url is None: - for show_name in set(allPossibleShowNames(show_obj)): - if image_type in ('poster', 'poster_thumb'): - image_url = self._retrieve_show_images_from_tmdb(show_obj, poster=True) - elif image_type == 'fanart': - image_url = self._retrieve_show_images_from_tmdb(show_obj, backdrop=True) - - if image_url: - break + if image_type in ('poster', 'poster_thumb'): + image_url = self._retrieve_show_images_from_tmdb(show_obj, poster=True) + elif image_type == 'fanart': + image_url = self._retrieve_show_images_from_tmdb(show_obj, backdrop=True) if image_url: image_data = metadata_helpers.getShowImage(image_url, which) @@ -965,8 +961,6 @@ class GenericMetadata(): return (indexer_id, name, indexer) def _retrieve_show_images_from_tmdb(self, show, backdrop=False, poster=False): - tmdb_id = None - # get TMDB configuration info tmdb = TMDB(sickbeard.TMDB_API_KEY) config = tmdb.Configuration() @@ -981,27 +975,14 @@ class GenericMetadata(): try: search = tmdb.Search() - for result in search.collection({'query': show.name}) + search.tv({'query': show.name}): - tmdb_id = result['id'] - external_ids = tmdb.TV(tmdb_id).external_ids() - if show.indexerid in [external_ids['tvdb_id'], external_ids['tvrage_id']]: - break + for show_name in set(allPossibleShowNames(show)): + for result in search.collection({'query': show_name})['results'] + search.tv({'query': show_name})['results']: + if backdrop and result['backdrop_path']: + return "{0}{1}{2}".format(base_url, max_size, result['backdrop_path']) + elif poster and result['poster_path']: + return "{0}{1}{2}".format(base_url, max_size, result['poster_path']) - if tmdb_id: - images = tmdb.Collections(tmdb_id).images() - if len(images) > 0: - # get backdrop urls - if backdrop: - rel_path = images['backdrops'][0]['file_path'] - url = "{0}{1}{2}".format(base_url, max_size, rel_path) - return url - - # get poster urls - if poster: - rel_path = images['posters'][0]['file_path'] - url = "{0}{1}{2}".format(base_url, max_size, rel_path) - return url - except: + except Exception, e: pass logger.log(u"Could not find any posters or background for " + show.name, logger.DEBUG) \ No newline at end of file diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 93d9cfa4..f8515c6e 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -829,7 +829,7 @@ class TVShow(object): self.airs = myEp["airs_dayofweek"] + " " + myEp["airs_time"] if getattr(myEp, 'firstaired', None) is not None: - self.startyear = int(myEp["firstaired"].split('-')[0]) + self.startyear = int(str(myEp["firstaired"]).split('-')[0]) self.status = getattr(myEp, 'status', '') @@ -855,7 +855,6 @@ class TVShow(object): i = imdb.IMDb() imdbTv = i.get_movie(str(re.sub("[^0-9]", "", self.imdbid))) - test = imdbTv.keys() for key in filter(lambda x: x.replace('_', ' ') in imdbTv.keys(), imdb_info.keys()): # Store only the first value for string type if type(imdb_info[key]) == type('') and type(imdbTv.get(key)) == type([]): @@ -1556,7 +1555,7 @@ class TVEpisode(object): self.deleteEpisode() return False - if myEp["absolute_number"] == None or myEp["absolute_number"] == "": + if getattr(myEp, 'absolute_number', None) is None: logger.log(u"This episode (" + self.show.name + " - " + str(season) + "x" + str( episode) + ") has no absolute number on " + sickbeard.indexerApi( self.indexer).name @@ -1564,7 +1563,7 @@ class TVEpisode(object): else: logger.log( str(self.show.indexerid) + ": The absolute_number for " + str(season) + "x" + str(episode) + " is : " + - myEp["absolute_number"], logger.DEBUG) + str(myEp["absolute_number"]), logger.DEBUG) self.absolute_number = int(myEp["absolute_number"]) self.name = getattr(myEp, 'episodename', "") @@ -1603,8 +1602,9 @@ class TVEpisode(object): u"The show dir is missing, not bothering to change the episode statuses since it'd probably be invalid") return - logger.log(str(self.show.indexerid) + u": Setting status for " + str(season) + "x" + str( - episode) + " based on status " + str(self.status) + " and existence of " + self.location, logger.DEBUG) + if self.location: + logger.log(str(self.show.indexerid) + u": Setting status for " + str(season) + "x" + str( + episode) + " based on status " + str(self.status) + " and existence of " + self.location, logger.DEBUG) if not ek.ek(os.path.isfile, self.location): From 6558b8ac7192b2ba14d73a6ebab7d0a0a3a04bcf Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 28 May 2014 23:24:23 -0700 Subject: [PATCH 26/82] Code cleanup --- sickbeard/versionChecker.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sickbeard/versionChecker.py b/sickbeard/versionChecker.py index bbe742c3..e78d9cb4 100644 --- a/sickbeard/versionChecker.py +++ b/sickbeard/versionChecker.py @@ -54,15 +54,11 @@ class CheckVersion(): self.updater = None def run(self, force=False): - updated = None if self.check_for_new_version(): if sickbeard.AUTO_UPDATE: logger.log(u"New update found for SickRage, starting auto-updater ...") - updated = sickbeard.versionCheckScheduler.action.update() - if updated: + if sickbeard.versionCheckScheduler.action.update(): logger.log(u"Update was successfull, restarting SickRage ...") - - # do a soft restart threading.Timer(2, sickbeard.invoke_restart, [False]).start() def find_install_type(self): @@ -141,6 +137,8 @@ class WindowsUpdateManager(UpdateManager): self.version_url = 'https://raw.github.com/' + self.github_repo_user + '/' + self.github_repo + '/' + self.branch + '/updates.txt' def _find_installed_version(self): + version = '' + try: version = sickbeard.version.SICKBEARD_VERSION return int(version[6:]) @@ -278,7 +276,7 @@ class GitUpdateManager(UpdateManager): self._num_commits_ahead = 0 def _git_error(self): - error_message = 'Unable to find your git executable - Shutdown SickRage and EITHER set git_path in your config.ini OR delete your .git folder and run from source to enable updates.' + error_message = 'Unable to find your git executable - Shutdown SickRage and EITHER set git_path in your config.ini OR delete your .git folder and run from source to enable updates.' sickbeard.NEWEST_VERSION_STRING = error_message def _find_working_git(self): @@ -324,7 +322,7 @@ class GitUpdateManager(UpdateManager): logger.log(u"Not using: " + cur_git, logger.DEBUG) # Still haven't found a working git - error_message = 'Unable to find your git executable - Shutdown SickRage and EITHER set git_path in your config.ini OR delete your .git folder and run from source to enable updates.' + error_message = 'Unable to find your git executable - Shutdown SickRage and EITHER set git_path in your config.ini OR delete your .git folder and run from source to enable updates.' sickbeard.NEWEST_VERSION_STRING = error_message return None From 42b621103f5a77abc1fe5823d40a376977f7bc5a Mon Sep 17 00:00:00 2001 From: echel0n Date: Thu, 29 May 2014 00:00:59 -0700 Subject: [PATCH 27/82] Fix for restart and PID issues. --- SickBeard.py | 41 +++++++++++++++++++++++++++-------------- sickbeard/__init__.py | 7 +++++-- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/SickBeard.py b/SickBeard.py index e5a36cc7..591eddf6 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +# !/usr/bin/env python2 # Author: Nic Wolfe # URL: http://code.google.com/p/sickbeard/ # @@ -19,12 +19,14 @@ # Check needed software dependencies to nudge users to fix their setup import sys + if sys.version_info < (2, 6): print "Sorry, requires Python 2.6 or 2.7." sys.exit(1) try: import Cheetah + if Cheetah.Version[0] != '2': raise ValueError except ValueError: @@ -35,11 +37,12 @@ except: sys.exit(1) import os + sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib'))) # We only need this for compiling an EXE and I will just always do that on 2.6+ if sys.hexversion >= 0x020600F0: - from multiprocessing import freeze_support # @UnresolvedImport + from multiprocessing import freeze_support # @UnresolvedImport import locale import datetime @@ -65,7 +68,8 @@ from lib.configobj import ConfigObj signal.signal(signal.SIGINT, sickbeard.sig_handler) signal.signal(signal.SIGTERM, sickbeard.sig_handler) -throwaway = datetime.datetime.strptime('20110101','%Y%m%d') +throwaway = datetime.datetime.strptime('20110101', '%Y%m%d') + def loadShowsFromDB(): """ @@ -80,10 +84,12 @@ def loadShowsFromDB(): curShow = TVShow(int(sqlShow["indexer"]), int(sqlShow["indexer_id"])) sickbeard.showList.append(curShow) except Exception, e: - logger.log(u"There was an error creating the show in " + sqlShow["location"] + ": " + str(e).decode('utf-8'), logger.ERROR) + logger.log( + u"There was an error creating the show in " + sqlShow["location"] + ": " + str(e).decode('utf-8'), + logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) - # TODO: update the existing shows if the showlist has something in it + # TODO: update the existing shows if the showlist has something in it def daemonize(): @@ -101,7 +107,7 @@ def daemonize(): sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) - os.setsid() # @UndefinedVariable - only available in UNIX + os.setsid(pid) # @UndefinedVariable - only available in UNIX # Make sure I can read my own files and shut out others prev = os.umask(0) @@ -139,6 +145,7 @@ def daemonize(): os.dup2(stdout.fileno(), sys.stdout.fileno()) os.dup2(stderr.fileno(), sys.stderr.fileno()) + def main(): """ TV for me @@ -194,7 +201,9 @@ def main(): threading.currentThread().name = "MAIN" try: - opts, args = getopt.getopt(sys.argv[1:], "qfdp::", ['quiet', 'forceupdate', 'daemon', 'port=', 'pidfile=', 'nolaunch', 'config=', 'datadir=']) # @UnusedVariable + opts, args = getopt.getopt(sys.argv[1:], "qfdp::", + ['quiet', 'forceupdate', 'daemon', 'port=', 'pidfile=', 'nolaunch', 'config=', + 'datadir=']) # @UnusedVariable except getopt.GetoptError: print "Available Options: --quiet, --forceupdate, --port, --daemon, --pidfile, --config, --datadir" sys.exit() @@ -300,13 +309,17 @@ def main(): CUR_DB_VERSION = db.DBConnection().checkDBVersion() if CUR_DB_VERSION > 0: if CUR_DB_VERSION < MIN_DB_VERSION: - raise SystemExit("Your database version (" + str(db.DBConnection().checkDBVersion()) + ") is too old to migrate from with this version of SickRage (" + str(MIN_DB_VERSION) + ").\n" + \ + raise SystemExit("Your database version (" + str( + db.DBConnection().checkDBVersion()) + ") is too old to migrate from with this version of SickRage (" + str( + MIN_DB_VERSION) + ").\n" + \ "Upgrade using a previous version of SB first, or start with no database file to begin fresh.") if CUR_DB_VERSION > MAX_DB_VERSION: - raise SystemExit("Your database version (" + str(db.DBConnection().checkDBVersion()) + ") has been incremented past what this version of SickRage supports (" + str(MAX_DB_VERSION) + ").\n" + \ + raise SystemExit("Your database version (" + str( + db.DBConnection().checkDBVersion()) + ") has been incremented past what this version of SickRage supports (" + str( + MAX_DB_VERSION) + ").\n" + \ "If you have used other forks of SB, your database may be unusable due to their modifications.") - # Initialize the config and our threads + # Initialize the config and our threads sickbeard.initialize(consoleLogging=consoleLogging) sickbeard.showList = [] @@ -342,16 +355,16 @@ def main(): initWebServer({ 'port': startPort, 'host': webhost, - 'data_root': os.path.join(sickbeard.PROG_DIR, 'gui/'+sickbeard.GUI_NAME), + 'data_root': os.path.join(sickbeard.PROG_DIR, 'gui/' + sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, - 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, + 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': sickbeard.HTTPS_CERT, 'https_key': sickbeard.HTTPS_KEY, - }) + }) except IOError: logger.log(u"Unable to start web server, is something else running on port %d?" % startPort, logger.ERROR) if sickbeard.LAUNCH_BROWSER and not sickbeard.DAEMON: @@ -372,7 +385,7 @@ def main(): # Start an update if we're supposed to if forceUpdate or sickbeard.UPDATE_SHOWS_ON_START: - sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable + sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable # Stay alive while my threads do the work while (True): diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 991b1b1d..c32181ac 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -1303,6 +1303,7 @@ def saveAndShutdown(restart=False): logger.log(u"Removing pidfile " + str(PIDFILE)) remove_pid_file(PIDFILE) + status = 0 if restart: install_type = versionCheckScheduler.action.install_type @@ -1325,9 +1326,11 @@ def saveAndShutdown(restart=False): popen_list += ['--nolaunch'] logger.log(u"Restarting SickRage with " + str(popen_list)) logger.close() - subprocess.Popen(popen_list, cwd=os.getcwd()) + p = subprocess.Popen(popen_list, cwd=os.getcwd()) + p.wait() + status = p.returncode - os._exit(0) + os._exit(status) def invoke_command(to_call, *args, **kwargs): From 6fc93be7b5a0e7fa2b28c8b7a453820fbadbc735 Mon Sep 17 00:00:00 2001 From: echel0n Date: Thu, 29 May 2014 01:00:13 -0700 Subject: [PATCH 28/82] Fix for restart spawning more then one process of SickRage --- sickbeard/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index c32181ac..66799e78 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -1326,11 +1326,12 @@ def saveAndShutdown(restart=False): popen_list += ['--nolaunch'] logger.log(u"Restarting SickRage with " + str(popen_list)) logger.close() - p = subprocess.Popen(popen_list, cwd=os.getcwd()) - p.wait() - status = p.returncode + subprocess.Popen(popen_list, cwd=os.getcwd()) + time.sleep(5) - os._exit(status) + logger.log(u"SickRage successfully restarted ...") + + os._exit(0) def invoke_command(to_call, *args, **kwargs): From 87c74769070883717daed94fd4b9567cf25388fd Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Thu, 29 May 2014 10:04:43 +0200 Subject: [PATCH 29/82] Revert "Make UI look better on iOS" This reverts commit 690b904b980c019723724ca8c849ed1b76988571. Apparently, this doesn't only make the UI look better, but it also makes it dysfunctional. --- gui/slick/interfaces/default/inc_top.tmpl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gui/slick/interfaces/default/inc_top.tmpl b/gui/slick/interfaces/default/inc_top.tmpl index 5015d8a3..b7bc1c18 100644 --- a/gui/slick/interfaces/default/inc_top.tmpl +++ b/gui/slick/interfaces/default/inc_top.tmpl @@ -15,10 +15,6 @@ - - - - From 4a4eec0a9e1ad81aa01238cca36c7a994773866d Mon Sep 17 00:00:00 2001 From: echel0n Date: Thu, 29 May 2014 02:04:09 -0700 Subject: [PATCH 30/82] Fix for restart issues --- SickBeard.py | 2 +- sickbeard/__init__.py | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/SickBeard.py b/SickBeard.py index 591eddf6..6ecc731c 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -107,7 +107,7 @@ def daemonize(): sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) - os.setsid(pid) # @UndefinedVariable - only available in UNIX + os.setsid() # unix # Make sure I can read my own files and shut out others prev = os.umask(0) diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 66799e78..d0e05570 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -1293,7 +1293,6 @@ def saveAll(): def saveAndShutdown(restart=False): halt() - saveAll() logger.log(u"Killing cherrypy") @@ -1303,7 +1302,6 @@ def saveAndShutdown(restart=False): logger.log(u"Removing pidfile " + str(PIDFILE)) remove_pid_file(PIDFILE) - status = 0 if restart: install_type = versionCheckScheduler.action.install_type @@ -1324,16 +1322,14 @@ def saveAndShutdown(restart=False): popen_list += MY_ARGS if '--nolaunch' not in popen_list: popen_list += ['--nolaunch'] + logger.log(u"Restarting SickRage with " + str(popen_list)) logger.close() - subprocess.Popen(popen_list, cwd=os.getcwd()) - time.sleep(5) - logger.log(u"SickRage successfully restarted ...") + subprocess.Popen(popen_list, cwd=os.getcwd()) os._exit(0) - def invoke_command(to_call, *args, **kwargs): global invoked_command From e1ee01579dcc82cd013238c601f97dc304c0c4fe Mon Sep 17 00:00:00 2001 From: echel0n Date: Thu, 29 May 2014 06:27:05 -0700 Subject: [PATCH 31/82] Fixed issues with TVDB retrieving banners and posters. Fixed unicode issues with Indexer API's Fixed issues with scene numbering. Fixed issues with black and white lists for anime shows when editing a show. --- gui/slick/interfaces/default/editShow.tmpl | 60 ++++++++++++++- lib/tvdb_api/tvdb_api.py | 88 ++++++++++------------ lib/tvrage_api/tvrage_api.py | 35 ++++----- sickbeard/scene_numbering.py | 2 +- sickbeard/show_queue.py | 11 ++- sickbeard/tv.py | 7 +- 6 files changed, 127 insertions(+), 76 deletions(-) diff --git a/gui/slick/interfaces/default/editShow.tmpl b/gui/slick/interfaces/default/editShow.tmpl index 22c5a72a..c9c90fd9 100644 --- a/gui/slick/interfaces/default/editShow.tmpl +++ b/gui/slick/interfaces/default/editShow.tmpl @@ -3,6 +3,7 @@ #from sickbeard import common #from sickbeard import exceptions #from sickbeard import scene_exceptions +#from sickbeard.blackandwhitelist import * #set global $title="Edit " + $show.name #set global $header=$show.name @@ -170,6 +171,7 @@ Realease Groups:
+
@@ -198,13 +200,26 @@ Realease Groups: \$('#submit').click(function(){ all_exceptions = [] - + \$("#exceptions_list option").each ( function() { all_exceptions.push( \$(this).val() ); }); \$("#exceptions_list").val(all_exceptions); - + + var realvalues = []; + + \$('#white option').each(function(i, selected) { + realvalues[i] = \$(selected).val(); + }); + \$("#whitelist").val(realvalues.join(",")); + + realvalues = []; + \$('#black option').each(function(i, selected) { + realvalues[i] = \$(selected).val(); + }); + \$("#blacklist").val(realvalues.join(",")); + }); \$('#addSceneName').click(function() { @@ -247,8 +262,45 @@ Realease Groups: \$("#SceneException").show(); } - \$(this).toggle_SceneException(); - + \$(this).toggle_SceneException(); + + \$('#removeW').click(function() { + return !\$('#white option:selected').remove().appendTo('#pool'); + }); + \$('#addW').click(function() { + return !\$('#pool option:selected').remove().appendTo('#white'); + }); + \$('#addB').click(function() { + return !\$('#pool option:selected').remove().appendTo('#black'); + }); + \$('#removeP').click(function() { + return !\$('#pool option:selected').remove(); + }); + \$('#removeB').click(function() { + return !\$('#black option:selected').remove().appendTo('#pool'); + }); + + \$('#addToWhite').click(function() { + var group = \$('#addToPoolText').attr("value") + if(group == "") + return + \$('#addToPoolText').attr("value", "") + var option = \$("

+
+ Scene Numbering +
+ +

+
+
Anime
diff --git a/sickbeard/naming.py b/sickbeard/naming.py index 1c8cc76f..eb0c5c27 100644 --- a/sickbeard/naming.py +++ b/sickbeard/naming.py @@ -54,6 +54,7 @@ class TVShow(): self.air_by_date = 0 self.sports = 0 self.anime = 0 + self.scene = 0 class TVEpisode(tv.TVEpisode): def __init__(self, season, episode, absolute_number, name): @@ -64,6 +65,7 @@ class TVEpisode(tv.TVEpisode): self._absolute_number = absolute_number self._scene_season = season self._scene_episode = episode + self._scene_absolute_number = absolute_number self._airdate = datetime.date(2010, 3, 9) self.show = TVShow() self._status = Quality.compositeStatus(common.DOWNLOADED, common.Quality.SDTV) diff --git a/sickbeard/tv.py b/sickbeard/tv.py index c972021d..9fc0580f 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -1895,7 +1895,16 @@ class TVEpisode(object): Returns: A string representing the episode's name and season/ep numbers """ - return self._format_pattern('Indexer#:[%SN - %Sx%0E - %EN] | Scene#:[%SN - %XSx%0XE - %EN]') + 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') + elif self.show.air_by_date: + return self._format_pattern('%SN - %AD - %EN') + else: + return self._format_pattern('%SN - %Sx%0E - %EN') def _ep_name(self): """ @@ -2000,7 +2009,8 @@ class TVEpisode(object): '%0XS': '%02d' % self.scene_season, '%XE': str(self.scene_episode), '%0XE': '%02d' % self.scene_episode, - '%AN': '%(#)03d' % {'#': self.absolute_number}, + '%A': '%(#)03d' % {'#': self.absolute_number}, + '%XA': '%(#)03d' % {'#': self.scene_absolute_number}, '%RN': release_name(self.release_name), '%RG': release_group(self.release_name), '%AD': str(self.airdate).replace('-', ' '), diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 8a9efe9d..f21fcffb 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -581,6 +581,9 @@ class Manage: subtitles_all_same = True last_subtitles = None + scene_all_same = True + last_scene = None + root_dir_list = [] for curShow in showList: @@ -622,12 +625,19 @@ class Manage: else: last_subtitles = curShow.subtitles + if scene_all_same: + if last_scene not in (None, curShow.scene): + scene_all_same = False + else: + last_scene = curShow.scene + t.showList = toEdit t.paused_value = last_paused if paused_all_same else None t.anime_value = last_anime if anime_all_same else None t.flatten_folders_value = last_flatten_folders if flatten_folders_all_same else None t.quality_value = last_quality if quality_all_same else None t.subtitles_value = last_subtitles if subtitles_all_same else None + t.scene_value = last_scene if scene_all_same else None t.root_dir_list = root_dir_list return _munge(t) @@ -3168,6 +3178,16 @@ class Home: else: do_update = True + if scene == showObj.scene: + do_update_scene_numbering = False + else: + do_update_scene_numbering = True + + if anime == showObj.anime: + do_update_scene_absolute_numbering = False + else: + do_update_scene_absolute_numbering = True + if type(anyQualities) != list: anyQualities = [anyQualities] @@ -3181,7 +3201,7 @@ class Home: if directCall: do_update_exceptions = False else: - if set(exceptions_list) == set(showObj.exceptions): + if directCall or set(exceptions_list) == set(showObj.exceptions): do_update_exceptions = False else: do_update_exceptions = True @@ -3303,6 +3323,13 @@ class Home: except exceptions.CantUpdateException, e: errors.append("Unable to force an update on scene exceptions of the show.") + if do_update_scene_numbering or do_update_scene_absolute_numbering: + try: + sickbeard.scene_numbering.xem_refresh(showObj.indexerid, showObj.indexer) # @UndefinedVariable + time.sleep(cpu_presets[sickbeard.CPU_PRESET]) + except exceptions.CantUpdateException, e: + errors.append("Unable to force an update on scene numbering of the show.") + if directCall: return errors From 1abef89b29daa2386d5a5007799293d6779a7149 Mon Sep 17 00:00:00 2001 From: echel0n Date: Thu, 29 May 2014 23:49:47 -0700 Subject: [PATCH 38/82] Scene numbering now updates every 1 hour or is forced when needed so that searches always have up-to-date information before hand. --- sickbeard/scene_numbering.py | 162 +++++++++++++++-------------------- sickbeard/show_queue.py | 16 ++-- sickbeard/tv.py | 3 +- sickbeard/webserve.py | 5 +- 4 files changed, 82 insertions(+), 104 deletions(-) diff --git a/sickbeard/scene_numbering.py b/sickbeard/scene_numbering.py index 46bc6325..4cc05c48 100644 --- a/sickbeard/scene_numbering.py +++ b/sickbeard/scene_numbering.py @@ -241,8 +241,7 @@ def find_xem_numbering(indexer_id, indexer, season, episode): indexer_id = int(indexer_id) indexer = int(indexer) - if xem_refresh_needed(indexer_id, indexer): - xem_refresh(indexer_id, indexer) + xem_refresh(indexer_id, indexer) myDB = db.DBConnection() @@ -270,8 +269,7 @@ def find_xem_absolute_numbering(indexer_id, indexer, absolute_number): indexer_id = int(indexer_id) indexer = int(indexer) - if xem_refresh_needed(indexer_id, indexer): - xem_refresh(indexer_id, indexer) + xem_refresh(indexer_id, indexer) myDB = db.DBConnection() @@ -298,8 +296,7 @@ def get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode indexer_id = int(indexer_id) indexer = int(indexer) - if xem_refresh_needed(indexer_id, indexer): - xem_refresh(indexer_id, indexer) + xem_refresh(indexer_id, indexer) myDB = db.DBConnection() @@ -327,8 +324,7 @@ def get_indexer_absolute_numbering_for_xem(indexer_id, indexer, sceneAbsoluteNum indexer_id = int(indexer_id) indexer = int(indexer) - if xem_refresh_needed(indexer_id, indexer): - xem_refresh(indexer_id, indexer) + xem_refresh(indexer_id, indexer) myDB = db.DBConnection() @@ -383,8 +379,7 @@ def get_xem_numbering_for_show(indexer_id, indexer): indexer_id = int(indexer_id) indexer = int(indexer) - if xem_refresh_needed(indexer_id, indexer): - xem_refresh(indexer_id, indexer) + xem_refresh(indexer_id, indexer) myDB = db.DBConnection() @@ -444,8 +439,7 @@ def get_xem_absolute_numbering_for_show(indexer_id, indexer): indexer_id = int(indexer_id) indexer = int(indexer) - if xem_refresh_needed(indexer_id, indexer): - xem_refresh(indexer_id, indexer) + xem_refresh(indexer_id, indexer) myDB = db.DBConnection() @@ -462,30 +456,7 @@ def get_xem_absolute_numbering_for_show(indexer_id, indexer): return result - -def xem_refresh_needed(indexer_id, indexer): - """ - Is a refresh needed on a show? - - @param indexer_id: int - @return: bool - """ - if indexer_id is None: - return False - - indexer_id = int(indexer_id) - indexer = int(indexer) - - myDB = db.DBConnection() - rows = myDB.select("SELECT last_refreshed FROM xem_refresh WHERE indexer = ? and indexer_id = ?", - [indexer, indexer_id]) - if rows: - return time.time() > (int(rows[0]['last_refreshed']) + MAX_XEM_AGE_SECS) - else: - return True - - -def xem_refresh(indexer_id, indexer): +def xem_refresh(indexer_id, indexer, force=False): """ Refresh data from xem for a tv show @@ -497,69 +468,78 @@ def xem_refresh(indexer_id, indexer): indexer_id = int(indexer_id) indexer = int(indexer) - try: - logger.log( - u'Looking up XEM scene mapping for show %s on %s' % (indexer_id, sickbeard.indexerApi(indexer).name,), - logger.DEBUG) - data = requests.get("http://thexem.de/map/all?id=%s&origin=%s&destination=scene" % ( - indexer_id, sickbeard.indexerApi(indexer).config['xem_origin'],), verify=False).json() + myDB = db.DBConnection() - if data is None or data == '': - logger.log(u'No XEN data for show "%s on %s", trying TVTumbler' % ( - indexer_id, sickbeard.indexerApi(indexer).name,), logger.MESSAGE) - data = requests.get("http://show-api.tvtumbler.com/api/thexem/all?id=%s&origin=%s&destination=scene" % ( + rows = myDB.select("SELECT last_refreshed FROM xem_refresh WHERE indexer = ? and indexer_id = ?", + [indexer, indexer_id]) + if rows: + refresh = time.time() > (int(rows[0]['last_refreshed']) + MAX_XEM_AGE_SECS) + else: + refresh = True + + if refresh or force: + try: + logger.log( + u'Looking up XEM scene mapping for show %s on %s' % (indexer_id, sickbeard.indexerApi(indexer).name,), + logger.DEBUG) + data = requests.get("http://thexem.de/map/all?id=%s&origin=%s&destination=scene" % ( indexer_id, sickbeard.indexerApi(indexer).config['xem_origin'],), verify=False).json() + if data is None or data == '': - logger.log(u'TVTumbler also failed for show "%s on %s". giving up.' % (indexer_id, indexer,), - logger.MESSAGE) - return None + logger.log(u'No XEN data for show "%s on %s", trying TVTumbler' % ( + indexer_id, sickbeard.indexerApi(indexer).name,), logger.MESSAGE) + data = requests.get("http://show-api.tvtumbler.com/api/thexem/all?id=%s&origin=%s&destination=scene" % ( + indexer_id, sickbeard.indexerApi(indexer).config['xem_origin'],), verify=False).json() + if data is None or data == '': + logger.log(u'TVTumbler also failed for show "%s on %s". giving up.' % (indexer_id, indexer,), + logger.MESSAGE) + return None - result = data - myDB = db.DBConnection() + result = data - ql = [] - if result: - ql.append(["INSERT OR REPLACE INTO xem_refresh (indexer, indexer_id, last_refreshed) VALUES (?,?,?)", - [indexer, indexer_id, time.time()]]) - if 'success' in result['result']: - for entry in result['data']: - if 'scene' in entry: - ql.append([ - "UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?", - [entry['scene']['season'], - entry['scene']['episode'], - entry['scene']['absolute'], - indexer_id, - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'], - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode'] - ]]) - if 'scene_2' in entry: # for doubles - ql.append([ - "UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?", - [entry['scene_2']['season'], - entry['scene_2']['episode'], - entry['scene_2']['absolute'], - indexer_id, - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'], - entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode'] - ]]) + ql = [] + if result: + ql.append(["INSERT OR REPLACE INTO xem_refresh (indexer, indexer_id, last_refreshed) VALUES (?,?,?)", + [indexer, indexer_id, time.time()]]) + if 'success' in result['result']: + for entry in result['data']: + if 'scene' in entry: + ql.append([ + "UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?", + [entry['scene']['season'], + entry['scene']['episode'], + entry['scene']['absolute'], + indexer_id, + entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'], + entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode'] + ]]) + if 'scene_2' in entry: # for doubles + ql.append([ + "UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?", + [entry['scene_2']['season'], + entry['scene_2']['episode'], + entry['scene_2']['absolute'], + indexer_id, + entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'], + entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode'] + ]]) + else: + logger.log(u'Failed to get XEM scene data for show %s from %s because "%s"' % ( + indexer_id, sickbeard.indexerApi(indexer).name, result['message']), logger.DEBUG) else: - logger.log(u'Failed to get XEM scene data for show %s from %s because "%s"' % ( - indexer_id, sickbeard.indexerApi(indexer).name, result['message']), logger.DEBUG) - else: - logger.log(u"Empty lookup result - no XEM data for show %s on %s" % ( - indexer_id, sickbeard.indexerApi(indexer).name,), logger.DEBUG) - except Exception, e: - logger.log(u"Exception while refreshing XEM data for show " + str(indexer_id) + " on " + sickbeard.indexerApi( - indexer).name + ": " + ex(e), logger.WARNING) - logger.log(traceback.format_exc(), logger.DEBUG) - return None + logger.log(u"Empty lookup result - no XEM data for show %s on %s" % ( + indexer_id, sickbeard.indexerApi(indexer).name,), logger.DEBUG) + except Exception, e: + logger.log(u"Exception while refreshing XEM data for show " + str(indexer_id) + " on " + sickbeard.indexerApi( + indexer).name + ": " + ex(e), logger.WARNING) + logger.log(traceback.format_exc(), logger.DEBUG) + return None - if ql: - myDB.mass_action(ql) + if ql: + myDB.mass_action(ql) - # fix xem scene numbering issues - # fix_xem_numbering(indexer_id, indexer) + # fix xem scene numbering issues + # fix_xem_numbering(indexer_id, indexer) def fix_xem_numbering(indexer_id, indexer): diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py index 68706f29..6be7cbca 100644 --- a/sickbeard/show_queue.py +++ b/sickbeard/show_queue.py @@ -369,10 +369,6 @@ class QueueItemAdd(ShowQueueItem): myDB.action("UPDATE tv_episodes SET status = ? WHERE status = ? AND showid = ? AND season != 0", [self.default_status, SKIPPED, self.show.indexerid]) - # Load XEM data to DB for show - if sickbeard.scene_numbering.xem_refresh_needed(self.show.indexerid, self.show.indexer): - sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer) - # if they started with WANTED eps then run the backlog if self.default_status == WANTED: logger.log(u"Launching backlog for this show since its episodes are WANTED") @@ -387,6 +383,9 @@ class QueueItemAdd(ShowQueueItem): # if there are specific episodes that need to be added by trakt sickbeard.traktWatchListCheckerSchedular.action.manageNewShow(self.show) + # Load XEM data to DB for show + sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer, force=True) + self.finish() def _finishEarly(self): @@ -417,6 +416,9 @@ class QueueItemRefresh(ShowQueueItem): self.show.updateMetadata() self.show.populateCache() + # Load XEM data to DB for show + sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer, force=self.force) + self.inProgress = False @@ -486,10 +488,6 @@ class QueueItemUpdate(ShowQueueItem): logger.log(u"Beginning update of " + self.show.name) - # Load XEM data to DB for show - if sickbeard.scene_numbering.xem_refresh_needed(self.show.indexerid, self.show.indexer) or self.force: - sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer) - logger.log(u"Retrieving show info from " + sickbeard.indexerApi(self.show.indexer).name + "", logger.DEBUG) try: self.show.loadFromIndexer(cache=not self.force) @@ -533,9 +531,7 @@ class QueueItemUpdate(ShowQueueItem): if IndexerEpList == None: logger.log(u"No data returned from " + sickbeard.indexerApi( self.show.indexer).name + ", unable to update this show", logger.ERROR) - else: - # for each ep we found on TVDB delete it from the DB list for curSeason in IndexerEpList: for curEpisode in IndexerEpList[curSeason]: diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 9fc0580f..3bdd913c 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -198,8 +198,7 @@ class TVShow(object): def getEpisode(self, season=None, episode=None, file=None, noCreate=False, absolute_number=None): # Load XEM data to DB for show - if sickbeard.scene_numbering.xem_refresh_needed(self.indexerid, self.indexer): - sickbeard.scene_numbering.xem_refresh(self.indexerid, self.indexer) + sickbeard.scene_numbering.xem_refresh(self.indexerid, self.indexer) if not season in self.episodes: self.episodes[season] = {} diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index f21fcffb..0751ee92 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -2962,6 +2962,9 @@ class Home: showObj.exceptions = scene_exceptions.get_scene_exceptions(showObj.indexerid) + # Update scene numbering in DB + sickbeard.scene_numbering.xem_refresh(showObj.indexerid, showObj.indexer, True) + myDB = db.DBConnection() seasonResults = myDB.select( @@ -3318,7 +3321,7 @@ class Home: if do_update_exceptions: try: - scene_exceptions.update_scene_exceptions(showObj.indexerid, exceptions_list) # @UndefinedVariable + scene_exceptions.update_scene_exceptions(showObj.indexerid, exceptions_list, force=True) # @UndefinedVariable time.sleep(cpu_presets[sickbeard.CPU_PRESET]) except exceptions.CantUpdateException, e: errors.append("Unable to force an update on scene exceptions of the show.") From f01c5852d4f1241b062233ed4f4a7bd7afc7f9b6 Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 00:36:47 -0700 Subject: [PATCH 39/82] Improved find propers code. Backlog and manual searches now check cache first for search results. --- sickbeard/failedProcessor.py | 1 + sickbeard/properFinder.py | 72 +++++------------------------ sickbeard/providers/generic.py | 23 ++++----- sickbeard/providers/iptorrents.py | 14 +++--- sickbeard/providers/kat.py | 14 +++--- sickbeard/providers/nextgen.py | 14 +++--- sickbeard/providers/publichd.py | 14 +++--- sickbeard/providers/scc.py | 14 +++--- sickbeard/providers/speedcd.py | 63 +++++++++++++------------ sickbeard/providers/thepiratebay.py | 15 +++--- sickbeard/providers/torrentday.py | 14 +++--- sickbeard/providers/torrentleech.py | 14 +++--- sickbeard/tv.py | 4 +- 13 files changed, 114 insertions(+), 162 deletions(-) diff --git a/sickbeard/failedProcessor.py b/sickbeard/failedProcessor.py index 3b5317ae..293da42d 100644 --- a/sickbeard/failedProcessor.py +++ b/sickbeard/failedProcessor.py @@ -76,6 +76,7 @@ class FailedProcessor(object): raise exceptions.FailedProcessingFailed() segment = {parsed.season_number:[]} + for episode in parsed.episode_numbers: epObj = parsed.show.getEpisode(parsed.season_number, episode) segment[parsed.season_number].append(epObj) diff --git a/sickbeard/properFinder.py b/sickbeard/properFinder.py index 74f3b962..cbdcf32d 100644 --- a/sickbeard/properFinder.py +++ b/sickbeard/properFinder.py @@ -116,11 +116,10 @@ class ProperFinder(): sortedPropers = sorted(propers.values(), key=operator.attrgetter('date'), reverse=True) finalPropers = [] for curProper in sortedPropers: - in_cache = False try: myParser = NameParser(False) - parse_result = myParser.parse(curProper.name) + parse_result = myParser.parse(curProper.name).convert() except InvalidNameException: logger.log(u"Unable to parse the filename " + curProper.name + " into a valid episode", logger.DEBUG) continue @@ -128,37 +127,26 @@ class ProperFinder(): if not parse_result.series_name: continue - cacheResult = sickbeard.name_cache.retrieveNameFromCache(parse_result.series_name) - if cacheResult: - in_cache = True - curProper.indexerid = int(cacheResult) - elif cacheResult == 0: - return None - - if not curProper.indexerid: - showResult = helpers.searchDBForShow(parse_result.series_name) - if showResult: - curProper.indexerid = int(showResult[0]) - - if not curProper.indexerid: - for curShow in sickbeard.showList: - if show_name_helpers.isGoodResult(curProper.name, curShow, False): - curProper.indexerid = curShow.indexerid - break - if not parse_result.show: - sickbeard.name_cache.addNameToCache(parse_result.series_name, 0) continue - if not in_cache: - sickbeard.name_cache.addNameToCache(parse_result.series_name, parse_result.show.indexerid) - if not parse_result.episode_numbers: logger.log( u"Ignoring " + curProper.name + " because it's for a full season rather than specific episode", logger.DEBUG) continue + showObj = parse_result.show + logger.log( + u"Successful match! Result " + parse_result.series_name + " matched to show " + showObj.name, + logger.DEBUG) + + # set the indexerid in the db to the show's indexerid + curProper.indexerid = showObj.indexerid + + # set the indexer in the db to the show's indexer + curProper.indexer = showObj.indexer + # populate our Proper instance if parse_result.air_by_date or parse_result.sports: curProper.season = -1 @@ -167,53 +155,17 @@ class ProperFinder(): if parse_result.is_anime: logger.log(u"I am sorry '"+curProper.name+"' seams to be an anime proper seach is not yet suported", logger.DEBUG) continue - curProper.episode = parse_result.ab_episode_numbers[0] else: curProper.season = parse_result.season_number if parse_result.season_number != None else 1 curProper.episode = parse_result.episode_numbers[0] curProper.quality = Quality.nameQuality(curProper.name, parse_result.is_anime) - # for each show in our list - for curShow in sickbeard.showList: - - genericName = self._genericName(parse_result.series_name) - - # get the scene name masks - sceneNames = set(show_name_helpers.makeSceneShowSearchStrings(curShow)) - - # for each scene name mask - for curSceneName in sceneNames: - - # if it matches - if genericName == self._genericName(curSceneName): - logger.log( - u"Successful match! Result " + parse_result.series_name + " matched to show " + curShow.name, - logger.DEBUG) - - # set the indexerid in the db to the show's indexerid - curProper.indexerid = curShow.indexerid - - # set the indexer in the db to the show's indexer - curProper.indexer = curShow.indexer - - # since we found it, break out - break - - # if we found something in the inner for loop break out of this one - if curProper.indexerid != -1: - break - if not show_name_helpers.filterBadReleases(curProper.name): logger.log(u"Proper " + curProper.name + " isn't a valid scene release that we want, igoring it", logger.DEBUG) continue - showObj = helpers.findCertainShow(sickbeard.showList, curProper.indexerid) - if not showObj: - logger.log(u"Unable to find the show with indexerID " + str(curProper.indexerid), logger.ERROR) - continue - if showObj.rls_ignore_words and search.filter_release_name(curProper.name, showObj.rls_ignore_words): logger.log(u"Ignoring " + curProper.name + " based on ignored words filter: " + showObj.rls_ignore_words, logger.MESSAGE) diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index d947b67e..ab80bafd 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -248,21 +248,15 @@ class GenericProvider: # mark season searched for season pack searches so we can skip later on searched_scene_season = epObj.scene_season - if not epObj.show.air_by_date: - if epObj.scene_season == 0 or epObj.scene_episode == 0: - logger.log( - u"Incomplete Indexer <-> Scene mapping detected for " + epObj.prettyName() + ", skipping search!") - continue - - # cacheResult = self.cache.searchCache([epObj], manualSearch) - #if len(cacheResult): - # results.update({epObj.episode:cacheResult[epObj]}) - # continue - if search_mode == 'sponly': for curString in self._get_season_search_strings(epObj): itemList += self._doSearch(curString, len(episodes)) else: + cacheResult = self.cache.searchCache([epObj], manualSearch) + if len(cacheResult): + results.update({epObj.episode: cacheResult[epObj]}) + continue + for curString in self._get_episode_search_strings(epObj): itemList += self._doSearch(curString, len(episodes)) @@ -271,12 +265,11 @@ class GenericProvider: continue # remove duplicate items - #itemList = [i for n, i in enumerate(itemList) if i not in itemList[n + 1:]] searchItems[epObj] = itemList - # if we have cached results return them. - # if len(results): - # return results + #if we have cached results return them. + if len(results): + return results for ep_obj in searchItems: for item in searchItems[ep_obj]: diff --git a/sickbeard/providers/iptorrents.py b/sickbeard/providers/iptorrents.py index b1a319a7..c025c407 100644 --- a/sickbeard/providers/iptorrents.py +++ b/sickbeard/providers/iptorrents.py @@ -261,14 +261,14 @@ class IPTorrentsProvider(generic.TorrentProvider): return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results diff --git a/sickbeard/providers/kat.py b/sickbeard/providers/kat.py index a9d94b9a..382d40f5 100644 --- a/sickbeard/providers/kat.py +++ b/sickbeard/providers/kat.py @@ -397,15 +397,15 @@ class KATProvider(generic.TorrentProvider): return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results diff --git a/sickbeard/providers/nextgen.py b/sickbeard/providers/nextgen.py index 765ee524..9cc51c88 100644 --- a/sickbeard/providers/nextgen.py +++ b/sickbeard/providers/nextgen.py @@ -309,14 +309,14 @@ class NextGenProvider(generic.TorrentProvider): return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results diff --git a/sickbeard/providers/publichd.py b/sickbeard/providers/publichd.py index 0af12c8f..200a6693 100644 --- a/sickbeard/providers/publichd.py +++ b/sickbeard/providers/publichd.py @@ -288,15 +288,15 @@ class PublicHDProvider(generic.TorrentProvider): return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results diff --git a/sickbeard/providers/scc.py b/sickbeard/providers/scc.py index b95849e0..b2c16372 100644 --- a/sickbeard/providers/scc.py +++ b/sickbeard/providers/scc.py @@ -303,15 +303,15 @@ class SCCProvider(generic.TorrentProvider): return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results diff --git a/sickbeard/providers/speedcd.py b/sickbeard/providers/speedcd.py index c5ad72c5..e54647b2 100644 --- a/sickbeard/providers/speedcd.py +++ b/sickbeard/providers/speedcd.py @@ -11,7 +11,7 @@ # SickRage is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with SickRage. If not, see . @@ -37,14 +37,14 @@ from lib import requests from lib.requests import exceptions from sickbeard.helpers import sanitizeSceneName -class SpeedCDProvider(generic.TorrentProvider): +class SpeedCDProvider(generic.TorrentProvider): urls = {'base_url': 'http://speed.cd/', 'login': 'http://speed.cd/takelogin.php', 'detail': 'http://speed.cd/t/%s', 'search': 'http://speed.cd/V3/API/API.php', 'download': 'http://speed.cd/download.php?torrent=%s', - } + } def __init__(self): @@ -64,7 +64,7 @@ class SpeedCDProvider(generic.TorrentProvider): self.url = self.urls['base_url'] - self.categories = {'Season': {'c14':1}, 'Episode': {'c2':1, 'c49':1}, 'RSS': {'c14':1, 'c2':1, 'c49':1}} + self.categories = {'Season': {'c14': 1}, 'Episode': {'c2': 1, 'c49': 1}, 'RSS': {'c14': 1, 'c2': 1, 'c49': 1}} def isEnabled(self): return self.enabled @@ -81,7 +81,7 @@ class SpeedCDProvider(generic.TorrentProvider): login_params = {'username': self.username, 'password': self.password - } + } try: response = self.session.post(self.urls['login'], data=login_params, timeout=30, verify=False) @@ -90,7 +90,7 @@ class SpeedCDProvider(generic.TorrentProvider): return False if re.search('Incorrect username or Password. Please try again.', response.text) \ - or response.status_code == 401: + or response.status_code == 401: logger.log(u'Invalid username or password for ' + self.name + ' Check your settings', logger.ERROR) return False @@ -104,7 +104,7 @@ class SpeedCDProvider(generic.TorrentProvider): if ep_obj.show.air_by_date or ep_obj.show.sports: ep_string = show_name + str(ep_obj.airdate).split('-')[0] else: - ep_string = show_name +' S%02d' % int(ep_obj.scene_season) #1) showName SXX + ep_string = show_name + ' S%02d' % int(ep_obj.scene_season) #1) showName SXX search_string['Season'].append(ep_string) @@ -130,8 +130,9 @@ class SpeedCDProvider(generic.TorrentProvider): search_string['Episode'].append(ep_string) else: for show_name in set(show_name_helpers.allPossibleShowNames(self.show)): - ep_string = show_name_helpers.sanitizeSceneName(show_name) +' '+ \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, 'episodenumber': ep_obj.scene_episode} + ep_string = show_name_helpers.sanitizeSceneName(show_name) + ' ' + \ + sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode} search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) @@ -152,7 +153,8 @@ class SpeedCDProvider(generic.TorrentProvider): search_string = '+'.join(search_string.split()) - post_data = dict({'/browse.php?' : None, 'cata': 'yes','jxt': 4,'jxw': 'b','search': search_string}, **self.categories[mode]) + post_data = dict({'/browse.php?': None, 'cata': 'yes', 'jxt': 4, 'jxw': 'b', 'search': search_string}, + **self.categories[mode]) data = self.session.post(self.urls['search'], data=post_data).json() @@ -167,7 +169,7 @@ class SpeedCDProvider(generic.TorrentProvider): continue title = re.sub('<[^>]*>', '', torrent['name']) - url = self.urls['download'] %(torrent['id']) + url = self.urls['download'] % (torrent['id']) seeders = int(torrent['seed']) leechers = int(torrent['leech']) @@ -192,7 +194,7 @@ class SpeedCDProvider(generic.TorrentProvider): title, url, seeders, leechers = item if url: - url = str(url).replace('&','&') + url = str(url).replace('&', '&') return (title, url) @@ -216,11 +218,12 @@ class SpeedCDProvider(generic.TorrentProvider): else: r = self.session.get(url, verify=False) except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError), e: - logger.log(u"Error loading "+self.name+" URL: " + ex(e), logger.ERROR) + logger.log(u"Error loading " + self.name + " URL: " + ex(e), logger.ERROR) return None if r.status_code != 200: - logger.log(self.name + u" page requested with url " + url +" returned status code is " + str(r.status_code) + ': ' + clients.http_error_code[r.status_code], logger.WARNING) + logger.log(self.name + u" page requested with url " + url + " returned status code is " + str( + r.status_code) + ': ' + clients.http_error_code[r.status_code], logger.WARNING) return None return r.content @@ -229,33 +232,34 @@ class SpeedCDProvider(generic.TorrentProvider): results = [] - sqlResults = db.DBConnection().select('SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' + - ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' + - ' WHERE e.airdate >= ' + str(search_date.toordinal()) + - ' AND (e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED]) + ')' + - ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))' - ) + sqlResults = db.DBConnection().select( + 'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' + + ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' + + ' WHERE e.airdate >= ' + str(search_date.toordinal()) + + ' AND (e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED]) + ')' + + ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))' + ) if not sqlResults: return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results def seedRatio(self): return self.ratio -class SpeedCDCache(tvcache.TVCache): +class SpeedCDCache(tvcache.TVCache): def __init__(self, provider): tvcache.TVCache.__init__(self, provider) @@ -298,9 +302,10 @@ class SpeedCDCache(tvcache.TVCache): if not title or not url: return None - logger.log(u"Attempting to cache item:[" + title +"]", logger.DEBUG) + logger.log(u"Attempting to cache item:[" + title + "]", logger.DEBUG) return self._addCacheEntry(title, url) + provider = SpeedCDProvider() diff --git a/sickbeard/providers/thepiratebay.py b/sickbeard/providers/thepiratebay.py index 3e3a3ea0..bbd18f56 100644 --- a/sickbeard/providers/thepiratebay.py +++ b/sickbeard/providers/thepiratebay.py @@ -377,15 +377,16 @@ class ThePirateBayProvider(generic.TorrentProvider): return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results diff --git a/sickbeard/providers/torrentday.py b/sickbeard/providers/torrentday.py index d3a18693..e6dc09a1 100644 --- a/sickbeard/providers/torrentday.py +++ b/sickbeard/providers/torrentday.py @@ -266,15 +266,15 @@ class TorrentDayProvider(generic.TorrentProvider): return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results diff --git a/sickbeard/providers/torrentleech.py b/sickbeard/providers/torrentleech.py index 0509b3c3..74af3ad6 100644 --- a/sickbeard/providers/torrentleech.py +++ b/sickbeard/providers/torrentleech.py @@ -262,15 +262,15 @@ class TorrentLeechProvider(generic.TorrentProvider): return [] for sqlshow in sqlResults: - self.show = curshow = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) - if not self.show: continue - curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) + self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) + if self.show: + curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') + searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today())) + for item in self._doSearch(searchString[0]): + title, url = self._get_title_and_url(item) + results.append(classes.Proper(title, url, datetime.datetime.today())) return results diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 3bdd913c..4a198d28 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -195,10 +195,10 @@ class TVShow(object): return ep_list - def getEpisode(self, season=None, episode=None, file=None, noCreate=False, absolute_number=None): + def getEpisode(self, season=None, episode=None, file=None, noCreate=False, absolute_number=None, forceUpdate=False): # Load XEM data to DB for show - sickbeard.scene_numbering.xem_refresh(self.indexerid, self.indexer) + sickbeard.scene_numbering.xem_refresh(self.indexerid, self.indexer, force=forceUpdate) if not season in self.episodes: self.episodes[season] = {} From 05cca0dfe02e6415e1349ba4b30a44be1f630ea0 Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 01:16:12 -0700 Subject: [PATCH 40/82] Fixed post-processing issues with shows being rejected and saying they didn't exist when infact they did. Fixed a issue in our name parser code that would of resulted in searches failing completely. --- sickbeard/name_parser/parser.py | 11 ++++++++--- sickbeard/postProcessor.py | 7 +++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 8c15f8f6..cd36951a 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -137,13 +137,18 @@ class NameParser(object): result.series_name = self.clean_series_name(result.series_name) cur_show = helpers.get_show_by_name(result.series_name, useIndexer=self.useIndexers) - if self.show and cur_show: + 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) - else: - result.show = self.show + continue + + result.show = cur_show if 'season_num' in named_groups: tmp_season = int(match.group('season_num')) diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index 6763272d..6cb4fa05 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -416,6 +416,9 @@ class PostProcessor(object): continue show = helpers.findCertainShow(sickbeard.showList, int(sql_results[0]["showid"])) + if not show: + continue + season = int(sql_results[0]["season"]) quality = int(sql_results[0]["quality"]) @@ -481,6 +484,10 @@ class PostProcessor(object): self._log(u"Parsed " + name + " into " + str(parse_result).decode('utf-8', 'xmlcharrefreplace'), logger.DEBUG) + # couldn't find this in our show list + if not parse_result.show: + return to_return + if parse_result.air_by_date: season = -1 episodes = [parse_result.air_date] From 70e7f1bfce3400ed94a4a806b5024490cde577d0 Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 03:01:49 -0700 Subject: [PATCH 41/82] Fixed issues with scene numbering being overwritten by ep objects. Converted more object saves to database to use transactionals, better performance. --- sickbeard/dailysearcher.py | 9 ++++- sickbeard/failed_history.py | 1 - sickbeard/naming.py | 6 +-- sickbeard/postProcessor.py | 25 ++++++++---- sickbeard/search.py | 8 +++- sickbeard/show_queue.py | 12 +++--- sickbeard/traktWatchListChecker.py | 2 + sickbeard/tv.py | 63 +++++++++++++++++++----------- sickbeard/webapi.py | 8 +++- sickbeard/webserve.py | 3 +- 10 files changed, 93 insertions(+), 44 deletions(-) diff --git a/sickbeard/dailysearcher.py b/sickbeard/dailysearcher.py index b129dc26..02009a04 100644 --- a/sickbeard/dailysearcher.py +++ b/sickbeard/dailysearcher.py @@ -47,6 +47,7 @@ class DailySearcher(): sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE status in (?,?) AND airdate >= ? AND airdate <= ?", [common.UNAIRED, common.WANTED, fromDate.toordinal(), curDate.toordinal()]) + sql_l = [] todaysEps = {} for sqlEp in sqlResults: @@ -70,7 +71,7 @@ class DailySearcher(): logger.log(u"New episode " + ep.prettyName() + " airs today, setting status to WANTED") ep.status = common.WANTED - ep.saveToDB() + sql_l.append(ep.get_sql()) if ep.status == common.WANTED: if show not in todaysEps: @@ -78,6 +79,12 @@ class DailySearcher(): else: todaysEps[show].append(ep) + sql_l.append(ep.get_sql()) + + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) + if len(todaysEps): for show in todaysEps: segment = todaysEps[show] diff --git a/sickbeard/failed_history.py b/sickbeard/failed_history.py index f98f5f61..2a354651 100644 --- a/sickbeard/failed_history.py +++ b/sickbeard/failed_history.py @@ -129,7 +129,6 @@ def revertEpisode(epObj): logger.log(u"WARNING: Episode not found in history. Setting it back to WANTED", logger.WARNING) epObj.status = WANTED - epObj.saveToDB() except EpisodeNotFoundException, e: diff --git a/sickbeard/naming.py b/sickbeard/naming.py index eb0c5c27..1b0deceb 100644 --- a/sickbeard/naming.py +++ b/sickbeard/naming.py @@ -63,9 +63,9 @@ class TVEpisode(tv.TVEpisode): self._season = season self._episode = episode self._absolute_number = absolute_number - self._scene_season = season - self._scene_episode = episode - self._scene_absolute_number = absolute_number + self.scene_season = season + self.scene_episode = episode + self.scene_absolute_number = absolute_number self._airdate = datetime.date(2010, 3, 9) self.show = TVShow() self._status = Quality.compositeStatus(common.DOWNLOADED, common.Quality.SDTV) diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index 6cb4fa05..201aa89d 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -915,6 +915,7 @@ class PostProcessor(object): ep_obj.show.writeMetadata(True) # update the ep info before we rename so the quality & release name go into the name properly + sql_l = [] for cur_ep in [ep_obj] + ep_obj.relatedEps: with cur_ep.lock: cur_release_name = None @@ -951,7 +952,7 @@ class PostProcessor(object): cur_ep.is_proper = self.is_proper - cur_ep.saveToDB() + sql_l.append(cur_ep.get_sql()) # Just want to keep this consistent for failed handling right now releaseName = show_name_helpers.determineReleaseName(self.folder_path, self.nzb_name) @@ -960,10 +961,13 @@ class PostProcessor(object): else: self._log(u"Couldn't find release in snatch history", logger.WARNING) + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) + # find the destination folder try: proper_path = ep_obj.proper_path() - test = proper_path proper_absolute_path = ek.ek(os.path.join, ep_obj.show.location, proper_path) dest_path = ek.ek(os.path.dirname, proper_absolute_path) @@ -1019,24 +1023,31 @@ class PostProcessor(object): cur_ep.downloadSubtitles(force=True) # put the new location in the database + sql_l = [] for cur_ep in [ep_obj] + ep_obj.relatedEps: with cur_ep.lock: cur_ep.location = ek.ek(os.path.join, dest_path, new_file_name) - cur_ep.saveToDB() + + sql_l.append(cur_ep.get_sql()) + # set file modify stamp to show airdate if sickbeard.AIRDATE_EPISODES: ep_obj.show.airdateModifyStamp(cur_ep) + # generate nfo/tbn + ep_obj.createMetaFiles() + sql_l.append(ep_obj.get_sql()) + + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) + # log it to history history.logDownload(ep_obj, self.file_path, new_ep_quality, self.release_group) # send notifications notifiers.notify_download(ep_obj._format_pattern('%SN - %Sx%0E - %EN - %QN')) - # generate nfo/tbn - ep_obj.createMetaFiles() - ep_obj.saveToDB() - # do the library update for XBMC notifiers.xbmc_notifier.update_library(ep_obj.show.name) diff --git a/sickbeard/search.py b/sickbeard/search.py index 8ca15682..42d5f9a5 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -161,17 +161,23 @@ def snatchEpisode(result, endStatus=SNATCHED): history.logSnatch(result) # don't notify when we re-download an episode + sql_l = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) - curEpObj.saveToDB() + + sql_l.append(curEpObj.get_sql()) if curEpObj.status not in Quality.DOWNLOADED: notifiers.notify_snatch(curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN')) + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) + return True diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py index 6be7cbca..9d4f44f6 100644 --- a/sickbeard/show_queue.py +++ b/sickbeard/show_queue.py @@ -284,7 +284,7 @@ class QueueItemAdd(ShowQueueItem): self.show.subtitles = self.subtitles if self.subtitles != None else sickbeard.SUBTITLES_DEFAULT self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.flatten_folders = self.flatten_folders if self.flatten_folders != None else sickbeard.FLATTEN_FOLDERS_DEFAULT - #self.show.anime = self.anime if self.anime != None else sickbeard.ANIME_DEFAULT + self.show.anime = self.anime if self.anime != None else sickbeard.ANIME_DEFAULT self.show.paused = False # be smartish about this @@ -294,10 +294,8 @@ class QueueItemAdd(ShowQueueItem): self.show.air_by_date = 0 if self.show.classification and "sports" in self.show.classification.lower(): self.show.sports = 1 - if self.show.genre and "animation" in self.show.genre.lower(): - self.show.anime = 1 - if sickbeard.scene_numbering.get_xem_numbering_for_show(self.show.indexerid, self.show.indexer): - self.show.scene = 1 + #if self.show.genre and "animation" in self.show.genre.lower(): + # self.show.anime = 1 except sickbeard.indexer_exception, e: logger.log( @@ -386,6 +384,10 @@ class QueueItemAdd(ShowQueueItem): # Load XEM data to DB for show sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer, force=True) + # check if show has XEM mapping so we can determin if searches should go by scene numbering or indexer numbering. + if sickbeard.scene_numbering.get_xem_numbering_for_show(self.show.indexerid, self.show.indexer): + self.show.scene = 1 + self.finish() def _finishEarly(self): diff --git a/sickbeard/traktWatchListChecker.py b/sickbeard/traktWatchListChecker.py index 90f66669..5d1edd29 100644 --- a/sickbeard/traktWatchListChecker.py +++ b/sickbeard/traktWatchListChecker.py @@ -23,6 +23,7 @@ from sickbeard import encodingKludge as ek from sickbeard import logger from sickbeard import helpers from sickbeard import search_queue +from sickbeard import db from sickbeard.common import SNATCHED, SNATCHED_PROPER, DOWNLOADED, SKIPPED, UNAIRED, IGNORED, ARCHIVED, WANTED, UNKNOWN from lib.trakt import * @@ -125,6 +126,7 @@ class TraktChecker(): epObj.status = WANTED epObj.saveToDB() + backlog = (show, ep_segment) if self.todoBacklog.count(backlog) == 0: self.todoBacklog.append(backlog) diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 4a198d28..79dfcace 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -17,7 +17,6 @@ # along with SickRage. If not, see . from __future__ import with_statement -import json import os.path import datetime @@ -25,7 +24,6 @@ import threading import re import glob import traceback -import requests import sickbeard @@ -378,6 +376,7 @@ class TVShow(object): mediaFiles = helpers.listMediaFiles(self._location) # create TVEpisodes from each media file (if possible) + sql_l = [] for mediaFile in mediaFiles: parse_result = None curEpisode = None @@ -419,7 +418,12 @@ class TVShow(object): except: logger.log(str(self.indexerid) + ": Could not refresh subtitles", logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) - curEpisode.saveToDB() + + sql_l.append(curEpisode.get_sql()) + + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) def loadEpisodesFromDB(self): @@ -533,8 +537,8 @@ class TVShow(object): logger.log(str(self.indexerid) + u": Loading info from " + sickbeard.indexerApi( self.indexer).name + " for episode " + str(season) + "x" + str(episode), logger.DEBUG) ep.loadFromIndexer(season, episode, tvapi=t) - if ep.dirty: - sql_l.append(ep.get_sql()) + + sql_l.append(ep.get_sql()) scannedEps[season][episode] = True @@ -612,6 +616,7 @@ class TVShow(object): parse_result.air_date) + " for show " + self.name + ", skipping", logger.WARNING) return None + sql_l = [] for curEpNum in episodes: episode = int(curEpNum) @@ -705,7 +710,11 @@ class TVShow(object): curEp.status = Quality.compositeStatus(newStatus, newQuality) with curEp.lock: - curEp.saveToDB() + sql_l.append(curEp.get_sql()) + + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) # creating metafiles on the root should be good enough if sickbeard.USE_FAILED_DOWNLOADS and rootEp is not None: @@ -990,6 +999,7 @@ class TVShow(object): myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE showid = ? AND location != ''", [self.indexerid]) + sql_l = [] for ep in sqlResults: curLoc = os.path.normpath(ep["location"]) season = int(ep["season"]) @@ -1022,12 +1032,17 @@ class TVShow(object): curEp.hasnfo = False curEp.hastbn = False curEp.release_name = '' - curEp.saveToDB() + + sql_l.append(curEp.get_sql()) else: # the file exists, set its modify file stamp if sickbeard.AIRDATE_EPISODES: self.airdateModifyStamp(curEp) + if len(sql_l): + myDB = db.DBConnection() + myDB.mass_action(sql_l) + def airdateModifyStamp(self, ep_obj): """ Make the modify date and time of a file reflect the show air date and time. @@ -1261,9 +1276,6 @@ class TVEpisode(object): self._season = season self._episode = episode self._absolute_number = 0 - self._scene_season = 0 - self._scene_episode = 0 - self._scene_absolute_number = 0 self._description = "" self._subtitles = list() self._subtitles_searchcount = 0 @@ -1282,6 +1294,10 @@ class TVEpisode(object): self.show = show + self.scene_season = 0 + self.scene_episode = 0 + self.scene_absolute_number = 0 + self._location = file self._indexer = int(self.show.indexer) @@ -1298,9 +1314,6 @@ class TVEpisode(object): season = property(lambda self: self._season, dirty_setter("_season")) episode = property(lambda self: self._episode, dirty_setter("_episode")) absolute_number = property(lambda self: self._absolute_number, dirty_setter("_absolute_number")) - scene_season = property(lambda self: self._scene_season, dirty_setter("_scene_season")) - scene_episode = property(lambda self: self._scene_episode, dirty_setter("_scene_episode")) - scene_absolute_number = property(lambda self: self._scene_absolute_number, dirty_setter("_scene_absolute_number")) description = property(lambda self: self._description, dirty_setter("_description")) subtitles = property(lambda self: self._subtitles, dirty_setter("_subtitles")) subtitles_searchcount = property(lambda self: self._subtitles_searchcount, dirty_setter("_subtitles_searchcount")) @@ -1827,13 +1840,12 @@ class TVEpisode(object): # use a custom update/insert method to get the data into the DB return [ - "INSERT OR REPLACE INTO tv_episodes (episode_id, indexerid, indexer, name, description, subtitles, subtitles_searchcount, subtitles_lastsearch, airdate, hasnfo, hastbn, status, location, file_size, release_name, is_proper, showid, season, episode, scene_season, scene_episode, absolute_number, scene_absolute_number) VALUES " - "((SELECT episode_id FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", + "INSERT OR REPLACE INTO tv_episodes (episode_id, indexerid, indexer, name, description, subtitles, subtitles_searchcount, subtitles_lastsearch, airdate, hasnfo, hastbn, status, location, file_size, release_name, is_proper, showid, season, episode, absolute_number) VALUES " + "((SELECT episode_id FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", [self.show.indexerid, self.season, self.episode, self.indexerid, self.indexer, self.name, self.description, ",".join([sub for sub in self.subtitles]), self.subtitles_searchcount, self.subtitles_lastsearch, self.airdate.toordinal(), self.hasnfo, self.hastbn, self.status, self.location, self.file_size, - self.release_name, self.is_proper, self.show.indexerid, self.season, self.episode, self.scene_season, - self.scene_episode, self.absolute_number, self.scene_absolute_number]] + self.release_name, self.is_proper, self.show.indexerid, self.season, self.episode, self.absolute_number]] def saveToDB(self, forceSave=False): """ @@ -1868,10 +1880,7 @@ class TVEpisode(object): "file_size": self.file_size, "release_name": self.release_name, "is_proper": self.is_proper, - "scene_season": self.scene_season, - "scene_episode": self.scene_episode, - "absolute_number": self.absolute_number, - "scene_absolute_number": self.scene_absolute_number + "absolute_number": self.absolute_number } controlValueDict = {"showid": self.show.indexerid, "season": self.season, @@ -2277,6 +2286,7 @@ class TVEpisode(object): logger.log(str(self.indexerid) + u": Unable to rename file " + cur_related_file, logger.ERROR) for cur_related_sub in related_subs: + absolute_proper_subs_path = ek.ek(os.path.join, sickbeard.SUBTITLES_DIR, self.formatted_filename()) cur_result = helpers.rename_ep_file(cur_related_sub, absolute_proper_subs_path, absolute_current_path_no_ext_length) if not cur_result: @@ -2294,7 +2304,14 @@ class TVEpisode(object): curEp.checkForMetaFiles() # save any changes to the database + + sql_l = [] with self.lock: - self.saveToDB() + sql_l.append(self.get_sql()) + for relEp in self.relatedEps: - relEp.saveToDB() + sql_l.append(relEp.get_sql()) + + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py index 122e197d..c37c1c98 100644 --- a/sickbeard/webapi.py +++ b/sickbeard/webapi.py @@ -978,6 +978,8 @@ class CMD_EpisodeSetStatus(ApiCall): failure = False start_backlog = False ep_segment = None + + sql_l = [] for epObj in ep_list: if ep_segment == None and self.status == WANTED: # figure out what segment the episode is in and remember it so we can backlog it @@ -1003,12 +1005,16 @@ class CMD_EpisodeSetStatus(ApiCall): continue epObj.status = self.status - epObj.saveToDB() + sql_l.append(epObj.get_sql()) if self.status == WANTED: start_backlog = True ep_results.append(_epResult(RESULT_SUCCESS, epObj)) + if len(sql_l): + myDB = db.DBConnection() + myDB.mass_action(sql_l) + extra_msg = "" if start_backlog: cur_backlog_queue_item = search_queue.BacklogQueueItem(showObj, ep_segment) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 0751ee92..38a5524d 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3526,8 +3526,7 @@ class Home: epObj.status = int(status) # mass add to database - if epObj.dirty: - sql_l.append(epObj.get_sql()) + sql_l.append(epObj.get_sql()) if len(sql_l) > 0: myDB = db.DBConnection() From db6cf0b22b093ff214485fbbb63b507bfc0255dc Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 04:06:51 -0700 Subject: [PATCH 42/82] Fix for daily searcher NoneType error. Added XEM icon to show display, indicates if show has scene mapping available or not plus clicking on the icon will take you to the XEM mapping page. --- gui/slick/images/xem.png | Bin 0 -> 6826 bytes gui/slick/interfaces/default/displayShow.tmpl | 14 +++++++------- gui/slick/interfaces/default/manage.tmpl | 15 +++++++++------ sickbeard/dailysearcher.py | 8 ++++---- sickbeard/webserve.py | 2 +- 5 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 gui/slick/images/xem.png diff --git a/gui/slick/images/xem.png b/gui/slick/images/xem.png new file mode 100644 index 0000000000000000000000000000000000000000..634def233941b7029a04dc2e7ffc63c3af727f35 GIT binary patch literal 6826 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 ZMmSv-#JXlTj;to&=0B#_%dWXR{~uyR<&XdX literal 0 HcmV?d00001 diff --git a/gui/slick/interfaces/default/displayShow.tmpl b/gui/slick/interfaces/default/displayShow.tmpl index 0c2d7af2..74316b3f 100644 --- a/gui/slick/interfaces/default/displayShow.tmpl +++ b/gui/slick/interfaces/default/displayShow.tmpl @@ -72,14 +72,12 @@

$show.name

+ #if not $show.imdbid ($show.startyear) - $show.runtime min #if $show.genre: - $show.genre[1:-1].replace('|',' | ') #end if - - $sickbeard.indexerApi($show.indexer).name - #else #if 'country_codes' in $show.imdb_info: #for $country in $show.imdb_info['country_codes'].split('|') @@ -89,11 +87,13 @@ #if 'year' in $show.imdb_info: ($show.imdb_info['year']) - $show.imdb_info['runtimes'] min - $show.imdb_info['genres'].replace('|',' | ') #end if - - [imdb] - $sickbeard.indexerApi($show.indexer).name - + [imdb] #end if +$sickbeard.indexerApi($show.indexer).name +#if $xem_numbering or $xem_absolute_numbering: + [xem] +#end if + #if $seasonResults: ##There is a special/season_0?## diff --git a/gui/slick/interfaces/default/manage.tmpl b/gui/slick/interfaces/default/manage.tmpl index d3936a62..1138d997 100644 --- a/gui/slick/interfaces/default/manage.tmpl +++ b/gui/slick/interfaces/default/manage.tmpl @@ -56,9 +56,12 @@ 6: { sorter: false}, 7: { sorter: false}, 8: { sorter: false}, - 9: { sorter: false} + 9: { sorter: false}, + 10: { sorter: false}, + 11: { sorter: false}, + 12: { sorter: false} #if $sickbeard.USE_SUBTITLES - , 10: { sorter: false} + , 13: { sorter: false} #end if } }); @@ -79,10 +82,11 @@ Edit
- + Show Name Quality Sports + Scene Anime Flat Folders Paused @@ -100,7 +104,7 @@ - + @@ -137,7 +141,6 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name)) -
$curShow.name #if $curShow.quality in $qualityPresets: $qualityPresetStrings[$curShow.quality] @@ -145,6 +148,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name)) Custom #end if \"Y\"" + \"Y\"" \"Y\"" \"Y\"" \"Y\"" @@ -155,7 +159,6 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name)) #if $sickbeard.USE_SUBTITLES: $curSubtitle #end if - $curDelete #end for diff --git a/sickbeard/dailysearcher.py b/sickbeard/dailysearcher.py index 02009a04..f7c9672b 100644 --- a/sickbeard/dailysearcher.py +++ b/sickbeard/dailysearcher.py @@ -79,11 +79,11 @@ class DailySearcher(): else: todaysEps[show].append(ep) - sql_l.append(ep.get_sql()) + sql_l.append(ep.get_sql()) - if len(sql_l) > 0: - myDB = db.DBConnection() - myDB.mass_action(sql_l) + if len(sql_l) > 0: + myDB = db.DBConnection() + myDB.mass_action(sql_l) if len(todaysEps): for show in todaysEps: diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 38a5524d..70f219f3 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -2963,7 +2963,7 @@ class Home: showObj.exceptions = scene_exceptions.get_scene_exceptions(showObj.indexerid) # Update scene numbering in DB - sickbeard.scene_numbering.xem_refresh(showObj.indexerid, showObj.indexer, True) + sickbeard.scene_numbering.xem_refresh(showObj.indexerid, showObj.indexer) myDB = db.DBConnection() From 997896a540a784766b8b6375b9549b2044a9007a Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 04:42:31 -0700 Subject: [PATCH 43/82] Fix for transactionals and None Types in sql lists --- sickbeard/dailysearcher.py | 2 +- sickbeard/db.py | 3 +++ sickbeard/network_timezones.py | 2 +- sickbeard/postProcessor.py | 4 ++-- sickbeard/providers/btn.py | 5 +++-- sickbeard/providers/hdbits.py | 5 +++-- sickbeard/providers/hdtorrents.py | 5 +++-- sickbeard/providers/iptorrents.py | 5 +++-- sickbeard/providers/kat.py | 5 +++-- sickbeard/providers/newznab.py | 5 +++-- sickbeard/providers/nextgen.py | 5 +++-- sickbeard/providers/publichd.py | 5 +++-- sickbeard/providers/scc.py | 5 +++-- sickbeard/providers/speedcd.py | 5 +++-- sickbeard/providers/thepiratebay.py | 5 +++-- sickbeard/providers/torrentday.py | 5 +++-- sickbeard/providers/torrentleech.py | 5 +++-- sickbeard/search.py | 2 +- sickbeard/tv.py | 10 +++++----- sickbeard/tvcache.py | 5 +++-- sickbeard/webapi.py | 2 +- sickbeard/webserve.py | 2 +- 22 files changed, 57 insertions(+), 40 deletions(-) diff --git a/sickbeard/dailysearcher.py b/sickbeard/dailysearcher.py index f7c9672b..d0ca71bd 100644 --- a/sickbeard/dailysearcher.py +++ b/sickbeard/dailysearcher.py @@ -81,7 +81,7 @@ class DailySearcher(): sql_l.append(ep.get_sql()) - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) diff --git a/sickbeard/db.py b/sickbeard/db.py index c84a5ee3..a324a745 100644 --- a/sickbeard/db.py +++ b/sickbeard/db.py @@ -30,6 +30,7 @@ from sickbeard import encodingKludge as ek from sickbeard import logger from sickbeard.exceptions import ex from sickbeard.common import cpu_presets +from itertools import ifilter db_lock = threading.Lock() @@ -113,6 +114,8 @@ class DBConnection: def mass_action(self, querylist, logTransaction=False): with db_lock: + # remove None types + querylist = [i for i in querylist if i!=None] if querylist == None: return diff --git a/sickbeard/network_timezones.py b/sickbeard/network_timezones.py index 3c7bd0c9..d4548748 100644 --- a/sickbeard/network_timezones.py +++ b/sickbeard/network_timezones.py @@ -186,7 +186,7 @@ def update_network_dict(): L = list(va for va in old_d) ql.append(["DELETE FROM network_timezones WHERE network_name IN (" + ','.join(['?'] * len(L)) + ")", L]) # change all network timezone infos at once (much faster) - if len(ql) > 0: + if ql: myDB.mass_action(ql) load_network_dict() diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index 201aa89d..d768ebfd 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -961,7 +961,7 @@ class PostProcessor(object): else: self._log(u"Couldn't find release in snatch history", logger.WARNING) - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) @@ -1038,7 +1038,7 @@ class PostProcessor(object): ep_obj.createMetaFiles() sql_l.append(ep_obj.get_sql()) - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) diff --git a/sickbeard/providers/btn.py b/sickbeard/providers/btn.py index aadae43d..66e6bbb4 100644 --- a/sickbeard/providers/btn.py +++ b/sickbeard/providers/btn.py @@ -341,8 +341,9 @@ class BTNCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) else: raise AuthException( diff --git a/sickbeard/providers/hdbits.py b/sickbeard/providers/hdbits.py index 5ae61bd6..925bff1c 100644 --- a/sickbeard/providers/hdbits.py +++ b/sickbeard/providers/hdbits.py @@ -233,8 +233,9 @@ class HDBitsCache(tvcache.TVCache): if ci is not None: ql.append(ci) - myDB = self._getDB() - myDB.mass_action(ql) + if ql: + myDB = self._getDB() + myDB.mass_action(ql) else: raise exceptions.AuthException( diff --git a/sickbeard/providers/hdtorrents.py b/sickbeard/providers/hdtorrents.py index e054dada..5de98cae 100644 --- a/sickbeard/providers/hdtorrents.py +++ b/sickbeard/providers/hdtorrents.py @@ -367,8 +367,9 @@ class HDTorrentsCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) def _parseItem(self, item): diff --git a/sickbeard/providers/iptorrents.py b/sickbeard/providers/iptorrents.py index c025c407..37afda01 100644 --- a/sickbeard/providers/iptorrents.py +++ b/sickbeard/providers/iptorrents.py @@ -308,8 +308,9 @@ class IPTorrentsCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) def _parseItem(self, item): diff --git a/sickbeard/providers/kat.py b/sickbeard/providers/kat.py index 382d40f5..187b0058 100644 --- a/sickbeard/providers/kat.py +++ b/sickbeard/providers/kat.py @@ -445,8 +445,9 @@ class KATCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) def _parseItem(self, item): diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index b49e9d18..7affc1a7 100644 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -341,8 +341,9 @@ class NewznabCache(tvcache.TVCache): if ci is not None: ql.append(ci) - myDB = self._getDB() - myDB.mass_action(ql) + if ql: + myDB = self._getDB() + myDB.mass_action(ql) else: raise AuthException( diff --git a/sickbeard/providers/nextgen.py b/sickbeard/providers/nextgen.py index 9cc51c88..c988c827 100644 --- a/sickbeard/providers/nextgen.py +++ b/sickbeard/providers/nextgen.py @@ -357,8 +357,9 @@ class NextGenCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) def _parseItem(self, item): diff --git a/sickbeard/providers/publichd.py b/sickbeard/providers/publichd.py index 200a6693..8d8c7b5f 100644 --- a/sickbeard/providers/publichd.py +++ b/sickbeard/providers/publichd.py @@ -337,8 +337,9 @@ class PublicHDCache(tvcache.TVCache): if ci is not None: ql.append(ci) - myDB = self._getDB() - myDB.mass_action(ql) + if ql: + myDB = self._getDB() + myDB.mass_action(ql) def _parseItem(self, item): diff --git a/sickbeard/providers/scc.py b/sickbeard/providers/scc.py index b2c16372..7d7c9110 100644 --- a/sickbeard/providers/scc.py +++ b/sickbeard/providers/scc.py @@ -352,8 +352,9 @@ class SCCCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) def _parseItem(self, item): diff --git a/sickbeard/providers/speedcd.py b/sickbeard/providers/speedcd.py index e54647b2..b42406c9 100644 --- a/sickbeard/providers/speedcd.py +++ b/sickbeard/providers/speedcd.py @@ -292,8 +292,9 @@ class SpeedCDCache(tvcache.TVCache): if ci is not None: ql.append(ci) - myDB = self._getDB() - myDB.mass_action(ql) + if ql: + myDB = self._getDB() + myDB.mass_action(ql) def _parseItem(self, item): diff --git a/sickbeard/providers/thepiratebay.py b/sickbeard/providers/thepiratebay.py index bbd18f56..3b1c56c9 100644 --- a/sickbeard/providers/thepiratebay.py +++ b/sickbeard/providers/thepiratebay.py @@ -427,8 +427,9 @@ class ThePirateBayCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) def _parseItem(self, item): diff --git a/sickbeard/providers/torrentday.py b/sickbeard/providers/torrentday.py index e6dc09a1..48660d10 100644 --- a/sickbeard/providers/torrentday.py +++ b/sickbeard/providers/torrentday.py @@ -315,8 +315,9 @@ class TorrentDayCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) def _parseItem(self, item): diff --git a/sickbeard/providers/torrentleech.py b/sickbeard/providers/torrentleech.py index 74af3ad6..db694040 100644 --- a/sickbeard/providers/torrentleech.py +++ b/sickbeard/providers/torrentleech.py @@ -311,8 +311,9 @@ class TorrentLeechCache(tvcache.TVCache): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) def _parseItem(self, item): diff --git a/sickbeard/search.py b/sickbeard/search.py index 42d5f9a5..4a20de07 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -174,7 +174,7 @@ def snatchEpisode(result, endStatus=SNATCHED): if curEpObj.status not in Quality.DOWNLOADED: notifiers.notify_snatch(curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN')) - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 79dfcace..eeb9ed00 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -421,7 +421,7 @@ class TVShow(object): sql_l.append(curEpisode.get_sql()) - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) @@ -542,7 +542,7 @@ class TVShow(object): scannedEps[season][episode] = True - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) @@ -712,7 +712,7 @@ class TVShow(object): with curEp.lock: sql_l.append(curEp.get_sql()) - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) @@ -1039,7 +1039,7 @@ class TVShow(object): if sickbeard.AIRDATE_EPISODES: self.airdateModifyStamp(curEp) - if len(sql_l): + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) @@ -2312,6 +2312,6 @@ class TVEpisode(object): for relEp in self.relatedEps: sql_l.append(relEp.get_sql()) - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) diff --git a/sickbeard/tvcache.py b/sickbeard/tvcache.py index c6ce10f0..101c17d9 100644 --- a/sickbeard/tvcache.py +++ b/sickbeard/tvcache.py @@ -128,8 +128,9 @@ class TVCache(): if ci is not None: cl.append(ci) - myDB = self._getDB() - myDB.mass_action(cl) + if cl: + myDB = self._getDB() + myDB.mass_action(cl) else: raise AuthException( diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py index c37c1c98..60314d51 100644 --- a/sickbeard/webapi.py +++ b/sickbeard/webapi.py @@ -1011,7 +1011,7 @@ class CMD_EpisodeSetStatus(ApiCall): start_backlog = True ep_results.append(_epResult(RESULT_SUCCESS, epObj)) - if len(sql_l): + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 70f219f3..db610c5a 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3528,7 +3528,7 @@ class Home: # mass add to database sql_l.append(epObj.get_sql()) - if len(sql_l) > 0: + if sql_l: myDB = db.DBConnection() myDB.mass_action(sql_l) From 9b78e3dc5e4f54c12b37f58c784da157168a690b Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 04:52:37 -0700 Subject: [PATCH 44/82] Fix for scene exception and scene numbering updates when editing a show. --- sickbeard/webserve.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index db610c5a..8508a6a6 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3321,14 +3321,14 @@ class Home: if do_update_exceptions: try: - scene_exceptions.update_scene_exceptions(showObj.indexerid, exceptions_list, force=True) # @UndefinedVariable + scene_exceptions.update_scene_exceptions(showObj.indexerid, exceptions_list) # @UndefinedVariable time.sleep(cpu_presets[sickbeard.CPU_PRESET]) except exceptions.CantUpdateException, e: errors.append("Unable to force an update on scene exceptions of the show.") if do_update_scene_numbering or do_update_scene_absolute_numbering: try: - sickbeard.scene_numbering.xem_refresh(showObj.indexerid, showObj.indexer) # @UndefinedVariable + sickbeard.scene_numbering.xem_refresh(showObj.indexerid, showObj.indexer, force=True) # @UndefinedVariable time.sleep(cpu_presets[sickbeard.CPU_PRESET]) except exceptions.CantUpdateException, e: errors.append("Unable to force an update on scene numbering of the show.") From 78c42119253cf8239d2b7e553bce888c5fd00e29 Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 05:30:28 -0700 Subject: [PATCH 45/82] Fixed issue with scene exception updating for custom names. --- sickbeard/databases/cache_db.py | 9 ++++++++- sickbeard/scene_exceptions.py | 11 ++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/sickbeard/databases/cache_db.py b/sickbeard/databases/cache_db.py index 606a6a54..52a9d8c4 100644 --- a/sickbeard/databases/cache_db.py +++ b/sickbeard/databases/cache_db.py @@ -73,4 +73,11 @@ class AddSceneExceptionsSeasons(AddSceneNameCache): return self.hasColumn("scene_exceptions", "season") def execute(self): - self.addColumn("scene_exceptions", "season", "NUMERIC", -1) \ No newline at end of file + self.addColumn("scene_exceptions", "season", "NUMERIC", -1) + +class AddSceneExceptionsCustom(AddSceneExceptionsSeasons): + def test(self): + return self.hasColumn("scene_exceptions", "custom") + + def execute(self): + self.addColumn("scene_exceptions", "custom", "NUMERIC", 0) \ No newline at end of file diff --git a/sickbeard/scene_exceptions.py b/sickbeard/scene_exceptions.py index 6f11252e..fd06412b 100644 --- a/sickbeard/scene_exceptions.py +++ b/sickbeard/scene_exceptions.py @@ -216,13 +216,14 @@ def update_scene_exceptions(indexer_id, scene_exceptions): myDB = db.DBConnection("cache.db") - myDB.action('DELETE FROM scene_exceptions WHERE indexer_id=?', [indexer_id]) + myDB.action('DELETE FROM scene_exceptions WHERE indexer_id=? and custom=1', [indexer_id]) logger.log(u"Updating internal scene name cache", logger.MESSAGE) - for cur_exception, cur_season in scene_exceptions: - exceptionIndexerCache[helpers.full_sanitizeSceneName(cur_exception)] = indexer_id - myDB.action("INSERT INTO scene_exceptions (indexer_id, show_name, season) VALUES (?,?,?)", - [indexer_id, cur_exception, cur_season]) + for cur_season in [-1] + sickbeard.scene_exceptions.get_scene_seasons(indexer_id): + for cur_exception in scene_exceptions: + exceptionIndexerCache[helpers.full_sanitizeSceneName(cur_exception)] = indexer_id + myDB.action("INSERT INTO scene_exceptions (indexer_id, show_name, season, custom) VALUES (?,?,?,?)", + [indexer_id, cur_exception, cur_season, 1]) name_cache.clearCache() From bea999b6399aa20db2494ee0f6bb632186539c99 Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 05:43:00 -0700 Subject: [PATCH 46/82] Fix for XBMC notifier when XBMC has no shows in library. --- sickbeard/notifiers/xbmc.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/sickbeard/notifiers/xbmc.py b/sickbeard/notifiers/xbmc.py index 95084be3..d1ce8adc 100644 --- a/sickbeard/notifiers/xbmc.py +++ b/sickbeard/notifiers/xbmc.py @@ -141,13 +141,15 @@ class XBMCNotifier: else: logger.log(u"Detected XBMC version >= 12, using XBMC JSON API", logger.DEBUG) command = '{"jsonrpc":"2.0","method":"GUI.ShowNotification","params":{"title":"%s","message":"%s", "image": "%s"},"id":1}' % ( - title.encode("utf-8"), message.encode("utf-8"), self.sb_logo_url) + title.encode("utf-8"), message.encode("utf-8"), self.sb_logo_url) notifyResult = self._send_to_xbmc_json(command, curHost, username, password) if notifyResult: result += curHost + ':' + notifyResult["result"].decode(sickbeard.SYS_ENCODING) else: if sickbeard.XBMC_ALWAYS_ON or force: - logger.log(u"Failed to detect XBMC version for '" + curHost + "', check configuration and try again.", logger.ERROR) + logger.log( + u"Failed to detect XBMC version for '" + curHost + "', check configuration and try again.", + logger.ERROR) result += curHost + ':False' return result @@ -191,7 +193,7 @@ class XBMCNotifier: return False - ############################################################################## + # ############################################################################# # Legacy HTTP API (pre XBMC 12) methods ############################################################################## @@ -281,7 +283,7 @@ class XBMCNotifier: # use this to get xml back for the path lookups xmlCommand = { - 'command': 'SetResponseFormat(webheader;false;webfooter;false;header;;footer;;opentag;;closetag;;closefinaltag;false)'} + 'command': 'SetResponseFormat(webheader;false;webfooter;false;header;;footer;;opentag;;closetag;;closefinaltag;false)'} # sql used to grab path(s) sqlCommand = {'command': 'QueryVideoDatabase(%s)' % (pathSql)} # set output back to default @@ -432,9 +434,12 @@ class XBMCNotifier: # get tvshowid by showName showsCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShows","id":1}' showsResponse = self._send_to_xbmc_json(showsCommand, host) - if (showsResponse == False): + + if showsResponse and "result" in showsResponse and "tvshows" in showsResponse["result"]: + shows = showsResponse["result"]["tvshows"] + else: + logger.log(u"XBMC: No tvshows in XBMC TV show list", logger.DEBUG) return False - shows = showsResponse["result"]["tvshows"] for show in shows: if (show["label"] == showName): @@ -451,7 +456,7 @@ class XBMCNotifier: # lookup tv-show path pathCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShowDetails","params":{"tvshowid":%d, "properties": ["file"]},"id":1}' % ( - tvshowid) + tvshowid) pathResponse = self._send_to_xbmc_json(pathCommand, host) path = pathResponse["result"]["tvshowdetails"]["file"] @@ -465,7 +470,7 @@ class XBMCNotifier: logger.log(u"XBMC Updating " + showName + " on " + host + " at " + path, logger.DEBUG) updateCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.Scan","params":{"directory":%s},"id":1}' % ( - json.dumps(path)) + json.dumps(path)) request = self._send_to_xbmc_json(updateCommand, host) if not request: logger.log(u"Update of show directory failed on " + showName + " on " + host + " at " + path, @@ -543,7 +548,9 @@ class XBMCNotifier: return True else: if sickbeard.XBMC_ALWAYS_ON: - logger.log(u"Failed to detect XBMC version for '" + host + "', check configuration and try again.", logger.ERROR) + logger.log( + u"Failed to detect XBMC version for '" + host + "', check configuration and try again.", + logger.ERROR) result = result + 1 # needed for the 'update xbmc' submenu command From 6ca979d51bf1b4440334376cda098cc56411b792 Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 06:00:04 -0700 Subject: [PATCH 47/82] Fix for post-processing and adding anime shows to your anidb mylist --- sickbeard/postProcessor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index d768ebfd..78c14d47 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -834,6 +834,9 @@ class PostProcessor(object): # reset per-file stuff self.in_history = False + # reset the anidb episode object + self.anidbEpisode = None + # try to find the file info (show, season, episodes, quality) = self._find_info() if not show: From 2c37523ab7a88d719fba0a4c0ad4b7630f0f401e Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 30 May 2014 07:36:06 -0700 Subject: [PATCH 48/82] Fix for manual anime searches --- sickbeard/webserve.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 8508a6a6..839f6f5f 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -168,17 +168,14 @@ def _getEpisode(show, season=None, episode=None, absolute=None): showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) if showObj is None: - return "Show not in show list" + return "Invalid show paramaters" - if showObj.is_anime and not absolute is None: - return "Invalid absolute number parameters" - elif season is None or episode is None: - return "Invalid season or episode number parameters" - - if showObj.is_anime: - epObj = showObj.getEpisode(absolute_number=int(absolute)) - else: + if absolute: + epObj = showObj.getEpisode(absolute=int(absolute)) + elif season and episode: epObj = showObj.getEpisode(int(season), int(episode)) + else: + return "Invalid paramaters" if epObj is None: return "Episode couldn't be retrieved" From d7396896b55a88b2cbea364a8bc6205bb4e8ec66 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 03:35:11 -0700 Subject: [PATCH 49/82] 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 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 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 zta7zFA1kkL7iMYWE{}0LpgON3JXS%-I;zL44uppdtNsd`-~`q;t7V=jX zjmL0#H`iO&mU36i5wK!j_G?Za7u+9_ZZAzeGf8~zj~Cq$^QxJ%E0~&UxQ*}DP)lXo zlc5Wo+H!M$LGF+<=N@kFFDN)(_ZM&CCTVLtcqBjr=-R`AX{=neVc~1G!w;otRg>dG=6uMgf7M&f}c<6X+IC z1VYa6+*CKz7I#pa47tvvK92huuvsx;UB^zE6)upc321Ktc|%L@v0drr*K>=ZWeqbB@T~ zl1f|fVa=#OaK*E9BsM7d|L9Y;B^cG9QA)@e5y<}7+0PjlSk_cBsC{B?=ZHMG zf~&NAvy#1!+M1Z)O%p>wSc<-eXmZcX2SZ*H=6Yr5zIGk8KO%A_Mo?9UYCf%zQ&@ZP z=5@W`Tzll9#65m&bs~JO(-7#2P?iOY>`P`jaRNWA;Ll|hbAa|Y{?5PKHs)7TJKAS!$=h z(^8byOu@PA$GG*A;%{1CRyA>~v!!f@F+t%dv=|d@UaVkgdSjEEDNS7u(AXN=rv)fc zA)^@yU~l_l@Kb9wzwN6t<^;_of&Jp~1xC&5 zE?M0?5P27C$gBQKaLIpi$v89MPRn)Y<)!p6tmvuM;*B&Uz2RPr(r#m^bE0!$z_~29 zEhk?J+3}i15A2WhHcA;&s9>1eTD{%B0L-?`I#IWY4`f)NMQ&lk#oO^cYKNKMg3(FP z+s$FCqajzYH5=Ga|Ii%M6+{mW@drQm=k&t_7+wn%Z8>@FMY%OCMZu+i0-{*moUh%p zCK0cAQz$oEQ$Dc{f{{-Itex_65>LaI@C1pmH}W8MvGeAGEKRaLyJZ=c-gZ_{ zo9ap~lxM<4GCqun=hChLV7vgR$G^O(q!A^;L z(Lp+-z0>zCeJMRtN=-^hPc?L;8ajc7aGbT@GXXKIx}Uyp5Tj^INxU>oAk{;%48(M@ zQ=#IShym+G@h+AnN(y zN}paDMt z;b#pW+-W{j2=OWG9Kl;W|5JKzE=ZmwmWEMFrGd`Rt@%ZBuf(DD7OfJb zXTj0V%zS6Ih;bZ^d9)bgwKX%hZC##|(>lK>`;Zsf{=Tzq!xRtunL~Fq!IqG3C4R=e z+cr$>HRE)fu@wArX;v`uB)ld%trO!@fyVvu%wVPNP{4O)1)P}yP6dltos2Dh+}XJ` zGZ=VZiNYU+4~o@Y{I$D?!MBt<=iy>D{wb3|?o2YrbJ032|MMX78od8Vdwn^;HHkID zmsnpgPh^Dyn`)29?lB5z^}tvYtnSl$c=XISrO6fXF>aoxMjN z=r|J0@P=6!ELS2b3S=O$)QH){4JfC+>|Ce4M#hDz3CX}&j_6%_8>wwy73pq>Q=NU~ z?34|b8iJ8OisQKfewro5Q*BRa=j2pFKNgKe@P5E3!FkfaU;n2e95&`)WQYdf>_Qr< z0?GW8x{Ib00sjE!n~t_k`PKiLy|enu;F34QTzssVQ8KG~OFDV!gx`@Z>< zGkoR+m*-{$$X4MFhmfY%ILlydbY|ufys*e=%xj&`nTY)a>&%(4@);MjjU~idy8KET zra#Y45wRQdsu5&A#F}pic?AziLUtf8)n4!pXqi1BZ&@#*jIp|`@r2f|`f+E>{w(#( zbIaatLq3b?f7%tBHe(GxXP}UX#AkV&oxQYl$7osp#Z*h*3|__BnR#G$;!AOFY>XfFriAT5VB4&%R7 zjwi(DY9tGQ1^5mz>x5i)NrXI#kiAR~$^|-bSsPo515*yx1?Q4H7r}E0#4mI%!QN2p zT!QrmkBL0Dp#Z-Lx1q=x6>u9$)NRJss3Nza+!4`F@=SeTAc9Xm zG}{^NWfJX-wyBnD;&KviqU}llYY3oUwCxY_yhXm%P|yK}f;2`^tqzGkkuK8)HAX}G<^jo3`AG;q#dw1;?Hw=!f`1>EEa5Dnj3OB~ap48mn zVhf>ZI-S8l!kEWE#^SCS8B@IOO7S3;gyqd2Fy7b(Cr$B-X<4nAeRA9P44`0({V!BROiArb~YCaEe=%gMBi@4ad7ab1p zPQ6HEl@pVoJ>C*0KQWY#%sb-SB@I%38Ult7Q<`yF$KtVRf*ga0&W2xM9a}^JC!A{+}=5AM{8)ZRA-x0S+ zpG@cIr>CCY4UOzXY}8XULZ>!w7p#p*3I-{!(OOv0DNX#4AABJ!o{DKbWAUJV1RuTI z7`-quU+OilJ3gh4`D>Yk$ZFOym~3J1TT$Pz=k&4+Q%~Y2dexY_#K98PXl96hB(1Mc zBEb(dU{A1wrNzG`@)mGpA{gB+p_k6VJ;wW2Xk-SZL#ZK&($P|lG9+Zic-J(J5go(Qb}wWs%-ZByu?$qgPpNHE3v<2tloKQ^!t`rcaX`$)`?m+ zJOd8ER^k)Y$vR4#LN9JNd#=%cK@Q7&3u&Z-Z#&}Sy>I&@zx|i__9+&nUwPl^0MwSN z=Nok07g9pkf>RjDXrMFW&U>WSaX6GQdpHm|pOo!<{_R-7Ja09vQw37m8fQ8)rzhUi zD!(eRFV#8~i9cwSwgE67N5_(P&Fj>jcpJ@5@b^g^ClvQaZX=^=)pGCh-F!b<-_24d zO0|M-q4;q3gf^?2{`4GTLs?cgjl3iYehw-W>%|LmM<2n@MY*HxqED)07TAXc$vW8` zo2A*ln^%@CqL!JGOmO+2BW?8N_| zoS2EVBC(7|y8vQ*_b%>CUxtF#WM3k@s4u&$)EL**+YznXA*sJU8!YI?=9ALw4i90xE?-^5r+RVyOP^x-Tv%@Pf^2bEGj?YBlA)wh%Q<=jDW zF!~Ve*ZS4a;L^K!fa9@?+*L*dSqJ7v2LLNdUtmRKdYVA;gu3^__ z`$|{ulNbfx@N=`MC*?1{>t#pFi|D~(zrKmLq>P@J_%{tY`zw8`p0X3>r(Z(m9J5Xh zA8tt~@n?>~)7{a?C}>ovA9HYUa@X6={)r!Jc#O?5Mhrgh52w*hm@cZo59CaI!mn&e zmwzZvpUy~0J3so1C4F@&c)XPqtzdY(**=!?_#69J!s8A0v6#o}>|+s+tL$STj~({0 zfJZqEQCU8ZYK_M{9;I*cXvFB9-#0!TFDWVAr$Yy&U0VUxmRP{-Ay7!Rtx$aC1N4b? zG}sLVBUh1^7`@YRF*rP5o35O?a9-)!4_m07%GZpj{xUqquPv142G*#p7n!klbhm8l z9`LwvBndwcdp9`RZkCS&zBJ56-SPYj@dnuDY`Oe#;mw%NI7j2IGU#zR+(8?7TO4+i zYT>0$5O#0&f%^@z7grg+F;E(*K@JL1&$Dh)D=K}{%)%a?#m#<#?^#S7H0fI&?pTj` z2(8WQtd$uztFyMi{*>6CBK?rdcwyBRd;7&C80yrP^JGX?Tfvi|V{N4&z@6$vZB=LO z5L;2mtH_YOw$67}tsP@O+a6gb;?7!QvgxdyY`-#~oeXo$ZdU(7(#=Y}__2Hf}ApS0!}T&XXSw z%j0GkU`+OQkUSNqglS*Y;3I-FEONNd;tm} ze8SNZL{LNcr(zIJAb7so!N{rrVClpoEJga@ZHdi{G~LUX$uqYGS`NRpwWYs1OcB*` zvFyNIfNES$8tt=jRnbv=DufDQl%2)xZ6evGwk!Fs6Js+qh0h;@v*AY_+>ut|PH1%V zmT+Ok3*o-4mz~fre2RMpOC;}Q|4?=3+}BMY<3TFY^=#W^`B^OqE^0g@-^3-Lu29!& z=z~gsob>%oa@T|CFQ&f!T?deAUs!+-%g28GF)O5t&H>KRB?v{jE*Jl}^RAsnw;J8Q znS94ECY5EX8`$CJI^WB654lFv%x|9c235olpGo*%RG1Yi)v|~72pA;-%45cr_Nt0+=F?yWJhvZ(< z5RBX)c~$pFo^5cFvq_@mZ!kn1J=%g`nQVmsO^H*IW50WIPqC2rNLmLSbZd*%=fA7Z z-Ge`(&y%`}b%rX~zMixOsu}|~SMAf*nOAdBaj@-PQaLUMK&)OEG9g_|UV?AkH#nZN;O95q9{_NV_4M|c;*mOqNx z)&WZh*DdeG>ht4EcUdF&RRmGB3O{J=r(yJP7tGX#!Ro8v# zpBwDwC8^KXq<%H2q3pcDG;?Wf5H>P5G#`uN#D zqmGNPGUH35EycshgE==#=bCoJuYC=ob!uPrXQkgMaZ_^V)Vey+K-bgovG(F^O428&lQ0F(#6|{Uc+CV#Xm%3F!W*D6Ho7o2 zkxOBUY_itlBp;4TfHS-l{{o_2YIF^+&=#OM<_&L6%%z4oz$***j`(z*)Ta4N`^kMv zcTF4&5#&-}gM>xwLhzWY6KH`F5-Qy(4et0nxtilBsrW!{B_`QyeAjZE1uQzl+4)X5 zCx2Mmy26@*l9snwZ{&fAT;lgYu@eRp4-!u;XJdz(SCTV6-z_M~IjafTt)1WDZ2_*8 zn_V*Z9S;JWSE2?Wpz*yGd{~9o7r`$hDj$_6&uvvsiHO@o>S+PlweAsXOyT@gFw&}2 z6hM2JE|kmF}!VKW%b;WImbC$ z-9SlBLz8<}e)em$5{RFSgdu3w8!0yn;i{m-xlLfEwr7c7!*ycs3Usa$(>zSRwNj=` zHD5div$2sEegIuF&mC5TcY)mK)WmE0#_>7p2UMbsg=`)q4y!wIP`v6{+2vW58PVdCty6_-pS|DL8Yii@zpTbXOjTeX?%Cqx< zX*$RwYoEjD3N&{9sJ+rY%|EOifcUR(b`{tu)g5xba<{y-{7tQHmLcHWS8bAy-f zly}0MBZa-vb2qkqkV~+JISJ0~Fm6lFO|&r@gwMn4m_XWUvcuK>7Oh7~}zQ zIfx7`GjD3rTtn!VKm&^^_++)MJ0m?COg%5+&?xl-6yVI6a_V)*R&pmnFtSWo+ZhOt97&wzluu6>Kc!9XbpF3w z{jqLe*L{E=hYt+izn?py6e%zRns8kow0E%%+ zcZcC^Q}BITkbpfs%MOi|pJ7{V+ti1$2L>PTTHS$mY6`z+3+t|??7MDf zC(bB+=c4m*%-rhyB|aElAABJ2J52SRl816{75iET>Vhg$u*xs!!JpQ7udMC6xfA|l z`aYX`>&Ja#3;&xb&vgDDJv-l_kjLD(>%0dAq_ zxqfg?A197)%6iz=*~$cX_(IvzUMt(+Y_5JSeA?g_+7I@tf!8z3pbTmXc3z|0k6IBH zs^`h-tu0S64sf2@;NEZISA7v&wW0mst_QxY?VXpR+_h2GhtVBgSN5cZF?$P0F%Z5w z&x|wfJ(@VA>@~tUMbBo45#jv`DUEH9+SrV0(HuhFV_hfBr^Wm5MXqwk={8J7oHzT; z&ennBLJ~UFi8(sZjQ`F+-b5cwb%IR*#bk7Pzb?=@;+NnNnP>vOWupeUXO>clrQ2>RF?8D=-wK~5igqa{sJA3JjhRqX z-X5Q@nA}&98+!O~7xsX=XHg67utDu80h~WE&>p-<{kQd`Q!#x6)hr;-u{O`dDjM-I zZ#l8hsL!6V`Ay0{1Tk~6qCoJP4J5KygKp3T7KM& zwlaB4G9iA^W!>GW!4|pNR`?GnpOSCi_0B0H#-3(xqK6n`%v)KBwr-@?KE9yzW!L5t zkX?#2gQQG^5fuLOx;eNPjvEq;{S{GEGp=r-4L}5oAw;jy(PsC4b6jSTb<10RA;Ma@`1y>9w%?k1KI+$Wd z1#0>PmwZS*u2{ZiU6l_&;vh;S`!(|ywlB*cAR~4A!Yrz=9_G@Zgf5X0%nRS4uff>M zyzT;XvOQgAY}!loqZ!uuz}n!$`b&!L3hOoA(IS@fTBw1C0}{`9Z3bgH9OWb4z1sBO z;Ey#nL;#-p-r=G1tJWo=st1+IqvEGm8NN-vujui9nt6AJhXl4vRh+B;wWyYOn^9ug z-A0Xr*Qw)wG55(O#@KrO?+*h#D)Rvb!o)H@`g8RdX#~WpyDadD-9E)jU z^qc~ml{u~L>`ed-<5k&p#0BvF2+iAD2EqGoAMg8k`@PMJnI#o9{!EAI6B{Ef@3Sy8 zISu-le=xNo>zZL1Jl40w^FbUMd6acFchxAueY3;C&IF(S1x^x;VwurH z79J^RmJb33ow-hjcKKZ-Chwkq$MXMPsurO4;akn<(4uE!L$y~2yP833wWhO64Z{Ih z%k2i4iT7!;2jKZhz!Q)2)c`%3v+#-gcgK z2cky+`kmQ{$-CB2nyf+Reng-l!5h~ZJE9?56(yBARio%&(+I?ro}koeO3mK2*1Tk` z@4|gOdS8_M*vUuJ%2lRf2C*z@J$vAVOAw}w1xJEG2#nl7X863;6b7m>Dl7(g3u{l} zLMk_JpRj?Jn9Q4qCr3kw7hJI~nLPq_U1@;mZ|VVv?J6m0oQ6jCY+sW8i5jdV6%2(G z0*1%@o;>Nddg@AAeNU5}Alm;z-nQ^27@ow&WMEL>OCN@-gwILB=Urqo04*?;0?>J? zv?oBn@}?G5|I3+74+6&_C*V|=lAxs8uR?mq9;v<;Tg68{=&vy|Bo6oA!n1e_ zdL228tRDOc9m48C=#nI%-(<=jypF#A_qxOjJom_$o6LBhK8`4H$CtWhJYkAaOf*0qchkzI@F_qQy>xlB@^>=x<#IVaG1OuS%{0J4V#hQt|{! zx??!%9)9pYX~XvA>P=y+{fV#DGR-b7!4g&IKBVcJr(z4LJFkit`5hKUyJ@8$xT1!- z2fu)(l#gV?rtRO9D%Z+4S#3|p_3*i_Ly-3v^tnEDK>$C(0tH+pvIu3l1T}xLu7@b7 zUQ`!cF_t8~(2TDJ;P;OIyMi8g=VD8MJ0J7CBH%VXT#3vpir+KUScZN@7fw?b&epl! zLXDJE7fien_cGfBmKtJ0UHYu<#Kx@ok2;j>2pbY!Fn2Io%Hqy;1Y14u=Z~oVW^q6l zvbKGsctrWtRL9*yR95}vf|JyNn)!^be=yYpUV%0u{BhJvcQ#>r-(I%EZHi!*P=TWO zI~Z`WbX`qe2KeQ$H9w|{mHiiL7n)eG>VI8PjOOX3sEe~o}|S>j*yyo^aak- zWgh@0cCIUZ{=nE@$lOfVaj&D8vtxWsEmi0)4eb7z5a%;%XuVYsA8q041g;m1G1)Mw zk7FMuShcT#35I)wY(A@|LF93)$E`pkUIms-aFNfeOVq;jNB@(7y%a2u{lwr%unbqu zvkfe5hGpqJd+;k-sSV65I?rNdGc_?>%0B3AuxRf`<0U-Y;$qS9tRC{+%C+gZ&^RGF zdE#Z14+)aQUbM_U+e2p2YxR(KP_L;A>wFQTu$a?QFa(N)RR`>J_!xP_Z^@7DaE_1! zBa2BFqD_erR?$dYr9}A!!-E>wYCzCrD-b>=?N|Y%4g@b^ap+-JS)R3qG z@R7BH4S}6?F#kF1f5D|Ufg?BDm4)4%Sm&OJ`Bsr;xV)Dj2l_@Ly$A_r?d zxqfChIG7HDkyH6>4rBYxu-3Q!yWIn(+U<5((O(D9BBy{2u#io}Oc}nP=H31~uu?*; zg6`)@T51NghVv5+8;1iXDYv%v!awD7{iz)z_-+Fh=xdX{>e!>@f;#;5=+J=4Bzq^| z!$hzp#t{R!A-Lk-Ooa3rX&ruGT-SZvgr#*X62tDk<#)Za&}T&+RU29+ z&J`#_15TdmGWbh0kpzuQu!zP&uH5z??cHZ7NVu-kheGw`Lyuy&j>_d6nrDxuCKOc~ zJ{M0VW79OlCJIS*90&id(9~?hJ=eKrA;`xDYv&0WBkLguOpL7fG4n7oJm4{E>~?mf z2l}wF9~46XL``*vmE!XUDXXkczJz~s{DrXw>6LBkbXVx);2mrd#gAG|Rk$IEgVu|| z_!7^vi4{t0qD>Quu7X}o27wcs@eevKi^i5GKKs z0c{_uRs}SvLjWADD797q$jDfdRAfu>?*R(C%c9%Vi~x{p+MjH*RCGE+qurJvA7$hc_~$u-5^ooX#hO=yK?YAc~y zV{#;Kp-n2!L669pTvAZ4+d5jFGX56go)BTw3u249gLjZ2yAy>jUeP0;m&V%M-M6631J)D*>z>#2&>@VVAcB#@tT#m5ej1~-2kMzaPR1>@Ns3co4b}8 z`+d0?|3S-BqP-da-CAGG$;zJHY%Vd8&9plqgBP(=#V_W#vyr7^s;{;~Nyk2c93Q@x zerwHeI+~2&ppG%a?bDxs0iSFDf9?C)^f7k47$%ckEh6Yg-7?L0MQ%YmRf&nyamjrA zzyp3In`mxSFskX*_DQ3rp=?64ZTk;`2FzrS_7dbw?)gWIpk1D#;gozpBqYt+DU8Sh`L-Vj`gQ-p|9TJ{F{OUWP$ zzw!L5ehs$b5}9Dci+KL&1bPofqoIU9FLE+@Ie*=Xb=Jmu^(2zn} z4t=>VY85S0@JpF(6S~kSd}+D`Ly6^$AU>W#DJsCEAil=Np!^6CIzAMFYqtROLexUWE)-u|P zb{Dx8g+a_4UM!a(Tu(;ib&fDgbZ2fs=ZGq5Apqx-THT*L#J&1i^AK{c-fSM~+ID^t zTs5MhEvrv=Uw2|LL2fVU98sx4&e;_T|;oo1S^wCPf`2pMmAwfQ1`yM*xTdso+udhfcPzJ8IINGiWwt8G8aVX%;$7>z3SFaW~gA@`g@mot3BDv&c; zm7MQhsC_N@!f2f(ck+3Ct2ff`jcz^ONxZCI*vDD#F3ja3R-S+qw~$UQ?oGyAyxMmh?d zR3p%wVR_Cu`FL9si^Gw3>!HfoIW$+W-DLP9tIgX%SI9?DdS+qQHnwscTz<5sI-`(= z^1JT#V>d9VRFEPqyj}Nx*VI-7m)^+(V9bn7Cw}DY%2@fwZhfvQ8;}J#Y}la7$>WYC zd_edzP};x4JsYRbyN6e|`FBgK0+0YE}?=6#kPh?riSpNY7aL!pZdudmD6g(&Z!USEWbI);|e7h zN-l{_ue4%4cx~?Bcc;g5Pcmi_ro9Fyhvam>grq-Vny&%_jmhnbdX)-4z4oWaf}}0+ z4JVrSwYs5oOMIIBdi&ZETHyU=`}GEw1DfO1!HMeN@Vxk3CTpQMe7V8+7-9Sg4`0E^ z3=kxbvj2jYjh;fdu>t?lV!e}NbE7!nAOSs5xrp!#F1p(m4M9`ZXl+{*;^`*yRL7HU zpl)5%kQFXi`$G#<&;S*TscG#Aw(&(?*I96ME2@v_NnS45 z@mKrI;UW*5@;i*-N4bTTN6r_H~Sz3T}GlCx?WE9N#b_$yWvu8;_dq@r zx#tGBOLu^dD{n3Pr0i2Sl*a`q5f=?Jy-=JklLe zVct6oBa>3?5-IizaIsBsADy}z^PJDB=T^))DmGh}y_6H#az}iBdXAuYJ7xCSk3|KM z;D>lVTCPus^knFP`%)o-d5Q7OT^ByUw7p#X=ndw+ZMv+Rxl(o}rb6?2f$<9{G18E8 z1tH8G;h}i3BHd3@uVDCeA9B-Clh0It16}plJ$x8Y=UFHBj-*5`0r9|=^ep#zz3T-( z_TDB_(RK~wjWVop;ebbVmHUAX)fkuJxUCxXse3@4Fsj@wFPLx7LPNCl?)cPG*z|nV z-@7fhd$$~-2({Oh9Lbd5P9~>Q%~aFD{oTIRJ7ygzk?Hwf!K_DSh5NgGV+*RXquq=D z1`Ll;#)wrfkAKdmP-lF?&v8`#WS#CIx+kwS#6iR&Lt?1hbZm$Ll`ludwR}KWdDJLw z>+WueVD2;v(0OX)mB;iy!M2jdSCUR$FZ;OKXhN9{vw^`|4gfhW$LopIR& zMIsUS6%UPTc90k!bu!$|j;+0S%F_eLT4-+GE^;r-jegWpEHQ^{lu624o)+0FJiNZQ zeVrX1Z7iXNsU@u6j()W04LEuqr|#EzwbfnW&2H0w+r8op&g z*0PD59t{%W|Bj^SK|gB+7Y|l87^9vRIf2CKWVxW@!G@7(X*h8zEi@`E?I4?0*zau_ z1Z~+qHtpR9((=h+gR+y>q@}%P)9y@9)6y;JA8u%|Ot#Kl=%L{Ec;oDhw=iWB6K;dg z(uqp;n=C!nGSlut4|*q4lI~!tb7zPmhr0bGQO)|O$Vbt~NG>psR5Ke5R8jmENx zeIzd*Fpo-!WMO#Nm8b-#Y8SJequEaSRjD^lf)O3HKshD%il_8gn`h2k&V&^hD)Xj| zsGgr2Tw!b=e5zc7L~Y9GqVuWgq*mDQr@Yr}+{wzXm$@C&^_iRC(Rw@ZWFnSrR+jVOS_bIXTiPre}5bQ zVmdI~+Z?|JNdbK{2d8mwd6Ij}eeS(I$-U*4dl_e!{z~}uCYoLOcZ|^_QaChBZ4>{W z_;-jqoh=DA3T~PX162idLjfH;{09`ZV(-(h25)1m*|DHtoa_IUHWs8j zXe?lJHTxgs3tmoe6sOyhAKe3NmBwPox_Jzr{If~voT0N3^f#2^3~fbz3uhQ3oaKz2 zDbBzrhZnOi6!PvaSIuo33RvqGc|5bg%DfF;F(dP)c`%!3-CElg#rv{{3zEhOYa~cs z#P|E8H$Eyz@=<}$N7p6!sKD|OCgV$&?vaoF@8qEGd%wBna7}mN{iMJQkWwgJZJ##d zhA&u7Hu~Tz(43(lwaa9bJ}7PQ)oy(`z}E&RV)G+{;`$3Z)!$c-w3|HS3Ts?wAKA#SRu1Thy=F^( zMf|h$0Ujf&UK6M<#Xcj!s0(A_zh?$C+ODuj5xd}`*&r$YsF*ho92sy~5Cm0hzmbUg}AEj3J*47_jh#>?d&en{1ztOBw( zwvQ>9!9_Hxx_xrV#crv4pYhbwvEV7X6hWKQ7h|{ChYmuhA?_T7z?+QJpS*0u2}2GF zM*a}Y${JD^KGMC>xb#de8PocRwKkswjBH6U{0Cpq;Uxy6&E$8-He=3>t~tP*`k#@N zDyt&uCqXiv@#Mj}H89-I1oNnzj1o5G-|hrrs`b}#a=fU1{g!Hle6q;5YjWZtTHJA!YlEX_`| zrd#GXu*b&f?B-?W1}^SOJ-lXiXyNhc{zaEREV7skBd~*+qxUBmQ669t1DaWBeB~fYG z%NNl5ui4GZ0m`w(D8X9foDSx)KZ!+bzXK)a?!-SouYJ_4;PPn*+FvEyFlOw1_h@HQ!K{Xm*Sb=l$P+X-_q|rS6RO-=bL2!gMub*sz4=M}Vi?`oR8u=- zL5k2trvW1O+Xh!^8x-HJIHCwqUE%iG6e*F;n{`3k;_|Fu`;jo5{5g$3WMyoX`6wyP z;})_>Lc1ZWlU0^bh3%Eu zc;(DA03*6Q%%b;2Y|rAI-s-ODS+`_-vhFwL_;qiXkzV&dfYsJ5yY}wteg?v4z@1q) zuEQ3w7iZKhpJiM3VP4&y`-EoDO6Lh=fjrZa3>!X-_QhT+4u;0#(my46*{P&b*yAY{ z9+vOd((fL8Z`QHB;b!s#J3*AJfW9A~U%wFoT)5|q< z{aRk;sXeUaA*5SsKmhRGS?jy|On~@8*qT3CRezEu!#i#m$wgJIqodd3!K&%~& z?N7@qaQH7Ux|=8*D?R~qkz?gLTk0%Ib@W>1>X2XN7Qf7LTjr?DGCtqX&iOx7nM^6r z=M=Tb*^P0w^gFnsX26+N{uwr2dzOFpWUst%Oh12T%M)!xq;NC|Yzi)4O)hR_`T)=* zt0XE?vdSnVMpiLEVFK)9C$qq^82J)`XQb5fKU0_nhS7jMrzr`gx{`SOca>jiFr^G0 z=h;I2DU^oC^gf-sYo99pKAmPu|8<8QrxV1cdxZN&&Smz*(Dq8N2P?aPf*!O|o$uC^ z_if|ye0s8*ae0HSZZOr^aj9z_dKs6!^3T8xKCZ@U!W7SqvGu*pVzGBz{d?W6y(^-3 zhJW_6rGH21-SN*w`|Vo(Hz#@J|3WuF&iS^yj~^XF*rVLK80dF{p9QwY{nZ~cE>9!x zcg4>}1FK}nb2_6W{FK}J*0Z6|v26SxjWAkep^ zlms_D%hqXyAim!c|07#@J^82oL=Qu^+gfxVL2|xlRyI>URfK>BVau5C9gPt5%SM5~J|{7IoNLd*)C@ajQ>#Amjz z?r48c+1$>y(?}5E=DfZhR$n0_xVeaism~o<=bJA+1s@+7DVGWJ^1&WHZm=Z>Q*sxX zVukD&U;o)FDJ`GXkt1n6%ct1lpW>;5OzLg!T1noFIoOvqV7MY)f2pA}%1!@i>GS(u z)NAM9YpGg&^5)!F> zwe>TdHuXq{gt%5?q<&!4D!^y>3Vj^GNoWxvyI;!iNgVC9M zhxr?wRd(?etzr`44kYt?0c+4>+#Adn=e5@PCrp{sZw-ru?!?1b4}RjvNC+b|Q zM#Rb^_%z^N8Q+Ync>KpCM7D(=S%YrSooJ`braG3e?tNx0PV_KDmRW)){xT$6vs7iAdP{^)v8p{xvNK__JGz+_VwJP6Ga--=Lb%E_#&Qsm zI63j@KdCC!y=AMl_9uG-`bJ|{12{miA6QF8^^;pK)r#{gRR8MwN#P&0KBBgoqfP>vVtp?H5xeb_y%{am}`aJ*OWkJ!f=cFyAy^u z+X*bcdliY%G+d`L>Fo}Z$bC0hCCn#;1mLR1dy zc03#jl+>U4bTzt({S;82jDIgqLD6HF(QW#NAE#HPtpS_PFu(-SCi5()HGGHAI?If@j{ zU?&dY*Pas#CZG1=iBI1U!k(Wm?ay}mldwO3w?EtL&r9~_Is3E8{yb)X*4UrB?9XlX z=Xdt!27a8)i9fS+WPHZ#${$a4gsCP`BQ657v;z@rzvyRa(`WQxl{8%M8jg3?4;)qE zxMC^ynsze;g6%ofn~nQivs{&TvhJd-H$U7%TbnOdTbEu(ud`{OLqJ(0hmSvU8bj8C^5k);D8qTMZd)t?o*8 zw)eIUmNaiwTRljd#NrRIm`O6pGZ~bxphjfc!e&=utzs?fOV>P1o>@n^T>Z3SjUEreEw}o=@73eJ?!5f! zN7wNlD- zDYxvEx~ofps(NBYF!H#jUOTxee%G0~L_u2eJ_gTWSYi30PCzp@=yDdi;2=;vv6PFZ z&>}EV)08%&Xi5&NIq@ltrm^UK_A_yEU*a=Yjlyi}lo9rd$A9>Uq0H)y-V}Dt=&Y>B zwqSGxzun_X6WgGe+R`perEBghFLzrS)&gsms2BgK!8dMH=rXJL zhFpHiorXMZ9Oh!m6CCa(rS6*8Elx5N8tgSc;Z zR0wj01ze7XO;Uis=azZ+IYmxc%rlx*UFtYg!ILN9I!N>zY;l*xOT!?8psqH)hy=u@aqRj|3E3khY zH{+#Vv-^tGXWQ>9PaKbBei)Yd$SLHE!2yUahGI7a7K$M-1gSGr3VE{iLE*rD)*N{_ zz$JD_B1O%ys|s*JgwZ4rpWZz@`qY^wQNo4U|z>h#Q}MyRRpQ5qSuOIyVCNVYW)NnpG6Inry- z-TDSDQny}sFQZ%An2HnkQ<}EGUOfKkXq)dg@-+}%A3LJgo^5Gas-@k~YL(a0w9J++ zQA=YaWf_iHu{s>j$2Pv30QP_&<@FO3DUqSqMdPeK|UNw^zciM2HA#@`iD(hMWY z=_^IY^WYH> zE9cYa^vyDFi$~g_ST?a-dY(qhkl^yA4Tvir(9^Npeo-q99Eo1%kxHVq7Y>~83k%9| z|DZBEnx%bJP4%CJKXbV`gDeEVAH!akYe$_ zqO&G$qqNTp<2Xksp80R`!3)nwZrSXX7Z!bMOYL4ulQUcTsagtA+Vb4-UOT7Qb}pw& z8SNaDYG*enEB4y?{GE&*ef zB5x)6;ZJsE%l$nht}?023Pu;h7=yRfoD&Ex`2sql3YK$aPPn9^>qy0b{TpecQ?*r- zZ|Sq7slHHg@Q#hy>r?Yx-}og4hL$IsZ`kTBUpq;xuE{A%Y#8Yjr#8bVfjL}0s=MV@ zo2kh%hSSfPRp`zvcV=;W6_?cI38RhW&ZN@d9X~4O`rxygQ&Y{y+fiS1oUtN)2rcVsW?a4e;9QX7cf&PxAJil-^|k?gM0I0NyYP{xi~inoMa{n(u~Mv!+|VdX2`t zW+csZPfFr=O2dC<45bb9YtQrAd2giOPS&@!)6Z*Xn%a5Tj8I)u^F9lU#0I7g(+(}K zSc}lsoVD_lv3~8p<@=sT(d`%6UK9#hR`1d5?x^;us=aMKi|Y2J)a}-mq)D}(DP?|X zY)UhiIn1G}0^xtY?}2bQ4<1tNC_9Of&D5A@#BFl3vZo~5nv`T~ys_|8&DQ=NWn=_z zNf;I{^8iklWjVeO>--otdCDAEs)%2>$=j~H{%QiAgumS73ZZyw(UV+)6gn$v=jFb`HNpYg4=pX=2= zD6{q|)qbE#6R$bfAF3B#Ub&Cu!pJq;FEeMKjBLT%fy*n_Dsf4y+!dRI*>-jzp|`L+(v2S!Y+Cj5v#nc!RY!r zpJf(&Yg<=%ZJndGQZnd#wRO5}Yix5Y=_!C)b3A_GotDjxr3{0jA~henp?rUo9z_iv za*p#1F=&s8{AZQ|64`%1rKAX1!Ntpeb{BZ)Hj;W9A3czWfmY-^Yhw zKYiJSa>TJqQtl_ieadZMve`42Jo{6Npx2LQrC`#|h4nreCZ}52 z&0Kha*UIlvb<@aDt5%MnG`uJRjK9zh-~+YDzR@fxi9XU}C^xzHX(%U$akCx94DG4z z!jN*q0g00y5wiK7o4<`;x5;d*kAF#cN5-Fzj_J zU_AclXWz&|9g^aq{i?BAz?D1oArhxLt0h*JaoJUSOd`QC@H$o;$UU@8;=pUTb>5(? zU}W+Sva-fA2DB)x&*COdRN=^8%&~4?C#v2ic4#u`sV`j0y2a4qo+K?clh330ZfNn^ z`Ih2SQ;Qx^`~j9{iK{4mL5DY|x4}l4bNX7P%+{RV^u(C-5)5 zk$D;AQWN-O-jWk|a79QBTG{9xV^oJl%iIOm{3l&V64|A?GZq=*6Bdo%3_vo?d9T6)S zJ%j(-_UkQ4(kbl9!bRbu-TH>XoLA}00zcijE!v-a{pePS>Ze=Ybw_ihY`6@&81ei< z0fFv0Hg<*z?OU;zzmoi~v!=i&a;h8Ho|KDgk076c;(;FtpcgKkbQuFTP0z009$a3pi7KgYpUtAx!_`>Ko(!hwj}V*uCyue}L^?0^anx zH!`z(4PN)6>lWW3VR4%W;28|!OfLP4QqC7FST zfHP9|5KR*uRGYX+rIG(h8`nZ?T%DecYaAclnb^4A^dOauD~C}YYiaKKaRyTEpgYO& zy<4QD%vT$c+(OF5luIGy7O6+x_?8WAkdV}qGUGhT#AMu(Va&BEHlv$Uy!FkQgGm$0 znPPEUZTfJ(A=T?C^m-$E7z$A^iRn|8y&!W2)AL|9Lv`cgfxGnnRG%*g4@4AfOB+}<_m*s?=HQAs zmSfFm-?->7YFE0ue3crmUTy>jao{MQLBgNIpO%q|XgrG^$q5-i<+gW%oE0s9q#F|ib2;?3iV(IiJ|jS zV#vpgrm8=>V<%OQZ4O3W!57ooUS9rtQl>-NteBmC5G={j^_EAOd!9=&zGV8tto;(# zs`Tz;`el6F1%HRpDP(%hfl2e;GexFv!IiHbW{90)v8m)uV)Z*n`mN_!tbUJjDXcy% zG+L&qIdJi^w6VR*Fpg{0)-t5Jr8yYOO`_;-W-o8r+YO2yo@g8Hcs2t?*Hc|0tSPmn z89}gOuTy-ipZBd*{@knb2dXkma`rMzQ9am%)len z2V+P16%FiJ8@S~xi^jtL1s{U_K@6jpCir$4Sti$3l*&D22ISZvk_=m|F<&@8xIZTtQdOzUzdyl6X{& zy^O#qO%{)XpH7lgT|JFP5(6mRi%pK;@X4m8SNcuGHBH(5hut*w=>*%xuxt{mi3uQk<nbf$5+1-{C+g18rluM#KUUnqs)Gss)i1*{YdK7XQ6v+a2xWaLH?5A znp#ffl3jA6LKcjoE8MY7v7+m_N}2Is7x11>i=t;##Lt{z$IVrmgeQ~^b8uaGMD{h0 zv#RIg+R~&38cN-fxz$exm&`>>3=KwR@|e=*aa<`99BW)wFj~Z8_vq3@x#sDfxZIx=g5imW*c!4t5g?yOwB6ux zzcVZ@pSH?{<{J&Cu9v{&CT2BwVwa&?ls2A@my|L?_d0U#nL&QrXxo~zDT6^4tF3dq zwq*Fj|79&35LRIQajZrBZ$l)Q4GgEydJ{Q~1i9jl#$%CMR-hV6jX@Sl!c9|;ARU58 zsNCpgxuFssP282G6msubC4m<%2_gR@Z(u-l=LGclE{|NPsjzAxd7^jiH==E0CGqXc zxuhCu!YbKYxv9q7tXUD?woDDSY%|x#Ca!o6o~f?|z^$oIPuA48ltH0!vYxd$ zqj4Rer%Zj1>kU)ip>)yup6=Laobx{6$0od=e0n4K^kVYqspQjR$*230Pk%~2-IRQ~ zHu)6eiSx6gi#b2rgmW^UEN*RX16QWT3Z8GBpPv;T;LgsAh39-7%lpK=B$v=VfpN|y zxv@YAbh)p$a%3#;F1MvAmbU@`9Gui<=R22_yR!?NODf!bvGGU{xT6CO z##-YZD53DmW=b#dt9_C;ui8iS0o8zh1@L!llJ~)cJO@!XAs;UTE>3qED>l^@Pe@8% zfe%$8D(D-y+zExTyfb43%XDXKOH=lzsP`e~RrkztZ4%5ZW~5dI@0eSf{fc%BWWE|v z0FYzr%AR-U>4J}G?qWq9FUKRJxq9cE0MFW7Xb#>%{%l2~FGuOK-hEBWLW9`7n2KgU zjoaMypU4Ye43+DRyB|C=nQaC(M2M51mC97MEDpZPTR`2vzPmeoD(lzE?9ZGxu{avx zO@yAUsMbOpng6oN4&!CyWp8fo0f+)jUoCf0tO+K7xcEhKGjg81BYP*~aLrIjGFI{C z;rsjgaFU6PQxRXVl$O3A3|TzB4^g^=Sz}w*Hi$3qxLWuT2|HaB?2gYxdY#pj&0QSv zBd^dc#|Sqzcw7FV>y4FdH}Ks5aymS>^5(&Fqdxrq;O+i$flM(sPLO-z?m-z~9F+p& zAbp75O9#rLPnvGXU$!jzta*OeJa5*sW(7j5OW%ca+v zka=`R6lS+cZSHQ{qPF$=IuFZ+=eM_Md!G28QoHBnRX-%SXB|@0m^-ULuCQ0Df3x<{ zE_uzoeB6Fb{%rab3f?h1mmulvqBVOXIOz=hOkUC%IPp)Wk_;4tN;NHdXqXsaFevo& zJoj`4K!{sbkfyD0b@0)Nc^HSTGmpdfCpE%j_i_VKx2rA!Re5a8wFPc<*+Zs#uIb)B zWv+UM5~Dy4#|U4HNL^O7dVTxy5}BN3c2do4U-eluFmVqfumM?a+KSvCw03m!eMg_* z%2j;ktD1KLC1x`@*2LWqTjJYFH0&@PlANC+f&n<9%RFRUL3zR)6IcKEmIbR>r*)f9_h9yIW4o&HF z7~bEok_~(le02DJ&|*2g<1vp%OQCW5!vvN>ZQ>b^LRiFN3zihP2bW!)Mxh^;J(NbF zOD!owHS?j+27)Yp)xOG5NkaEAAs-guOinHfXb~?v)|j0}zrzy`!*0kz0g^`8;L4jx zhe~(7qR|t6!z0@9$5>gZI1vpkogUrWhv#)iEaY~~Fgjy(mlwGC*%op;bh7NoL9B+H zDb0x0CL(K?*~@Y*_;?a9sI;9Q-k#+rv9DH->3Gi+1C?AWO+00HoV@#*K&ud5PGQxN ziSQt)9X2(E`-%I5j$LpcYg$TpsWLYW?+27!oy0qFHoZ|18M0Sa*4^12(le1;oOq7$ zqqS5o_`RD?;P(t})=b0iWoA$W+v9xQJ$_?#K({;GR$APKeB3So&30cd6S2Gr8Q^5I z(0nsXL57~OFEFD9JR1XXxQ@7Jw}Wo{U!hHM+8fH7H|S2$V?6%WV!ro2V-{o-?VBq4 zZ)~2uD;f)%vcE#wmAjXfJDk**rJ(kYRqqgWL=NO{*IM!ALFG=cP&7NGMy^JyddwCa0p?QBlkyrO5=KiF}z$MkMc- zZ%Ki1z8uJN>|U#6OfQ)R9;Z5=bq(M)t4g*LG+9`!gCK6rL~P*Bq@BPsEk1g=hE@1g z--C1~qqd3lOa+=j{MaMSqGc`b(-=Ebx&E7Tk?nbc-I^e1ypqG-HN)^pm9b8ORLa%( za(8r|!->?`0*Q(1rF)Kc%nvuP9PBzqL3}FQ-?16g&ofLlOIl<#RkeG=AVyJYX->4V z8kFv`Xtz{7UB!|NQNf$X5Xa~P-nz330j`IL_q3y5{@4Z_dl8>%vrB=jp@lbnc&MIhmX}nt1ad7|G-A zm)q9-x$p=pSbvc671e^^<7Zgz?L+wvy72N}zk3(%qhJahf8fmn<^~?U+5ITBHFh!! zhvZR@s{$m|hq&@GGOe6P4yJOLa|kCzTKO{M9L@vto5L+1luA5%U$SGp*evX!pPLW2 z9eZjZ)g>)vkpb#h#p7&mJUVed;^~(&dnNAw3ZOOLzyJ4dGSBJWPXdR4BL8ACuxE8& zr)@--SkoFc?mHf~F-F1yserNM#*QwFR3ISDCWwz7UOIHq9!Oa{)B<`w^`xxuj~xft zshyl9eR;KB1BnZ;)*3sU3OQ+Lc*ka|aFm&8J9x*4!m=JJ zZ<~=PnQPgWe4pRKeI1j5EenxHe~H8YC40zf6CH|W@AJ^tDt-m`LdWp6J-wVbq-Z@G zhz<1!dz;e!)<^@hJ0fYjLkWju=%5wBkSm$|)AyN@wd{<~^=diutz<3!25L9!+W|_x z&%nnPLmhQm_`>&)9y95j*!UTC8=F3v^v6V~g!4sr_g&eEH$NvMV%r>k&KvT>;1x4a z4gAGvm+ltBD0M6TkI7}~%rT*0uJ`BxI`|vk>czH-!;Ly1^%u%gu0SruKxWTc4SE-+~|vca1v) zX2U|tuzfUvIW0HXR!^Sb9SV@QK2fde>^9ChTJY^7(vTxH2x<*yG>EzTPe_pga7hJf8e6r;q2-0Y)o|{`?~#Kkh$f zJctM8?4%Q(Mre&x<=l7JCD1p;V?7B>aN(`I-{;+9<~dSoyCQu zJdEAS4?Pv06K6e4TgG&`*Ce!WiVQUbWEHs@%j9~v7yAh zUC2&*7SG;C`^=xoZGuZYdouQ0DbT}8I8v9rLF&aq*-FYaNtCTepPvd>Dh%R^bB|>3 z)79XLjm(s>aow>StPo)dBrbzFO;yrL{xz7!Hzsw1=y_$vYTNE;#$9|u4tsFN$bGOS zx2vRM99M}Pp-_8pb~|#&1W-H<7+d~P{aG-27G->L%W5gjUT37M547ZN7Nh=5+QxV6 z$aJ|{n2vk}SbOfs)bD3@&GPr z*na$%`tfTfLZnuPfUu^V_0;*6BGA1;Q9|)U>2Ksm?0(`V%|e^d~!(RETyV zOu@04{dpLrP5s$U9kxFwB>OWwjV{~gd;MAYC%-?BP^7p1+_b;#&)MqFU(tarU9{cK zmK7><$k-HP|AC*>G0pp3qnNuaP42?^-(!aPexrxdD6w++GR_a!mvqykvP!Opufpsd zjI6-e68&QFeQwmKA?sTHWQE7p+ZbbpJ$irvvjYOmKB;Yeh0G#AQ_|JgVPTmY1Vqc2 z|GdmYzzV7&&;eg|g@t-5jXKs8KPmoA_h|;Eqby8+PQvs%3se2BFx54r=-mS*;U|OY zB@7?~W$bxuS00ojeJJC96qFC}#ROnVc{Qei*zvvvvE}!@k@2;l$k?)s(N>apg9$`> zW0OwGdvvtG23I_aQ;$!_j!YP@gO@Cf+wg<*V7%p050iBU#`S#Z0b?3TTmGjv*iN^w zU6ru$)9UL|Xp^+c1mdG45c_I>R67-;*~2M`rG?eF!G`d_0g>| zf3EMJCI>p1>9ksAu-PFeI%!tfbg(asFQ%UFPMz))bxL|rM*yiWMajOb$E(oxC0#}r z`F(ll_kLdzNB7>B=kjb{MnM~3tV}%n8TiXsKp}L0Lnozd0-EvB+?crSCGy*OzK1g0 zOZHAQ0;BYdd!@TO8CdbyewZi(vbb zTnHum;ih!5H^~5Z%f1Frkr($j3|Re4aCsBC2Vxwg!)D1L{Gi5avVZ3=3@p~`FDrbD zm5PIa)g51gC=S6d*-vJI^@HBPszx>nt`GL!EnNLQxN1^xJxp!`SK3m@gX^CRj-GH` zdoyrZWHB)h1ZTwC>f>y(5f^V^&Atn|PW9kAla`!K1HsrX_-cW5wc7Yyz5>vF7F>C( z`XE#4C%xe7)skJ|>i(VJvO+o3m4`nE_S1s|&Ns0|*;?SGWIv;ikY}1In_FJ-VX=z_ zYg&76AA!@d*7+u}{sX(7)J4}LtE30gd$1h&5o3w-KvV^{XT_FVuE*L-Thq7``9+u8 zRLqhKr~=p7u`o58{I%8RmCSwHTzx#v$KiHxxZTM6mH&lRfOY8>4WckrOgFmDG&rvk z4y@=pSu`$S;n^E5bK=Jv*n^RC3V~{Pcl8s&mG47s8?QLE-pzw^1**A*fPKY~kqJ5RtM;~C-f)oU zk_}y!k5^_BgM2r1(eSc#Da}bkfk&6Tn=H#$2@m!<6}xoqhpqwl$H1uxQJLa=R?RX# zgyJ`F=OJoYbIVIU|7%InBnE>E-s@}le@$Z3cIi9bu$s!+ZBkojg*J};5q7UuSG$fd zNIBJO=|sP!9?Nq((iYg3?oM23*Qsht2g5>Gzf33Ig?D>&0=I8(@V?#~@MX5jb@U~a z=z~^;K-Pf0{}3}w*Jxbjm0(siBTUiQyJvZm`PyGICq!dpG_fg{&w|O4u_I4`6g_4h%eY-cf5 zlKKoi(|SqiY3-TR0ZA+3Qy3+Zp_k$goPJz$RFCtT4yP=Gk*9M|a1fGNEbEaaYtQwo zImoN#h-5XGU)JgC@{-5-aq=DRuH5}WP%vOn?AiNL=P_GY0n!CpT>d#2wq2N>(S=_g zW4mxW-@PvUf9$;ncobFN@I7Z{60%`QmJlFlU>67wG$2R|5FkJ(0%~YVQ$ql%oP9R(G8Lq$YvAV};YHWbu|+?q9bi=v34=KcMrY?k7E-_LVB?{~fL_kDX^ zzdgPEPn|O}XBMP{E=aeEaDny8=>_u2DH-S0(2_9s=QxUU$d(Ci=Eph_+!cv{Tw9r6 zV`n}tIK~WGaf(!;qO{*)-NGBjwlou+n68S5L4wJ-Dsj%+tpmB$mM0r1e^=lVuGVR!3Cxh^$UD#xLQmoU-r9;$NyTJ#0}7{}Wy;;o3`mbPavcH-}%wJ`S5 z)Te~o{u6`yxK+3giPxHbdxT@$IU=cS@pH1IVjCvn@e7=Ix4JjO5?>w*jYySS|9ss0 z=IcG!MD|sm!<(}YSNpF0y<%xSlcS=Z$x%_yd-lZ5-x(4R>HX`KBX4RVT)7D% z$9!53kJ>wd?mdz4YgRNTcdT`UiSAf#Jd6V?o73Fgk~lXuw(Yb!@C$cZ%0?6sR_T3g zE82&b-Gf!+oYs?C_MKe7N&m+a`Q0jMNBme_hMNUf;K!;aId)OL5NhwKvS%yhlV8;K zEv-hrZ++HVR+zN#!#pGTw=p-BnE$Q~YT{@=XllQR`XD!|N$GVGtl@`1R=vnRVr_eP zmkYE|yRd~%lNShJ_%94Rl2eNW;o zTQjBT$-7UEr2WY`aq}@GohXZSTAx_*1&IlfgK-w}JrW3o|ky!iIX;`#2re;voApC2Db z=Pf74@c?nujt{pTXS(h<(;`eKl>GQCFXwsF=qz9R#>vTblPFK_Q+s;YeX4GQ+CG)T zLMuu_wWlNvoH>q$lMYcA#cIz zgi<;ILML`t|L#b6tubWP(zZ(;)EUa!+TBPDrT{GXfG^E?i<=s+2{#_vo|)i~!pLko|UQoC!e`#!_Kt2(9j z>EWp_VYDZ9>#csSZcje)A}n979DLjwY@C%ti9=qtApw<_;RyzCoYqK$0rn! z9KB>Ew3vj(O1ib>T*Y`K85||nwbIBGX>7EX8tibcFr@X#SMKI#vhR=)9>^Y6?WN8D zE|BbM>2jkTi!4{0Gug>L95#BH9Mk+W{R&89C)`Y8Xu-6-rf`w#K zwCc+GPJkS-Ra=bUOv}}gSNI!DHLN*KY#mRmB~awf_YTTvC$@ydxVIe1MkR|k+hqza zq5hFGyJiwW$E`G`&Kz6x22M1!p)|F1=xJ&hR^4(op*Tfi`ymorBRic)4jyL>Y^U=_ zIU(3BVs4xsK7IeGv;V{0c!~smiz^d5@GAu7x}w(UA{JG)(|Vjv)lb$FRaCPI7uxfr zJMXw>INyH6o(V_GmY%&74gVtZ)A6g&t`d5Uwa3eY3#;0Q@kH65O^V2v6=!6nY0qt4 zoHQPhZ6rHXIG>Ill}7j@nU3uAqpWK?!$(|9MLC4;$Gi*kb&(?0A7q!*o#z!XBtS}$@`xg$^Zgv#=) z*^Rdq-S~2O*W_bbto?x4yC<~WCdX$Y?7?i8x6TQP{$NjDBx>!#uw=I@kwjBYndp3O zo!E)aLT5+%^!3M;IeZ6^BBMJ`ur9_rN;KhlCzvN=wj-QKNFo?#DuQQ2Q-W_Mf8nV)|QqG5uvPW-IOY_)fijx9K)F z2dl56UAyzlJ@32Li?NQ*K|VRKvpg9WTQ^p8?DW=z&zDF}-8tr5e~L?_D_9`IYaju}VRY832WEI^h?&#{WNfUsoka+Ij71^Ez~-01sm6xou! zsN=J>-p*Ffxn^SV7#0*V!BL>-EfxC&&PUF&sfAH`z_<#wiDyC+s;MOShiFYPUd6E}ze!xO)< zl$CTEOi%75$4oAvXUfSFOU=?$n#vZhTYvzmT1V8D>_eo_i+!-7;w4 zE(>hwPG9coE=E_o%f5kRWH01TBK+@2;%~cY;>`%dnYX`vge050V(8^0Ihvh+JIU)N zq|IJ2#yu)nZdyTInh}i<8j;R0b5xs z_EzAV(bax#X}Q>2{uiSwwt)2m8s7ZNC-!m{@$oI4`%l#9-Cy*8p-6w%F%_?sTlT^!MkiufB6vCEF=x<+&v5nYRjE+wK%i0I6S z?)PH1JclB>Zz8&VqO;_-8=WjTgZ~}|8S4VW$MRZF= zXN8y_u`7t^CZS`pd1RNH)Nm{kpBxiV7vyWOI*O7%KA89T!R8OLNi6p{3J(~aigNZ_^ToMV&h9Iq57t4)#t(84DLBo&L!sCd#o|iLL+jxwUk?Zri8LQ%W=xNcwTj$46Qk7 zxo!8YSxp%E^Livh~+p ztr#q?mK1`^Dw)-;Tjrd~KD6Waj1-wNQj`rZAnsvh&&vzIa#OzSd3i?yUFYDT#7&3T zWf@bph#T>X(o)D(T5wF>b)(XTt|+$-Vjsqi+6sAzqhjd-{^iG7Yv~G!VY%GjT6u6Wl1aP`kZuA zy8l@8d1y!;NA}9=nQ5VA2mdZja+%z7NZ#D1C zfE7#Sg?IT?EZyhmb}p5v4hxy*kmAHH9*7|NZ{JvT40Zt{zYO*FCwwe6MyDWnm&nJeZu}c zRtC{g!Ko5%oy1;{mPvc#u^P&llNJ!Qx;=X^1CoQI<9IQ1+gFAhEK+fJeGSgVcugsO zErsL)H0X?;LsFT$C#0p4Ou8{^R+mpKxe<{BFU<~)%L#vgy&Z2xDBBXl?>G{BCWmV@P2SF< zf(2iW`C?Dt7`uGziPsN{lyyN{7CqhKXDO}E*H^B z^b4^G-%C>}?>QqcvGfJoLr&1J0W;!o>eZ>EmyicsL;=h2&xRg%i!Mg$ECDW>(QE90IL;X{!r0zTCerq*E&J44P%Goo86m|Xa6}R-EziP?~ z)26sGrdvs^k&4xYD*6tS`l;wEk`n>tgw7umx+1_uM@eguzqGb~oGAW^84Cv&exzx0Kn;$Ap4)W4u-|LH{+ zhi)1rQT)!sWZ0`i!Ttq1i-(CH>-d;5a#^*KyE{QAUkf)Pf645*Gw8=P)yYzaV(x`G z)N2=`Nll&L(c&Ee#4D6J`cg!}}HB`Z!26HE5s znJgxje1*ozlPjIVSR_-FQ*OuP#9uf=Zb`h~ad*}C6D8W})bh|s&MxvIW~LUB=Fq6l zX;sEFJ5lx!XcwVkk!W_%Qg{=zXTQMw_zKHpg|SO_$#lZFrDCoa%E4H^s!}_hjpd=M zhP_N&HQ@@XUB=pw6eTory7;=p@)d4`d&in^ACz*tILaofI!ZKdgloubAsV7jifhN^6Mg(4H7Vk*i9`X$d`gqc*?me$dC1{piuJy$Fh?MH@ zBHt9B9T;oWv^9J zgWH3jl+E$V^SRWA>{w_t`?#w7o>ER}$I|F;!rE%|*P)R{e=lnAXyT?_w8Xe7lcjag z@w}jS=(4!rHa=KiRkh<{?03rXYK1vVUl>eeT47JSS+MjhuG9w`{ioM9?do_b*U=vf zUt*Xg6Exo?Q;Fda0yzqV(_()CYTVo1Xgb_Avz=rgWQS;_DXp*<3?&B`wkWe5 zRn?8Nsi*D5N10D$qTE7q835i%pOTT3o!wDM*HH)yRgd{-vV8;|nZ`&~IiD;5YvUIIo;D^TR; zEQo6wYSb_BSPPWzabWv)F@98&-NpNLdA&M|yspEcdr8_-l*CnXA%USp4A*br-yV(a zB&y{5f7YscBxxs>+<|*&K!7rqzK7O{9fx;trY!5k-9EO8bfgGXZ%q(UNssg4N6Hs+ zX0?WYNN;X5B-n`Jm(0UeWcQsN?;rgmcX{orog;+_?roCIj zT6M3rfXiIALmHXY$0AF@l5SSNpen3uK*>myw{n@gN}iKsq*auQD9L!?c)P?U*(AdI z>c3Ve(KmuQYrVn4-HQT=*UDT|HcwIf73hfE+I)7(PgK?+IN4Q4@}zMT?F`i!9IPYq zcoyGu=gg2kIH-%o>k^Sv_*?f_YxYxRl4#fAt*0%I#MQPW!tJDw{%sDdbHFHVcGcx% z!m5qZxrC@*S}sphvcb*`b;e=5bPiu($%wc_;8dn07j7@{^F~LOmChhDn8g=jQ^LJ0 zx!20~Fe~&hqY-)OCwET8&l#2<8Jm|Kl)lWVBpXnoTCY0?6$#jGU8zE)9(qYG-vDOtb-!Phwdkg1fy|5~~{YPp8*@BN3JyAqJwq!iv76 zwM5S#Dsin&TaCikPfIr1e(WriG{(f4jm{ttH&#YM5#KHN<~l)|OwC83219}kr0dG* z6Qx@hEDD_;V7*wPFv^IjRr};!uLVgs~64&&>`;Fh5)< zf(h@(`h=9qYp5XFok-agePO4bYb<&50s+?QM?K+J_`zfm^H|s@%xgIL4&3IQU<5HtLh}Nx9 zdqB2pwJ=Kt;|C;BshI9`>hK2f`>8cUN{g>Lbb%DVdNb9Kq4v0D?MHZi&uqHJrkJw8yyMrcH_TOI@ zj7DUAayy-&Kj^Hi-CqjkGo`sC041de= zivQ%qw83H=;^hcN8Sjh#V$LN^p3jtryhPl^f9Z)OD=c5h_>u)z@n4+wP-I!9U?uV` z{wpT2bdp$&Naa}=5pH-SM(HDr9*8fFHZS6{t^h=gj+D)Bm^Q+*=^m%>>-dQb^goN= z{-^d!rAe(t{KjPBx3TS4cFofmG`AK`+>(U-=JxzmJ#Yikl{LjMtIx?qm4TR?MNnZ2 zXGkroAL&4;_Hd9|yd!P=#oLjqJ72pF)o+z^8B}Tatv`@L@U`FvwC1cbmSbXky=u%p z`ysN~47#+RU1B?oZ3kKErtnHb)q_*0{|c)Gn>=Xdw(eAM3yGWE@)uE3`5w_~{P2!w zCf`&+Cyyt#5F2)c5?5*HmcArA@mf*6;GwohyALQ#T-69$67vxuOQ5<8!lI?IT+J}S zQp;I@_heVU#;|TPS(_;Q4Ut>#gXM3iLe>F^nC@Zq8qs5C^%`Oi5T*1StgI@R3qU%U zNe{3DVakJCSwUG-PpJCicUvYC$Qiw00!^q2xsbDiDDq>3x*e^A2@N-o^t;f9<37g` zZKb1KQId85ZQ{)(Y5zc#$-g>=a2u`RkjxCDobr_ftMqSRkuA|DuKbm@=1$v^c2)T| z&a^G-fy9zsxHAQ9#&h?d3I{TlOMY-L*_yQ$m049YhfD3q4q858fB+lMN)mv&2t2Br(GeJkO-fO5+SjbN#!#M%YdYioYcDY&UC4d(aC94(n#bD-;TT4 zxh(k^o!ESU8vN0^>dvaV>3p|lLz3?ot$Jk(;%L=7Tz*ID)}YI<#=4Y!irG1|zmKA~zM^2W=YBPD6cWJncGXMmKuYjH9Vu_W!x@Kn=qGlFGCA3C)> zGUk`gMNl1gZ)Q8QrmB4zJG`r{rccqVmiFy?SV?CS)AoH1myKL|9KnHk>3!?<*Q}~l)Fs}n{U=AfT=0lw!(8RbQcUh&W>rlSe>=m! zaP<-V%xz*1+(?nPCI*M#Gdzggm($9JYKbM?v2agDp1_vQk91J$ny92XzQ~TqgBoSt zTa7$KpkZVn4)&s^vps5a$4}nQaj)L2yGHIR^mplUbOD4@Q`_nrkflhgpM@9eEQH`g zl-k;5k@?6S-y<^VN2x?6R!JA1OMDgKyDhuuLS#rGSgA>F$B`($Cxo&C*}=%AtbA~` zHn!+shr0U6z5FI{8(nhf)npySi2rD{!KZ0w$hPUBupc`rTLs!U_bY@li zF?h2sVX}yr^zBDxWlT?#c(+BC7v1bttcedOVCy=77x1!UNGvE<% zZpsN+F=S2-PLlX*!ufXmTdpEoNa4eeY$>c_-s3gx{UqZ^qT^m95H-ze;nf7SuivE# zNJlClJi(Gn$h!8Aw(n%yTh}Gg_6e4~TaMK%=(ye}{eoL9;cxg8*@)B*vFej)#Thbr zst6HIEoa0*t*LsEaN(fszjjP2Anx$xzf$K&-d-NFem`Lt3vb33la{P^!mEibbkcaU zgnpD*au|OMgVt#d#6dH0x_(txo_~@>Tw;l&7}a#7)!3^NEu2q2YPUOnBd@g=X-CE6 zEV=Bl>V8nbIMxvPdtp%Ob@%uIg{6z;2%{wIYsOZ<-_{d&(2s6^wnomcy8VEMOSZ zz%bM_R51ro#Vr*z8#M(r3pE*4&YiFpY9BgVIo+6lXb;n|mkq)x!P-rn!a>qdsxBQT z7cdKYNJuOs1uv?k5GMs?0Fo9ZBOdKF%Mu@lG*s>XnH9p039Oyvwu7ku(`7jHAD7_) zc2fRT8DtDORT-N7Z!d$F%VDG#m-BDyVgHzaT?Xksrz*oZ9>PCiR7D!N{c5!_R}BgWz$X)!EJ!B|9Qk}z`RY#T_Ud)kI zcQK)?oyoMSTbM~Ai;rd46L^I@|1GQA)Wi~N?}8b1k4L#YS zkon0SV)5JstBARJcVvD_C57rWQ_G!pP!Y2rWq-l0k(C7%G1sG8G+cBW(Pbl^ikQvl z(wflKVqQllH-ai+J``8WZjb0r6W4v{wpzNB(~0j~i6sM_ukKgqGSTgTikMOSS1X-Z z#-Q6}*%k6%Y3Ua5uQe5ai_k5#bScearn4zZY zn3-xmkmh(Ag9p|cxwS1kjs*$Z7Ds8__*hCDwuL;PRS^?dcc1`aN>B0q!c2e~+4gbl zO|7|=X0COm^CD@=y#5funK5b_24s4a!^o01o~=T?er8Le<`ZiJr-eJiTu4aS`EK}_ z+_-Wtwtlj6#1(>eVt|WI8Q>YG2xOZ6cmn ztxlnxi{!WCVZgFKB?caEA+fTo$0e4s=K`dVxM`qH$4@Uyy(YvJX5nHi3}+m>+>)n# zXEb{vbos~wi2o+o%G(%-{$^4i`X?sJ?;6O)syowNI##INV3fJj>8ob1SX zJeeH0?5|abw(!cb47mrWC2qQT`!7gKijsVTT$CqnDt#3jN5b=tlW<~5V-brb<xk<5jPGi-j=kgeFU%UfI-%UKn2yV`(UO@lm}n zX>eg5D?ss%LA(#_H9Q1kn&a0i1 zX5^&$e$wx_^^NV4_ei$T%l53VtjHT`I*g`Nyj{-z@)AKDCrQfSVMWAXU=C#0cC~D$ zu$d@D#EI2(RS>JH>-i%t>rty=JazIhH>m2C<^RlV|AstYA@QXWU)g}yop8Z(cT~yC zFU1GFyuEnt4)(cm4-ME?d^EeTu=uE1IJ<200Yqx$CEIfQP{M|Yg1cm+w@M814IHvh zFro;4d3ZgcL!-AAmJmT=$yL%ih#@rKfJh}YAS!|?We0UL$-V-?U6ZU&r0kMs%AP7^ zXB|`HmNDa=OuJXb7w^ch3dxyEF=EGfp>5uP|90|Me6-Gz&tI^0b(c&G^%8AqO;O!Y zmyM!3QrN3}*)g%4x9Md~t1Kv6TuEP3heAH1L2z{C^D>qOf3I3c+Qr-BY_D@acM~lS z)!Qu5yiwHPg%{D3hqwz_^aL@`Bp+mDWIcnXlc(bCUORAN@eriK{#<2&(ccW!4Lv1V z9+h3TUv9$`|L!XsSp0jSaAEQ9afK-r0}fzmoq>cHN=TyW4KA4&Z!>?bSc*$w+Oqd# z_qy$S%YLx(-?>|`=sFyK@V8}QaaTVE&pjZCOq4`gl1R~+_U6s# z165myx;i!FYy0N1?<~(h1xFvSL_kxhT7xUau!PImHp??fHoO?YkQSLB7sqGfd0Bo- zz{wKrYtnWoL#~t|M#?~479Wher?M{-uZ)4G5l_u7%Us5GXG6;&TO=8_+A#jD{@XNX z*H;C_$7%{&u#M}$H^9`=WDq_SW?dOf^o9r>h>YMlESWT^{PFeoZ@fW|bom2*6Q#F|K z4G%TV6IULcW&I|jP7iEH1b130S@+V!;$-w@vfdRMAIH~sK`_Z&m9Y1+_G79k2wKv#bBx}VfGkWellBXc+aw~JL(*~SI za)ajK%~V`X^}Vhqr73J+`yoAN8jw16#IzC15!GLm z*R-0#pj(cb=comaI@nRO9d&`D7CLIKqt0>E>5jU{QO7vy1V;@xYMP^FI%;P}O>xu? zj+*MI8IGFlsOgq!wcnJg;eB~J$4v7jRTfnJmi<=^t%b7iOQ)?U=mRQdmZ|CdN$ z6gBx6Xbmb0#=r)MORg-)gV&)$!^(nn;A>P_uoS8ww{c~`W(cHI7Oa3nFs4am!B$8= zt+JpTjzZq)!~q>rD+_J|t!ZV!bl3%%&4?G`{FMcBU=L&mDhnP0U-Qa>1yBitTaYJ6 zX-WD}1-WUY1?jCw3ywlwYtn)aZAc5Wbkc%dklD7fU^P@h)*0yGAPhc}Jit*HmVqAP z+7TCQhCqALfO0qrd1sLZL|5&XS_gHGI;6^t4aV}ATbkY4?6zjNH@l6rT%OE%l#|-LH~9BkpFsrnSZ5!mA~A7ga1bVP5#yXoBg-=Z}s2i zzukX_|4#oJ|6TsO{cHW}{P+0p_21`T@4w&wfd4`NL;i>TkN6+;Kjwej|AhZZ|I_|w z{2Tq7{LlGc^uOxg?%(0x>96p=?ceSH!2hxT6aRky*Zu?kZ~Wi-fASyp|Li~F|JBc@ z1CFU<`Z42}c`W8w?6C&Nl8-e!*63K{W6@<3eQ(wyvN6L8%<5fTQ?Kiqz75VWHRBy! zGwK+c`Kqp&d4?9VUDsmT8Cq;Ce4w;CRk~JZzoEr_t7~!0A)cm&=3#X8JgaN*tqd)G zilNnQ4PP0Wx7gIYujpF6Wu{h-yF&@rm|DV8r6uwxO5#*FtTZ2QQ~1gat^PEn)vqzM zq@dE0)+?<+p`kSxX=uqe!DOX1yu#2L&R1Had4|>~-_RN_hkxi=%EyM5Ql_*f+YGIV z$Iwpu2&Nj^>3iWqT}v%7wA6npt?2?oYdX%*n#Cxs8Fy2fJ)>*>a<~D$)V07TFjHxP zJ*b(6*1RD!f?Eu&MFHFlGr=^qmfT@(`5e4uXlaW~Ep0I*DXrCmy4H%V|JH2`rJW8R zXi9B?J9MSr4!6NNT^V=6y}B~*f{D6{$%C&A6&nXLl&bSA_;eMQ2)8KZS))|^op2Xy z(p24!y7E4(sd}-dN_bXNi5sDnseCOBRsRJ;C4H`|29Ihg`4M6*~nwjeKt96ySS659xG*q+Jrt;sct3Vr5HLq`|7MiYFw$WAERQN=xR-Y@? zdLIl>s!bnLrFVyTrP6Z@)pnzy&hVJ(%=Wsi@}XbC}xbk)B;{HavVEr!bZ*-!%x!%C$FUaHifO)v{K>S}OzL!I-y zriOg2tDy(rFI^2Y3^i<-Qs<5`)Omg3ZKckC3l3{4_d87u|4XS6$8JkNQO_leVQWN*U?Mh9$6@D|+gXrK{=7bT#99 zOas<;D)>QDGye%=l$uqdtJ&AUE~VzY2g8)Qd`V~Vh zeM+fi8=zEI*Q_^Gak{QbropAUD($V*wG9llJPCZJTJcX^1;2;AN?rFU9Mo0l3|(E{ z3fk(bY&!JN)yhm=t?CYM=&Jk%L*1|%%HcevZp?+dHFeWn@U*5@Z-Akux_KN7H`Of# zO5N($)vf0$b=y$*)KItYfoC*z$5YT;S9dmp1BP1jqOR_GL05N|YijL!O|83MQ}-+~ z)V){1hq}5iQK|Jq40V5;t{%uT)q_I~_0Z!=J^Zer9vN$>M{ic@vGa8G_|=Ab;$vMs z`ID|T{HUv^R_N;KVTO91xxthI;N9Lv4N z80w{DQ@wnhQmb-Yiw^F;_hd*`ozB1JN zuPe2?tEoQd0=H`F!&~4Yr9K)77c2GgD7ZwaPe#M}O6?gAUQ>NK%v7I^hu;mg_YXK` zsC|DzKU3G1!)&FiYfUOg*Y*1$QP+(IaEsE-yJ3^2$83gWL}P%+!5N;c8v4e?9Eg^`sa> zPx{c%8+-t*O+EQ$U2k{`v@!KY=}_O$8z+ON>nSx#Pidv=P14{KrJwdO3{d*%Ip9%x zYCXs?^rrn`qoFr@7J|C&4?#Uc4|pL<*PHi*WxC#C0er9NEe}FVT~Et^LQ`*51VaqH zb-u2*j??uvb>MNOr*DN(y54rFskgn&(A#=U{fw5-Uf0iT2TJJ~8q_uQcJZ)T*V{h_ z38sElL)fD09iE3QQ}5Ul-Zk{I--EG+-f0Z1R(j{{T7Y5dJ#`pr=vf7(p0z^Pdo71|HNE#caGlco%rx~rR~vfv z61dXP`!0l*hTbm?4jOv@YIs`LbDo01hCbjN7;NeT&w*DAebCELs_TQVfc1uc&g1Z* zt`GSD5|utQ0Y29CVIM(nrJtK<>gTQ2_49nDetr{pUDI>lfC{A#-w7`m`iK`{tFDjS zrRk&IgG+UN^b9zt>lY*#`UU6d`i0MF`h~*`eauTRUf0LoXy{|d>H4_EhCc3GLmz(u z%-8h^E8#;;zvv@4qUjg^0-x*pCHtV4((~%TkGekb2lz?XCmn*rx<2_@L!bPPp-*`q zzA*Is&mq~=r#66MU7yw)#u6ov;Zo|<30cY!m(F;~6!`!4BF@D2{Z3PFE zQRg1RhOQ0!b$`|kuW1wksX6(mMuA6lRnPyy^X?ot%&G`3q zv+hd6^oC%Z5kp)t#1%taG5P@&V|)c~8ZqW;a9G8}{0LtfF|j-Km^#}b$Bc>V59b*% zo`>`pPY)v|zAL<{#ngQX!bXg@3MQ(UdU^1w5tFbDTJum@L-}Lj8(HC4!S`H zqmI@X9@guqau{RQ(FZ{%vyKr5yYxEdd$3!t6Z1YiuE%NR@URi5*1{JmPJaWwRB^_K zP)W=m!IN5C%sp_qii-`xEF-SYn_66*3L`FV6I^1(dGcYh5f?uke$wLVRzo`@&f6It z)8gu_h7EdL!rSne5tq0Dp3vibZ^9!+T>U3tg%Ouj1W)R54c>xBjkx3|;gE`Jcm#q* zT%-BW(eP+2)wQ!xFEtpcG>@8r+RgCj3p9`30`)50V_dCyj8&*3Ob=V}9&;>eW95md zr+H#dQ=ZsHnkP0@dFnLLJazoa!=A7wuBGyLnrj|Un)1ZA&^+<2l&5Z*=Be9SdAzMO zkGGBT)N7-8>ZL1BLb~QjXsbMl8JZ{Y4CV24)I7d3m8X7J%~L-^d6Kd;Pf|POY0y{m zG-$6p$^A7?@>$B$Fh}z=?4Uf2256o}9hIl?K+V(mY~@KAqpRRdY2b8BxGtJYcx$>m@ zHBb6$nx}0C*b3V<&lzXK%dkW9oY@IpfzLEgMi=-7KGi(!y1|>USM#*bgrDIN-E&rV z&2v^c>Vt--Ll4cP>9$kzWVVBCaHbKj)m8B-4(6(OeLDQ4;*E48-aH*H z(Bor9!*_aoY#6>*@pTTu6g@s}G7M7jo;TqqBR>8I_|Ay0n`_2<&xbrSzTRm@d_oiW z#E4J)48Aquec!+@D!%^D(9Eby|E#O6BNx|0K(DKx26<*(V*>oD>YCreX-3_c#?aRA zYBy;9&^-ln>@UJKou zkZO7p&eFY!opi6Sv+k|mMfWBZ>D~rQb#HQ+?rnG@%Z8hDZ{up+oAN8mh_ejuX}t{Z z=~o!u)Y}bj(>n}rv-=FM|9-<8c;4_f-(q-M>@>VBUpKsIy9}DT>1|!l^tL(8^roL~ zdfPTPy=Poxde5w5dNbyj-gcLp-u81%?^#!x-VRrp-i}L5@7Y(I-cHx*-p=1CZx=4@ zx`vgvTOY%l`IO=9o?+C}GR=D0EWI8hWj*z(s;94ohm3m0T6j#aXO=@}vtCRb^fMC} zR}-|6MuHjvlU0JA2X`3>#u|v#6HJyuW_u$crW5Q}39(`8TBPa;Ehnjjv}@sPJ)u=E zC{hWn2g5x^LYoKROe0b2VI-=quvsPQPs4*M(Rct-40)izr`V#they7gJaB z#l~yCIv&jzcaG-s#A&|xI-0L;tmgBctNH4ksreFOG+*K{&F7n?`Rbpc`I3fez6KLC zU-C@N*YHZs$185W#zQn;N?Xm>q(JkXHdynWzEJa}j@Numuho3bF4KJe#+olMPxCcz zs`*+h(0nahYQD6qHD9aNny+=K=4(?=^QAY^d~KU(zB5ua-8ts=_Sbyfax`D&0L|BZpyul_Nb~hPkL{Qd zny=SL&DVRB=Ib+B^JQP4`TAa{`TC8~eEr92zMOHIZ@@*GZ{S4DH)xXP8$4O_os+Nm zhD_CbL#JuJVbe9=xid81d6#Ow^Ji=EYraczHDBH(ns4Iens3s4%{O_m=9_Yj z=F1OizNtRVH|;FVH+{I~n~|saE}g6SF1teW6)e$wGmACftm`!2?E0E-PG`+``4r7J zH%ar&YoPfG8yoet2aWpb5xu@X%B*iZs@FH$ne}51Y4u~nNh#q#d`gOaYmAMKuc01%_O}-OES6{N#+PMDds{mDfR+0sm^FKDQ=NU z@?4>k;uol-x{FnkcZo`>ca=&?Sg4W`uT)9Cx<*p{GtH!=3^S?0y+)GtuE&Y{bAPZm z_dA5yJF0^1hOTde$t=En~A`pq>^x05+;tvCqIiRO{HU zVWQC{_I#LTq{mK&GmN&esc?~TM(h9>qMsRi4xFoJ#14gZM!VR)X8YJ)Fu^!0wjVsE zI>bH-`;3mUJK#0_?ARS}iP0%`5L|3@jvWYLqf6`%vuo@)xZLO#I~V2{nX$9sOuc)Z zK2WLki2DS*s;8$BJgljNAK;u3@+FE)SC-0>DdVnKu@D@Vi(9V`uTdp z*INJB{gA8Y)E@&Q^Z`j@VXZbW_6~SJ8x;GkHaOO!pA);v7!o_l92z^#9LC!dyvdTg zzn~PBLl9QNO>isR32Wg#cn}_iC*c{`1Y6)0cn#i$kKq7R!9n-|eukrP3~Im_zP}(A z>OvwkfW~kdG=&z>3euq+bbwCK1-e5o$c7v^2hN9)Z~=^iiyOulEgcLX(nn80&gEr6>+CfL?0-2BnePIxs1H&K}M#Ffx2qr>4 zOosxv9Ik+cun3kyDTH7pl*4Mc74C#}@BlmvkHS;%0_=nj;ZxWLmGCu$;b({)Nx7f_ zGyy-H0o`CE#n*?0|P*7kmhx!soCbs^AECM$;ytEu0NKpbzwg92f+{U^I+_JeUCsp#-jjRd6HR z47bBtco;Uq^RNwe!rSmM?1w7&1&+aApf1>7PzUNleegpIXagM}3(kd6Fd62-5?BV; zLK)l$cfcd?ENp|fU=Mr_-#|6|2r(D#FGz+AXb&BsEA)VK;S!hu%ivlF!HsYaJP6Og zHrN3b@D{ued*Dm>2ONZ-;5X35&_19ZB*W>@9NIuT=mg!N4-9~zFdQy~i(oR$fZ0$4 zSHUt^4rOo?+zxBues~m~f{pM3Y=w{EAn0T1bI=|-K^F9Zfp89-3m3vvxB|-HA$SMA zf}@~~qaTA0QlJg=g26Bn3ZMkm!wxtA#&~1^UT6yKp(AvL9?%Q=!UR|f>)|)|1I3^u@KcmsCBmv9jN0^h~^3sT`M7yv_H7@Q9y;bNE!^I$$Kgk`V_?tvHJ z6?hYN!zZvG4uNqAa)fwDhUSn7gW){55H5yGVLn^~E8zyX1#XA?;X!x=o`;uVH|&Ei z;cNIAym|Wz&V)WN6sExvSObs14u63;i8_Y5a5}Vy-q0V0!5Fv!WbR>941FFXf3;RE;#D&Yq>3bB)kAL>I2G>6u37IcQL&>gZM8-~Mp$cLq{3T}ei zU@bfcufoUh9sCaUrtB|Bg2v#77SIOTLr>@fgJ2ls!dRFK#c(6s3hUrLcnBVYCt(vj z4==&%@DA*QKSAYFHb{Y{&99f@dmy4Vptb zbcOEF3kJea$c3>m38ujumyAG1mSwP4eo+RU=zFwpTKwU7Z@|>`%oWRLI>ysna~^h!%&z2 zGvNwY3M=6zxCL&9HLwmg!HcjHK86EO1qa~}9EKzC8<>|e?n5#(fdI6E3}_D>p*swO zTo?@(K>=J2^PvRR!xnfQK7fzmQ`iTU@GTsKqfqBE+9I@oHqZ@*LN1JhiEtUrhDERr zUWHHKD4brv+6MZ=D3}6sU%@Q3p^L5+Mm1 z!s*Zg+Cx|92j{~`xB$k%M97C3FbfLdDp(4oPzE=`8h8+%gKh8z?1GQsQ`iRwA#OJ7 zcxV7A&=gw1nUDqJVK!V1*TZe_AUp*x!<(=dzJ(+3Cunns7aBlANP#oqY{-TYFb2lM z#V`q`!VD;Y%V8m01FK*)+z#tu18j#%_yK-`8Za-Xok1#`4SgX82Ek~!2qwcUSPa)d zDFk5^+zIR8es~z3fQ|4RY=igUefSir;TY6F>|FXWB*SUY20FoD7!R|d5Ej59SPIv} z4X_>_fhXZ9*a*+T3$P8|f?e@E|-5&%t)s32(z*_!j zz=sfqpP|kb^bH6=24ulV7z5+r5|{=BPy|=O3U~}Yfhsrzhv7Fc77!mageK4oIzWHO zgBh?8mcVkj8P>ph*a%zT4fqTWz_;)n9D<+V2>b@-Le>J{h5B$hw1&3O0lGmJ42E;z z0vHc@Fd6b;2F!!2p%|`(5Znk4!87m*?0~o69oPjQ!Ct6@ui+aA!$J5NeuL=!#z2%o z^i_^o^k2#!zW~U4{PL@edKOsp6}Giy|4P6%h`qeEDL}~LVzB>qN9pC%7x(v$t3f?K zO8;h*{;eoIuPQ`-6C*l}XZ~t`@7HRz`=az8Md`1J(tjMK|13%`52d?5IS$VKWx5(v zkrkr0eu$yQl^r6me&X;HI@^b)t&P&Z9;IIrr9blw*SDr!6lI?tW#1=C-z&<`fZCwi zpeVgR%71EAObhyF}?bM(NY$ms|)7c~PmgYl+$_N}nC2?-Ql( zFE2MazW{3QD1Ba(zB~E}@EGX^P+JjB)C)j7VhAUyo1fn};X=$3MASy2;V1eIwpRNJ zz1#l9UVg5hM8}WVU*zO@tK%+C+oJSwj$ct;#eTozR)P90w8Z{>RNi*C;(rsBQ|T=I zQAd@qkDwPf(QiQA<>>2(h4WjF-46I1)`6R+-_W~$+eocszY}F&9%a8YN`Fn1zL;{|=ajAa zmwd1QB;Gqvw>bJJ5o!l&YSZ<(89+T0Wq(?f{Wnqeo{ww8o<`-l-kL<&fAmqU{hlcO zfhfHZ<^QWF`~6Y+ZBhDlQ8M|XC@OwVC2{lcVw67JwM5+$mH#N~le7WH#-0CH6K)=M zZr_x7T-@eiF$;Tl{&weWcdmBlX?Ko3---84M|J1r_Z+i32fOpHJKuinxVv+!JFmKP zsylzm8)IJbwbm)8J3qQ}qdPCUbD}#Ry7Qkq_qp?)jP3Gs$98vI&$etet&gM1biz9T zMngw+#~+%aRVOm$h*!6dyJL+zwzz#<#u4#%;uzwNAMSYJjt^hp|C*TEabY(DXh+Kb zIcgm0m#Fcmm5y40`ZB_D$AOP9OTD^dUJ)Il0siONs&TocDr2^#_A{j4$u~6?II8qX zF|Tk`$+ws{JL=1h`WJ0h?2kIC^#6XCf49`<4R^fwCCXjo@U#>DXUG0KNBz+XM?baH z=M8r(sdn7IMWy`4HpJ3j1j#sha;m>R?BCgd+4bq4AbRJpjAY}wDyCRu8MHVakyz)VM-7++H(Z;j`n z=A&MMdKv0;$NnPJnV6%;9D+xF^Ep4D1a5>i@CdvJZ^Fm$4IBo&J4Y-+GiVR}U>wYX zQdkQwz-#acR6`A<^f*w^2?oG$m;s9+2zS8a@CxjLz3?6U3CTSV6tsa(&>t>@X>bLE z;68W`-h;2)1mOwEP8u*^@5KpX`p)ms6(njbHKF7td0(WbX&_AJ5q4KpK0gn0Gnm zt(aF}Ua-w}U)PF#E6f|W+UBjT+3&!7=oQ;s*@nFj%o&b3(3U+0%u^n>-Sf`io($&n zRL4K&$1oQ>?6{xFUIgZVykjVczT5$y(lO=a^ge zW30q1af{uVm{I;qzjFw)=sLUoj&j1^gqogc*XKIN?i19m2nZ?t#8`d%Ep}@o?S07!OYz|2F>zGOx{@-ELg-LBdY?zft~k3T6}*p1J}= z{wp{H&6U5*Un!1xsUzH{(t-z<=-)f@nkQ@)Ho4#$NW0|$Ib5` z%z2ny_X{v@e7@G4hk4F`TL1GgPml5+#O&);>)*|{s|H342%O!%Q~M5q{;dcXo#kX9p%N42;a5JU72EFl^$ad4azD0&ZAQvpQE6jJl9>7~pl- zcs*wxjOTm=crjF2P=fmb^b;m*hD=DY>sICKGV!yJg#pBR1uapgfdtb-jOW0;J$GQQr5tnLLFSEX#H za&zq;cl@5pEXTe|*iHCx{N(BalC9O08k?>{*kG=FZKZRcN`k4YX_5J7CT9=UZ#h!0fpJ3D!P7 zz|UR+T$w+2w%E^{JvTovdHTe;6DQL}=LIGf1`4O=2PWlDn=xw^i3Vm*wJhu`v_CO_ zQ;P};{-4j|w23oj%_|H{EGYOl+0*9bPn`QdEx?ghoJeKv?4oJY1GZ!W+_Jw+B+;|t7~NAyLrrqou$yrN0zbMxmEWH{N#AeAE8L5GaM)PjlA=82}Zq5S(+Gb{fJ zyF6C@oP0=wa7sCQQX#VET8Cjr(w#V2$}AoV@~0NgoK3ByBLHilvP@UZD4ZUcXvH=+ ze?BcNKQL#a%m%aCQm$F;W@A?{an2m8sZF+<@#Oq@Qm>9b1mmVoq9o-+CW+_Iq|sX$ zsTIj_O%(Y|O{Yqb^#7+tWQ*WrAt9ex|Dz2kJ<@_Q0<(%{PLgSVYJgOYGL=hPY(*)Jr79B{L^Z$!}{n`I8!)72CgTbhL~Ayun$~MKwCB-AcQ*TlwEL zG-+S6{)Zdb|EooKLPMM&MoI+7j}L*_ryNI4 zZv2cCRx&dfjv{&Zw`q&-iG{Q0+UYw(eQ*d>ePPk85Hp%7SGmv$ve;5j&95g{TQ;^O35ADS9NbaV-E%ZZ;>rFTJ_8+wm|lk(%l?G zwxZWbqPAO>Gq+xVF@SCqMnXgAqc2LwguPL6_qjW4QnKW(H86cy+55jspv~iB<~^gA zl~#7gY{nQzAJw1eG)p40)18&d3DaC(-wls?CBAyC*C5904JtWt0k8EB;7xVmc(}QHW6)qGBA28i{6xriXrI>+Vy|<>(+NF(*3) zU+12&H;c&%90XwpTjZ2r>bLLQjv>lkHZ{a-+qrvp)bHKp`6hv{V3U9gguNBdnecxn zJ2e~l9;p{uA?xHy_kzUfY~8!#%=)ugaZQ}Zd5iI%wJ{#U6cSp`{N z|Mp4|Bl^Ej>A|CSPlnUcNjq`zi)Y9WBfyWAw33@f!evO(V>VXn;hT$H zJ3LalLu=Z;uSm1W6z{t25sUPfyyrbJtm0cV8gA>bSU{ zwe?I4GAHilgY~EHxM0V2iMCz_@EGgq&Wv9(QYcY9Z|fQ7vfIXBw*Hiz=j}Lad^*L$ zx0hD0&@zydww{eq-i|$z1$t!jwv)}`vhLXcZ4pkK4H8l5$xK#oMx0sVIvXDywM3BN=~TIV!!xvwauq*0!xDoxbOct$VQ6g<1LDoqNw^ zA)=p`@U7o^ptW^R{dNuj(vfRwu0M0f-cxsFtXicbspDstXx?e`&gEE7BB7_1Sa3Tk z_>-IT!o$RIu=zic47O7z(*m=E@Ho4p^3wX77Od}N3@c?lejF?5%oq=OQ#%vCaf3!X z78Sp2vpD8>6xEMO+Ef4LBOUP!b>*1iGBe$*Q*R+M#lJTjsY*As=gmro1JenM=2#=v zqk2JaK9L#uV+~?$4!q6D$1w|y^I~+zE5yJ5;UwayLerl8Pll)yW{Q{A%#3*(rTRAK z9wML4+WwC#U5sr0S+=^KQ4X=>GO|QU_a9fXTE=tu^ri)zF-kpVOCHB_l(3aR{wG6T z|Ae(yYcv9QN(Rz<1k@lXjiCL+^2>#}>q-z%T-N8#|(A=hN(@a@TC940Ft& zR|h|S1;y+yzC{3L$IwgN+Ydw5j7|Ja9+|bOqgugPJI>#WHBP+-!>pZXy*WE~luDZK za*U^2^BFt0opRDioA+$qzOQ|5+q~^(oS`;v#yLlf6?W|2eDZFLyf^PW>*QTZ7*Ctq z)~LOhG` zkhTQRQasBP`C8@CicziBYV4qE05?2qg$D>lJa2E+;S<7b zN4V_>w|xPu_y-C8gJ+2%*D|$0Enwy_q6?5Q3lRJQWC+|YKnQrW0<}%SGx!Cs7JvzE zmZ$~bT!w>|3*iiYF9bIptw3#43)|Jg1^6R9FoO|%i`BvvnAkP0s{#`6}zQsX)FHnXa(v*wM;F8lVz>=%cB*j zZ7QTfow4DFR{JB}NsYy$J-t99J(1AhU}~T<5>Kd5Z)Cj+Me!e0p?>^BL%mSLy^(=v zSO^wPj1F|h`r!f|Qb{Hwap>>}>QFDjq}mxtM#CBC5P2}{f29u#=G&a~Bix1E< z*ujfPoUR5sqdlou3S>lPFdPMMPdpM?JCI7ydOQVz$Fyfzc3#pnzZdVpQ58ar7-eQMuu< zjL#QL1j`0Cv@z@A*F%gb}LKUUl7435H9~<%5#iVQ7aHuC9VwD(55g)LT1yoQJPfPONG~47 zBOShAI;x$K!5-KQ_DG-+lwfDH3q>z#KXOB3vB6|K)-O2X0gizv@-U8k>WmI{A%X}F z*8QPDB79m=lp+S^HL^sN8W2oQy z8CK!hDjZrn0A-L*s0(!zH45pB4kBfilo;*rXDdvQ5*rku<6+?#M8Y6akJ3j`flehJ z6-E4w$D^U1NIa5E#TiTjB_^tAxx`W5V`!1crf{bUBVzhN*9eULooGu$Yt!md(b~0Y zv}Iz_+~`T@2z`fWnz&F5i$q;4s`gWRCeG2R!2vows^S=Z8gX%pUW~Z7MPEi-+@ePV zuERu+MO@sX-y$w<(R&dWx9A*zqaO%&t8g#MAVdu%0a4o%NsRPH2AMD2v3`iU@zjCP z&`>rNZ7UKtS)2AD8BO*_j-o;=rFl{NAV%V`wWu~>lvy+$W+C+9zm^Y57d1AG=`O*u zh;~N%qsh^!?FwMnw`GIoP*0 zj_QrRAYs@uj8;s8DFGR?HX`x!nhB`7Uxf%5N)3jSDd`>QXKFCo9gTFQW6we1M0AlU z3G}IF)~-g(zCl6~-x&VKo>D!v8taOLkmJ_Wt;MD__QKK%IZGQrZJ}tj=Ar&jIMT~zE`e%a;}H(lJf1|V zvo8j5E+Ij#_n<_jcOZ*&ibfxbqHJP8-n1(*`pl98XE}NTWCWnN{&9k_o$Cbtw!nyHHekFsh74 z6TLu2-MFSXX2Sg`0%U5T7_C zb`nM1h1!Td6Z$aX0c9}M!)`T=vI=LJ^r)o^JW)8Y?Kh3Fv^_Em87(W5%)HVg(JoXQ zjN{-cHV_?*87&#@M-}UerO;pN@u$Z15KrUlQn4fwyH0f_P_?@7Poa?^o$ygbR3wBy z+FAkwj*(~=Mmv$7(IHWiAoWJkCH3@=vZsg)#88XTTvTKb|1clQF%*lQmmEdlLX+xsa`wW9FPY$53&$JZATWVZqEfm6ezK#N9EGaHW(5|M$moVayIC&->D!aBN(5v zHTA?GQH(h=^qxp;Ad+Nt=?x8`KwyrG(!JcS|Q4q?nr#}@@ zJsiAKA%UYEtzssKITEZ%f+5_WN+7Sb9JfTBogPnr6myxLxN(PBHVjZv4~=XWBg@4i zx^}=MtYV=(N%gT;jH;egACj1g52V(j<^f6JzF%*<>Rq6EF>_&;4DXq(x>HT}(ZqCC zdzj%As%0P85Q+`w7HO1gNO8jL}Y;E!1vmB@(EOc#wfgJ9x~)&#?PK3Wv^Vqped)i7#P z3d00+Zm}NV2$vSAafB=*>TGW`4(W}-UoY|?zBZ|PG1=}N#UFKHP+=Yy?F#cjU5^f; z5>bMPA~gdw36LRG&^cgmhVDH!h#3PL1Q&{;UGj7i!JG_T8JfHv3xSd(nZp~=#ciV)H8gdE2P7gEKx})nM6J*6Gipqd-BziOme}oN%10bVk zw#Mk-00T~F#Uu|>KGfSE8jgxh1~HBXhS~*w8SruLC^!xUlBqku8K+qpkk(qd3kLm*}I<~M@Ls$nxeHV%u zoSAM9126~@W03mUmsEYjYHbMrZah(>2pU#i(85U^M7)QrZp9AC!?9?Xp#bkp4N~h_ zFRq~3c@3$U(bFG@Ajns&Hi)kpVJ28&Ebi4$OB(8p4RV^p+vga!qy7&u}{aEgtQOuytm$rM(kd@e{EI z7i=QSZJvOl1IPH&&X`bc08*{)?EPpfeb3&zM2NIx^N+FbKu+ z5On@euc7U?lM3A+Cx z)*V3`Cz2jh^hXo$6h)0stggql z7)7A6vvv-kyhNc;q=5sYQJrWR#z8>#!Xk-2(F{k$l(q6~M4>GJa$9>VpcCRM+hitE zC>_Yffe8MHik?0WL?Vb=B$A9^(lLt8J_AQ39%r;I7;TdtA={{M#DYm$B8puIYt9^a z4@A)#2cmWc3k>NX0UF8$7)=SR^~p-M5<>(lg@Y074`e3NBpgd0Z^?tS!b{H=FUuw% zvM_AW6S@KeC&YHiDa+$zB;2bPGD&7+y-1ED=opRnC^KRie)X$?{!wHLDp#zFOG9x} zgR_k&ZDXzd@r+4GUG2iKjH2~>Ua*>?u41ss+KaMRdVyC|jJ!<)9~cb{qHZdqi+D`q zM&1pKLO2hq!PyFO7i$`LV3rJ35CSr+P^kNMm3uHU!nO_bND>R#7@|;GYSLOYxHiTI zO25KzYcQr4-=T968|JJ&5NpWZs3krB1r?sg2CYy8nivYPpOc10qgkB6NDlEuw~l@Q z(uAEnOmPg?DOC_>q$Gj=fWpjSFopkG^x#I~X-$t-fy)@h=+Y@0d^jX&MDIE{tOiFz z3d310%EYitg0fQ>{S83jnk_0A+gyx8I4B7f!`@tUEqMB|0fD6*4ksW!fMJluDKF7P zECr##Z76NV!p&M?(sDbdWnzp~Qz5yrA^anQnd2o{-r+u=831DCAlAd-71`ra#yP$g zj^o78AVra+K>i>VR3%Y*Lr@cry*?rQ<0dLX%NVvAvmR!O!Bk$2+f`~ElujCBVJn$% z=>pO$S;-}*X)nU)Eo3VUtdO%RHjF=-Txe8u%p_ANfFU(BTX9WL;-2oDu&$jL9fXbE zkQv3M=Xz@z>BWeZwJ$;n_UX{C4t3$*jVG$Gj)P58REHi>z(_rsNXEcvkS@p-7%*TO z>K%l~y)kS7N*|Olwjz1_IO}Lq#(*cok^`b4_>SbFjX(^e<_-175z83jI{2 zdh(o2wBrb@P9-yj>qGD~j(;SRhV@8@4N$pGm7WDg)h96~Hoz`0PaRkK{a zE))tYC{ZZgcrb`uCoOwjN^!YJFEV(TSjCkY&Z>B%N75oQ4q2Tbg)`_xZ&Y^C;uu}V zBYm80#v`Z(SRz6>VVt1HRiawiB8Fs)V<>H{@$`TzgTZE02FV+6#rqf<@ zz!1Z~JJ}_30-#J0lmu2vxf7f~oTTN6ni0K>&VW|z7_vH9_&$WyS7fwGtivC9wl0N= zsWA0rML`5p$T{rZilQfQH0qUqG^b31ono+=;n714#MGkni9$zI3^lah6!0=L=VGBZ z>qLZ7Llk%E0Uih@1Wvj+f)c;S(XbnYcOYf3(vzddj+q>pA~S;?=K{M~y9t9f4olvkMZL|?otE5U| zO#~AH>YbusF*rmd0i_oY7MiJ|pB$h*9L2B``ubF8un)zbiQB;sX18(B*CKTEx^#~D zK{7ND?Walwvx6jqkMyFYb*3;fNTaf7m5k5{lpboRHdK(J{>&Uma)l__%}Dh0L+M3k zQNd^m8Ul}^S49hgj_@!PM2^6L-H|ojVtTx%h>FZhqN~S)`eV)?WEwyfIb=9QfN6W8 z<7^El4;~=5WF89f!BG|W1eL~PaXQ16@_4hCqj3!OQYwX+nJ66Vq_7nsiY$AkWVI@V zazhMlE;Djpnf0$qtju_F|WfPa9rc8*>f5i8k(AqZwbzwH@~$F$5(eH@%|6f`uPdDgD88ye2py=U*a=j}WHf_L>_c+tg|?C%#i z(0}P=m-k=MeEqHP>nzsE0hvLv;Ap^ai9#=&NsvBqx+s7rDFn7IBeS1a&!iB`%hC5O%=+WW#@oI#un2`80L9IzyeQ&QiP7+2B7% z?N)ohzgL~B&V&6vb-tJ{Q14O~!hDgK+ttPD615-Z1L{(B8Dey~xUwp9x>4OE=ELe{b&Gnpx)pr4soT{Z>Q3awUFvT29LIavP}GOj5%q}SJ!13^sYlggz#lhex_&}EnPJNG zkNAi2Jf)uYIG#}-Q6E(wgZbllJ^}ob#_m(<)9N$oS@oRyEL6JvoT$%>`gu`F{Q{ob z)ECtY>Px_0MEInBS$#!)ReeppgkQV*y3pFyH`F)Px8U2e>f4etx-NW2Y`?3%haCF8 z`WN*Bn13j>r(OL>{a9>&qJFAg7TPPG%b%%#RX+EZVE;_v%&rey{!j^^fW``Ta@#yZR6HpX&dp|EvD2{!9J0`iuIjdR_fZ zy`k_q0LO8n%ID-beka$-a{`X*{CC*aw zW0@>-mOCq)l}Mfby`)xU#89VSr)@QO);Jwb$mw*#j&6tawaZD@@rcun5MDH`l(s!i zFDMHne`|ofq@qqALRjncOE|<|QW~e7j_DUnd9c3f-)$y-?P|dASh|i~tx#W4gV1A$ zDbqjXtV4dpJ^qA~bm~;f8FofYKCO2~oej~Z!w=Q`&h_ib*c zb-LS!FsPpoR~LxOFROPs*}n^&?4QmBt-dI(E#)E!U zxe~nA-Bm(=Uh?~(Q?IUeext5&u5}JM*E!c`xFP=y&W(=kOK)-xJ2%7r7Cb%9yPaE| z+nn2-J79W5-RZoDTEW!XP_({4-6d`6ZfUE9&U>8qI%`bsuw35<*S8rrJB<4t=N?e+ zHC*lLKA76o`<)L6h3(;kQtNF; z^Bw2A&i9;GQC8n~{>Ax$^F!xH#^%S)PhkI3=Vj*==Vze(D@(ri`M=Jeo&R#ato|F1 z&ab~nO4gY4>A2T8QRlDDarlwvb=XCXz2;-jpnrb@{SC33=HMe;K2qt2^~H^i zvl?d4O1o^B4L$*Q4)%ryZ7eRHBSAM=Xl~Y6vxcUo;HOy-eB>?8YZhogPEbOa7zAo}bT3U2@`5L=DcRgU~MXaKIYg<|x z#lEqB08t7S!JP=8-ef64a4| zAFIVFA|52K2eFp8@snD-JCTGH51%p!v1!p&F9ic*wLC#}_0VdGqHr|Q@71f3MM1ic z4UY^b8PG6dH`Lf-qFz>8Tf06OTpowR)xn|Fjra$#$sipNI<vjAW?s$qPC>lR17|Z*M`Fz;OmLuazvT#8#g9f;GiWLPj>5g z`h1`!;6Y1wV$((>4?dZe6i>zziR4D%OC-Z+%57-X+MhLD^i9f^8q1iE#c2m%b=9zX zc?(mwS<*vgOOO!^OYZ0b+G=@4U(>TK(|po)6RvN^$+|eTnL!})35_kQq+rkv1Xddz z3~XvFx;T-R7GKKO88P`Ta3-$&!!2;|$Jdt2LjmQu#eLm44z0& zAmv(ES;8BFmTe=_+LDy&5^qVMc`|TFE5rgoel(6HJ{@UD0s=Y+1ckr=s7?ZmR5xmC zW1?FMNQ-aNsm#?TqZJqLY-$3#E(m&pSW6dyPJ*1K2MIzC(%c514iNKcfa2oQ!FR@) z&024!Rbk;-(CL0xb5PUIK8LWoqhrsWJwCi<>s-eBypE22)X%@b_pS?l7hO!;mwzGE zOVDq05cadByB8ghD(GIcU8iJSuq+cUwNm@Cg_ke9T=KytDttxw$}l_V`YXfjg@wrT zE3UYru<)wF!s8m}go_JZx4pQyCVWu*hqA-M)z|E}7CGX&hr(eu96nSN1|km&&J7=; zk>F+lDSp2=314?TO$5VRLsm`EYNk;Nfb9#?G^pDdFdZ-B1_od?G>Kx!8NSw>U})6* z8cfo(h3j5)1Ni}B>t1xD2Wbn<02UyJ5bK**2MDb!SHS5Q#c-P0$a9!&f#O zZmAEVnr`-ixHuSGEbR)(S!6oe<*2q&FRAnK?cIy=-^()3^PRHSx0kWfZOG@_WAZ^K zN-{{NA{cahH{T)&kW^x=nB|5>a(h!#c*h-U*iKh3zw@px=#7nQn!4C~X29yOWTo~E z>ITUqV9hRs#}T%M3Cu|8bra#2xG8z7wc>@831kqmx43h-RxVTw+JFd7J{YJoR-o|@44!r+j@a8@6psD{C z-+!_1T@U%@`F!ub@y3gN54$&Yq686!aYJqO;1V<6K)i~vM|jc2ex2m53@)He3@`nx z4wfBRe`$?-NZR&bN7zKi)JdemH!t{zu5v-C?K^f{%b}HqEv6lW7ohxg0&ih>=v1iz zmN2u3d}zlGVPIor6hSg$TjUgmRpezj(4nFp5YS|`hT?8nj&kGJ)($CQ!Wfip=rJn` z+p@T8d~^m~qg!Goh^%7kCNJ$-HHZVYBsYs+dQX;u0L-Urs;E|JEey7{wYC+uk_i%% zvn@O0Dg>FcG1|3?15$vuG7wD>G87QflRb$;owcIQnXIrFMJz4x9dgoHy%q;72s^sv zpjm1&nhQqE7{LdJ0H}1J6QFB}PZu0|0^mSu8FW{2F{mrQmB*;}0G;X5ab#iiixjw(Yrp8~BhmAzPuTo*-0J{-YPAv{7V1v=8D)C*uYL!=-SDBYrnX7Uu zQ3|TEy0+Gzo12%HTbY|zoaguF<<;ia*5;~Wc$4c_dF;mXD*eiJRc&=)ZLLzZm9@F9 zn_F2}s7iAu<>r=^tAc_8Ra%+r_xTYKl~d!Z!SYT`jhZxRQgLbNwCQEjCQm7zR5@*W zWn~5Szmed|NrnD$KcW)|dbu0bu)Tt#UxmA^Ar4m>g($3vZ8m z3lRD7CW?1{LzV=OI>Ess9Ca9L;S>iz4sv9i;=mip zpfbleIPH6DNDWT_BNo<=j&3;N#Esq=j+5UOoN}s$ot%Ra#vSi~ktZ0=Jd3dF?DUzA z3oqIyaPhuN_8-`H>AuTgx*X3HS6+2c+d#eA!#v~~1J@eLAp_SL^YwrmJnkEBI(*nO z2y*kyx7_mXeYftr%|NE@?YHmShjSix-F^3a1aRDA-@R`J_u0|nv2+{`$qWGa1AqrJ zXb% zK_tksBFOsU62R1{JoKa+PPu^!1L%wd&<_bz8>lfLqcA8|>`gZ?!$6$@nSZch7?AcM zif)j$$;~n_d-fawJ&M9S2W!*>F8R%!J8#~61AP0P0WKrp9fSZZku4Nhv}p0-B^Kml z*HQz^0LuX@2rE~vq~)sBt5>fv!2UV}=rmwE`z{R;wAk+Mo}Qjw0!|x7`!uXIV9)#v z00wbi$bufU3=OSY7Ze;4%wgcLre1WzSv%=UO-qfCg}W23#QU zE`bX#yeJDUz8FWr00#svz4WrnF1!5l%dfcNN`cbSs{{@nyjtLzYp%WaS}8{=6cyK{ zfuiF28w}XRhnox>HgL0nTL|w?!>za7e#aemLRc8MI~(5fUIXtla1TI4$$bEb3md5q zeBgtC($f3yzyE;;Kz#7QhXAFe4-<|YIRbGYtP}%}K3ZD(*kg}BPQnvUJSp&Dfv28& z8t}|BANj~f3F3mv$3FIP1D_y#@{^zZ6ahA$7AP(K3<2h64LoPyvuU75rJu_HnxFT8 zrqa^S8~B2OFB*7(0Q)Zqy!hgm4SdDGSHJqzuW5Km;OhpyVc?qvzD0mP-!||a1K-Vp z($eo`!1uF&u`Dh97Z0@g2L^ta4W&Oa@M8nVlDni^xl55tQETO_m9HEaTG47{D$jjp z%ha?~rAVbXr68pcr3j_?r0k^Jq{yVWq^P8vq==+wq-3OAq)40%pg@#0AFN4eStuJI zkcX6rS|(B!S~&_CfTmTm^vW6WNz3_bBry?jYuOUXfk3+@${dOtiW-U;D`IX1aCmY%;10l@0E!uk7!FJ*S}0bm zOfe$m{hTXOnn0F7m|&a%pfoX}gtFujEk_=G^fAEWfF}SHBorf00kj;UB+;_uV*rW} zBR)iaP;^jiP-IYCP*hMnP$WnAsNpo^6l*a#Zur_V>^B_s{nC_S&DF-)7%mkzP)^IIK-i zDV?6lRO`vv~;hb(={8RtOvS_Y-AzWw)T^PCu#*6V__2W`) z1NE{{h+_zhB0^UhqMpxSEMd$tp70!8d+0h3*T{)%Y#dEbSnHf#pm=|U>P_nKxZlmV&%z(?v}m2` zt#Y?T+uSDfn{m_SX54kTS?;>rjr%VAy$5$)vVZ#K%e}b$lD_|Pzj{FNev7`<@(9jr z^T+!vywUPF&I;S#lY)KN^OLt%cxy%9TlqNdtb7u`PvPNx75bv@tb7*tRz8R4dG&ex zz92cFOaF^X|6UONOE@L2e_zI}6@72ztLE;?*Ku>@>z+$}d*$2G8onbc@2q^^w2ps~ zR`3JdTq(q@71n;dD z&5o_Br1L(`Hr&PGZ@akP;qWF7@89UWI?dtj8-4$VlwFSfo$c_a@8P8Ll{a#DCug5? zzW8tf?%Q1GTx5Kkr!IE%4I1l$H)-_knJb;E@H;5KtDW=>nd@;&=6dG_&j;(0IohUf z#ElvLcw6R1@Z5|$GyL7+-I%#uZq3|j+~4Ks-`%(yL!aJ@8#3>8-iJFd+TVMfWB=|0 zPo^#J$b4{u-~Glf`e<81w*G*}@t~uB4~hP;a|C)ih4a)SS*Gz{r}~hT?xUhA#XB`m z0Dn@<9~PIk+@CW3u+%mD9@^8!B`N=^$%=Puc)vy)dCNx0{hCjEyr1zf;{@8XhV~q4 zFmK!Nj?EXGFFN{0%$H2)J;DX4mjSQhmgARE&;KB;^jEO?g|XFql=S-d6}bMY`0y+B zHRoyZldLZ}UpJw@29xe1z5!d>(4Ib~W3MS%{id=1Fz(JM^(_-i8{RzJt+CwSF?QDc zA!AO!ejlbx$R1ygH>G*KjWyX^Gd|=fMWcZn4}rDM2TQ+FTni@T zgl z30_GZ3IMCgSW&K#y}7E|>ROE$$~1|pkR*k`rdtNlYpb~K45-tZQS0kw%(Nh(xUOu~ zS>-s_wfl8Ow`N(V=32D|caCxHGM0#|#8^-w#+h0&3sE!9b=~=`^RXcA&ToTe0be`A=_q_3%>}0I-1+bTFIs4W zX4!z^6z>A=CPER7DAv^F0l^g`?c9aJ?Si6-3ygWuVlKTeS+qn};DOR44+yT9Xh&`+ zWELVVgy=3^wsh%ocj@w_OI>VOQh~wMyO=I?W4GLOmzf~V4kt7aSFGgj<|_QspmES) zYwX~3#j2H1K@>*%MZ{gb20H^C_@zPPpu41r9k|zYK!KGIak7Cv079LZPKNQD0K%Rf zPdj%Cd&sqnE^S@B4c9=oYcc9Vj*!&tcDpcjca!YGNYERzVvDtjBy0Z_TeVPViB12H#^lZX$14B)*4G1t|*yLu1A?C~aDH|YwV zN+j&j4YSQF+WL_ZSGGu?XX1tjB#Vt&g#6%kUGAr7IDyG`Wn0+nt#E%u!zPz|EFNr8 zo3{$L>vF#ZJ1%^L!hIJFJ0Rm+7uzoev;*$NVCNV=ZI;dBwBia1E6iK5rF_~MR8FHg z1L#tWXGnZ$bg`9_0cRPr>spL^JQ?6($4A_8&nFG8D>!UK-|e2my`VI>-oCZnzSjD= z=ZOw?hVEvb<=D5+HRkhO+0r)qNZ3jOFdBMKiTg?f_adzm;T{u#?#P*YiO6QrIA2%l z63J)uIeB>pY|nFPULMVtY4hcl?DJg;*H_RV4Y@oAg6>G3Jg(LPCxB-ACR$GdLCl4^ z$IFG5FDM4i1lvF7>!7aGRK&~%2A%?0_Ca@;0n%6IATn6t5rCbfr_3WQu|ut)yr+`%Bs zb@g^VckC<5aXJ-HCB8s;I%D)wRi!Wh^MEYcP|FwgSO8|nX_mE`&BCirtO~3k>E|xC z5Bgx+ko%0lN3^EZk9vlWK4UF3-$zjo@?F#Pv@X&Bw~}t5#2hP;J!N~g1iC9YII+#_zQE1q zG<@j=_XXK==DsuF%T(-n6Ro@U(1|{J;<~aIZTF+?*%Nq=z3Fd#+jV7!`kUV}XHm2U z>bG4XF~X#Q(dGU%A>&wz`#l&kj-t4BUt5l%{J?doXC6QK5&SX7PORn;eqw=v0)CnS zFIzM8S3LNc!N~2p|C#|mw`S6>Uk^`meL$-zZmp1FPS9@H=5N zMs0B2SAVaavwjK2x@#)ne)ci~`_XG%LdBRpL`mO8ho<{5^)z3(`DO6OG^R58XnZ9i zAxJaP9tvZ=bS}mP>BcXOR#oW+{B(8o(}H1Q^7PXPxZ34Wi7KHJgS||xXpa*+(sI4F zPcZ-k{w6kTrxJ%hNQ>15qQ*!|%POs!%!sZy0-FYK*k&u80;ud82xX$WF3v|#lsm^A z*W8?wcN|Df z2*xVBpNOZNl;SxjC8wMe=9kV4g|kZvmtLG8=X6TWJUR6W2bdHNbt=qT)Z)d1gM&&9 zVtS#%;f))+_&Ksjv*R@9_;D20=l3;Z5VB|yPBJOAWchN1e`BL+bQ%@stx7d>85H1P ztEak}iqn8SA8bmhM54P}`IE^ND?%Y0Xi~j6zNw%M&#vi9T z6^=P6%x4vjU&%MGSFUVoYRB{sM@*GkID*$-c66u?er96Zwyj%Nty1`}U(Xj=%Q+{7 zqnc{drV~%ZF(!qhnF`}-b@ItLXsU2f3hyh!F(;)?YM42bqc7e+5a1GnUp86&{>h|F z@#Fe|w)=lqo%#-=&UTUotp3=4_T>eRu>tM#@g<7KfsLFr8bvt(M)xvSpWFVeyG{&VX3Ia0ki7lV8Bfhc|Tw0zBF>;qewZ?ot$he4MHv z6f=SEgb4(yyaO@Sff{`s(W3~$8&82L)2Iff%PU^%>M6(?uuna!bhhx!DJ}IkH4Ca0 zz8lmJk=Y6(!fZ=hwU;hX{)I5lS+qD1Xvcd)A$i(0{P;$7HBz%8)m=A?k9uQ0RP(30dxqBch5XZ$9JtsJ z;I$K#pncg2@Z&9_TXw7^|H<0i4f81>|Eby>2<+T`8oomASErvGm~uLD?2IXAo`vpZ zmx=P(=R{ZeciZ?Yb@m>$SDQzaI@iDZynO*?UdfEo?dO*=121@2npvp}OW}I`MHlbI zOuNp1fJv^tR1$ufs8mjva)RKZ(qPM4lVNu`y+n7)yfjcEC1*`X>3C}gqLuH_@y_5t z*%ffl=StvLnOO4r!NIE~Mc4Rud;ADY@M|sQ5X~i}2TKn!Z_`j(dL43s=0M>3gPMNB zDtOxC-<_FnnD>fTH6-LB&U zH}Jc3l~OAMfkTJrCDc2p5f22)?!2qy?!$qSyGppl|319TQr>0x!D;s+hNkw>hwIb> zr=RiQ)Q19i-Kxn~6zE&ShjcJ&jT>E5w!pL<)RIRZllYpl4g~I3QM5A|*l=*e7)V%% zm4!=*?0B+MVz}C8}1$%BJ4L{7|4I5b!^3 zOxNG~3_L{~Eu0HC_Xp4*((sYPDv%!B20r>RG;?rihQq2>kef;`Q2yPerL`YtDYoxL zt7k@xS;}>*(hkoRav=XOLf-nyE6FInV04iWmi^ zJSPDko}!-n?99(S|M@S>6thuKP)aix0_v5uH>nfP1BXjXzle9lzM#~XUIeAgGFko0 zU&&ElMed7i{+iC$mtZ*s7t_8D2j2*6gCP+3CTb$WNQYuP@N!O@O;seLhO0qGi4b%} z1d>(4FiRaj9C%P%(45)A4y^zsQ2i~CjlHy4W`Hr%KJX!H{`SgkNX}slJ0-3rY`Wo- z@8yz-j}XWJ9`%JvK6cf|FGe>ct7mwwli4%&WB>Gx0{Oc*FQv~MF##ko~-MJCX1_?I92@J9z>k#z!GGycTzTmKuPCWhRRtB*`T5l~<+b_p{^s)Xy81c{3luMwsyR)wo69i@$j_f!KCgU! zYi%1|WV$fF$<1H1SheMs7vp4FdHJ$s%a^H&d`!@q%JUbkSXRDh=7 z(XR5f%hj}k{DK*aqKoi0=W+}X*5G4h`NdI{->hbo2lLDGRV=@}w%2Vc4=!AUyCjHc zMSh9G=S3A>ZmtTk);lt56cf3Q$sKNSMRhS235qAHl8)wDC8s?%ZN^oSHdVf*y%Wyb_?9Pqp;;< zom5(5zK(}X7%o6pytf3PUWnN|X8ZuMfsagZ9N@g3k%1TR15}C{80kS#5sBh+zA(@p z1n`pyKLY$BJ5oke7@#8<#!j$8nqY-T2#g*V6Es;N9J-=kc;mRn7@YV3T0Z+7{IQpz zQ&7w_;K@gdxNw0N4A6Vg#0U(bF?o^_l@rjpz!R$Y!|f!lWK2e;AQWZ^y$6}D;S#|x zhK!J)W-$tUX)yCo?8^kOwr=)G?5ybTuNNG{%XEasVOSr^KA!EAV9f|0o#5*!9lSF- z4K=lnGc9d=2N+JB$s}85*gWlxiT0ana$k*i*4`wL7RL$Bb>>-)`GT~zQERuv@%n=C zgrm$07ac{)A}r1_Ima(yEYpx}>o{`$9V-xygSSad09#Of78#k@z`nG2hay-La!47(6jdWk_^Ielk zyVmDBL?2G@`K}}VdfyEfZAh>MpyVE1A^|0~CU3cr| zua`N&fLk;9jA#)MlWK%NLEd>fX z&3So3FJSlL=H%qlf-t#^^c={`ysGMaFcra6Bea}aysu^kyOla^uBZ=`xb(ELVCD>v zrjofq+m%Bu&X}$7qN+Jl-JHUloJMWNvg9ncvSJq8Gz8=$FN{+lZ}R-S0z?;y$-%$1 zv=M14%bUuiN$RE;&-2^z>gsbE-J*POH`M1aS*7OH2Rxl5P{f2U%3D0Q8E^N2Jpx!l zt!!RZPV?N#oSfN9L0XoRvpjEdFh8$qUS3{F-U_&BE30aTz7puF#fw(wlrLVh7mC_{T;~l5bywE4k!Yxki0lM7Rc!g=j5y=nJ2RtuOg%| zke7!zcLiD&S20+WL0PyS9^~Xirj|@WPIfNN>4sW;+zfM`C#?~Kiv`g>rj?ExSS|7k z8JEd{wWOdx=atpxN)!Wl#Sy~oY{^6M2CDNGA^GN%7_|PJ0e2PdX5>v~f#(#tIdY2` z%k$$vyv@NL1YWOXtT3{`(Leyqo(dCwep(4pPsm`654!-TH92U9%Q1co7m=wjU zoQXl%%;w`~&MY|=v>eOAqX&u2Ez#eg@~9;x3$Z%==1{U|af$t66*%#xqs}n&t_YoV zQxSllJ-yZdonb^X%oZ&v=_9(f-x91oFgTN6zOu$_Jz>(G%!s<6so`u!@M+4(`fQ7% z@*f)nKD27yb;Ir|Hka)kHkswYY;ULOn`xD}nTCnHcQcJ&VVVlAIz07wTs6~tgGt{) z;|(<4KjS?#eFtqmzOF=58{UPVzH`P~XG`#XrMJ3wwi@43I{NMzzKm(Un}iSXd0$RS z-#=TTw&J@($(|6u$6)uGuP)t(?=Ib+b?75aC_kQpz2>U?j+do zn&sO`e=_EO7yUoLr@x^@F5V8K{@;>{zW~epqLTIplU;t_#k=L@n(r#vbTJQzUtnS| z$+2;{8q~=!pM*x_pDF8RpBy4LSZnF+%f3-=GJYh9!C{O|AlJE;A_SWF2+Eo^Q#&DlhWvM zvZT|#lYf?HXT#^+uO>rn&a$;Gc^fR~+06B@CHQue{%#ZRgYh<4`W_fZ+)$X zP5RqQUCyWFMi=jJ@oP%_mJ)Ac+4$%*HKR`Jvax3BMHyj}KjsX{&&E{CQ>(6%1-5J% zZRQ7h3)g(NL%+NcZ#=^~q2|U376|B4E*2FQRuops@?2FB-m94jIKNU;n?cZDXq;Bp zFs-_7dR=|ZaSe^r>O7_yb%wQQ=8T%k>T2;bQ<-HAvm56$H8wUQDn%6b0Po$QK&t1? zo1^AewALePcvGu&)IPI8`(LzR2CY0G!@}Sqv7A;@GhK6GRm*ZzEM6inCla6VRlam! z%U58TR^Q=RiSsc^aXlDc*9fKWcXSGOAb>AUT4HywCy4ofAb=MZ;*?Iz(6zT6^19YW zd?Oycp&kLo1s`nzxQ@S-+AcxV>Y0ba*{?3k^T~8$lWX zP=}gN4o0KHYDKf!o=qRsbae{--3sU8q;Vzr8GjRgQzP6pHZmvx;<>nS<*6HkJA*+u zL9~?8nJw0hv0#U4>9LIMMhCw%(JB)HUO)0$2Kwg%s zov)XA5p7HbgI*2Ug%2ePG{R%R*@3`0s&QT4y3yWXUkVih#heTTb`KY}sXf{osw?q~ zG&ioqL*0O-h_&W0HY=Cy&F5aH&IhYAvS2umO#6iM{0o>FEFTz0*5P;n$?LG$FS?;$ zX#BD7UJh zwYyZXgP8<4fni9PTMi&p)Fab)po4zSrApyt=b)c$JV&OpJxPX=uH&A6F8mlux1q+% z=$8&85?gmU{Ouq`1*Oe56xDL=zGzP26{36il~-zW(HzmQDm*yvs=}*_<`rVKyYOn_ zc%#*!>+tqGg;#7Ubu+H>-$H+HU3J^4RoJDu9r(=h!4>N6 z*7p?7e(y~6zB%`h=ib@687qv?G~8@-X!lX5%}JY;|NY>*;Rc=ywQL_iTmXJ~pWg+B z*ZQS$A=)ZLoN1-1?t?Y;)zgb+Rv&-I{fod|^nfbYS*y0dxKZ$x$k&znXF|(GpbygX zhlYUNaKpnxsL?|xY0bX^XZTD3p>`M)zSw#qs8?sw^u{A_^$1;}>`2BT#Oe>B+#WTu zS>p2;cOVE`8XF&nh3#pIifU$5S3mJ&HLR+uKP)U-d8+a0r#mG=sB!{gKyB(11TRb9 zrEs$4G%2IL#w}>8!N-gPsc*#Dl6R?Fwvexp&AkKLaE*ul5e)MCIH!Jzm`AD12;K%7s`VQ?DiAe+f@!CHdSW%TypD0qF6#2Nav1OAMmg0i) znvmhcr)Z(2pSGh4lBDm`{tKl3f97G7=Cc>5yyrgq{_AL;_VaT~vDK>7^ZB~}EB^c! zz9>OiWt~AFVdZBk?F$S;7dJ&&<4SfBOoxr)Hd4t9JE#&TlA3V{6=EOzOJ28KR78u$ z=5(YQH?7xQQln~0tx)(3kf~X!gFT7D(3;_k&$c_HnJ?52empHFQE*>kE7f-EMczo^ zz8DBRBOWOg`7--pmNQEo2X+kIx?v(v11xmFdgIx!vtuv{e+|eV;XCvB4mL zj0;Jekr6UaKzmeGG*e7QL|kQp%&;sf8c(c6Pn-r*`i)!rhafOcSEp<_eQ0a{>8Ee) zrvMqkcMN3IpoWIDj-%TGe3v4D8EQyJYk9cS-4EI#OMV-=W;WeC{Gp?f+Zk8=6)E~`){8Fu*bPfOthqF1Bn3YZ@8kR)Dm zpH*?S4;$6xtAfz16}c*iJD0zC)Y zwfF;pVG@?#b8=w~BOMYcD3GY+%b9d69Fmb9k_C}cQzkKfppqR+mtx7_L6|hDpa3Mz zND>pn;LP?hVyE))kcHMTkV3QkET=Z|K)eJY9u^dc?>Wd0z$8g>K9Z!jsqzDMWT40X%faYK%p)Nt33~f0QSZMha2@ z9uzDqipoX4pq!9Bl4&3zpIPs8?d19R@w-IXW`z7^fDJP4-W~(|$Do6p>)>@E*#E_n zgOm1v(@Y2J)DA9M8n=@iXYv%{{91sfm7=v9Kl|#PBBBpx~_pL zyxI!;zB7c4d+#^{l=h>tQkBlq#@QZq4l%P$(NtO4T#2(nmDminURGANTC}Y)*v_-@ zm~azZd<-4KOguxX*az(Z9(uP&JtryY06q;Z+Mm1Kq?Z1?|;`RA!il6%H zpT<~O)!5kBCC|SGb$+X&Ha3P2*R$ync%0+E#>Sq7=Ddc=r*fVfd+qt_iqyO7)Yul7 znMp;jD0NRA5Jck=gzZOwV`DGVtCzR`bnJJ31oG^!Unb$g&9DD$Yz>gHuaAx0_QszJ zuK4Y3M{fJ`pEr&Db*$(QcqC-xe-^;&EP%aUI-pP#K#@>KB}Fww!Azbyxs>?i$z@ub zJh>c5#pKDAXn+$yRiL`YaMoHE$I@B98NPS9!I6)PngxD`3lKO1reS8oadnNe>gr6r zOKY<|bPlm5rWFmjSX924jZDaWsaq#sWHa3$uV@G$z?!Nb)2qlGWJT@RwKk{n*{`*ZBQx z05}=XC3C+%bfOc67dOnFZz}N8Wo^rsu2{Kz6+f=f87}I=JJ@>U4Q#Sl;UBDy4f)r_ z@d-sgj+6OE{Oi@I-@l=VVQM(R@%!=NgiV|MIKvKsyUl-+fBV3W>XZGaoT_&EPvZi( z@}GH@^6&DW?caXRZq%PW+Nr{^^mBLnafJaiIfH&7zT|XCRt1A$zyDPKfz#;ZQvW*t zWq8T3A4}W(5NIaPECqInH0k&fX z=YI-sz}bXPjsyJLw{y-2KAn2M{~2|-zWNeBsDA%PXayeP{zHQM{T~%wOrY1(MEj4O z_5k#ci;3n>_&@onPy0Xf>~nBx;Ip5Lf8rAd4m|(-=hdgb@I_n}6@OuQIbyGQ7*`8# zjEw~lfPZXkKc&Uk^J6)xZb+$mVR(6E$M?q|G6>I(<-86}!Nu5qAJsA88GH64lx@-_ zjRk_V>iAUzmQW`oqhA1J56S{_^xKIj;hT-cf{+BEtOj%Nq~S-RrN8?MICMI)DFx z%}B~5+6DF_;kV6t?TyD?9b2)vUcE*UKgPt?y)l-9v=Kx4|NGaUh1#K7pREUFZ0yft ztM;!NTSb(}e(E$FWG2Ch8oLLk7aTSAauLjUUY-mc!r3`c3>zgmH?~HN6^%J#YrtOw zDzXeJvHfqrj{}U$*dNFKh{%uqhk6|)qSPyrt83Ixcfk(#=+=xK85?_f^N;JkUNlzs zW8|(6&c^D{7p)%p^w@vA5{8M1Vj=BE%+5!;$uYKH@txlc5o;?HAL5ZZ)&r8!dNjjiCffY*P@ zL4aJImhb=vH^zf?=INe$a-yf>X%C)tNdpI*8VYz~21j@VCiBz?3ZEOW=`J$Y^b@!% zAbq5&DayrXv2t^<(OTyPdNiWvoBA|DJqDTROB)+-j1ino%}~%`*39*s)yzwy^IO5* zR@81OxeIU$RH;R|c(*M!WDQ_heH=&yRBDBtfop4YQ+4d8aKNsoch%}>T}R)_Fuw!T z7poZxA9egh9HC~4{DR>CYlnFOLn`%%VBcwOYaBd&?z&%f#8b~4InoT`Uv9Y)Ekpw< z6e;2oxf4HV*$W_nQ!!N8R()WjsFydpk z9vLc7M>yO>RYu!j6m*~>MNv_odzo#I2*!QjG6v0*VR(*FeU8nLEPqB?k+PSI#`Yt| ze^ctu9Gm`w>$g58gR^OGR=;y{a8eCbTwszMQ<8FkT(>n`pWsG(F;kLRL8;0q%PG&v zsi+jXD*$_wM^HJ#>rX zK6s=rmHHNlxo5m9MJEx}@%=Z({)&=U2d063)32mzpp+fBedKtMq=xR7dX-9*cX-uv zjXDCHfD`Zd)v2N@md;r{w5sU2dJs`d0jMzhm3r@QXFZqOZE}}3SWJ|FDHlR@hE>Y#_zd24~Da37`bC55Sy%i8AcbA z$a6_YMcxqn$l!56CpfIe@t{Bj#{B;3np&`-;-Y`6tM|{eZZP_{sK0R*`DdrS^v{vX z+wAur&(}B`NXv3VKr#q^T%pYbzkj|T)z**Mu#O1T#Y=MM&u?s8%8RrBD}O0_4g8s+ zlj9V?INAF3V~r<0nMzrRL4g^^u%AEHSf=jZIhN6_8+8_?VWO~K#x$sG2ww(AW9NJ0 z6OpBqi0@=fAPJpF;r#R%kSp|w9A(hx9@Q=rT&z4A;CVlb>-$=siPtiYhT?Igqvy|A z_aCZj^t@D5h(x?SHyb#Ct#>#Ym}O_tm_s-5mAM9RO#y(L3IK0PjYAT0Q2|qF(oN;c zNVbO}{fccq6XXPQ#u|{=;guXbwxEh}VgYR_7i|WwIj^d&p{b1emEr{d|6}h<0OKsqv*-Kv+to_D+Fc#i zEo*iAz7LFSNjBIR-^Mmz8{3jkY-3}aFZV8CFTJDesV1VRqTeUVr|6VhC!O`G&c zW2b4Gv`K?o{{A=xy#MpOGxP0gB^lDRY5q2^v@`F_ymQYt^UlmWGn_%Ic8R5#1tW0y8|y$z)de_lxLmCWU3gI_bg@v$VQ;l|oeFlr z+>PIQ{5IehlFex#n>H)lV6HCR3Ooxg*rxQEtI#4`Y)C1xbNfNFIb3sCaymz?+{vLfK z%)Lj`C}@>(WuDN>3CO7q)I7dhe5ZgI`ive927uDj^`|k-aPcRQ7@Fklj0LIG?bB%6 zsJ>PY4Of*7P3i@*J9&%_h#gamdT@X29B~Z|>`ozRC!s$TIDz<1s4lR1fx|a)#^a_? z&UKvQ0LG~l!b!=WBu-6l=TLn!e!CQH5UfhQb(E@%uqa5JM?`>z-$duwixi~TNvdy_ zsGB$Am>^K~#LLJ|QjNP znZiUca4P*X763SBmKtka01flZVCV+Zq<@qy#88Jm?iSexzN1!Rym*cmPBo#`ePIQbc1he#l4v`MG3{ z4B-%tV8O~@RWOJvp~%-|!BFCuTLIbJ|b+e{=hJ{X({%k^i;rCwuMX_oDrfzwg_} z{Eo&i+ZRb^gzs$-K)*m1-0ZP=S_T8OdUXX4*L#?IdLB1ib3-VtmicK7<~j1FJNhWF z3`3eNUCR(v+Ny@Zc{rFcOg{mmJZ!m=p)p{(rBblvgMsaz*f(J?B0T^6g`$7Vu94)9 zVMz%rvrgirHo(JY23;pff&M5wVXb6A?pjGY{dnEuGL}958;@n|k1Q)BNy=4z>;CD# zuzg`2gUpfTi+rvq6t`m>hqzFQ9_Mm%X3UuTaeot&Va(_}j~n{pqL=SDMJ}PjJ?G>#DfE`b-+N-Jcgip#^^l0*$Jsj?W^Kk7&d<@dwbc4g*pdVXy`_dy8<^{*G zAMj@SGaSy|O~=6$=Z<&B&dThI{S;JRcq40Xtj}5oB5DA^;=$H5$RBa6liYGX1Qy+{ zW2DnNdgI)m>5$PB+&TGk1b>!Z&ye=T2A127Z0IHWl0>ac}x z_RO>T%qAaiCWiAHa*d&H>o}ur769e$FH;v6RX_;@MTCh+%z+Pi0c-_9)Kz-o;JvZ>Z0$S-!e6x1p6{ES!-i*if zJP~23!vqU`r(7FhcJP}l3r*AQF$4Dthx5 zV5{0&#GQQa0)^gsS!)>>F-u_~B2ln?@-o8>DsJgp-ZStOj z%Dd*!VeekN^7kNP^0504z%hBKk9ZzVus!~S=Uw!q=WS1TN4)q`Ai_Srw-(j$A@91U z)rX(?2;;&U4Kt`=t@o_DE>Wzud(TNan9+|ukHi7iJPOK>DfRJ{I5-CI)~t~Q5zpjy z^J?7HSDv_Lb362VK0y-Y72}6&3hsG#i7qDC3-?af<`=vdKlN$vGoSq& zyc+oY7Z$wm!nN0a@r#Glr@!=NZ0Ae3a9oenYZ|6?Fp&Ohfc<-{A`G_Hn!R_AwFvCf zV!c51BBbU9ac>!8e6GrLgQWeSPmw(t%En?~>NR_UW+)gB7bI zppiZL0K&)bIQHwg#fHs0xTtiHVPLibV!cO?l_a==H(_KfuJj3zb6eZ#Rqu4bj=t3i zDM9SfZvd@b+a7RTyJN|_nLTCL^;a4^r8WXZ51^!jf`U zb_%OeNEp%$S&a4VLGI1x)%4$+r|dxoGK0dvSo2i+x7?q1)ElSyY1Ec3zp{fq_eTLBb z5twFZK426V`lrb7+0mKc*r{dUAf>kevc(HSi$aT+ghES07c5&IS`j*1*7M2W8d!;I zGghs>_>wiD5Uz0zg}OuQLmTGfs+|zz-)cjA2AAvQJ9dKpl2G^Mi?Aenh4FjkRiWLB zLRas>qolaOS3&yi=AKY0t1v=)x03Xh(BjaoSM1vty6yHvXn!KKQ-p}S_P3JGU} zU5`J2ctW8As$$XI_k<1}LJ1tcHx#10Tj)W=9eU{D&<8G=9|}F9LRUQcSSSQ>wcLJ-(7#3#X^(F0h5j-P8eV}|8{q3=3WZ(@LBcKc$KU!k zf-vx%?=E@irM-K<_q}7GZ@!KP4*rbc5UxOOG=@qt{>6NeF%F`o0~i_i>v8s}esXf? z!lw6T$;iEJSakHQdYpxDQXl!aSJ~~oaRd_!)DF;}(aiCt!!vw-Tx8-9z_GM13-{)c z>ryWs1D%nD`~LoE?pjK97+JVCkG47LSQ@f$(|SRdB?~uWFJ={Z%T$l8KRrG}%fn%u zeG_=+v9ye_KRbR?ivBY)ar@T6mzIgcI27<@;yTiAVyq3M15dr8$6HR9G}eg{q>vn- z<4of%1~BB8xz8SRf%|fChsGhR9F-Uv#&QXgGI8-N7mm$6vg?6**6J9iAOV|Xc*^2gtFdmX|(eFC9p#$bj3 zvy7`Jj{-xOnX#C|E`W)`_$T=ab8L06DFYq(?1_TptaSQDe;iIvO$QLOmXkwnF$NDP zBiF;(;|T^2nV=jwIansSk2H|191^>qn^7nq$X_rG$0eCayMr{QxgyMJIPufGQ+@Y$ z-h14B>)0T2=jdem0Ky*>e#hf;&hT9L-!VSh>FZe-I%V1iy}biUT_@+GGxfaHakLyd zrO@kU&!K97Q$mf-H}ls8cK*6>k)eSox?q2pzy3GRU%l-~nc)pEkKO*iWFD)>)&BD5 z=*zO!*p3b+d;b6N{55FiufhMV^VbuZu@hqr7KZgSIx}WsT==h^zhZd1>-k;`c)8=| zKx5_~=C6H6$p7!g$MfdaapI?k!G&ggTx7?`#b&w+dxI_2lxN~k{xE<2Z=An|7Ck33 zILu=|8hX(A!#sANminIa*R%dGfBj!MfBlCO822(`Fb3N?n16@!SMIN3_pAf(b|iTZJzFF#JGg#0=f6B_-xnZ4q9xbl1w^>@ z^Jgt`&gbK5Ktj;Up!o7{eFQ0Se&3wl=lu)>8{B|;pV(a?;hKR49{V$ZT~WOR0y$b< z6RIIX%@{nf3W}(2A#uJ-L=gMIlq4Kd;wVzEIysOqxfXV(@VgQ18jCJ;1P13*vYI4D zmhT|&dm+DXcR1`0f!Mn^J9;liPHg5q0(xI3;(FebUFNGVDd z>N^d@9@nmp&;%p3_FgL5l&*LX+Pa6_0qPqyjhpu%y3dp|-3&?}POPe~V7h8*lNFWq z4Heh`SE{A80w)eDR8uuN1f+q&t~h9g3lq4hk8_1QR!Ep8>e*+vwJAvOx6{;tUndcz zW~y1|P(OEeV`2`3_tp6{&6Blh6e;iN0~Fe2;KeX3!OwwQKLz^<%V5D5RseWo1$*a1 zum`Lz!G7`D%5}5_bTw&Rx!neVCPk@@c<4GuE1vHS1 zz4ig3B}0=b?6wLda%AjZADZk{o_6bWKnD;xd+3MH9oMDQzDrV+wNLfHM*VBG)P*#K zr;woERMtM8#C5)suv|HN=7uu%Y-4@p>$Pk>qCZLDGL9D_GY?h0Bc4K#kMCfT-mhG| z8rP|k^|+ouy!VrV5A~IS&r?sm+INkVbE7_>!|AL3R_mJ;S%-tHcn@CN!mEmAmX^ES z*mv><6XYedfRNpQbP{+UMLHLpt#Kfr;?&|y5a&sDf6X+_ENz&N<4IZvM}y=B|8c&p zXILi>xatC>EE_RR$$B}%ja-21M zFw#NqvB_~ZJ6oJfS7Dpcxon5C)46=tMo8maiKj#NT;p8pTz5Uve8Y`8#Y)}e+}z`& zaQtVVa~tGoP`!?`UprF0!?`mdrUKvYE-4J>0IuDl++hc=9DZCxX`D|=2oJr0ST(@>qT{T_eHxzu`dR!w=X~Dz!WX~vxi5bO zhE+^|kNeVBaqk7=T>0`Vj`OPe90Z(jMWwSwxeq1OA30x_^z?i~DY*m#Zr}Pg%H%sr zefN&f{!;Dvs~?Jk^Vi>Cct4^6`rn8y zCYXOLB(Oj3o&fq2ZIt*yd#Urc&QJgD?|WeW2XS$ngIz=%C*}O?=l|&Z(=UDrG6Vl? zkzYCg_{Pb9`PVnq|8XuuW&GR!Rkt2+E*(xy1tE3xl^aUuodmB%nIVy6naO=k3|WLo;m0q$izc_Bb1d zqN9H`tr1N)pC9xGIxuj+lyXJ5t;{wgLt{@ou6+iH+af;>^GCzX!teNM_0F?kfY zT=%Y?9ja6k=?C;4#Wq>G&V2;#(@&>=l78%X`nc?O4txg)`OP}~u)oG#H3xD<-2dEw zAN1oerx*7gbxziSf;*a^L*k9B(Y3L+oqvHv=1!3GYuFL|2G{^qbpopC+k>sul^rUToOH*j*mOVz0fpH;kbS72;uG{5}rQxMmqhY9@$Avu?-;GJxDK8 zfyp2Whx0;xLrYKebUMZK>bpWnfZyAofZlWJ1if^e<}NO?D)Y%6;+#|VgnLn(&}9^t zb=@P_tHp*chVysg9dPYY(NsD;^_S_RxP}Im{MK03fygJFN+0X+_eGBn#a`$s#zjAn zOG@i|L$L9S^uwOjCRN4KVNTvcw8v$Qx2H#q%f3fsKgrXFP;Qc!qY!w453rML%5tyB zQ6eBn--=%^*MLzwj%1VxV8NlWl04PHlHdQAtX=M>_9S|lb(lI*=^u7-eH%Qnl#bqC zMS980^xy+qHytv-oDjb%0(A^wP}!(6-RXsGX#{s#?o2`JKso~85Rayh%eR`wr=d>$ z1cifwK?jt>qx4}|XduxU0RAmw=u>58d=R`qr0)mVJ&_a9v>}Sm`rgb8LYpy<0K^ki zi>Mf2cW!^^!n4vXe5(x@A)8sK2_LR{E-Ld-J<+9)Lj3$B=tvoXP%#WpvSKA2hR#ya zIUABNNFtOc(5>@fjK&f<4n>!y6=aIabYDv5*8}Yl(IoKh&+nR7%uLL>d#zGbsJi*Eaz8%#L0U z?peWEN3`Pi0$p{zAiGhM_R>$^=msi4P5d6JO@}4RHTwr<-ZMTMg3Mb*Iy8`?F>f{#KkT%^d_@XZHlAQx3UdC<=X%;g$OK}u@*EFkH#|2 z17j$kEHAb>_*S{O%d|$Hgov%g{&D#2SJT_b{D`o0%BI)fW5#A*2Gy8uJs2U;PoGpL zXvsm7kWDLN1?#_0Qh#%U4tWrj;mg@Ph{NLc*g+wRD{A{gEY4@bXkV-y`^6&3l{(VV zIGLGY#ECliECKv7d4DT}lbsUBDIMaJi4CX1{Q=LaX5LlB1tVBPz#;u}0zv|bAh)m>-WekF|c_~C3LFGNty>^)i<9Yc#+Kz93;fUMp;lGyA`}1 zMqBcPiiIrHTG0%wrW%c~OIL<}mvB4p5~Fja4FF_D5w!?D5SJF}{WsOjWw-)_x0R9J}1wGp$clZey~3hBVjaO1B(~b+C8-eVwRR>os}^O-Xzw_NA9Ty+*ttD) zj>MIfmy}jOuPm;@IrEazn&M*l)fN{s_9UWgkZ5Jw2>V8IPo?z32$E7evUkKJu{&mO zT)?*j$4{Wu#7S{%CE08;^14d3eTXem-)P^2i?z5TEj!&hdQ^nh1#`zJ2!xHBnXbuuav8-+W`afO_LXW9p|R#fE1D2$&I_!u`3@1N7ECDOq%BkNG^y zu=ms(L$Th2)fhb#sPCkYpAg2@Oh0>%RHhW}$pvkrI*MNGNTuGpd9603a0f1aDRlem z&=X*g!JdsuLgSu|!u_`9P9$}z=Q_mo>TS+YPIuVFq}Y2%5)d?2O2E+4Ukb@Mf%S$u zQ-~*IN_QGvSqdu~=%Ba)!DTMM$v6isLE+MiVJ=1L(>*FIo!ApI)u|+QXGyC%&7DIC zfxwutwsT6t!$PXxo9HiEXa-dD7syUgU!mTIDD!Q~LWN-|`jChLA5j+c8xkdSwrCLL z8A5J+3b+R2+MgF1Q{x z8XEY?TWAu5clZti#%ENOhZ`V+h}hg*iUV?nm`|x{;1;_c38uh8Uy*0HX0W}o*REzr zt+%T zwpV@xwUekyg;Gb+QJ#(`VL;`bI6|)pI^j%^bfLnAtB!O%Y!Ud$G#%9m{GJM&fPO-C znfu$oY10W+mr^h4o{+sH0I8Ku@>&|C<=|BjLZ|e;J%URq^qO{sexL%$!SV zMSO_gK@@yHuIuSu#;C!NZ}j^Z-zEpq{ji+^gJ(Aof_xI!dMul+XO&>nxzLjVJ!JJu zBy{8s3f@k&3%^~`a2QbvKkYj?@OmxX2LU}gVHh$uBxeRB!BDX*ZizRz?nJf&o{)%gQ!#^eQ{+Wj1b&MFH`Xr?2}a_F>QoF|_cTvGb$^4Gsf+)Kr%K$5)(&(EPj zgoKJMTHoSKNG@@X`OWy?@eCGhP7s5UY5QE_95X)7LGw9Sz&Sw-MmBK#15%?)G7PY8 zEoiA2b_v|q>_8gdH*e1Hbq}b6GP`t{Xfxg6do{uAg2{>B%v9J*fy#areFDt(jU^{r z%mJOOKK{5Y<>Y=3I{#M9@YSlfD)lHnufh50?3j`6Ox87q(#c|e`|aQ88^<#gx!!H_ z#|J4Nxy?_%g4Q0vv}))V4lQir{LTkK+5qY92TI--@0Vd@u}ji)J|m=j*OZM$Pdk-L z8YerZXWVfI4T_x3w&XRb9d}^LF5Vnmw-W7RP?hDMX@vbSJWAIG`h_Ej%`PyZ@JkIv zCS7B0d+HaCU-FeG~6W?XQLng<0Ptyyk9-9Sjr`fE-R!Z?tp zEITg$_8pb_2O&24v&{0TQF`ZeDjPz1!Ek=YqQIb7%k^7eRyaC^nJU0^(RW3$XNt+# zVwnt>@Il}x^@I(Yylhhv$L1R z1Y%vo3C)uATHZ_$D1@l$g_>KUbg|&O_3IPG#gO%_MZc`zip5$@lWl3HNj47ERnAWg=zYnxO2ZiKhVJt z%gh*eEXV--zF1hRhc5bbY1$C6?+*2G!($k+fINg@ ztZlHq?x%#`F?V9E1b}wX^Fup30nhb7WKDB=la#sgO- zMo7~>HvUfhRF?{~8S3unJHQxoFMhHQDEXs_+l#bLLDTK@gdps4)E`MyDTGNUX0r>w zzTb}FMHp`eay|eXbcWzeSXNM3GY;*;x@AXzCMDSsinBDG9j)wmuXVWDc42i*4*P-o zJ)g`XMz_?t{;XVq4c6DO9AMKPDzl3&iUCScryh8N6c34!MqWLcQYTu zU$dCy>zF6wkEowp8aO-DbRl{}9Z)kI9~r*B5bJ9U{@$D8eG~ki>6J3cR@h2VLRb>C zCj|B0u6ZH1rj{j(O%7`Ipo+^&X5G=Sv3KO*u*#%KxMOyb>q4K@=DKojWfETEbLA;M zdjAdK{NIRvp6l{pj2!M+?yfkqU)*M^kNvE1-L>noX}h|*yViGY=pt;yZ`0;2m-_Bo zeeC@r+gumN^4y)89{1qBmq&@%C>LGX)rDg^@PY?$as3}I|I78>lWUPV(Ky)Tc$ppAGxANz=ziW+0ySNTdT= z=ge8-&w)Pi+{k!|9sWe0Jx8?j=86_Me;)Pukp)oE5Q>&e7yG3bM3&(g=0#%A%2H?- zYt%E=D_0q0b!0VyX9Re&ICAkiV;zZf8LWH#25Yx5k%(-90c~V!B(iNrWc$|3B0FHQ z^Rh_f@?DlJa>bQb5ics*eK|CoyFzs)q&|C6k-dBO78NbWfh%0y7>Vpp7`VeCzJ4eC z1`~IQ`9LCZcjTT(B608#Lp}`4d&S{CQMGcv$zvq)z=Na$JfyXvB2YX`Jn;dcMRapXy;_Z^|7hNnc^82KP|20`U+;Ma)5Lmx6RUY1Ba zEjAw(H4=Fy@{wnOK1btKks_4WM;|?IIDpn5>Z(CPdEFRT+6P68Y4pbyH$< z((oCJ)P}>KExLGjBJsJ;TdOa85q+B%WYH0DIWknH^B&24>xA7Z`OZAlkBY zzZa3h+Yj{E>#x6V68 zss06ie|aGBS3(UXNXx$lLY<{R9dH0B;YXH5GvB$@gv-~%gzz&m_af^Sk<4Ha23Ip<#68m`ZdS;qZiE6ScXrpV<14O5eqmAIz8p`or}m=3RX z8j}#k`OwO?8PhAH(RP?-h+VX8dRufxM|5bk6XwpEnYFcWm_Dm*#yQ%3X7p_M1l|TO zg$3u*w!N)=cCC1b7R-Sei9b8qejW%arwv7Brp>6F1#)Hz|8vi;nqFBst#Wo08vZLQ z;TD}fyRs8e*0zfQ%GsTgq!|STRnd8jC0ZB}$5{yHZ1{@~h1>iEO!>5$HpDnR8mSV( z@@UOW1W-BcJY=w@vT`P}7>&-JhER3Mw%5*rd+l7m0%)GR2#q1ff9tQD-Wf(zxydU(~GFn-GbMRVYzG*Vu$aP=k8XnC|CQVxsN(KVz7 zR!|BZfw6=NpcH5(A2w_W1r-%k3($Nj=G4@pVZfmVX3!NCtc}p2y*5(L^sGY@lSag{ zE{GOVixzfOR(2yAKqPwh*)^y<2C<$Ls3DXY3ZkaH7CD?gjU^3=w%Ie=+M_d&?`U*G zL&L@fG@VWOp|>vBx^2$(DDca6fFTd=ESRIz<-1mc5H0bFy7~sRuPY}tG+b5Cs9`sY zvSu0sMx`Pa#EFuuLDd6Cj;>aFDyOlrAs^RV3k`uG7uWIox*icBuX9iaD9;P`1 ziL%I0G{}8H6$>u{0{DcuR0iZL4P$i9i$rij8($#hUBqJ`go}mscpnlAy$vgVX@-YL zBn0w;0tFL2x-LK&BB6$LeDDLpVeBz{_AUa5`R7PHI(uYi$QVHOh5k?@X zM@Cq7AY#%nkuPK!6ciTX4KHN^LmA_tR}?jJ89@M)N>Z#?Rs%B1vXX403^@&DwIWp5 zN|B>p;1hKzPEax+{J9GTozQ3BUTl6>N+v=5FuMXM;-Q$mb5!^Z?-%J8W{yRl`$uxz z1~n!X*UB2Kd!rz{BBaj^8`jzC`jtFu@^xm?8tf*4>{8)w5;Q_SMnh*S6-#+6NI_v~ zE&C@+ZIs92k{f?m>#K%fdD&_wN6HR+rw_?TI^)Ev@Q=mrV609GTaVxB?tt=!h2 zcm;t0gs>Qwe=McZ_`g7$z;#o*-us1Lb$@9?5IlS?OGf`O6Z;7Zn6nwN!xi>^F z-C}jr0!PEEZfYf1c(SBe6jw?N zrr795JFf4f8)2>1_5WgyL? zC^R8oYri{HCuRWEbc+7sT;`gdM4n8$P-9}pTYE$txjsYkzOe>UvR>aOG`(lYjSw8h zD_gmABS+=h9nr7(C)J-meMnJvmJ zLxh@8iGjH~Ruhw9xn9+)q~;uq*}{n}-wC55`#vtJjax%^yvDtk~fQiFMOD z-&y5DtF|v7S|jpGfwyy-LQ+dH6$C)KGntz!KZSD0nnD85dH0cFAY zGRFHyeHIFar%Xb8&15M|@|=mj9tpRWtz9RfbYb}mPnU4TOKpSAc6Hf~otQiAQdhuq zC4N^4U0-GQ)tfhO-m`l*o-xr5*NJw$Pj!Qj336j!BTYAn)ii{Yft%%SExD~o-NrkM z)a{_!Pl7w{6neG!j?J6zI8U230Jo+K%QvgdJ zcn~fu9smX(JSq0bqmMoQ_!E!grIe>W_@So-KK#rxA9?oKXP^7%^H1}JB0PrjsZT%i zna?WqIrVuwaUySY;pU;hWc2#$ ze}W%gDfx3~KltJ6fAN=pMax|H>s*W1e*~L9fBkQMeEh^u{uY-D{T&1Shs{4bcu@UZ zsehzNsed|n@E5=QXN^-0EzRH-bNmBh;V|ZzSQ{wF=e)O&N;Djfg$v?|a1l{L93P*# z#jkV-%w;4j*N%mXo)B;a&(^BaAhmpQ2_-mBIV4hs?-tI55qY*JSf}!fxvQR({X>2L z;le@$hd?-e#IS(b80G+cR#XdaCxzo+6q1De;%Ydk0;tV&iRy#Cg}_TxNim{R)e#w8 zv~-$NjL51n0vERwF;=}(&n~07sY!xT#mRiyWB9A6z<))>Fe=zFffe&Ksv;a7t&l*4 z0zt0Fj6sg0D21^@%77Jy3ku7^IQ2PHO=QGF)ug~=HAMw5>%fC(QxVpP5hF(8cNPz8 zOl!aehUSj2S?8SFHXCpJ%>k4G^r^B!1S0YT1*!zOZ&Gs`VUcW3vP?Jwr8^3w5JEPNnlJ;<(Ji?3LJag z=xvrTNCXPIr5Z|0F8~7bGL{T`yrzP1q^Z6zT#8@=rD{xD+wyQY5^l;b3&&SnXaFy< zUIfF%@WH#=R$Ro#T-RK*maxu1SGR@r8weZMuHB@aHg|8>u;tQjT!^;yvaOePt=rnQ zV`ul}+jebTx9y5`UFg&h%9U4LwOd_9xOz|NHP-^JxmIBd=7t+r-*oe;oA`>$&8tNt z3d2n|uSP$l;nsaV+;;mu`P+ZX9s6!WHJ}X9g4l>znyNV5Mz~X}cO94kY!+6mV4ijN z4A|3rciTM&HA%bB9XxPoM%&$Oht*y89-eXF(BZ=e4&4p&jC(*!0ySgCtTq(8DlNSa z73it^5z_>AaBj5-TE;9L?C4T~3ChQNY^!eTHvF@Um1Zeb=Ftz3#akQ6HI zw3Bd5+KX&J%Myq+S3JK_81m&ge=jA3vpv~Q347m_(cE$!fF^#ZSb%F%mEQf#*sOGc3cSO^*{`W zYe`@U30TvSt_Gny_+Ff70+w7*clmSOL;&kUSgy+phOEjYD{BEup!^3Imc{Pi>M_MS zz?KKVf_cz`c~k|X#(z4)mDV(o6w6fvc49!0n0P#{@Qa7Bp`mA2n+h~*@Y)t3eFESzXu7fP1umyan25mU&NiRJr)@n9mT_gTsYh4O)2Di~a4 zFqq|9Wn-uw49dztQd4W`tUlBtRn8o%2i&}StEmk(?zP=nm=u3{p{i2HrD^~$lW705F&l+rKN_CZV!)rrH zNtd=;k92RyBFe-k*kV5(joA9P*4+$6S`gZhX+e1$${@*57%Rw+g`@dFesl@;iePby z;F2H7iwjqTApos2qKb>+5tWx!Hdd+AHDP)lNDh`7mgN#w4kUskr#wOCI})NK2$7^{VmCnGTkG9x*TDY zAS5IclyHy53X6%-993mVats|l%xLgzSB3OY0tI+n;U-^&1Ii*kTEz5MlL1tvXy(X@ zs%3`26x1122~t|4`GmYYSSQJImBPbNp($1M=0XxI_E>0cX_CLzhG9+3{DSiG^6|@y zkqbl+Q2T@F0Z>uc{J=j4Z>UCKUuqAYXe$7Xc4DQiwUKrhr!fEtqW}U9OB@4PC{WDs zq|A8>8KOvmWhD(5qzu3kn0C_9F%Ap#W5L=DqFXZRXn|z6erwPz8Nt}jUrS_hSql>q zuJ*yrto1OmhDNGqhS4aUk%7?xym0TK@r6Qlb&ZYn^{uUr6NyZnI#uP@mXuXgC9r^* z6_8g8Zy4@JjvQ^vkWCk$nH8w|c^jx$IYM}juu1u~wUL$xK2puK@l&QS#aTlNhZhya zWCae&)Ui_$-Iy`@{v$>kLTB7qkD49gs$evlmlq#3p?JiIapOzNE2}Xzs7W>q&1)VO zvn-LHvlGOK*;oK*dvzd~cXNgJEdJ<{antqp;#U28-Zh zp^qD-##5gFGwdghnKV+?_RP8-*o2XcY2w+kXwIu;#H`w;(^_E$FQ6|+m?^viwuam} zlf?QwZ~-;*=4WU3Jncc$1(>6clmH6WDxatn{slM`0odhk)#x^@X|;5_ zIT*3#GHf;>y*p^XQMvGs)kUZ%=Uti>!gLzhJxX1zi$t5D?osL*-yn#qHf39wbof?g zInp;f*C~}*m4r3w?*@i|B-}`7Vs#Gzlo5%S58*zkTkWFx!kNQ# zpe|WfACEVb!+&Euo&;54Q$aG>l`+ zSdVO$8pF~Ur^11J!~%vPfYrK@Zg>fT zGT}@f=*EL8?B+K!=kS921hED&a%4cZwosNHf^q}R9(-WNk5r=1$*-x-XEEX4R4ES> zMG$j*ax`H$gFc*x1qo!3`Dm7cKrt{n3C<0(pmPD)@wp)2VnDFuiO3w$3WqcRSO}3t z4p|J5rlyBK7bGZE8S6<$;HrtxQv(kmY?clYgh+)OU^N&@1}yo76%zmrVKOU>8)TAZ zNt9$+lBCdVm>)2OT)r6){Q0pFQATSoC`fSDT~vV9&U|OVkSv_&keuoH@13#iH%w8# zGLi~}cu=NzjO>ls6~?$;-+-Mf*0$`(VRp;O?F4rsWcBS!8v2n5jxw%0$8}|k$d{&H zapB_s2we1jJY8&wR=V!0)h_p$y7U$kc9^zpr}+JUrgqtm9GLqX0~5USa@XC3frxKt zTzlPIh;q9(>40vY+mqTm_m;W0!nhB=+iu@~hjxK_r;qsvtHpKintQ;v>5I_y?t2cp zhx%F%Y9jq%-}T=6?)UM55%+-yA9{H12j*fE%XJ@jpBR{GVB05;%$>_EuMf|~ZWs2t zu+`O%&{ppt`X^tQ`{JkidCIb2AA*hr9cB3B|kheMyxoMNwF2^3ZR#S02dUt` zO05?2B`~jnd99c|wN7=ZZkX4r4dB8&@KEIQ#(~e{uJ1PP`l=n0YH(*@%&x%B?^R;n zt*%BX?7>#G2UZMwCSa!=bpx2Eo5Y>I`FFF?w}FjfNu@;f)ZVPWTa^C0RqgZtY^mOc ztzP1{iMk)BRqr$*++p;))B&Wx!_~RgkEiZY2eVAHKd27*Hisc$bT77oxntsC$K+n@ zl-TrcQxBZ|w*1W^6k{{i5KW`V#)W4E!tVCG}PHHFZ?=s+ZL(>Q$WVy+(aqeM7w_A$(K)vHF(! zw)pyv`mXw(I)Mzw_slPTfr2LWkn=F&|Ytr51b#p1_xHEH&36U+Db&AHf3N;Q{S155{|Mjzq<#VQm+GIP{z|<8^(21(qW)Fk z(Hr$|>i@!||K7qqZ@-5Be;4!HP~XAtU3J>Hr=csyQeT5Ls7$S7FuL>WwW_73?(zWsUk%cdr7^A&NDeJJaVsX-`SRE^M^kTRYB zW|&%hzn*G!#;9Qq>sJ4*Qp4ej_q`0wC}*@_A5mlY_LCaxu%(ZK-FRn$vsX=Ybbp8^ zznm#jW{hX5^I3J4GtJqi_+{z8vz<04sir$KoOYD7jW46qUkBpobY?oUoOAFy7r*~{ z6Jwg~+@j_1FO?EqiZ*otN@E#c z0dp>Nz6AH|KY14nHMR=B)p)vT4g9XfZ;V>!bUEG5dS?SncdCuf7tuGcw6cAB_$oI^ zY@0=;+X=PBlrBw|!k&FB|K=J0tZ~xmviH^FG0E%d*M1S?qRkWjOXv zyJT`>DeqDHQTG$o9nQymTKc&&C*PJ{>l~lR*=W;U2;l%?yjx=JTmSc%a5Dan!`H&B z)Z4apuR7=)at<4pd!74$-S0f$Txep^HIoTPV-GqH$shea?C`}mJotv^-k!i?bx-1_ z^S@Afo0#cybRYF&RpT5%4_7TTPdPtPAH~lZrJP%)VvHjr33`XO28bGerz_3gL!-ltr1I0Y{Ep@7K6;>2{JAD1o0;XMl%5! zWfrj+WjWp(c-P?|Koij@F0^oSbtCVVW5f!<~a zK?<07i7Uq2G+N?e+7KC{YDEH>MglWGxruAt42MyRLp}{Uf4bm=nDMqUUqTOx$I4ttpp|CYFbM zreY6bt#_bEZO>o}mu6d@)oqe5DSlX^iCA)7Biy@ZwE7+KrloEAD&qnnv*S%=ewY78Qzp`TVA>1!W9?R#ALIk zej*@m)oRdOvW6;PVOv{u+uB%*WH8pmo;$IwqDJ&Z<>loe{0L=Q)2dBeY(hnB0z;{Y zb%{oAG7{8KudET^SO6dapn@e*Nx~QiVilDYv5Javc&bFKkol~^nOyq7Pt$NT(d4j! zz5Nqccs9CdT0zV}y0sy(9%#1|BnwH(S6qNex-tsVYa`Ne*B~{5F;0m%hBQjzbl}>x zqPv^fAWe78hVE{Oc_UPl%^1R|*i>1glNyU{)SgLC*a#op-J5DQZ|vT@siwPT)8=jl zwyCCOb9eXVZWy<8Z$KU-*os)*ieL;Q80B>VCiOZb)E#mwAda!br9NaFEbSa1$e^@P zu`5w%+gsZfZlej-t@1IVkA#s8s|5nH1j>t6Z;!2rtzax|ZPVJS@g-c=)Fc_P$`(PS z;I&m#Q!!*_C1IjozDw-U^18dP=S$*ZT*1dc8)!jR< zyRxZCMzkTxFhDa443QZx)UIc`K_&eNvRS=N50V&|IE0$P7|!V6 z+R&SmjwyA5jpi*`$T0I3eM6bW=fGL1j%iUYML)~+_chJ7Odv*6cqThK?wC+0( z-nnbennSGe!!`=7uV%cNUrSS2_g(kGO8SJ6>OPY!)4hVpX&Y`kYpXLLn~oBjjiuHO zUx5@DiA>K7)z4a%1t9p zw~F}q0pLg0In(Glp6LLEMYScu9GWsFBE=)!i;f94s1nN^!cMbAOgMN)J@|p5wG}~w zcja&>_Qc?>dnyT7M~JATRH2*x;d<#bAMpGC7BTCpdoUYxub}%ib`a7@Ku1F}L2cOB z-Hm^CHE`4&4s15k4krdgBT5g~vtF#t2Ax@B)P^R~=>mg_7_K)xnlP!blKO-KdFkS^ z($XO%p+GdhAR2I*qWR%?7&kZY2um~+b@H2v-Do0F>p8sC0M}4ND+AHu%F3c>rBhTH zElN-X3ZmCxiX7rl34~bS*4cr^uYA0?CZ^~F)hU{w_7tKwp>xTdNSlI;OxuDG-`09j&e&IgA^ z-O7C4?ZBHZ3JWVMae4=m`Jqs;Q(RSr3m+ishkG9q!9vwi*n)or5$2W_8e0mYb&#WJ zY)mRuUtO)56WB_3!y(6w6*`6a1%+xTu9$G6EiKV}RbGkr0F^!oZ_CZswXmE>%0cpr zQ(i4|Ml}&BD#jfTk%+yuDuUY{{%3<=}zg&6NGI?hn>+DCzmSiRHWI9BYd84umGQrOGNb&UWH0j^QLFFwj>-((y+&RUPR zh|woF5apYaW7*d@Rg7^53%_Rr<(VhP>2Nw{(jJE{vS3yg4)h%S&h@Qk`c^6;aS3C)xQ z0niJ66d)Gh$rXW!)NTC>vgdvXF1PdG~CqS4&bTx!Rra(ndUR&Wj zY?fpf1c`7itxgS1;^PI{KyxD%LX)V?*fFKJ0Zb!k0ZBN`fng0+QA$oguU`R$ERBfG zOw1AJ!W`X5%?bTf%47L}18@YH#}g5^Y;rCEN$k*Z9Te2FD1-yxb}E2pf3&X4R}9vo zLrv|hnmMcF9LbuTqMf4&#M60#&-J~WKTo6QX$NI*%vi7x_6~1opaz-P#hMP=vOeJM zC4-->r~k`&wpRd=uP`XI3opvxe%6>Vza(u1WYHmBv_RaV4wbjh1o5J6&}ExNe}N9KAh`o8w}EWO==A0j&Av zJhs;s#Sl~p&r~*-u>4x_lgj~M7|uEwDYeyv(W*%wi7S?M4{0Q5B4aUQH+h2B5%e(( zzaljrKER#mMG{)U$LLlmi_v=Fq_~Kz3r~Kvwt{$qYLe3eg)IAGpzi4dtK!P~qEHLXHZc zLo-&!WNEY;)_ny~Ygt{J_@ID?fT5&jgUX7@x{9P0+?g2dPZOI!T=5Nshz0AW9kX0A z4mxipL|C(_Sjb9FCSf+4I`?94=(Glv2p7D4uxQ3osI*avh&}+uhhUaiGNbeClL)0v zW>&r&l#;0~KXQxwfxqa(Fxg`9bt&gR@E1}HRQ`+ji^V1azuYat#&5nxW5qtkd=k># zkOBCe@E7b`C2EOXn_v-_RPahLahFHbh5+RaSr+t}7Gsig^bl9B;phUpB<<^|5E?{n z#IPYZjQl6_7lx;hILJN#>_`l`DF6ps3p0QS9|66ib0*YThM}N%7T}Eh1;n?EoFz#q ztZ!KYDX^uqh1`~fWy>|T!mQX|%DuXp@r3kiL*qpK zkgrff?9OnJLnKViM2?$^*4AiS#58b_`e+8KngVzNQq6+R))wXxw9FN1Vm%Kk?p(1X z%3hy_O84176C%#(lgw7UWek^fR(;CnpRQ4N6ycjuv%+MT>>ON-$~k2F5&KKA$%`A;5sQlwj-5#d(41L*%_8U?lE ze%vUZ82?GJH8TVS0X+d*jDF>sx_MDaJ)$n>X&TaBPm|BY@=o<}jXdRC5 z$Pud*`4|Qw0)uCvGX#c<7}i2V0D8D`6)MF=0i(oeFDV%&&N>0*yqO%wrFmAmkKj9Q zRk}P9FRxp&a{czYVJy-0THCUH7uW%i%l^r&0`Vzp3i&g@b#N%?QO*tqb>I+!I z;vF^t$wMhaUyDj9hpr8(d2uoTh3_XTZ- z*F}8j`+i;S<8>gTmp-8RCNldnlkzzEg$O1t5g7;~u*5~Jj^l@cK_?gV`C|QY8v?`2 zN4WcyOOKW?9>6^y1bs}CSUD9yh1LQAtfy90i$N}J^Wz%`2}p;)7Nc7Yuk+{&eg{Yw{}ivN4MZhGq9j^V+SBYDnu(&?8~`>S|*5znf`G3N}Kknk4c zb#2$~dMC}7)6>6(tJCqy)Vi|+Cnu_R(#MxwKW>*&kd%9=@-*LJId+t4&ypK=-7$9h z6g5uXXHDbHOAR-Vqn^pjbB04Sc}Z%jl-4Xyo10PNn$cKUsNJk-GHrh6kV()W7}}96 z!D?snLc#_OLfy|=Zhq`%n{81n2F*MT$#%%anG)LJE0d))Z4@?uL_6b@U6{drVEVYx(b3x53=YLp#*F%rSd{vS;BwL zo>AwAiY5&+*t~qq7yYnhSVIYWUPu=V4ox}%lb?_` zthuPo6jMA*B2(A-=945L79U-Q*Dc^UBT;;}T-L(EK8~n5;Q2$?jKjBEfP=aS0t>o0 ziRxg82Ps znVLy5IVNLutnUl&eTV7ag-I9L0IKcjP4{Zvi`Vx@TerAH{^PpYE;~a2`ei{}O%0Ik zG@;F;*p9#%8)7!u(ksNni6Ssx=)Hxz8&<=bqQhH8 zQ1?cTY6#;|`Gjpvaw6=Eps7kL{tLf_kY!x^r-y?e6l4leQz9frld zo_8PZ@Avdv?xBah4?L1Z_^9{TS;b8%SQspvR#F`fH=G@An?ha?=c0vj zIG*9qXM1OzGt0oavjcdBf^8sTU(5;ymo1-ySpud2$Wmw}CZ|XyM-i?ptR|buV%z44twhh}=@G|Tz1%tCM-mzil<+NP9UG2I8-OH80uL`Q& zfvbai!njZoH!22i2#0S(9KoC5^=2T*VvlIbsZZ@?Pz>u9JdYH-9rpW?l&fJ8yaQn& zofun!w`{(1I|ya+e|NyU_?~e1Ae}Vf(l8s$h7B9;EyUSA_*#BH+^%NG4@lVa9t=LT z;o)%Y2bPXjkKhdpoN-r=K8EsVE>X=QlJVb8B1S?6z&dgWxxeb7Y+$}+g8RUx=%pXm-*NO!s`*yHmj_6bnBL>?7FcjFCLxc#Y09j>9NfN?E zR+NKb#mZ7F-|^seTk*KV3n1hw2w0(F3E1@}fIJUQ$PvpS4@nS8j+v;pC@anb9)zPd z0YR9sL33g81z-`6lPZn}`RIZfB=|qP*b$GSlHwAi6xS-4H%CaHSAxvrOf>3B7zH*PZ0<@c2%-`IFyzi* zSw0rbyo9`#0lecu3=%zsA}4}d$V!M87M5zQuy6>Fvckf0=CnUlRxL23N?NWsLhQ_+4=DIo=ShE#Kp%`eTKFra}Ox6_enuR17Wi1JMM<*#}GVEFB0Hfb?MW0QFIp8mNa!Q8;%gTee^|&fnjq4YKyq1Z}New~0w(YNXKk^4J5HFti?Bo5x#qU zaKpy=xQb&_aC30WVqCir#K^uQxbyPMb|IWAu2jLRg1duTuHJ*DbB*?l@jQ6lo*?c& zfSn%C(P!Uc+m_XD4bBhl+et6C1(yeLBf=d)96A)Z>p&uScOtmro`b>Qq1j5`OSy%g zFQHEKI#spj@V&wN?hghpdEmid@S%s*2OcR3b_auxJ{H{k_~PIbPpaVlBTof)@-hMj z8+=B*f8^O6(4PwiagzFDA4hq9A{g9L75rqd=mikH2)D(ko~^;1I6IBoxnZ6SziT96 zP!97to8&yFX`AbU*Ym@Bo46UqoDkfQeW=Y4{rpwY!Q9~LzTD(gI}5YV6y6^ z;8#Hx{F=7gGN0ibq5=9*(ZvLFk|x^s?)(Jwm&HW$E5TR)=@@hKn@mSFt!#w*>P%Av!+2 z^M~p5+v0LG9e4)_Ufl()D+@b9lRo-+zPl@9Lpl%GX#@gzqwe%i(nt6vuR1| zA)fR*={k9-*LfHE$$&)sM*8?q(#O)LPygx&mXqH7`cIFnOucvvetxx|<{hu@uXNY; zV%_OiN0FL$|M{m!s~vSLt<;gqUeLMfm#@wELB(t7S6{2$t9oJotK;v2?v0-wuk8x_ z5;*kEW9bl6`m^I}QuO=IFVj89(c5EtQtRL&D!J%MrUMT(pFI7^U#8pECDU(`N91}H za+OZkolXasKVT?>U(@ijmw|PrCmv10Hl2PeJ)>tvdInJ*m zJ|2e|zvG3_vEb&U5^zBoK}9~(@wC$`DE!2M1Q?rOJ*N>)is?$fk$xi%`!~~R)Q(F3 zlpf&u$Ctyc1CV|`oj$(qM|H>I>AD})VUU2gbltvp#0}p-l;(mFzH_aeFtB8j;C=S2C5zx`T;v80Ty0p{PwJ52ea# zg?gOC$2a~s{R;$@KKircw76m2JMT&o5Y$^~D#z04hfcp$uu;Dupst&MO>#qaabb@Yc5jCFdKfg2-hJdx%hCn!z+Zx;1MYw#*H_C z=WB4Of!W4_om|~Ne&+aD=aArB3dYW!1B^b;6MZfn&YwpWU}tRFv~0ZHKhiN>qBX}^ zvsM!z9F48((iVoG+b;*yPfk+?JBEhMO%fNY52lS5x-ncR?j~Hhgjtos+VE(4X`-yo z?7kZgWfWE;M5Y%{kYU3PobdD+L)tr_6FTvm>0(L3o$ZdBbDrzYr7a$O7PiH8@rtwS zUf?csm(Rien0xU`ca>l8G%R%S3Ns<|)pB(L;ayJAFLxJ`bj5-zuXNqBuovjM3u)=P%Xg!7;LBT5o%cxqcdp;*Gj&wbFX*Z8(jBBrX6t84t2BJLp*hs>+VImZ&B`oTY>Lea2qGH z%H2;o_nJEps|J|v#Qj^?$-W!tJ@{>Nar@KZ^RB=5J{VR@`UBX&1``Bx;scMk?xSkk zV)~xr&QpPFcBseP$0a?BpHS+_BTq@dAN&wvds?XvKl2fk8*p6MB)a>&xIPnk zK%dTdHn{Cy{F3|Sue?M84PUj$*W521<>M&okKBt<8DIZ~T6Vd6aYCurzM1%A9nQDh zISbuy&vOIcp{MV{oi#!WhXG5hmG6DvA zpx=1X@=BUVI-R~96c}OBd36}AFwh(Y{xkeIR>KwpOb_(M!UxGPmbU!Qn@6rA|AR3` z^FQC;Kdle{^XAbu@;?D}WE%OObcX+#LH;M5=kq@^x&q*J(&T}_550MOMiw7*6ZxQy z(>@=xZymZIK^@>QnAtkX@p0rNPxzgId7U~?VyvxWDF7$0!_l?}Kg;hR z=j3O4NQcB_c%Jybz#`oN`Z)9e25e!Dz%^kIhyRl>pCX^r1J)6Qmd8Poj=hmi{|M{? zC~jn7gDL7kBA6S*0(#*~kRr`-rsJp6DJMlf2NZ9^HGTpJii4?S@`cA?s>y9YO{IH) z5CzXw*UM1jDb(q!$jzJJDNgx(Ob7TD!@~&wlGgl7KoSQoNtzGYi?8R3nVwZH^KFLHbtwgwH{G_MEkFINp>3S z7s}};NQ-=AQVxSCf8a0vhw~R$o3dPq*1>H7;eC}3_zUA!=)@d-xfRy9N)$I!-WPun zHvEO-X#PS6*9mPV7IMyoI4<}L2bV4Z<~WXs3UQfciQ_DFE^wC30R!dWWy_V0yK3=j z@WswWAmdd@Yw<-D*ke8Ga9h$M2MgZLCTH`O#HHsmyscC;EO54M7c6XT9K9>z>=6Ea zr_oZBRXt8e%D3z+wVv*g|i&;$5g>fG(z zbMU-t4;_YKm89R*B62V%9(vgMf9-t@U|dDD|IH@dhHgkh4G=Ku0x1Lt_3rN7@4FvK zHf>tcCQVZaC6J`erU~69A=$KP4G?L707U~9saPdy@Kr1tv0{bzHxB|-DAI>Ps}@Z# zYQ?Hmi&ndJ|GzW$-p%gayODxEeD8IVvomvM=FIn*GiT=Bo3@i{SwXXRaoSQ&*S&$m zyLwo8R(u+IaOhshkeHG7IgWz@2JHqnZp|?}Z8uqD7%NCi`_f}+X_#(q3kH0arm0C5l&b(g>rHNalM8m)(LkT4*VEM}_WgA3gNUK%XV@p4jF*!JhAAPgByEdTzBN2wx;BhYolBP> z^!f_@a{Y=*y&fMutzM3V(bb=R!9Ua!abw_abbZ_qa`gDjvA zHgoy<^)1bPnm+w?c+`_@yE zkLp+GZ*SYSO^=sFGIPhB^YwSl*H;eQt=He<=gwzz8`-%hocGfCCw|XgzWqM^$3Bi0 z8N6Swf8Z0`4*i2Di~f@j>36PKrq_Rp)3-hRX}un+^&>=9Kg8&K?(_Muck1z`odSdNpE zukS_SU>c!o&|^t{@|$=uB#geXaUZkg+Uxb-GU@&2Kc#;fVfs%}5U0oICXmNHQat@A zvzZTJI7gB2|8Mz~#?_xuZbd`lIiWb@L2%BP?1>wEd-@9AH_ zY00bKr##8Dp*E6>DGNYB^66JIVzD1~esUMqV$CxYtQHC9CkbaK*uW*6n>YG{2_nK?7}{^w?9oTUm?yz>;tthTa| zAn}}@V#Tc$#o*HA+_a3D4IPUDt++mIo<6p3mBf1OU)tBD>G7$ol-JX-=T!`gOm}AH zBf4yo4~b~NCK@P&Wd!MOX=;);LvaGZyf}knD4Z0t7%Ul+jo7C{DRdSSO{X=B6i0OC zijgY0*o2hTT&Yr%!aALOUrXun_ry+BJX!vd**BN@fo&$RUxgqnUG)lc_n$WdI$uB)#z^;_A3r_gR{dvq0_fe2@FJ7?V5{4{TfGed7 zqz_+0W>QEd*e2$S-8rF0A(0k$PKxPn7+pmwDIsE|0Y-8`*<#6NzqoK(UcMA}Qm($5 zZJHA(pT1`~40~KQIcb#|6<3M{E19QyRXmQ)&uUgnr)V{+*IZBTn$^nFST{BiJsc{r zPh7RO-gMIjbq1P#`pigMTU$HFq2j1IdnsoHJ>3|e_rh>Dw+V)BLjEHo6`kEzONts; zAUFB~Zp(tL3%La!nTgUn<4ozo7XUNn;4{Hm5pE#^g*T4wXEzGZ!fC3Cdr9dOu8N!J zvNKb*XXu_K>r>__#A3F>rVT8O`m4e6SBVgYU4rz7R~<7KF5M>n$%q9K788RU=Vi}7 z|NQLvc$DQrxaiZ0+4J$Fpz)%MrD&IA&%cE3@508b)sSEzBE!#JN`=RUL;9B@XV1R^ zA;4tM$1!kR0i=p9%ASvXi79(NCR6r&b`s3Fq>p?c0v;Z~yJ_&Hk7BL_-eQifZR1uF zGmF_5-ItIXyBGO|Gq{wb7)&lI0xKEEU3Ae!O2Be%#R~Q%kSbDora`aB)ShTweEDrn z8r}^LjVDx|H{Mu3r(q7=titvN7s2Mtq3`d^nRC;eIU8`-6@$9H12m;C-{2WtWVZ$R zU3Jw}TV;b+^)W-Gkc`wQy-M3i_AMmfXc&A|P1A6F35KLF82bGv;C7DN)*qh%a2!4j zf~SNr3z=cxa>tM4!x=9#h}9R_E{N07iX#)dy-+j+L_ujjGJA&Kr(GZxfu8)1} zQ>Z1|7cvySarA*S-3LE} z4Z}qjBP}kSvJZzz@rl@_vVe41AtNpQ;EhgKsNdwCoW=Ld{2LJa?5 z)*msP;+PwgD!DTK;`2E@IQ8FS3U!wx~lLiU&bXrDlT zvX!18dFOC?a?DM~gAxeDaDpofU!bM}o{bM^Nzu+p$D6ni5B7ougnA!^6OhSGm;a^6 zK;s|Cbb71_zsjE!J1?E14;rV_7mZ~KA0#iiWj}VyMx&9gL0^nh6;%b5IE)$wEbL1! z!$(>1VwfvIpa|i3U>-{pGfM15N+Bd04;E?~j!!W1E6E@tE6I=>L}LuT1Ou!^`m{M;JiD6?LZ{K+}-~ z)He|4R{**{@+RO#z(K$`fVQK51<)pdRy=eQ*8qjZ^S~7&AzjsY5t3eiYMLw%slHX_7KtB*y@;j?pf!}oqIkD zrsq}OKUbloZPQqwcYJ*CLq;8*L*ekIA*6+ne>tf$q%=hAiYpn(xkXn=Hv7f%?0A

$header

#else

$title

#end if - - -
diff --git a/sickbeard/failedProcessor.py b/sickbeard/failedProcessor.py index 293da42d..9633fda3 100644 --- a/sickbeard/failedProcessor.py +++ b/sickbeard/failedProcessor.py @@ -52,10 +52,10 @@ class FailedProcessor(object): self._log(u"Warning: unable to find a valid release name.", logger.WARNING) raise exceptions.FailedProcessingFailed() - parser = NameParser(False) try: - parsed = parser.parse(releaseName).convert() + parser = NameParser(False, convert=True) + parsed = parser.parse(releaseName) except InvalidNameException: self._log(u"Error: release name is invalid: " + releaseName, logger.WARNING) raise exceptions.FailedProcessingFailed() diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index 78c14d47..fbe1057d 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -479,8 +479,8 @@ class PostProcessor(object): return to_return # parse the name to break it into show name, season, and episode - np = NameParser(file, useIndexers=True) - parse_result = np.parse(name).convert() + np = NameParser(file, useIndexers=True, convert=True) + parse_result = np.parse(name) self._log(u"Parsed " + name + " into " + str(parse_result).decode('utf-8', 'xmlcharrefreplace'), logger.DEBUG) diff --git a/sickbeard/tvcache.py b/sickbeard/tvcache.py index 101c17d9..aac429cf 100644 --- a/sickbeard/tvcache.py +++ b/sickbeard/tvcache.py @@ -264,8 +264,8 @@ class TVCache(): def _addCacheEntry(self, name, url, quality=None): try: - myParser = NameParser() - parse_result = myParser.parse(name).convert() + myParser = NameParser(convert=True) + parse_result = myParser.parse(name) except InvalidNameException: logger.log(u"Unable to parse the filename " + name + " into a valid episode", logger.DEBUG) return None From 90d011990c755f96a8041f92962e5d05d01b5d2c Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 04:04:20 -0700 Subject: [PATCH 51/82] Fix for missing regex module for python2.7 users --- lib/regex/Python27/_regex.so | Bin 0 -> 1092775 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/regex/Python27/_regex.so diff --git a/lib/regex/Python27/_regex.so b/lib/regex/Python27/_regex.so new file mode 100644 index 0000000000000000000000000000000000000000..760556b7e6194a1caedb2a9c16ffc3efb9c605bf GIT binary patch literal 1092775 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

6@%JOt=py=lE<6FBa=TS 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

-j)TSGrag(9>a$6QA;?8{@pPRNKeg0el` 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

EMkV5y+x&B)IWxcga+-f7lF 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 literal 0 HcmV?d00001 From c5811791d0ce5975b3679aab4eb336d31c0d502b Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 04:12:48 -0700 Subject: [PATCH 52/82] Fix for missing regex module for python2.6 users --- lib/regex/Python26/_regex.so | Bin 0 -> 1092655 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/regex/Python26/_regex.so diff --git a/lib/regex/Python26/_regex.so b/lib/regex/Python26/_regex.so new file mode 100644 index 0000000000000000000000000000000000000000..fb66edca1ed6a723c4e094461274c418140724b6 GIT binary patch literal 1092655 zcmdSi3s@Uf{y+Yqr5bBB(N@LV8Y^A#4r*Q4S`D_egHjuN6Rnj{N(Ky|L6bzJXgNK>RgNKbX+bD!q`86AH)~kwDKi-c63)FkZ^QQ1?U~eN#vtF(B&Xe`j{{2sXTnLljmcDt^AMeXJ^2F}F?!V@|2a1n8=E=ruvVzCD zP945~=KR?Q54+^*v3pPUoLU%i=DwlwQa|&}7p+2G7vQ~msg&P^^1DbS-BiAURve%2Kl{FCFJKO^F_N^UT=}#+mN=u z+>XQ@^7?1nf;;j4E}Plk{zVe)@_P^PUU|I_@9)R!19*K9uj)m$5B1X_zYojrqw@Qh z{PNG^1WzE{DX&k`vZo~dG}$vqKWp>Vw)g+5w`(MzOMah2;PdkO0^Yxf*EgEh`}X@w z?OSgRyXdHl-^5!-f4lyePrp2R!v&pZZ9g}=Ywu70`OM)jY`^i!&tCs(-v^HT{P6CT zKb_oi!1ELC4f$`|=Z3|xXLp?P$Iz%}4lBF=KG%7Bt(^A#%GbV*^uGN3qg@BZoO@m8 zp8ed0dHWrC!=E0Q^2}ksJLl2UzdzhNq2;yx4u9yP>64Ft;poTve>^Ymxt6c@?ff;d z?x57R`%>$d#qTX$d&ZyY)>d4*;m?0RXXVvDJ+WU!QGd&$hiYXHK9*elq<-R)lit4N z{gG$hx8sRl_T1+7zCQ8Yb9yK3IDhZDDd*0*bKKS6PWgOF>bh}TMt`;b_JckSuKjf1 zkB_UYcI`c)@YVa0kG?tg#!1KCx$)B5TTeJ(-vyJ3-uOIxZ#-+odENJY|IE~h`*>IU z^6-1tywm^M$D=EcK4p61`|RtQrrm!>XX)d^s$Yt4Jf{DfBYWp$=C9aZ|KQZm_L}=x z$(rox=eYfm@4R2Xby?|QN42!R@E>i-TNA3Hhiz>ias2Q*cYb{PevMD9f8>X+jyQdh zRsE>_U0;SvkK^u6_je?@e>xc{)kdv8(Z2X?831Zf z^XL%umNi5^z9I5)4Y6Mj4Bk#==4N*=tecN4ms)xv5O)Ga7-#0}3JwueIWQh6{ z*4#MP>@SOki2r_w`l%VB{%@5`cUS%khbVu^5I$^(?RF30ONOWiHSX@NJa-PU-R2?c zVe}B~>Zu{(|2D*Sn}+b4hseKvh;q&tqFqfKBL4Xy;-?Q$pH~l2pF4)g=Y=7*+dV`( z=^tW$e;8uBR}4|ka;Z z43SU1RDhc+LDF-FsOQWfe1@zub~pJPI>i1yF+_R3l00_TKM$AlWp^HMDBoKPJ|a6V zKP!xXHEon!gelh^H{H7SsFQs5(+-l0r*TGP4Dn-)_O`dyx7CcVgfEeKj>@O?e$yAj ztB`-N({y!xqki@oiS0gXx>cS-B_FljIJW!8(Pn({K4yGuvl(xd^Dc3hmZi1bXO`29 z*0clV&Hmab&GC{MZ+S>|)u@LT)628Ws)r}j{Wh!K9yQ%6=c!itSEt9{Yk60?&$71r zLb{)1?boJspNe|$%rW%<( z8ALg)Yt0mnW3a=Fx9a&5EB-mtt>gHrwZG&ukWUQdxfI)d-m2%P&3vr-e9@}sznX4c z51)?u@zQbs*=kp6f+0UvKBrmvJZ!pEesztm+Ew&Qvp%cL#m3mR|8A}ez8;14w$Th+ zYHUT*=2+#~lAiyuR{Xm3_zsju!+u%ixef8!1~c9|Uyii)3+JO%&zD&ByvB^Td_NrD z;8Uhs^)MdoM5Fe0xOE(H-dXt+puGjJFze@ZGdrye$I)}230Awh2<7jLnr^kjr>yq# zpy^h-`jh1km~NHxRI5EaVY*eGMyuX%-dXjgTlGWn=UDqi=i?hFrw_-`s^_G&U9=x- zyDv(AtNMq&JI(T_d8hiBZIuW8r&XR-tDe`Um%qcxAIHUt51}43)Pv>MTIHwX>q2|; zpntIHEgK$%OR>mGJBs>@qupBd_Lj9@ z)NeeBct5rCd#reBCnt)l^VGA-Y=@p~bH6qsKKPJX&sM!1WE~ee-zQ_c9<)zuzb=Ej z*PHoR{+iXU&@Wl}yR7~v=TPQDDS@EoC zWeX~6D;HJQ1uAQ2O`Ej1W@+WD^7)G^&1Jh^QdZGWt}-ZJTz!QEp1rJW26C9RxV)~e zvQDe5EL&6=DD&6W_$zAzmuue33u_mZdCP0-DreREC3o-TWoOk_FJ3UGd~v->l}G`~ z&aGT-y`5PZC=OIE(aI$7Tq)DcKy7_Rz*<`9_g5}mAbVC3xZGb^7O1Hgs4ZJuQ(?2k zHOtB78xbg5Rb@ljg6c(57l4KJix-zwl-E_3Ev#9*pnB;dYe6}@PL*c%(&~zu1(mZW z%{;YiR!xc8hFV8TX6%@;50YVJgTH*~f-Ey=+OzbmrqtFfLDrJh^!b-mRs_ms zs_OM#Uer)gHcR%isJ6DIR;6oe%On@65>-g=)GrNGFG<_tl$zQl+H>XI3wg zMpY+qGb=BvuUuMDStg~MxwyJQPpa{&x-{OOTiKxM9V;3eIKQ&|(ixQt2Tru* zHMI-M=1U!4DuKJyirNhzwqcxZGb)!=$_Z&T^SbIKa%S%K3|LfK?yss`A`2JStBzt| zQ|eexlk-DPyd{-O>M8^3rNSsWii@QK#V=O9kDLoegD5jrEf1jb)nQk=zBEu?y;QXV zmHmv$f&7=$EE_28qROR}wbGUNc@(|u;3#;_07vVdwe zXle6}3PPf;qPE&Uu&AzbX~5{c%u^CE(tTE0E0-_!SC!AN3{+QGVhmTtP=at{OtXV} zUnU2$rq&ps5mr%EzI0J#UD@)g%B6D5Fdi+ivQ1k&kmc?d2dV>$E6o#VcbTgtYBZDc zYpBIb%4HxPSX{lpoOM{?lCF@GyLzb%`N*MxV-#@Eg35*E^@{_8`z{d+P;Z`9*k(g1WN#vhTH*m#L{?xy%EsY}F!l>g{e>ZTW)git>SjP`|W#VRhw#vVncI z@-VmkKWQ%uWc-!39vEz`bu|kEWeaKoHdNNu)Ex_#Nz%7%(cztIDxRU5Zpvkbdw z#%knTVwH4Rd2O}XGU{X$sj$_9zg&t?yHrl-T^gjdsP1wZA{(r%R0mMMxUBAS^s;JB zY%MdJu$q-yQc*6)&)BPqnk8~5WDY6Ax-DQqr7ZB*)JcPp>8m|6nO+9U%Im7jrEt{? z20Jr#PN-}a)yhQN+Kz?x4CH*P#M}W@xU_yrWo>mu+GZ>>x@0RmV@H-$t10l{A*)tn zr8-$^%XgUwn9IyckszKY7$*+4WNo8->A*B%{^Ih%uEA)_R*+ws=s>TdCIr@k2J>oS zarJzEz?j{fSXXmmt|sXU_3kvSta3qlpj@s{=GWDsV=Pl$)zp&WvnG|Dd}7|I18+}0 zas0shQ_KrI^J*0rd;hOqX*v|HjY%DmRst88b{9re*wJ`kyA{9KUen{`V>(UmBcB4-@cBEdoVkyg@h8G{)BT6-X8s-Irz8JP z@&b4lxd$F4KL;Ksp9xQpTjl8^FGYNc+$yJbR{DNf<#do+<#dymd|=i?4!KpHTym>C z`Q%o4Jmgk+baJaaK60yms>rSK_{pvEG>}{636fjoX(qSI(@t*HPY1bGo=$SBJYD2g zd7|W2dAiB1^2Eul?Iy@CMmy;vxAM^@rMD9+9|yUWkBi*O$4zeKlS6LpZ!WpDzxm{g zP<{`&wOt>%wcRRmYrB4OYr75P)^>yB)^?l8t@FB_ycXr}9KxgIEjaJG$%F684PW_* zlV5@S6XbnyBV5xaryt*D#5>4a5$`5H#p(yh{g<2N@sQt!{B?47(kzdU{OR}2ex{1N z9pwpKs`6k47kiQJ?B=?}+V(iGjhx{Yt zlOp#c-ZM45{C$Ym$=mzQdMG7tLq6@~Z=jqV#nNJV7 z?|3txIQeSilOT^FpA>oUI5QtjPp=;*>c>Iedb?SkEOOtm=K5~(49o{|$fIp$KKbOH zW6XR!iZ_Rvy ze3Ug`B5&Pf_77d;(Q#&ZqU3j4?T5TIXqKmkJf3al6DL0q)rv*U96EZzCU%c=tK!<+u7b4|xpz zK#;r$`81PzR+{zSPHwfI4)V^c%=j+ysMT+fTlLdT-iiH7!Exy(x8`*T z@&?5Bkz4aU*LmsX>_U7NxizoLCtryD4U#un=Mj1CS?2z>k*BcT4)W`fPbYcoSu>v~ zdH$DXy~W7ekWUY}FJbmS335O3Ns(LgYHdb(y=mAl7kNAKag*PL^5l@aJ}}FZPaa1; zLGlOCPMXQx&!L{lqi34sZYO^P<>?^zM9qA<$h9-fe4^x?$fuh;7y0y%drmj=iIYEr zd=lhtHz&o@SP(o%{{t(?RaC z+7G#VyqQmw{5|B;O|Dt(hum|DnNOVjW8{+{?^|c?SBl)1XXc~LGGDFs^BMASkjIfv z7P;>vbA2~?AM(i|_kV};ojiV`nU9Cu8ozY%+;h$S@{wEPR~5M%@j>!mQO;&^Yn+Ob zyI(WQ-%TFe!z@pXJPPk2*Y-5yLx( z(G-Tx;KW}3&VmAnt$#=hOG=XP=*yo0R-d>{H^}Ys(%N$RsSw>tNydtaU9*` z+CS0$$=&c=@?3a6xfkvsANi3v-s$97a4-39;icrca3A>@@G5dI+)sWnyn*}@c#!-G zcr*F6@K*9$;cevi!Q087f_IQ_fOnF=3GX8R5*{TV_OV(2-Q)+uW8|m6d&sB5 z6Xch|`^Za|G&Z=apGCfrND0A5O71NV`ygjbQ@0QZx3z#GV4fCtI9!kfwe4R0myg}0Ia1aBwb`%|-? zJIIfKcar}O-bH>6JW5^x?+-5xsAlyT)Jz~b|lWX{% zUI)4Lz3WbL4c|BGA`il&(j`U#F7?;a+m< zd%vaRL3|(BN3P-fqE+NUxSw3Z_Y51zt?wTO$*u4EHIoPNJ-}9S>-&doI zec%+i^?hIs-=DR{uh=Ft9|yVhy?Ph9^>-Gs$h}+4eB9*L_d>1j?ONOQsXx3TKRU&) zfqTg>xx-vDCCKN)`^c-|De~u#zZOjIw`&mZAYTS| zkzWbVA`ijch$)%6Ye1Y749M*hWg1O-vjO@e+T8s zAs>nOT=IS4`Q-b&<%b@G0c-%EZ7;!DXtMLB)s!x3La{w?DD z^6797`7F3jej(gTJ`Y|>?t}ZtE8tb+m%#nxOW+OUet3|)4&F?@4Bkq9IlPS>_1{ju z3En||CGzPc55l|18{tv%YvJAG5qONe72ZRB70MYWzZLNb^4sBkzAF-Q!WIorwI_}*Lx`E$3K{ctDw2gtvR zd@JIkke`Zta>)zf`Q-E99`Z}zI{C}DoAux&4QKzuv--tZ3cec_$tqv2iThry%dN5Z?wkA}y{bKyPY9(bJm z9C(8KJa`}Z9C(WS0=V{v^!9%d+(G^}j*E*t0nZ}$As;vSrSKebKRlPb0iI8O72HD} zg6rfha4-4o@KW--;Xd-e!mG%ig8RukP(Kai&mulZ{sO$2Jn&bvfAV#RZzF#d-cBBa zcaXmU?<9W@-bMZyJW9U$8MB<-ZgIlcXt!X4yga2NSPcoz9$ zxSPBVo*P1Xz2tv}my+KL_mOwNtH>XR`^leyH;_LM50XdW z&E#9)t>mx3+sL=U+sS+29pvx9JIOzScaeVvkCOMnyUBOJW8^=>d&r03e2J4g;0f}5 z;eF&|;3@J$;95An{k!1~^54Q;lKfp`L?}YovpMqDBuYvo?f5zYQX&{dxK1jY5-b{YMJ(&NHzl``c@_)hG$+yEh z$iIVkl8?O8+-?`Se~sx;@^OgoCNF@;$i46$@=|!5+y_sPSHb(p{qPj|D!6uCdi%cx z?jUc6yT~7fXOVA$yUE*7Z#m>$@Lcj9cs_Xw?je5*+ttb6g?q_AgqMn}CB6OMbemZ}4)QSKUF0{yv&e6UyU8Db=a4@M&m~_A&nJHg?je5#u9Lq8_mck$ zUP}Hs{@$jK{D&vZ`l%w1BOgEcSMUb%@8Cgl2j=Okf$(Ju1|0O zFT)+=Z^B*V+u>Q{-@)DFd*J?64*CA@T=H@7eDYJ_9`Y%0o%|;}ANP`9fcR2!FUAoc z`5rhgs>mymkDq)gyn)>MySqX16^L&pzZ%|3ejU7xyanD)egnLNJOlHJPV!q2-$ni) zJWBpFyqo+T%u8eBTM*wvek1ysIQicZpCJDyypOyGo+5u2uKg*!{eJ>?kbeeuk@vx~ z$iIcV$$x<7knf54b}soL@O<)P;U4mn;5vCe+)F+gUP^vG+(&*Pyo$UG?kB$l-auXh z50VGq&EySuZr)110`YC+&G2^eUoqe4AioRoo#c;7({>I5m5T79b1>Q%#6XSl0ycP3& z?S}OBKkNa_|H%)9yU34+XOT~UyU8!ce&vvR5T8pv37$``!#(6BaGiWQ+)Ez9eU(yj z5BeD&`To}YhkPFTXFvHIY`1~D1M}@5c@ehTOghP86GG9H#|Z90lbg=6L^aJOSpDpdi&3K5bd9Q z54ekbZ+I5D8}24Q4W2`O7Ce{yTzEctDcnQ85U!IifqTjOto#4uD-iD^Uj?rsZ-)EH zAMG&fvw^$?@j>!i;mzcC!&}MkhqsYG25%?tgm;iX4eum>4&Ft+86G8X#OIW{$zMZ! zjQl_F9`ZOmPQD$UAYWo#|B`=#_!RjUaP6k__CE>zvxEE_#Jk9M!n4TtLOyQt1FZg^ z{4jVf`BCtE@{{2n^54UC@-yLHavfeuJ`3(6Uj(lrzXt9nzYg9&-U<(r-vVzYZ-=*% zKL~Fle;VFS-UaUxl@F;m7yqi1|p96`J?*;E6KN{ahh?BbzpCBI#?;}46o+3XPuHBN}{(lE| zkWYlW$j^djk)I8Blh1|ckS~Vkk}rejldpn%$Xnn#`EmHWa9;8o5noEa9nY+VMe**b5ldprflD`UXBYzFvPW}eGgZwRcCwT_Wqb~Ay5g#Rg zAKp#=89YY*CA^1xCp=Ex4^NQqfpMgdd~bM)-1`5uX}6}g|NRl~AU^=^B0n6SMSd*Y zO@1mohr9ruOI`@iCw~aX#Y5hYenThsA|Ee#4A-Hh;(E4={65?_i;_PD?z2sfE4k{&IhxGAg@Jyko*dGGx;^}R`MI*ZR8KZ z+sXe5?;u|T??;?K<9wmPh-c9}yJVw4ho+I>-ABgV-#L2%#J_+(qaeuXs{CmWw z$Ww6b_Vo5Y()#=l`4!gZKgs7~zL7=#EAn@fkHma9hx{OTF8QJGeDe3<9`fJ7b@Fj= zFZnU>Qt}hvKJt^{Rpj|_Klz#P2J*@9AbByonfyF>EBPFF8@UhOPJSu8gM0xPmYm4hJLt*{0`(3Cw~N+B7Y68-I3n@--J8J-+{Zx zx5Kl@lW;eA73MiP(~Qav$7BUIVWpuZ8=`SHT;|w_)BDByU7~Gx_cC zR`Ms{ZRCH0x0A1jcaU#_cam>|cagshkCMmX-Q>OS82L_k4|zX4PCg9nHbK4zypOyK z&o@)#qpbFSXL|eJ5AGm85bh#B1fE5H1l&zN4xU4v1J5Nt8J?d+;dvhwyIlPv9}~Z{R)TKfvSUBXPZuAa}w0$S0$nq{t6IymnW5`}gBMfP*{> z@hyLc$EAm zcsF?)JVt&OyodZ@c%1xkc!GR2ypQ}F>-v}cImBy!NpJt_;12Sa;V$xb;aTKYqW!qZ zyM%qOGdwTSN~zX~2BZ-)1fUk{Iy z-vLjMKLhV0-waQYzXjLsPH+FsxIT4|e}Q-x`3O9(&mtcScaxt9&mo@*&n2G@&nLea z?jf&&>*SZgz2pISDf#7aANg|Jr>!DyLcE{+I(P&54e%iO1^7F7&E$VZd@K2V@HX-e zcsu!%@DB3T@J{mQ;a%iWc$B;w-c25Z$H?D>_mF=DkCT4~Pmu3~_mTI*Q{X+7j;AYLb*0r!%h4=*LZ2<{^< zhgXp=g!{>tz#GVG;X(2%;LYT#;H~7%@HX-`csu!h@DB37!aK=3;a%iw;ZgE!@NV+| zz+>cn@E-D?;c@c4FrQD59{}$oA7{<~$xnxC_oTP~3Apd%ATLC`i+l<^i~L-;n|vlb zhx{UVF8O?TK6xj`DGzxMTqj?Ge7xi<;icr)V_xJVzXkKFD)Q^#e)2yc{|53>{D1L+ z%i&(~f8qa2TS|T<;(g?QfLD}7p z9$e)FGl0OgcBEKK?A0_|Ny8lDodOO-b`C8=PL;eyxPW~!9K^}wm zk-q^?k-rPq?n`g~-@qN@zrbDOd*S$Ik?#w4lTU`{kRJfgCC`HAlOGQEkRJut$#dXd z^5fv8Ah{^3&lBgKF8)>o1bsp#Je2WKsXPP4chv2#>r|X=6r_jQ7jWxaUL*b zoksdzl~zM{vfW7Eq0%E%y46VEsM2bvP6mzibtK(rU;~YDW5Ol~zM_vhP=c zac8Nt8lsbNBmH}oRzq_#W~5J6X*DD#qel8zl~zM>veQV9RcSQ@C)5(d}hT5dxNDotKHN+-;MtbKQNvokX={3^dsI(eVlO7}enM$jnG?{Cp zKU8ToWlp+{^xG<}hSa3XNN-bVHIybbBmJ^UtEqId?-#ZI8&uk@(s3jGyh^Jnbuwn8 zpHk_uDjhY_kEpa7YLlHt`d*b*Lu|6$NZ+B-sxwKp8tEHVS`Demppm{#rPWZH^c(4G zR9X$8NuQCvLZ#Kvne-azT9sBqX3}G%FHvbVR3>wc^n8_8LuArzq%TxyH8dt&MtX)y ztEqibGty_Pv>GCleLow=U!~R1n2a0g->bA55|c3_eX>fcp)eUW(#NW_8UmA@MtZDD ztD!I1Zln)UX*J{}TaEPoDy@dPWY9>DRB1KDCH+Qvm`bamE$K7TJ7-H;4QWZQk^V-d z)lio780pVcS`A^zTqFIVN~@tO={C}DtF#)jk}e~?O{LXPmDG&%%POrdQIdT>8OL9x zJt`eH($A~38mf{pBmI<0t05{GHPVl$v>KX{oksdzm7c89?MC_zl~zMkveii6sM1qZ zI%uS?Q)x9+CH+SF8kJTlvtkd*Wo=}S~v4MoXZBRyZG)ew|) z8|e#GS`9r(myw>K((2MEsTt|BRay-}$-bTa{d&uY+&87KY?(M#US{jZr1bE|dMLH; z@?rBfN=N$9d1goY&Ak4&>Mte!$2W}lZ{)>_U!NMThd1c!KRZ*;i0QAT>W!5TICF+t zd0XI{d3tzD|A%V*;Kb)-J+1y|Jv8xXSu9zEKMsu2BNI2w%GMHx%MnRb$v^Y9jA)g> zjBhtCR6i#=k7$%4tFC-v^SQEG;I~q^btv2+v!(pC!je~iY+mww$-sF;P{k+Dk@thE zw>np6{!X$S$gg>fN)D#=mh|P$HJQup@e9La($W&2mX2huNy{%hCOs|j3I?{{rAC^K zgXz#$BSZbeowr6eE_5C-S<~|5jlF!~o#8W#bwVG$ANs5?wDaKQj?fS8&SBw|nNnA+ zE$6Qbr$T*hS>T+ybz^JG)ODfM!OI+2Yoo*(tB23nXyhO2FAkp(I40Czy>&{aYIR*| zs0-}-yc&@@hi}b1uv*@HE5T;{Kc8vE^ln$jbN0;ePwRVKYS<0^RI<#K7gdAp+ zP$D%sN*P`mYS(-femnd_|Cm@oB5+jGJN5q#ees*nFOKE^)LRbFf6UPIicyc~8853w zVytHrviIrMP$DCg8YcD8`;bxI@cQR9zoxyuGaL)WGkR}SX-#ul>1&L1Di`TwjnNXM z9+k@=Xt~)!OpnSTu>4G0yy`P7KicLQ!954uX?auBc}vt7Vb$RpJf2b?1S%NQC;ty;E^S!Foh;VtVjv~#q?{W4ZHMg!Z;dU#J7gIWKfUso;L zdtp<*^X90LUvh;6+P0UxG(G*_w{L7Kyd`m(u{GHPW2R&;f6LSzq15nYSy%TrNp%EV zSAUh`mU8!Js3z(>LNm%|Yro;0hN#xLvp6v7>aTL8cFl0rh~%wmZ|4oRx4^io`&G== zDGt@ro>wy&IBYOh zySiUxxpm4Yl~Mh>=w1eoSHYXAW(U*G)zdGOCi>Ej46UW`htp>*KiauEs#j!QBOP6T zd||5|nd*(`nN2SRR_T#5RkRVd>@7XCN{)6oRewS#IV||&najuN&z~v7)UO%R={oOw zxo(;saXMF@cVTenfq@ahos;V`^>BBq6v$}jdgOestR0z=DgEbXvK6;fgS1yYvZr&k z|H76z&j)vo(A6n!#(%p}qUHQAJYNsT3g;AucNESpoHcuuI@WBYYWYCCL9&t>dDM9l{(fL{H<_E8=G7xNsm34P5-I54Kfg$A)mTk7J*JZl!#yrN;*~2}tvEa@&ruxC%qxy~vh>K9Zas3X5f)mX zp@(PX$`HIIx1`{;`nAOo*?S}BZ#TA@Q^%r(+g4lfSJN`_zCE|JAsJ!%f1UbAGB>(__hrdZ#4mbzF_ug3LgTr?-r`QL@WKcCwed%TBd|-DOwzq#7%NYBPD!yluMluDW&J zgtzF!*R;zLJ+vW1m;PQw$*WmL+tO&2UhuLkKxwBKrLA9A9O-n(ew+F32%J5T?|Oas zpW0Q4jC>1`Zz1v>TpIQ21>fjf3z2Uj^8I$BF}}%BDOH(7yxx{6BlNb&sB0!i&T{8P zi^DIK4F6M5mQ5>Izx?QuiY=in8G6Nz$e5?jF1UHCPZreeCq?K~Yft!7m%PXjyUX}g zIHxfDX5s9Tie%xe;_%Nhd;WfA5!+?=h>)Z$1ab|d9X#3a6l$sc|a;=pZGas|o4mE1+4%wa* zbdFVPW`APT*XNNU_wb_ZhP@^f_uu1_vTDT}XSt4O_(`%p}PM36ecD62&W-T6P%V+)0GsCZ|dO1*VuzXxU$ICqf zt5uoxbDfkz>gU}5Qa>Z4epX(!Yu(hUy4jjuH_w~nxYVqzS}xd4waix4@<)5MTqz}& z^^ASXC^{asVdkgm<04sZuMbr}QXdj(R)?w|eV`srl$0@_^QjKZI!|O)rHA%ZNwlZ` z!|B2~GW)#yiwsRo=hO+G_k|itoognQcDS8Qm2$NfTyf!r&TC(n^TfIOoD1bb>N-8+ zwf+xK4~bB>dtrD|X*i)~Wat9qJd2!C68Ha`FWQd*m-DO*3kwp?vo?n}gkF}sW|j`*r0Q#u467=y$&o5YVw#cPOs`rmGO}1YiMVRC zEo07ht{LfUd{7D*dTIE=@W{f@Fa6HOm6A5DG#ARXpmWk2vRbC`0WjyJ?r>~j!E4S* z>v!F%(N9RBRf*q~^H;Wy^8Z7fqzo`)+vDnCHrZ;`(7KTP)9uA{&zVjUG8P=``M&?a#RWmfFgc+Uk8s)xWWS zZ^&tC6;!V0wirn{427Xz`8YJrl>JSfE&r%`wC9(+%Ggj)HZMmhLyl5%wjt8*hT>zA zFQ{Cb`qhlA{FV$FgY|03{ zK6j&(*Qsxvs&4nnouQZX@N~IWnC=Q3>s(!U;py}0vt|Bc&fg-^n!R#yG%xU7aOa%B zS9-yEJv`MB*z4Pkr_TxWNL;Yt!gE@e_c>SV>I&`CUgIW$w0*gWphsMK_un(8Cu zyb67urH6meTgDITmjbnvWXleIm={fK|4cd`nIp=?Z)_xx?TDP7omls!41+u5-qmk1 zhG~sakMou-61kT|%Ct1g%&%o)hAjMBrc_v7H2FnR+N%BfT*qWFa$C@d&?CzmB*Q=d znj!ZqC0P0oqcqnGTT$$}C z34dAGKgXw6qzc2E694%`HG!xe-W-^e_fApMN2?C+U2N=k_&s$8F#MG+7lw%k)s_q1 zU3p$%Byg9yxj0ci3?aLAqPVPH|C%0JqGbdw$@@ZfG*`FvO&yt1i1Vcoa*Sf~QsSK4 zhr2jx2jzUo%pNz^BX1_Ef9u!jErD#8DyWpwFGIx2$Mnefl@ryyz^@YLCi?q(?=<_1 zA~_IW^?P%Bud~;mOrU;|^0i1E=S9`ka#kWNE9v2las?ob_Xu6>*jI^6g^|7Wmh)r> zk~()10{F6Z2iYfM|g7fC_Vgs|BT#-yzBk9eS3woDjZx zzsw9Q8@v_rf^qB3*`+#~r-v7A%`|RlBrf<^ZCZ;2?^nHNsyL8Ykf=W?F;+Db#n}c| z2lka)Ya{iF*W~~dhBI#-m>dKpJDE3F-n&`Vhj9d&kVy_%bkf;>Tt_E zt>X2`k>gtn3;q*u7q(2!&X`v5(UkDw2eiR)WZ-`2+u6bW&dG)XTlErd&IJG|E3Z+VxA1Hmy_N3}#)V-e# z{U4g+YtuXCMWkeAlt)c(Z;tkUVf82BfE4Xo*}9zba+h0fgl75|u1^e?o0kO}2UZ=N ze;M)T?-IX{72kUk#&wnNNw&Dvll>W1Q1Vjg!fbJS+TzUZ?==vrE?;E7jqSewDVKBP zK%BY`k~pdTUsuV6iBb6E@PX}w`hV-Z_I*|BEhGA*nrwZmIZphLSpQ0fX51!~%k5;p zF|c^F(641i-K*_8o3@E2Kazh2&L^W>Q+FxXz60e78X1}8Kf)HbF4Hfkr&-L4jF_O5 zPPXTkS`YoYm-FTgd&Q(AX2kC$!r0Wi(!rUB%4L*m$K=|KOlOlh8p}9%wLC+SiPp{0 zpj69on4H)KZ+NuINjetcQARBc!n;uXR*BcQcgkWJ=yc*4o_afW#(4@_u|m;*%^WCx$|VizR2uXibI*% z871LLe@Qs5x=qoblw7XAC#x~~Q#G*tQ_j!A+3Tu=aqBlH@y8F0@~Z)Rdfq!FkrO7J zCWC6rg6zY34>ra{V|X(L?ful|LqAmoDhi!zX3f+7raE=WIy@`;u*9tQkX!4seK#qO90sc;#C^-Qm` zagywfTBTV%FH$4=S*m6tvmHCGQQMHy?Q4}+!6s*;YJ$NP)ta;ER}~u>(SNF%kBqOqP=(`yu~uzyUpwB+P>a-v$-8**u=Z=K{*$J*G|mPu9eBwBh494FaQ z*MFn~`QBJZ%JhDsL(;P44^A;^r3_nE<&hccIJN5F`EATNW#%B~d4nGQq&WO>;$X>1 zZYhk_rOxD9J2fnDh5VZt$X0b0SQ)%BTUC8XRb6OPgKkd9RTW4ZYb|LRce}Jxb*f#N zU8;GUtG`%zxU_pUO_N!mx3K?T1)Bpes0OVUT$Ek9>JuZs`l)Jbr7A<@g#DNN4wn3S zA0JG=B@LtZFIHMwO4qxx|9;so*-nY1J0#uvgjqkvv`BU?D{+nNzqA0EIR?(w!(Zy* zt%FY3~Hs6#3fMpa66zNk5+F>Xpbd&NFK!!%5FoAN09s@2&t7&T6p zqt~)xpHTlO=e4KEdl`cr+tpMBS2wDDTE?IDt!g48#-1#PEs`%Ak;k;j#ZpA0A5f=k z%lIO>Optq*a)Wuq$iX<(Sd(W-t5?^XM%?$mm~p*tTJ5N1`~%-8oA}wYlE0a`)5tt1 zM^bJ79%G#mPvvE6$rVOz%6KZi#aM5|hsrAkyy*+`?8XLv{@L7Ma=v*SWW8mwUhnmT z+yA4ak+BCQkn2seBt`G2-88p1+T7k)wY_hRR&DxaQoiIn2FUs?<2QaSn{1i5L0%FE z2^ZEY6q5BALt74S&65@vxX4xyqHOd&_7}YT%I@^jEp$FtblCB?nB&o;E=SVPORvj5UJ>$}aNNtptzcHOI&+(O|9|*r@Jt%0`C`jzKbomxM7Kne|~CkEH3|(VDko-4Ala z5|d>Tf__Pwv#o!y>Sw#E39EkIREee?fy?Ew@~3REp6~%zF9q-vb+xdkS^Bi1b!+Ji>H6h?R`@%arUed? z{^+V4;}i&O&Q0`7@k$D|*MFwYdg-anu0EL%9yni({=gVZjN@F$`A?C163G9jfLrok zA$|7d4B19i;%>G3krlDTt;U8vuKyr?L#vDp8T)JYJH~d>+B+U+y5u=vuxp7tK+)=t zmpe3x$wt=0VS&986{s7~A6X?sh1@?%3^Ue{cfIRu=hNWx(!mWJmslp5 zg*WRFTmHib^LMEGFV^!<$v^SX8#2JXY}SwZ3_)b7OzDChQrL&(*Hu4Xy*TPetNKk| zC*>GCpQY~f$aI&pSv?QZ3;v-V`#Pt;RUCd-W@66f7DHdwo#(!+hhI%xtQv0k%d=Zf zck9QzXJi+VJBMn#GV^ITb1)CR<@mc~by>8np;SHFlT3=kuOyz60+fV5(OXW>u`+p3 zGBL;Jyf383e08vVMR_0Py<-gK*7D>s>7NGbSC;oaX0K1#6fp4_wkyDCDY z$frl<<;wgqU(NbfltiXgm9&iU6ifdyE#u|E?G;BdB%onWyFYyvM2$Taz|!%sbTZqYk;cq!GuV^M^~W&T^((Voi9c>LN?t72C-aJBN~gv-_1sd9+M(t+H*KIh zFO~_N%lU`fRc_(8O61XxQ98MbDjr^vEq%Ii8C7!3hLU5pBqqs#BUMuWw_@W~<8t%b z(d-dy_k%J14VL2Ha%?4ETzJLb%y3n2VQYWtVVsp1xjTUmwr(W^cm7&RhjqXtrvjBUSD@952zavJN^ z>jUd%?lf0<1*^zSzqKi;PicPDs@X>B^Hp)1MG_4^s$;ZPQ&S~pbH)%~#cCl=*m-SHviYJF!Y7q})?ch;8b!W^Gh5)dI(x{gZlx7E>9w zWd7M0=UOs1=#d6jVzjKI7u=@Cf^YBGU z_*%hmg1PgGTjVS@@8Bj^%Bt3WG#a&~hnrMACjTxymU(_R8kH=rsy})2 zfXgj?tD)UGSl(iJZeq2!%j9%2#?zKnSqXJ3Od7rH%&{3pbGDkLRPfy7_fim}y$!_A z{IBtwt#}#z)TP#hiLYnNb$*__Id)vO`3Z!;n8ZqT5JD+Ah?@iBbh%`?WurQo)vb4o zr|O6TjO`~Ts8!?yd@XU0Y@@aJpXukjdG|>MP1$O2)qc_tr#J#_!{AL>S09Ui&u=&%Fv+&PL*C!4vBpFC@ghbBsXG;91^3+gvr2CHCMr0 zV&H!MTIn{WijK<&%npB*w|0Fi5H9nKpm0sV*Lv@+f-}$k+ zJTQ*7D{<{Vj18+x`KjtU{vcIfvJdJoPm#kc?I8T6diwn3tEvRkBZasM9D9pxlqpz&zMr)KC z)n&evaJ)PtYK+z&W7PC$W2}=~2q;Z9_Y+BZ zkRtSq(M?InTV}}p5^@nj)bk$+xnYR0a_jd-A?4cD*?5U@B(^4AmpU~rEM%y6Ha;PJ zfb>MpM)mQ0dBmuSa*wn%dB!LsrqribjdI1|+0q(sl301t=xjbhWfi)rLGBK{BJEDP z%Ajh0&ZfVaDb-m^s#E?Au2mPyTHqil^p+1*9lf8}&nUFBu}Aht_%ZO#?P_0~jq6Qr zP~0-{N~1j_uCm&{l(}66sN1Dm6K@L3-Wg|sSyWw$T0c@iTC*DMWv;DuLN1Pt(R#GA zsamZbnJKe@1=6z(-t95I<|O4AiSk^6^5hxu^$n`%bELCUWjx$0@GVu9aTRZ-bYRBd*a@oLP3dpAfwy52j`Le3+v{TdBxJ;UoOswzHTTYmJ zn7R)>{?x;>wW7Q)dgoZ>ZyEoTJiJgjd?5D$RShgw%}%Nj{4#j9;z)f;g|3DbiWM4H ziZ|QQBkB7H_5Ysz~@EMZ`>pKR3M*gjCJZCNRE<~2IkZHRtc6PBW1fXJEue* zZoAc^_^jT2&2dz^!)A4lO6_-5N%+T-@HcY$B)*rul|_w@se{@w{>k^vUHA>k^{}j= z%VRCKDr~_^Mr^YhY9+Q6vERha-Blj~QMXca5^k%nk;cDBsadl>s>4S$+qA%_4Wkb; z&H&@twV1~+zFsDk#*{VDBOfC%=aj}AHIeg`q(fJ^ zjRyr^B_7_a78enn#{uG*a{arFg03>KV19t%+pvbxBJXW=_uJ!gl4cGBE2c%Ops? z&~uCWlzAw%Par##7%AVGk%#1}B*yg1BZJi@2cG4~<|RF0p8qQOUWb$_{GPS$NO|Jg z`?6|)1M?^2e!uk*c=;yLs(p=Ikh8iUFPk<#;2uhi4D837Zk5@}%2)N4dMV?Ifxvy# zc3w2vopiJE!TLk>@YlvXS3aFDUt{UtPkk|Il+gt{)W@3T^QBwlN?E>_G)g)e8Tmgl zO40ki`MmUdy=9HsdwHOT`E^y|KGh)@1H1a%km{eLFTHs~QR7Fl@wrECm?zH+FWNZt z`W0#GKWnaki?ROA|C9BPN?X5P)}Je1Pnjnhm(32=uetx@c>j%^l@HP#F8zy?+x%jb z`hK1HL73g_@6&19YZ_{ML#|(!wtmt7_Wr6yJXqf&%=LFu-{%*HxE_OW`P{T8=eY@Qx(NINf<#wz!cT>WpTdq47-&BTBHoS{t)e%B~Qghg;IOS_$CQs!T-bDyTC_PUH#t~2sIYuL`97i zHLa;8^+sB3GlDe(6Fj36i~>r%R9agf+R{E$W*}CC=u9A|r-SsVx3;$0yS>@-a0y6q%}RDsCI`hQkZzne~?`VDEajKXs&l z(i(i!>k~w$35xA|1JQ`olQf!o)T|TQ88K9zBWkZFP9JIu(&!#XS9r4?NTdalf4x(EApj*Bo*ps927g<&r*%k zrKiJ6QAnSk4>I9SkK!SXW$~v^%i+@SDTbE4koWm1R5Y}->AlSMVNUmVc?rCAL!Isg zJkp4Vd1FN8x%V>f@cF-a7xwWd^Ev+?bfwnbG(Q<%UTPpsj>rW2=*WMeJdF(sobKP) zI$D_}{m%3r7QMz6t#h1i-xjT*Xi)*o=glbdpW#ylzgnM6`zYv!H7vxlA3P2KbX2H%xZMRag%W4&lYVV*@Yq|OU@5!r=hM+uU zKuJBad#{pTckfYt{jS*Gc5mAx?_uqZaWLq|SuZm0C@jU*sZYr_v?db_!g#izFxsqDf8H2egmOFj7{Te8zG-+#n)>Ejh5Qh{-!-E1|2jTx zN{8#;H3}AdhvwA(WOPevA9d|54-SMbyk!KKwU=VnLjM5Hm%Z)Y>+YR*6n4Al!?WUGu$oY69PtezTC4mI5ieF9T``OBt;f;`|B`vajx!crIY*Ix z)(cLoeMKz#$eg8x!Y=yp|8l%3w%abS0aLW`rX!psobk@?K*0;DzzSk0^}Hx_Pa&tQ zhr}-Nrbm?9Gx4UTF@JwGrzNiDUf8|4Fyxf=PJ095O)KCt@unl3r6u^Lg$?cjzGB2= z)&F+9>BmdswehA0I7=q6d9(<;7Y?HlKezjc*>D?rAAmpNL(Ai}@unmENjr+oDWA#v z%ttY1ckuxH(Ow07Cf@V_XX&J!#Rd<5fB3?f-NpZd>n~kge=N9Pz)(-zB|y~RBRuaa z?Ez9_6W)%P_h|EGyKc}V;@-=$4So`;_41k5BPWh0`uY$jp4Sn^GeULI-+cv!ht~$K zCuhlob27oOu_w+s#m((A8)=D;Dn7@TyOCwY^q}ugbQKTTTdK)E7)`22otm){Nxtm1p&lcs;rw3qi7 zA+(!JyAwOcoIw<9@0fj^@1Y5X?T38Q`oDmpDc+;nIi;P#v6c_p*pPbfWiTdm4W=(J zm45Nu^G#i2I&H;|!uUXz0cK9YV_$+ztVarxu|g4!1v2TJ0tPm z{e|m_{gvVUn5pMv&*XbP%|GTGeAn|(yFNZS)|o@jmwk={ySuIr=y)M~qk?Ypr_gof zZ@F$){{B_D{I2mmA%70d@Nb#ZpmIKiIn$H=uOza`r?ATAQ@E8`H2D&ZOIL*$c9x8XUwvxqKIAjW9q=mK54--tm>BrQx%HBBhlg}(Y)G{w zhQfCf6Bs1DXOWX3tM214Uc6s=NLk@Dv8rmX4d-P-u|6SwVk=QwEdEOB#l1H&Z-g>7 z?!@0v=TEAgxVNR$Z5f{izOe7t=sq~j_MK|PKjREmUI_O9_>Qt=oa}KF2*t_9{OSBC zjdy>OolpEyLU@?j!k`{FHqsS$DpGjz#I434cW@1*y(TF;vFD{j*kR9vgSu+_hY z6NW`<;i!x$9BWyd+Q0A-+kf%ZI#a)zsNy-QFG)xntsI_J6LCLmqUtwZR4i>8FnUkv zm2F^<8YrlNb=z(I4?4ctpXloBuN@WXFyQul8x&jK5-hvl}y=J5)Fvpn;NmrH@oSgOy|x44YXF3U)csUz>8ll4G_K7^|nZw$GpEHoBY!&vr4&{ zw@Ewl6W9k&)hU#vw2N?cg@W&d{q`I=G(kgw@Y@=2kK+Hslv{hO&;XUUlUDXlsy zz_`3A_0qt7z4B50S@o|D>lfvW)q6J1cKlLxWupozs~dGk8Bow)X(z3ArtA&}@_OU! zT4(8ih6cc)RTQ@K0q`MbS%Z&r{}nz4=5r!H)SIb&oh6rY>QqJuwjI2SO1ZU)bTI%g zv{S~b^qGybYW+)h6q^xZ298H+j0R-pr;L|@@CYxn_H~wGVGZH2`MxUPv52WWziJ@> z-rvu;YMB;(>YHY{k1@-ANYd+Fu{aUgl8C(C9$jV{%~xJcDEGXOyL9rQiY2aQ+@*FC))A{ zsr(?7r~Rb^+E1+8t{RfZTf!rf2V+y(y;Wf-U0tk&)7xvM?7QSqGYQnZ7m1_sp6@>s z&1hLdA%i-x$Z8vHBAPBS5l#D{jnpN}+6Y4S)LiO>szhXSGWzPQ@v&U2-ycTseLP#e zxUKs>XUS*h9Tt5Ef2-W2>Vi|`o6D=md}~MQ@MLs(`VDrVEi1*rRzoDOrvKtLy~>FW zHp(!b`B^&nGq{T140*4f<*JLgT=;Txv(<+F>Bk>F@9=nZU25!Z{hYcZb(9-@r?MZ2 zXv>_ipTx4AgYriiUCG9b6`r8KwEFw{Kk3g|I(*(?>X7^k46JC6Wn6pc4`M6#w{BfD>(z($H>Rb9_Q;-%~z?ve==Vmm>&Q`JKtOO(Z9fEu*V|s!*aRmMer|@t8Jgvtd@M!P~0C>aO`~a zBIEmJAHaLlOgy@5Ks!dWDZ`KcFp>5qs6E^5A_K)v6s!DmB7pxoZS zjgQ&5kqRF!49OzI;)~M>;p0H_Wmkl#-w>~5e8`;ye7HN*P>2xVm(J5S>p;EVGyKwo zO8lb&AG7UDEp>O68e~7G<0INT$kF@V8r)PwNQobz8cmtxeGNSOC|OL~yd! zagjLJBg4#vVSHk*b$Ww2 zYbqRC!bcMF$|LF;jOWb5q|p5WiJn6V1o)H%l$JY*=?*rGK}=ZqsM$Z{mUY_FNEM4wXf)pEqnrR^7Py> z@uU!{xI>cM0rDW=b#v3-Yjc)%>;$BpfE15DoEq6KnD3&Tlm|Dnd5}S>ogV}77)s1O z9}Z%`CD^H8!ChBKWL69+><=GHMxRKHi91V2xbf(SZ>RrU1oEXKkf@ZvSj>N!{tuBu zUdO_A{z7U=pRV`#2o>>PeE%6!{=*1mTRz$Jth?;(LHTRgOp8zG_qw-3%P9Pb-}!Ix zEhN8ucUVsTn(f}|&}2<`RcNr*`D$mHrvE#Y6td>VD=*jVOnljD;Z?`q!JI^;Ikgr3w{+$@yNpZqqwGx`*Q)RK&B zN4POk-R^QX0wL{;!7yp6a;kXWa42hNsoR=sWE!29rlXd7A>MfOaq&l!BVQFXiE z4nqY9DuAljgx3pmjn#!;!(WBBLsh_*eHZKqIgRvYVC*m{%3_>^>BEeMR&|ae>${0% zufPpf4k|PnJ)sZ$z2{`ti_W|a+7GrzUm~sP-PEgcvOnWJNIcLV1sc~0jmw@f2PCW1 zXh;6bR-X;=H?4@jnFH|mynwU#V}D`s_udD?pVI&2I(LFUNfL{|t-I6R$-B_q@s)TK z-!uYxARY&ixTMGrEIz->kPSX(|7Q`G2HpQ&f-piI3e76F}1wHeV+$7MuMcn{cwjiD7C=DE}`&$+kkAj)6tlm5j+ zv9FsHYy37Gl;E}^8x0d=IN3)_eDqR711J#3#=_L0ijY|ma?;w>RdCW^7ZhlHu&}3} znj3a}B7(=d;YsQqX}>@>VY-=oB-zxf*o3LB_YjY!wF zllW<>q0Y%11q6xAtC7N=;RhtpT68)u!f#1IM_Vo8a*guqgRPP)M4)zvxJPkV+U~vD zjw`OW%y8I*_fUnO0X%UpPP9R;#2q2TYL(OAwG+!oR}Ls3S1_Zy*3E3Imn>Ah*c0Q#2#VSlZhD=Uhii{ zD)D-V+7I#Sk6r*;9}!w7KWWgqrUI?!fL7#{#V11E;s#$bl%`uW(d}??SP=;!_$k_#9Ni=OR&|rQM(L7~&JAQKC;vn!;yd-D`Wm zC4%6g!a>?!82U_|togFEiQQEAI}5s8nrf>8gHH;B`#oVW_@HPK!c0M!)60Cf-Fq$M zf31~^-*Q*!pVXR4p%{^((!Pjf@75>;x|l{`nVr{mZ`&T*v7Gjz#qaYSE?nfZrk`zX z{&!42*qMk*D|WJSaR|q@V*Y3nksD5IVCXJ#;<1LwYRZpJO8s~svFyD;`JubM&A-jT zoN2LCZrywN7kJ4?^P|Cz(4vtSuGE`x6>m(&Y5cjv_@rd6;m@E0|H*OwjF0U=n+9cP zPfM6P5^gZ_{|?)?rzyg_Na`qmp+O_OSG-x;cWLuhc}}0i>$g2O!fB6eZ^yc@;5!s< z&z(bl*(Hax=VlH{L>?g(=PldsIQam9p>|w`5g1l-4Tl(p5Ab3ZsbSWntRP2$z4`pOT{MX z@Q|-WpK!9Dq4X*KfJ&eHwdZ5!Hg7R@EA06qv=?sm4&gQAaWr}wCnQBW)>8l>X-K>6sSX-?-D z4Q)R<>r%d)xic0$D80e;&uiG;ygnIWfAsuLciU6taXgut#C|Vc`%asG-sFF{G}snh z!R|Erm-KTQ!@5eeGk7as{H2DhwmRL)9VW73e)8v*_JRJD=KFo=FUlcARJU$>Wqxu0 zTJwEwg8sXjB7YvI4S!nI!r^C+YqURxETBPT&En^+K{?wU9e?VwWb72rS zGDPwH8rM6ItUdk>3P6zIgtWOGdWZBxzaWObgrBzPKQ23$f94*SByWAKlN0|{0I9SC z!_)zY^lR|PQEVGwJazqRW8Uh-g)7JTsk^KE$=QzR8)-KN#gddCZI{NJAN3|8tJLZ* zw0mor|6^5bRfN*~q}OOv;g!=XD6T^O(r-;L`(eYIe*+~)zz^6-cuxaJW&B$beArxO z$>>*R&c8Wxhh{30{<(`DCrrSFVclSELq$)!zZvK+_&)RT7Fws=l1o!!rlW*%LimmP zNhX1rnhZNVnkda%J$}eGoX6nwQoYeM>Bxl`C}CL3zvtcB||EvRLfm;BV_JD8x8V{kf6&`Ks~ zoAcw|L=zLVbM95i=-=mGS(={CJx-7I2aaxPX59@6L;{W8&`;UD^c>bmh|^-xJ5Jz07G1UNdIjqQD#P z9eZEOoQnHWOg&WM_pfW$W9j~r@V=Bu6#%?De{W@_6*SonfDpm83RCjg?Vk=A}rx$D)u6kUE63a-p6vTy};$7#RBJALBOpr!iU)n0gLNB zw#zjzILDN(fhn&qvQUMjToX1lAAkHXtd993E3t;A=0eE+i5vYx5ADH?e&Blg_xs!B zTAAJ49tO7m0r0WgwK6A`u9e}wwSOBQm2S-sf`B~&Sc=#B_uH>69Ko51xTnH`IaJCQ*upX!oQ@Z`93%L z&}^=O3F$vq9c}kxweGsW&5drw2Dil>bKqr%*j>r2kGYXG13%6EyF2Ernt4aLIhT#* zLv!v)cxTilyhMGoE^i@U<*+q{Ys=%uf3>#qJ|Ni(OgtWk&EZKiTZdm&AqatWs{VK+ z?G&R-IQL9OlKRu(lvoWCel^+h5uVOH%lR`l=G=2$!@lGJIj^Cy^V4qTcaKk_b|lv^ z#LfJnQ;)i1BsckL?6--gd%Jj($o%0Zeem~7G+p~go?5e8jfE)1O)pp81fuXRY0LKZ zOm1jZ+SDp1{-j)uF<;bR-c_&j4k?V4{zcRcynbwIKHtMn^N(m=Pf9}hWRm~y`wBY0 z1iReIjtcR{{%_$Hr3CVCuhSoyAeG%{v3{kANbaiAYXtFL3D1;F^nFN>sGR}6%Ap-7 z)`JieB(6WY!Q24HB|M2t)*=JLXE&o>Xwc!;CL-5bG%U1e;7ER<&>-=GB>a&6a_17E zGJEQ*%fg}5VBE1}QZQA-R;NyKiLu%J^>7;FLV^;#`6OskdbQS3`XH}w+pd4IN%I!Q zB1@mCAu*ZaPYplhvyzeh0vNh3C23Z-Z=Uw8N}o^mid)&S1Yhtl@0(oxwj5VQV5kUw z{($#SYkyFR$Asy{eoVX@`Z>0zrY=?r67;ieG&;9*`Mhr>N8 zC?(Ge>9}s`x)d0jL;}D$6gcyD^if_HWDUv&yf&jx;#TQbizlm3LU>i;EVMB0sD*H0TQJjl2$(E`$^QZ>(e9z z6C|c3J+{nvVX2+n^)STOITEk;)_8)jPIQ8ooyN-V3#Oxask^6aXxd{WUNzaYt zCO2$n(?9!*6eK#i3$lo1UU-jR)v1XJB)xjMi429Vn%Bb#(?7{iH40{{As5q;z%^;I zt=_CQ-&UK$^+Y^oWX?~;N1NB@52b2}KV;t7JMGcY-sudV2H8*OJ?dwO)2%p({41=L zB0nkGGsGp{M2RFh+*W7NaG52+A+p9W&AD}AHWq`%T2bmRnY$2LH<92*WmL3s%jYqM zcrW7pt(aqj-H-E%pywg2&Q+^*u6@FSC|-Wg14{cnQ}yK`+CZ? z?EpQ_f_eNP8TTaz<Qv1pTYFJxNa2AJ&k1RI|Odh(Elz zptL7Q*En}y^0**YENADYH0sI{4mDnm_mxwAdCHNKN)Wr~7t_D5AWL*J^

NoBp5`AtBzqtNyz!3_1xndWL0Xp8=DEE6?U&1QlIrn{!xZ9gJoy;fgYm>X|rRre$6`@kXG+^>nb&muqsH%jIs6M9P+?Nih3VuCbSt9#W zGr)~fKM?@mic)BD{Gx=dBCYCssne7G(4MlSrDy8z{RWjY?`|>9WFG@(pRGYkPl79+EWM3{rn>cF6=hvfBul`AF;}g@L7_C+7J6DJu#Sz)Nh*yFeEwSSxR5q zWg&7_IN3T@4Pku@1XxKsm-H@d3PFq)#AEKeR^J;UExC%6|J7#OwF0Y2ZD5hDA+a zk{NW-Fs>w{hqv~Oc8cdccq9$yPJ7hpWrNgg>eq$8X+8ME)s^R%+xQ6Pe7r=*mrf59 zPic_XHa-0#a~nt+{aO^I)OXenwz-h8a&IqLHTm=&ev^T+7KCu@k2?fg$yt%uAFu7H z4KD=Zek3+XeH;m_2AqIvycIzYc<$=w|c%V!FDUOqkF4h?4FFK{=AOhbMwsT6I>(AD<^vb zA|5XEw9u*f(YmheWht?aFFPg2|IEy>(z{r2#XyIDrb z72fW*TAd~26?>rFJ7(u)lXX~#0W;>${lkt#)8_2@)Fv09Pp2bL0%XJ`X)|dbk}?<2 z^N4x-H{Ykz?e9qah_0cPt@B@_xw(H%=8pa7-2~$9#Y0U-bo#ZOSV;#XG)6$JGQEqR zGqfsuyH_}GXdd%gS#0=XT{5)rY0eKexseT>$0l+kj*0oB7rOq~h6K7C&LY>Mb0e?! zF}r9JrdRy@2P60}$nc!TW z;4(je{{+wQRRog1n_sXP_;>8=c5LG|KU2bclZQ@eQIRuv|ece>A|V7ouDzMVjW>^IDhi&z3+quoCX zuKKmhUN5pQ3Nv(Ad7c9kN$|q)KlTA62CX+2*7zP9^KqQxt*-$G|`R)Y$wq}AKp>e z-_}nIu3iU#&J}ONjyP)_QRgiAON`*H7dc_*JXUWks4u4utn}Y-mJF*k03TQan0T}x zKapMx{~TQXSmBqI^l$O@b>WS~y@E)oixRoyhj+9`o(dtGWju503WP-$@yE5*fOn1o zZz6CA`gHzvY& zx<}DkUbJ1JBTS*?#vuI{#p?>c3BPMUoY0NgMZ=l7he&5}zEfUKs3|%R!}TfI(2{Pe zTv)Gb>kOpE|ESe${sYr#X$deqwI)ADLTR zNLQP_=PZliILct~TE!Qjo7-x}L1%Fs>vC<=lHPkbhbX(RiGQGhI#!4Lkxc#;*A3GF;Rk}vGuNBy_ReQ3w0V>JL^_+TvuGDbjMOg`d+e6 zAxiwltJn>8vd@PZ+&bPLy%c{L@~^xWJojg9`qCTKX5*=T^%gZ)xH+VY(8;B~#2FNm zy=Nqh9py$q0G?_IP9hiHLBUEqq;|u@TkRh1J!L%93J)yw4>?QL&1*2YXer}jxW!k9 zhr`QwNDdyo#yA6T!Za! zneEcdGu8@zNj+t2UYZ<&GFKcg3!ymo1IK$5?%bt$zmIue!@|JI8s#u~)-Cy@S?TZ< z)h~|wfI_U)Uupcu!M;+LRfPx$gn&)A8U*}JbwvT&P1A*+8NP}NaJ0PYU}Q=-8@!1@ zl-)p0J}%`}T<0ed4({_AvR`q^DyotpF!*kUN6$rg-e)$^h*5|pVGVFFdY6P8&&HIP-%@mg#RXA|5^jVZB)ZhMj zi|Hc@vRG zp`#-il|*;?6zCJY`DLr&g8F3B%Q!uTTJB>-Ef>oKS;}(LbqU4%Rca^txA~We*}}4o z%2{hwPOj`SD(5PxoESBvayF8l$H|E+8kmI%a!CI@nd|I#zB46Utq>RvF(MsWboswi z+HU!lK;_JkFJ4LB#{9`Q<9Vf9n5o1i$pFh07itbzP48)3ed%7kMhZRl&*h2eEAtj< z_UqAhWp}|H+^D$Rt;8lI`bv7Ui8u%jG0BIS+~9IdQ3kSL4o~Q~|DkpD?qtQ7@S1FGd^4j{i`cqxS zw6JzLT}3Fn-e_#ACfZkq#6;6Z!vnSKS|zCKxHQ3p{bCX)>=!(-|5ofT_kvoj_)}Ks z%63^HbQ}HeTK5tsdy}a2bt^ww5HUoUZ4DgSdTP@RxgU1Gi>nmr^ zh*Y;cz_(cdu0O1D22+=t8AN$k zBI3}d7a2=boo9+>;a%hb0a1UNm>c$!Wb`ky_Ajhhtn5vGHP?TPxFQi< zH|G|A5P4CNZBWfo{N1II1xIKc(mhv^|Dp0C!fz49paBAS9a>T`Up{ae2bka^0BhY}Zihbxzx_Mv z-aV!9C=ty+rmzsnMe`%;Nt7|3L}N0wcn)3M==vGmE=JenN#vTNKJ(e2!W&Q_*MT*< zx|jb~aHL_{@Ve!P74MnWYUWfpE!wZ$%kSP!v*4|2-cSy2o)7VNPd#sgtzbw!lC0%A z)U`%C~?b?_wD^!|vYkAYRo9M#d7wstNU)9jd4<4<>MAy?P&~1#bGPp}n zS_QB{E;^MJtPr*&e|si3Ohrwf%qKX+jE4GB-Y3R0x#U_l*}1X_BpIX0GeH9DkZgNL z@=DGZkC;P0Hh|8O^f`ep3-OjW_v#$8ni2{BK(MBHEe{8EucOBG$+e?VdmRk!pdObi z^6Z#;Iu6!13vy4#A&gFEQ#~Cc(fcO%xQF(1)Cs<#yP2EGK0J*Mh}5Xgx*0PG5x>@r zd{2|Zi_qK5jTmGbQ7bRA&<|XwVkOkjBqkFJLd@HXpGl9Co#IsLSY>*NES~IUqH6(=@x(buNgDG^fT zwp06rfpkR595!@BT*Y<$C=`!X$o1L%K%P!_GgH2`^>eM9q40#6xs%Bs#UwGcP&1V0 zWZ$JP8Wr6rqP30^uuBnndbzzv#BqVh{V4pK*+E}vag7POCJHgmidmi_DtWmr$au5@jXrWf)6&~ zOfYi^782H{Y_~03$WNF>H&Pt4xhhCDnf$X%Yp6G6y1<6;1_}*=>+>tjSH0&v!3Lwg z7dn?tFHJTpy0$dq|C)bj0{#vDVdfp;y^(5$gRo_PDBP`8iJ9=t9`G`!316>THR&xe zKf<55G8NzrfR7=93mK=VIg@ej< zj@hc83t7w6Z)=xSEO`DLbA z>}K6}hKzoX>;3~Wdgjx(6*ne4GQPCoGf`o=GYG|euDI+CtINN^^x^+&Ld)%H zMicM{Bl}xSJx*3rGn4+Uwa6IV`k7An-@xT|b82q$ea+nMQPlr3J;JB=xZGOY!I$As zK8$ni$u*eWaHBh0v~EiHsT%kLt}I+Mj5%bjY;eiwbLqQX@3-n>fas|>U;S;3gdDf9 z_DHX|r=H$qjD7wsarIU5f8Cr~V~(p|bC;_t7qX?aa`et!Cl|N zwIy|L;fC_#Ch2*UrU|3+nTr2OMP3MP`j1DUH+-xsKh~EYJIaqYmLGe|k88@0Ys-%v z^aLJ2?Sfv~2dPf?Z;ffJt;PI!mABkHt)T3wPLKRg64BnIb2_dI_c=WWnBU9zy(Zps z*K~pHcL!?7%QVu9s!cMkV?_ER@^Zb?U`kwFUs#vGHpz_947N zK5>ZLZJ@bJFbB;j!W?PeNQL0z=2@HUyM*B2@0Z(eDz~@3^<`8}|M6IyDTs~t#qnqM zd=7o}c2&Z)Dm%E^jK1j5)Msv_Rg)GU-WFD1BGT)4@^-_aPDt?z=H)WSd(OPP&xq#A z{TYmv;o?PAYp>45vq}%p_N00}z!4@j>Y<(oPViuiJaGH4IS!oEs)rWdxO!;if&JcO znMNl~wKvqbxglqr4+^|Y3q$4CRQs#d{yNA0a`{y_dNH3rH=yvj0}7vCF3j9+5oWy1 zD5@%dL`Tv)ZKmsSowV4(GHyBBgz0{3PewjlPWB9D5vS=lA{^j(-;*^W+uQE_HR+A- zYn()!Mv2=b04pF+-O!gg)PdA8621Ku=;1)kq z#nOIIpsmi#pmQKUI_Z6_20+y{SsTAGy$^P+e;Z8_H$(0M)=>6%K5;-YJ>qolpw{Zl*XbtGHMRkIKbLQW zB9-`WUv}^Y@M#8}>E*;=`^+>p^_7hS_^E98Mvv*s2$3pnRC(raY?m;^z)`H>;e&(w zME`R7;e{}TW9;HV8cjyah(Y!O6F!h$Uq!{-i2uTAad2?`S&E=9)~q<+$_-gZf`&3t zJ#2r4MD?isC8Ekd{9c890lm7$-PUyzUGiTYkqm?n8GJa|w^$+h7x@Q$-QuV!RAgK6 zzs!@L;b*;63a1p(ae9uWv~I3TdJh(0Ie=b@a{P1i8WrrZqjh3O_EIb*v z(BDoq*s<5hG90l3aANMm7EUlk2@}=9f3aoAAEN$pV_PdQCEwDEY$IhvIoW9<2QL(r zQ(AV%@0q66v9#K}o~sdC*rgZIoF0?E<{g3B%5oijX2{eeU?mYzgFn+)l)`=SQFZjh z-e*dSvtSyv?yWUAVvi^ifQ`uIY?ZKpbp_4<4e(loP?!FR>y2m#Iv?Sq4<8bt|ClBS zg)P$KX}RhzsgMF~u|c5`ghT3V4E~7FRJ}y>k@VyFFH;d@wSu0-hVIU=eWudFszCIo zxCRXb+MP+sZyN#|Ga0nrh5HM?$_S3MQ+Ty?Bw^e)_V80FhsfzJ+m%k!@fuJ@EJ9i#uKIow^Sh=ctkISqA zZ{@fL_Ur$yK{60DC*%Il8#EDd-f904OqwNYxe!kN8|tJFK-yfsQjM2wZ?dmaS>~%& zk~45oHeK=X0>_}6L9ie!q@; z*YD7nQ{T~k=3q{33Re{AUaqL!TRYDt++*6DGo(Bn%HNUx+!|Z_Zj1fl;5Z2RYf_v+|@ert0|@b#V#5i;KbOo{7|B2qsPg zJ?EQ3xnYs?Kg!J=+V$iSRX5eA55EcWKlDw0q(|`Z)u)bt3m8Bq zD_j_GN!~%@{So&Nu6(%3;O4!AOKm**-h904XfxtQ3Mx$uy#;puuRxo0uqr2;=U+IU zIlpZe%2w#{RvwF}g`T)0QlgQGLOVSVmh>|fRg-yL+*8(X09Dw?ziwnPSQ&DMu%UU# z>&E9IpJIMW@0H#pe4q4ZpAT#3F$l(bZIgJZ(Or_Mbnze+PJ zJ6M>{&slUUZ#aoWV8r?#5zg?KLae_rVg(ao_azhU80K2)558{tOc>d~& z`P3ESUNyiz!)4*1f0xENpI_c~8CfdfHmxIt zg(5Cp?|!JtOeac6U+`3-IMUQCqnErEOcl@r#u%mBTEp_mZ#yk)%){q^Dw2243Y|?=Rd~Uf;;~Vm#N(uhUd!*LW_YZ^gV~exR7W zuI=7w%#uzUYJ!8sIV1{+MS2t(GNCZBJ5|8xzMdC04(6x!i9^+yJjK0r&AlcPW;u~C zzjeBm-zm0rIRP`GuUO_eHeU+*!l5haUFvfCDnAH0>fjHxH^r8{Ff`sX>m0U$7sb5` zaohV^YmaW`yV{cfpN&+GzTsS9?mfp%lAV6`0X5=vn{QIh{kw1EO)y)NB5@}Zbg>Dq zTi@K=sT^TO^ zd@kW%N=YAKF{kV_L(YnK6>cfZ>%P6zieh98asNhdFtrrAr;C5`I!H6; zHr+Ss=Sk*gYn5#$mU+2aZRHh>Xy}0>0LAUZZn+>og?Ed!x9KBP=Vf3zduRT%V!2@O z8p9HGhr0Mdumax5POc+3=M)}LThHV#JaZ!jg2(!J7tU34f8nVzyp@jID64z9IdsD6%r*2g}tL+w@YR8E>Mt-YPkRWYM7>&_^rEr{zVC?A|7KwvVH zwS;gM@e?&3Dd;BQNH-YbKd~xxwCjzl$4m+K?XEmU3XSn~GS!9?sm*y&9t|oy0{(6X zZ~cX*&1x?^_D|s-X5kmxs)YZG=kE?bkjHLEtC5Fb5&j=YYH9f_Pkq4*q16llfNMDpKcD*lc}`0H?x zKhz-orWign&XTvhZS1m!1)b+H0_P8An%Ef)BcD09c#&r^xQCNCL;PBIZQ1_ROz5k7 z^Bu$ZnL5num;F!qV~3-@cc2khdtc3IGwEb66YiMJ zSZ4Dnn$B3)dy&~kyOFQi;9q96u3~92j~89;POTbLz;{Y&TC z*+*wAQLpzZ^PhCuHeqYT8#lO7LQgZ#9zyYg;Ur^zc%you*^FrItzbH8Sa<7rhLDoNk*;Zcm(TEY^O`jkSS!$teROD`v+#;*+0EZ z;dUG^xE>ku+hD3~lo4Lr>eW+ZZbx;NzK~5enAt z>+lEG?+xMap2CL~8|o@GA^bHOmn@6F7Z-<#$yqorvgi?{kD^cAZ{*5H&#`3HyxtHL z4vB1tmIYsxz+=6iV5e5c4~Ju&xLHGJ-WvCZF{sWCHshbsFm)Spp<-<44izhE$TKhAxiz$u53AL3)@> zFZ${7IT!`7N9IO%R|8Nma=eB1I5*SgMiP;gV42hS5e93(zhpFOv35+6xdV?R+|n=aVOsHtuUg9oY=WDryYA3Y z5%12cTC00qC)F~TI!IyGIc7ymfiUsvr}2T~F8?xm99@fUK$eg{u=YP@8ndZIVhT)92$LO-p1yu}H$f;pdas zt${xBw-pxef&N)_$}Pe26fTe8u=y#)in9S(??#`Toh-{ws_*Zv%hOnbR9dSOW15tU>wee!%d8{a z$P)uU&HZ~~%vWlhMQ5AtKgaTVa?U+!liMQ?qos4*WzP=A;xIf&`crG#bEk2j`GAw% z4s0&Bq}S2Qx%|J{_2H@H579^2?{QdcAmPBA&$7K~k8H*cK@C!Abz@6=Zg5=sbMQT@ zRyf(QrUGL!d52vO$A@DY5|m*E*Aj5*bgxl=xsgEgJjV&#(}As#DL&>foikBtMjd_y zJjHwBb+rj>0(H!UP25tJFX8zB^SZ_&v-?(NF+o03bE-rO;L{|GG3)ToF2IW2EegoX z38pCD;wQG^h_h1!00ta4@}NsbDy88fAL^y9H@znREsB@*9Rys72)VJsj03B%L4p|& z7y*Z%d+uQzZLJQz$~w`Bm4(P4CI2DYB=W)b|3mc;r+0XdPIw@H;wMf3uuFMz{jNcz)mBz~R^7*+kEF}G3 zNl#2f|1pOMYVjGOBJg!8%-%-m#>F2~tb-YC!n?Vbf@Q%}Y%k&8ZKe~8u@1A(Kgp~l zqSK^BDsMB)tcg{|S-aMBq%ZgcMcTbTt5(AMk-9Hj7yRN4!@h5*INuN9yGiAu|Clup zzKacf`z5@u+r$47U8pPDsEa_}r^2g=vs&#E z0VBg=<&jy8LJ1$A3-#RoS-|TXUncO7x51_^tu3s*2z%wO_kXj&!f7hZkfBt*XVwH4 zK_*C%ac=H3?2(f&_NC!tF9j3r`%g$(NRaY(Du1W)cN%}El_(h&Y3V~=2dX*wOCr2< zi=JJci}q8i_*(m}|A#f&r)Mrx;s8{ItK>9=N}=27!80s{_UJdLhS2HBeM|7?clx1;-VrIkPIK%7Yq ztVw#qh$No8FRM0Z3#9g~$DKg^Z;54HCr9iP1L|i>;?ej&-=fu?5oxGdvq?EF>l`Ju4J`(=Ty_z(})!hhn z+|x+QYIXd>W}%>5r+!IHk0xFTAkC^iO5bor;k|3#>lAD>r(i6wq59@u#<5Yyx#%KBsT$@>2>sb=%J;MX=XBS`P@C%-O)mGlL`j)< zs#9OqK@Dz(B_-NKN}!buA#eEHeaP?sF87l*6!k1c_C?=K5m3KB@#}Dt*Mb{CvhFB- zUTuVDE(8k}WAH4!<<9F?d%3W^Bg*Y@Mc*^CO=G&N{k7nXu(=m@Z_Zp{B?6b$*rxW# zMYJn?T*3FuZ0;E^!B_SE@DcWE77YHO|BLwJ{?Lz?#%u3s=f1m1ECq|e3s}iQ;B&i= z*gyxJG2Sx%Xs)}pxnjal5L6*SO9poG3iuHZ2Rz>M|;xf$JH!sV@=bil^<)f{pTu;SPfCM|mhk7?GQ; zX9|m`XzI{7|3&*a;T3*v?Kca%Sb=3Ynl=b8l8M;j z=fJP$PfIi{>#J^Hzfu)E;8TA(>$=pRtq*-ud^TIYe27@_o~B~A z(7!?MkRB@ZP$4XD;UjFUSg;a4HllS!07ovQ;^_v!E;IiYzEDlGlx3-`X?gHaH-%-t zt=QjMdXY|7>dThTji?J2v2OCOtHLhhFQTf9_Yx6nJcywiZ zBo#fr@^^9kC1CPteJ<($#qUg2*teDw{G?QYeRf@N0P8s4LQV9Nhas{O{6x|_3r6#y zcnRQD%km%RXK{SZT-sb|Z}|7~kyo%h&Kw#J~NnP%3@-{SBt7kqeLIJNRWK zoO463~9&f>jR;DBL~Lp8ZrWXu0DNaj43>A&f%OdAo6lUo;oqYCU!@K@H6XD@jh%|P}AD> z7`Kq{C!n3*D-YU)KT(-RxR$|Lw5XcjW6o>nbQW#mWDTQaGIuFMVYT*&PQL-|Jchb2VG6|M6IK zRSKu1{1-vK1?Nf&&RHGp>>$k%zrcFPS+osd7=o3cB~It3CCPORT)LHzL7u0xbuPRd z#!2-P?cP6N3V=)cUx2+r26G+S3q&rTwD^hs4YM6>VbztVZemOtF#pDj@%}Ntv|uWW z^5X#cutN2{m$B{4!^Fx~jPSa=47vXT>X?E0`UZ9A~XezA_wiVjGW8{c#i6|jg7-b^HcU_m3lT=*t+ahH!+qs;c8Ilb$%+_O6r0i$V;Ur zSW8?Cv-KTjYbPw15kvAJjZJ{$IX7A3Eczk5%^h=t#o`b-5@Uje>NP`_-WgpjWGLAQ zwQu9!V<5A4nV}vI|3y_tmBwf3pH;+O)npDCb6bOLTK?2+{*2!{PUU%}m92 znTlD6N31JcNv9Qz$40FGss_I;)u{prdh#xAM zvBIq_y-xKnTNA$h#Sf(qz}O@uZn&w6Mz8A4AH|EXKz1|* z4l4g{fV0>fRchw)u++{U@K&B>2DsdRl*|8IU(7j%9mC2`@w?B69W$oMSTplWOEr%z z*Zcwgtoa|6zU*KAvgP}H$>>W37F&ww%70~-FLk9ar0hK4+!51e)cmk)Hk71 z4M;y$1Px0DLw$w87rxaWT=FrXmEwdPPCYJ5+e;rWy{U7uFA4-a2M-zts%EJ;Ds zoS>k$neB{sRq9&=P83>=-fH3{_)bzVG^U{2)^R{~=rjQz!C9bK8n$MSvr|r4^R2eNtCJoK&;#K9P-?o6 zR2SUy(K5=rbJPe%T0}bC$B7UB%Mls1o>Dbj=HpN3bn&<|!Z0reWbrnE!Ea;mHji(a zKHbY-(cxQC7wya?z!UYX)4Qr6%e$Vd8Z!LhZX&DrwenRV*r8s?b1T;TX-pyBX2gIw z**3%^KdYVW5%wu^7o+LNY3TBm>Se&4eg>}GkjsTms$-2J)HK$0ucF2vI{dlZYQMF{ z`%c4kdO?v!lJH0qqhKRC4HL*wT6kI{m-Fet$|CVXI;5YZ+x0HY?#cK`NS{y!yWg70P2!{!&ewQEooWl8@SKKBF7wy@b>Q!g{ExHhAz*Ei&y5R+^_c>%doP zi`uR`4K>O~H_B299)V0WQdUB&Ca)Vot^GrBW=xBY_i=_}o*K={CXHecS!dk5oUHtJ z-3+oYVs5K2aI#Z>R(x6XpMMw8Q#>cg4f%fQ{qq&?0SeeUYl060Y5ooKC2lSa$^Mz8 z#@VT;G!`}2@;cq}!AA);a*G>8%)GF`6~?7<3IF6o?kv2%UJOpfz`_w!j{+0531mJJ z7ygy=*WqSt3=3ZDGcEBooNDG_Xlu=QgO3t1ql!0EQOvyiSRRVAE=u9F^iS%m$*d;> zO1_ISTL19*nc+ff-W)D5(8MaR2@ewfm0jkiXssz+Z)Ta9QcXn7>>#x%|iqI7E#s9Y{1aEYWnO7PiTEnuyrvEzD$T2@<<7p5NSprg9eGhcwmY^;p3_ z$)ue0j}r5274vN2)NpFgb7_Y0derAjL)QxS8d^ZSiv%cxC1RtW`SkRyYDBYax45Y+_^ETa!* zV?P*uF%jLY{1sv`B!85aH;thzOGF;v#@gnm4D>1JvY=1EGJ{COq53n*xpJ+>Kve{n zj2gS~n9)TZvo-Z)WjdHnEXn-OiNWAtLH48>4Hp#lE3Qj({>hj5CfgpXoF(7Rl9v$x ze?9Iee;{1$O39|Qysg>I={3rdYO*-bTVokdjqnppIhc81sI9xRn|=r``0_}7H}US{ zYVxn}DujbNGhzfWX(#G*Gn-83W<#l|pXgHb77b)Z!siwOv%Yr*UwuoJZHUTpi zK2%)XL|(GEUkVpDLn$xr_+Rbf#?jv{Zh2RQwDJgeO*H+^(289oh}V!GCXl+KA<_Cw zIc~uCyZ9}dvg;dyGAfGObRMMD^mKlSR#?einj3Q8p$rNv)#VQ`Mo88 zruHTq&XxZ@U|PM$AQyi5_@&ol z-s9G5gwxKVB5-0^Ueg*8-755i{O~_M=gF zT-nDqv`1I9I}=wm-`DP~PByJl*3P}#qi;D^{?H&%$zyh-+hf*}Uzb~vXmqhMUe?SX zt*d@SiKP5^DY%ZggCTp|UDc+Jv9Tfoo$MBxlnu(%nfF&*yP2d~{2Ri{5mE=r5iiIa z+Jw|a;;wg!Oe`(M`{s<30D5sOYVWsqy3c0r$xLFbBB`4#<(<*tJ*W`!M*go40&EXN zPA%`eQWB-ny^xo{sa2`bsbIZG5^&bg;S-`qgpBuc@ZkNnrqgqVr9(AP?{q7wBSh^@ z46429HbZm(?KHK4SUHmm?O@>$#O@Z4Kg!92{ByuAg^E2qk z$ZOMEs=3%xewq2u3V)do_t7XXK0vw;Px-yfH>3PiwMQ&y`Ng~}{;+V)scK03)h6t}fgrn7HRU~~=geUxID z$(z^8xqfdancz;ZXQXoPuOXGB+r*V}%k!H)%R<#{JNR|-f#!veQz#k6P?u`puedt@ zCyFmF#t)BfG4=;l(+0Y9z9#?SeU>gdqDoHY3cV#NEO)^8VzM^WPIxQvhRa+wtt!=i7i*xZP-peEgctuC+Uoh!aFdJ7 zZkD@%C3B3duLTOmp?3O-MCO==2pKXmD{E~u8-ug+!<+J*psj|_K>#mlgSC!zVca47 zdpeN+@`f539CDzLbaW&&L^nx;AG6Km@V0f7&ezKR6J$DdGo1iTV9uPW!vAT6C|5Ib z#`x937Iiz5-n- z92unZ+2R97IS{F9iwgg(`4ig3k`K4$8p(LLM|NhjdNv?qENB- z({v89EI1k4eIr6Ny20&RrAFr0B*u(vaGePSbG4GSdxYa^!>01Ek^8yx21ks*DR3h} zRdAP}1@7M_*p+8Gr&gs-4G!X+ej3b94W?`4Qj%8a_Qbv*5LF2IIQDk%WxY#SB>@Ut zbF(1$nr+X?b^;OkIPO+15 z2Rfb4lt1b$;V@=-@PI&J{;+4jAJ07>GfTb+*;eLv-s*d|({1qZXj@X`TbU1?{8=`F zgTh6|*Xhg$-~BOZTd zB#7**b=Y~a*#JTO^Ue*1TTJ3Mo;p`M;X0J!hK6~cPWmT2bSoBsj+MQiT)PnKhFzJ5hR5~zmnJ6DqTFq z@BD8Ni-N?w64Wwnk*?{{eoD6IV<7NH8FP?_&v0siBQWxV? z{!Cr-eLyTZD-#b5q@PM?8K!1vVg|&%nsqlDJ^g^qU)I_yhR;cea`|1A>iY+*3%@mQ zEn+!#L4GohCWfC|g!GN!hxcaP_Egf7_9rI4UFZy07yPC)OegzSMu?pV?X{Bt z(11yDva)KD;NayWVKn%)20s`cqGhF%z1kqG6aU^t_v_JY&0BPN;2bUv#21Y`gq@6A zdv5l(&Z1wK4$$3_{#foP>ev0q2WKZ^rnAF z42E=Nk-9>SdE)-;t1M$~vKW`YS*GZPWi*q;WxNo%@tp22rK07}rcU~=_I@|Z8agoJ zfdvl!Ml_^vGhX`U09h5z93}Orrtl-sTOpq+*AHmBod{ShquSt>eL}o(V`m*A$F7vl zNU%3v{f5p!=xYX{mrd(WjY;~)K7OIrfT1%e-vs@<7M#QKEv|!?g1M@!H761@SFArV z=V4Lr{+9Sm6!Ai}DqOObw&6dj1_rV#Cwr@z8TLVzg=xg-rRF8>v9Pre5eKGpzpx3W z)@fQ%?y-AdCa~huLlHH5EGNO49y$Q+$8k9-RA;JUgr)WJDk-;*vT4zt|EgKbp?(7u zSPIC0me=Ux=m)=Aa0CkzkVEz0M4Y866m-aY$lNblEdkpc)CgH;hKf5m*-Z>NxTZ+s z%+*5%2MAxYCbpP0aX0Un+{cax*Te!Un<*sn@ca6fF>B&+J+dZTzYzwKx>V-zk6XE_ zbs-yhd-TgJ3llGcpZlr)F`HEK3@IHj663(!A8f+}6RwHRFpuW#w&0rra=@DS%^ugp zb>b6tK{O{a$3;?ym}Sve$umm&Re2s*A5Um~6#0m%rdJgQFW_DolpVuN;^#AboHgI-L*B|$cL^}v4Br22|Of{*u z#9K2an31=8<&KW`AS$II^_s>EgGh#ZugrCGleC1i)k=$2>$L=_NJK~?C_xc|#QQl0 zNvR0RJm25i=iGZ{G86qj&;S3-=abxX_Sr9Muf5jVYpuQa+R?ZzWdQ{T#U+DQmE`*C zMY(>u$#px@_nyx_A`M2?mTciRtbT;)h?vC_r4L?NCeM_{j=5z?!;A5mwz%uOWn zdBuMi*9J{DABh?y$#;Qt9?j^>7;fhxsMWNHKo-znNbWHHSWO>K-y9*1<5?4_|(ZKB0z(_JjYWLwDoB{!jJ9 z;>PFtB}dci{_Ek#9V4atA3v0Kbc%>Al&8*fCtF15W~a-cN7J4ivTy8ntbco0nUvo? z$dT--Q`j`|3E5qF|FW=&w`hW?yxl*WCa?_J+&pIT`GJ-_B6%FQ;^utM&6VSk&##V= ze8x8?6>^|Fun7Z)QNhNQ?}q;x$ao4F^*kEOR2S5V9(Zcd6Fx!8>4{BfR;FhaqJH+~ zPSls#EKF#nLF@gSp?4t(!_dpT|`y4C-biY2#(BQvHx$Gh?U-w$& z%T}q;{(G1*Tr_-l>mG_=u)!axF)AF?!n^E+l`t!0Xj8MvquhA5#w_PVvy3lRN2o@Q z(?YYNc~?@c++)%i*vszoXeU=W@yt{{wWUnvX*^RUY@Z*!+NY`ql2WzBjf!oFu&$5l5joO<%+^Fpoj#|PW3w;Uqk9n<| zTjHU=&+Jj=zby0?4w}fbuzfb=B5c2I6_4*-M0G9BH=D3QI49#S>&G|@S{}!`V2M!9 zZ-w5I^Bh&QPZ^f0Vu|}B|Gv8o@s~&?tX0@U&_8HV%ls?&Eo(Z4l$ksc-EX!M_>;*> z?A7pXS^8F zj-UX?3%4X&s01Yn`}EvSBVb1}n(^FlQP|IjQudR-%SXk@%%PS1L**G-k*fB+tE8XQ zan?Hh_0itcXIYNSeVjPsxLMr!`F{JG)=si;JRvPscvt?GuR5HlHtXiGZowwD%X<#b zH&qPJpV!O(5B)K+I>queu*7tTqKpj7P3-A@&#pj=!PTMQ9E7OIp16&$wOMd1zvJ)^ zNu*u(kfVj~Qi-EyK^;On^%zDcS-pfERA8eyqHQ*IF*~dD>;>lkYdIc1St^( zdoEsDyMc94g&P@6Z}tKsDNgeKfL|L&;MwqCxH9k~01rkArjkAu;dN*yxLA)VTezE{ z7vOGT&IYXpTzLo_+VZm6p5#CX5V=JgA0$f6(I8HfU4{L3#8c!thvlWi~oHAdxm!`G2H%^{mx8- z^i#R9gUsnE%OV@#-(og9_himbF-bYsEC*OoX7ec2QC+hdCG_O zt0SEOd%2ggEa^$`rT(ehUcq`CFGc+T{1To6KDn1%B|ewvTKGNw6T1B!?kiE_g_bYQ zDi!rL4=f_9mp)uAaV)&P#{-X(P`7l%7A026yZ~0zLn5d22g2Zd;NW~($fpNTR*fND zDuA|E%VmQpds%NMbAWrt^&+kGyPv0*p6X}kvLMhQ2ZK$H=LRiLzx(a<(i8kM$YIk2 zt0E6?6%PFUJZRu;)Q`}Qduv8K=(V}0-j~(dte_+wg$fA;ClK~F8d~4@T^6(N=F2Gg z(hI{L_gUcP4DI*|E;3e%_(bd zCpBfnmdFvtr{~h4hY+DURdtT>>ZlslZXiSmuXp3liF~4ARAC6K0e7o2EXv?rPM~Y0 zzV=I``4FtvnKW-CtrKZx#GyGNFA?8c<2xN_HNI{hITirj%yB#?X?OOn?O8Rv`Xz5_ z4e529OogMh`!|!f_jZC^zQJIX##n-HnAWROikP}1+SPJJoG#a(r{C?FUb?eC0d2{I zCYv~(+CtbFMO@&a#H-c9R{obOsUlhZ;>2B&iUs5JTS%>Uef38dewM0!-@8&on5y|j zVxsI7K&nd+9lnu;sw>t|cH9wH^qNoxi41j=qaRU>ejB*PS3%5&Hsl(h-63W8&?S)b zEv{s`*968*bdh3bcE$f!fx`}+vB1ZGLmodbkI~4g&x}S=+9c*>pMa7}MDh%8!*idD z5KOeEyt_h5ksOZXI6^#CK8hoi4JWsJv1Q}7ZQn7!CbNMhG<_S3ud=N1Lnn|9fgw7M zlIvjS5!x)h^mzYi)G9ZvIruW)2cl$NA>M~KnCLdOCY9T{D!*N>cl0HHOwU{ch<5o{ z>MEj}si}dfkg5GS{}--uFSCN<3eq`Jc~%Q7EY@xSnaZ7vaIN7B_e6S`FC?p^7nNqE z)f)ZW*^vmgZ1-8V;g!M7n`?r{q&@yXlb2~4k-Ty;vu+;rR<>{_{v))P|L$G%Q&27E zt!^Gg%N8ETf0~h=&^Jx(_@eft5}T2BaUiqQ^j;!=rDTpd|8iIB5kE{rZZoat=Qc~^ zIqp27!Eivw!8Ik+ql^w;)w9MTSwc2cc> zg0N&p-O#fm(Upu%XZbasv`+GCj%AxrnaW+*f9cQ~Vms^=Jn?V2QP8^?cQ;SwX)@9$ zjbi=J@2~;&GNTO|({(GHu6qtzVc-FKalVzl+7CiiXEHnRCHMiQI_QV4ojt5Fr|%%7 zDm3{q3)YzeyAaV>=C`O}s4UWXP6{b(yaUK|p2v`zMq%@L(7=~;p8wss>5Nap5jv5E zN+UGJ-eMyZ8y(Xckv8xMVQ_mVYpz>F54`kfm?4?J>TzBaO=9V=-W41gv-ebPZ^$`R zzBBbmkIn--P!h#7%A(HH*RnM;uqZ$b>Zc!TP%~6dR!}RG=*oK;syH&4hRXc!-QE$y zN`!I!Zz(-g&rhcybE=m)$!dsTTf_LJaubj**j#8l$%i8wQ!5T=;(a8(;TI+e9%^|g zs+gU0^tN+j^pP7umBp^faV-p(cO#+$1O1HKLaJP>onGm~P!P)ikUh*~mN$ayatG(P z^wOJ=n*MxuFZ;PN=9Utx1Xc09*bGJPB0rY-m;Ngp=<~@hP;~7pccg6CShtmOua>hT zWWnXWRRTOak`&oXvYigM=WskCKHG!ZBRHq+g_>Y2Re%oI{@QzeH=^j0U(R8oK|8%9N(VN>38`;$=x)3tuzDHNyEWd9X zD7E6*Wqfn>{clUyGXK`K;fQLdXo+?IU~hQMBDxZg{#FjY#`9wn=S^aAA*f`|$^6U> zMG$wkccc)ZUs;a9%Q&V#@6&W|s&IDCRQY9WH{L5)@sXtuXUQ~sE^<0P(8ge! z-MVq2WW)P^HUh8#6y2L_IFttlPJH#hD|SElFdVxzxbI41XK@o`y_?b>8t8~x-O-Z3 z49)B$SpaX^ka?K~Uh8w`+X#l1ro@>OEs;n&+)^|_p3^@#1^md3^Bz_m_zTBvAFM9M zEmIFP!J}kx>4{w5Dt}x1X2wfKTZeDSH#qDYH-S4Y<3va7NXpO&C@ZwDZ=8$t`F@>OlY~$J4$ni^I<#;oGd;X zHbP&~&DMiUD}y}^l7YdP^&yzGJZS!?;upsU4%%QdL7D3vG&2EMSH|$5Jhl9aTu-uH zCz}OV+VBmY8N7$RWI3PYK{@YI0-Vt}AYuqSR3j>bH$aj9;Z4y7(g{{k@8ErisXn)F z8)!WwNJH^jI}L`2-=!dY%gf$OL2?9h_!Y%0u;2c{P5g2jXeGB=!3ac@Zu#PHZ|dDV zC*~bKq^#^~78n!WO)I?g4WyZ^yC}V8v-G0Tb*)2P=uD(%BeTP3qf5XX3ela?KX~|k zwQj4pUiL6X-8%Rt!<)+eFxW+8ps)CbzM$r0u1Bz*-&Ag=V3qy$)6pz9A4m6LeB86N z5g{q-_Ce5usS%-k{1N_AL^4ocIX}goq(!FcP2R@;zN^;D zD6)}1^#f{LRnoZfhrYv(B!3MJvGDPCp0)7ti}%A`VL0Z^UNn#HLsc!Rf7ysie)QWv z{7rzmjAwz>pm`q5Z5twss40*0qh6y~Now8w>hq3<7G|IySWoxBebObTE z?5Y-3!yk_tK>hKk&gw6jyGr?0PG9*lhadg%c&mHTYCEyhSH<0zVJ$3bK&t=xAdyrr4o>2i*Gz8*dIwdh#LDH8~%=Wzpe+` zLMhDIsrX%8W49dDF_{2!_kKI+TgN#$;~$5hVkUry!bRxMH? z&d#W?{s3jmrJ1Tg&-}h`Y3X(4%Ckl<{E^rG5z}JN`zJ8w^}YedCSJS zus9PD8}wFOnB;v91rqsQ94FaU8J||hrpMVDU0FsX@BDUQsN`+i=Gyv4Q@0o1 z;xM6OY>HpGa1n5oH6Bu2&%;Bktcr-7>|vy=+ifcRL&AbOWa=VD+^M1y|B=j3X7_}D z=~o(%h4ZYsJ+y6$?RT+S68XXY3CdG*r}9jEO~D`pfbd+_^n>6adR4SPj>_%5LGd2K zmXya!Kh6Ib*mL+v<@fgM)(=0ayy*o3i8S~(a7;|^+&eLodL&(QB(*)vD&+d08JPVo z2ul!rh8i?zJyL2E)>UAK-r<>Ac7GIxWT_WQVwU%}b~22m@}}JW7Qz}x(z^=9<>8R~9PdIk$9 z%~r(voME6of2aD@cqkhfJ?K|^7i;cRzc2h@eSXr1bgA7xfyM8-^&?N(tZ8+!Fs0HT z!F$_3krReP@^Z4pf|AyjHSHBVKtd$nwU1>96FK}t%*B!0V&C;k)|_AKrGH5->r>&- z{l3=fG3(0pxwZ8@7K+9FKCUlbW-6r_YQ&4(2UY7|qTZl1A&&PC&r&CHTQFDUNA3kF(4=cDSb^|xn|L#z*Mx%}j< zJiFVE&WiP5S`>lz{F|xD_VFn66O?Q7#2hlLUtHO=Rm`yYw2q+$)r?R`N%NC)L4d7;u(@*hH&0Y9VfqafohqTIr3bq z#12fNE;fKdV9`|T%F`mfW;Tl`)4RV#^9VE8LMrgrGJ2YQu04k)3z@2QBqo?JTkKcf zH4@i^FXQ#HEPR=umzCj5b0Tlxwx}7%t$9~Y*|gBR6<|M6=(!>htq3lw?PoAr{`5T4 zA{w{hM5fR|hmN9~l$*y3i9!{Lm#}`%n;>TV?IUw;Z>kQ@%Gta`mFzv}Pgt+4uv4GE zMYXW`=gj(=Gn+5Js4kz?89?pe`H0nX#K{$pX>dCEHzMQ$#l~p$vNvgx5vnO!7GCt! z!ed!|%`N(!yiHvcs4mkNe>jpK`{d88?1lWwT0~ik_5w1sM0rsmjwc7V-xls$3ChrF zS#Kc_vR;S;(Y#Z#`l%_~ldy&ap1s2BWH5R|0FCmden+qO*Avg|&@_WcJh~Z)^3U7f z7&kM7%PTzpEsCyU1z0peH7n5bqV3&)Nf>-7WnSwnBaZ|Jj%D7^751Uw75>P-{TGsZk6DlRm~4b)<-N>iRO?P>zGBV@n(t8mV6Sy+s~>GYl^@xxoo6gD5hOGrsK+OAJ*)g{jw&^D62k@sTSZ>>$;&|| zXwIyI4$YZxgK?fz)(tcje94+wG(UFJzb4z$(%M4yjk;L<^HR%4(-tkSAs@rID@b!) zY)9PMcyv?$S2o~X*PlDHRDXI>ynbzPboJjDtG_G!HCg?Jzo{+2)+GuTjVd*C*`;w5 zPM}$%)CKg&k?6e)rX$h(wV}+i-K=eQIZ~a>czW3axon%cV^^=xn|dSK4Nfzt1rN-a z%x6tH=WBZ_Fa%pESr%VNju;1dnTM=ME&LCyPd~qhqkPmnayce@Czx${96gCY62>2w zH#5j(-i(PjLf8l&TuH8RGZ9!9L7bB>vNqfLBx_Ek-tSPaNH(+2IN|E8`ohnuq_RNT z+_pDMl8WeGP52~UHHHojvL=TC4fjM^&QdlUhI}mwh6k};3?pWi#mKV?Nx1~)BnWYSEjaGk-) zg$_;i#smtb!6Yw|tBssWqhAsD(?+TFeK%Rp_&rPYEQ{)CT40y#**M?IfP2~HTY(6| zjm}uZ#tURbu#Q^m^T!i$L&9pg6IO3`y)t9^eIb&eqRRinM>r^34R)o*&! z=2AAeo{EZczY`u0sEmqw(^1|S4+v<+K{v1XIn_7 zpXT#?Ecm+>tW~*8CFOvFuwFNj8vK$hMf*wLwbpOncdad(v~w_-OvUduZ&Xuu`dK7z zMB;ebN#>A9^CY&Q04F}n13K1U!WWu)h_4YH@Kr$-aePgFurscL;B6|EUJ>H!^6NX# zo$m&ZkOh7%wZ{b0<@n6Dy4-lW@v-$hyWc)OJ`>1S9G^XyjykvbW>9Zc+4z*&tt_^C zM2CJ>T78mBil^GSkM9I!@%9w2VB_{)L%$B^?c))+Ei>El_) z5cN#pPC7V-n6Va7Q)GKDyM|ZC`j_K$mi)W_c+U1Vv3X^AeSWy6QVE$821eC*Gp>ih zi#0SZHU!Q%9=L+Rsv=(AXfmwgjD6{kQzg7+`dW zu)n#h$Lv#V!1@~3Rd!Shh=Cb*0Aetc+9P_4(@RBh+&c2}ctcH`UcSS`y7BnQe;@Uu z@ClgRc>H#;s^}MbXS2=}a^h{Re=&m9jgmKAfo~j6%LVJ(tR;!=lMWBXA_xAk*jsPf z6a+~To!P%pL+}IsGk#&d=tjBQc0kms>2}`qokERn+Efq}oK4H)W_F{GyoUD5X1k5` zxoPJDSE$dO(->Dq_NP)uYTH?#96mRi&-S`8g36mdMzY1^@TU|BR^sRn>7n~6;Jc7& zQDxN}Fs%ouC}Jnm$K(~H@JCgdrAp(cjo`RCYYJ z$y@ssLGY%%McHEO*%x>VX7XP|e;5&>?+)cRye99LY2Dtmn>v)ArSc82@^SiQ2XvS6 z?$#K*PTrjW!E8*wEy8a!A01#>I?qR^mhiPP+yifj^}7u|F7;b-E11oHORto{i-5Z2 zZu>!v>8NdU@Sr|-y;+>iC$lBcnYCW_`JR-jzTT+@0WVmF=Q^|d9o}SWG$ec29@fw( zb&F;_3jJlI)fl+mjB8mpi_ALP2UWD{yw+M4i)77B`;i_>*4>OB=si~u#L3(f3h^Yn zAc7o-gCqjR(UHzfhB%z@Z2)6JoK2h2cxO=E-XKmJ`ICEvpw%~f)BeM5fe^0XSF!xe z@nuWRNl<3tP?Ocp;LdKPPJ_FZKw?3wU9`Ay>Fm$IN_peHTB*^;x|S&?pXyD$`3O_2 zPgIQUUEiW?bi0Jp_sk&kC*uW1<9%!%@)-#LOxQzAY#NSm$WpnpkduTwbMA>0+P#nw zj5L8$a)xAgJw;NkWVLJ9%^4DW#HwP156-~)qhFEBW=U`(=~0)k0j`(dKu6{p6ew*0 z#oLaa$*n`EWe>15j8WErv|M&FyZZ}LnyaUZIvRflWn3W2Xq;F}HzPy>L1Ysl?Bd0z;dfmujry!%I-oc2cy+1#7j zn^$6py!ob57bVUh0C@T0=v*fJJYiD5;0YQi(VyvS50KP_zBY&CkU%GKTt3L!U@*^~ zIibG#7U990b^&R@#e#WesAFEv-qlF)^rroo@5$=n48(BdoEDo;Ww2!TvpQ8*Sx{q; znId2Kk)-E#d@T8MQ#F4U3cT!Oh(3{@I$C26)2~rk#|SMvvWt0+%eNk)40@B?8fmNa{8Aez>RSc}l{5 zVoGKxFZWXt7|HpTKCMdqO2U@z2XW$F?AJ*}ytZ8u)L<_4Z7e;&p zW$bZjBAI)rO2a^^mMvL?@>=ai#sMp$YFVqgJd?<+Fn4nj9}7ChMh!lDnl=Wfu+a)pf(K11Oi^MAg&ql&N<8V0W!<^)qYrlIdXNFKxn9w-{+S&HdUQAN?QlRcBSsE-LSBYYoX9!Z1W)j7v5ncT zjbq^%&VN~pUiK%@E=M5B)Vw^`NAVuPNF9RC%N}o;#B%#_%3TKbP*U8Kxw6V2%~AIYJHrPj^!5i|?Uo6a;M}lfc5a#Hw~}R# z(fnd&4;>pEK%44MVZmsS^WZ=#VDFlL!&9u^>|ozoNTU3A5)kG}dsK*wS&rDd?EZ}? zaPjWX(7Wq)kmlL&hs)Qyf37VSBnn||2naM>G0ankIf}aO1Uf`SdNo|;Wj2QxgIcPn z%a34ljqc~;@~f!dJ=Jf#Ee&+@1iINkH&39O4P%pvdgMroo&&zADw`g}ml53YUM$yp z*oy@`+dK*!y%X;0Lxo}vF9L*+AhUjDjk_~meF^h;k?t2Hp3tBbiTp3v5VO9K)u@k9 zTY15gPd9qjvbNnL(Iaij3Sl<@xseE7n-L!^eTS%y4I6ZV^ALjnh|1s+7#O0+2s6-Q zH~4gPB9vZos6*+{<2#`A9;S}qLz|k1nH^@!Hw1=^0t*w<03K{vV2f9vtVPXv!-unc zG)urnw4mF&E+MDxm>x3P%M7BrAt!s80sJOxLZU2j#6lKLI96539(h@+7#<=Gc9>TVlQKaRBnN> z^RE*SD4Q>9GPViFyYk($#rnrXq!Hqdg{O{($Bu0Pw@%Fd#)-gDh(MN0uhv^rpG5vw zPW(OB$O@^;8C5&=FpS1X#1oe>8r5JNs*#g($^7@iwV&7hfq8Ok+L)?h2*ewo)55>8 zu^59TW)zt5oLS?H>lx%psmAhG&+*MPak4o?FtPHoNvWmA{}Nl~2?<(OnDP zkonpX;obFlD(Aug56h43nJi~Zz!(0N87H+pyetVKLQC?cnBX;HipZI7U?cteUgpw+ zv9-Lr-pH4w%HK-m#~E=dQ{DPuRVP(4aZRc^1$-PKlkBPb0bEGqNFw>!tM$aF0t)V~ zd55Kkw(qdsSp9D=(~G=OllA2+8vx(OLikUv6OA>#QY0<46Oz`)k}c;AHq!dLNNWz? z>T{o^auIbUfL^^wMC3&O=XE^Wap1?{KU#ate_3&q& zmD4-ssr7L1f^v)krhTzo>P&^AE2hR z`OaH-?2b&DeeH4RPNbUp>@B>oU#+)rDet=d&RaNY7s$Z2{-tmKY%KMa7ba|;OyAY4 z$HW=ylZ6B4B2WfA+@dDacipOVHfRla;BKB!=}crVq^`2Yt?Fy;l8CGIW-ZMwuWg-M zrQKcL^gO#j*d|tiqfQCs>?C9JN(91;eG?KBH;2OMXH|pS*anT@PV2l@hL0#@0=84J z&qk^k&dGNFYM7GfGEY03<%BgI@P%yty~Ed4!WS6W(c!FzLm4OP0Yy{=k#@qDw{Ylp z`ADb@rk#Zx&|LUP1opzqc0s&`n0wk`E&=B53^BJnS?Dz_U!5GV&|&UQhq*111E$9@ zXIfO_*7Y@a3UglO9dJcQTc;VS;%Hhj!l6l|s&MRs?TV)ePp^ZGuJKf`a^UGR|H=+{ z+IMw?r>wwF49K?fV?)VQJKiPD)K5M;!M)A4H(N39m&m7u&s6>)+5-|@q`^gEmRdp?84OC)D0;I0gE zW)SsPyU6rj=3L&A7AK#k4Lm|3@+gESa`(EFW)z$GO35G5FHxQr?i1BCr==M&Uh|dTqOUv;CN9ODlas|$p5)yq3^Z%LpqcH zcF6(PX#^s{@gSU4*0^P|=6)mpS&K#c*Bb5HEKy>B$@>R`A$Ih4h$f_TFLUwmjpV|1 z?16x>Dbl#ozwmOK4zqduB`$>Z zm#Y}Rd6*{c!8#scjCm?jlXc8{TZ5EUbL@GU=T5h7E>II*c7WcT9_wXBj#43)e{piCcMI5} zDU-bv<2N`+g(YXBhQe#@ru9bMv%O_b-wje`Dm!3mnkG!zI`R``rW~z)+}ENWP8&|= zwV|_;Tjk{7iVUpIa5*&lFP`K;t5F>#&{ku82EU@rg5=NN$es#ImMiqvg$NcwEvT$6MAXnq{0PZv_WXI7KLBe)SrXhjzJ^IZx72~+Ecr%bp$cf zL~`!4VHNLrnJoaDaK~QjtpM|gzbkNM&*gD=h7C4*f(YBoek2yCkhzA|BsW*;mv`UZ z4Tzxq-H!BnzOj(#bsL^S{`n1F*KX;i&g74O-3g9#e!mxul=$aH>JLt)e4Kx};@xp7 z7xC_XrMADf>9!>z{hh+LckkHt9%}n_T)dGS>#E(4ei&=_>{7dbqTD9>Z0-ILzZC=4 z`d8Ia>ho<_slm8dyG|-g92|6%S`&I-tS_RsX46fXIQUW6)ZrbQs#Q~8;)FFn(nfN+ zcU%s99|2_U!^{&Z(49P#99Rymt7E@?p@STF4!b%iSZm1Xadqh_quHolP*WSiLB6817H){O1d)Vj?RY$4Oz0~Nt%vqb_`}KRq+WiW04hQf~%59>v*6v@AcAdRP zb(Gq@_YK-TKi00PVG)&NPAhSIa#M|n0TW>hJ3ZH7;Eq-cy;Ruj?~VAK`#4K<@@XQX zlULr`M4!~$%MGqWw>{gTxi_&~gWsueTrXozt*&zUFC#zdFOl#y>>-6Z+8np3HbbI0 zJ#6;Cj?JE(aC`skdY?e7OlkbUT!<+fR60#i;Vr=Qm#?}%%+OaU31XFOZ0Os&a^p*UA-cp5g z*%scT4yW>WJZ=i|gi8P6ryXW~x&lmMIErP_La6?3D>0GNr`vlC+jetN(YR?LeBcwa_K3uyVaPNnR^&IlZNMUX`u@5oNgXW z`V-6=;Lu9T zk0*L$TZR7gV#N3(#GWnFq^dI=;cun=3PaTmgD?JvMKDY^C(0TRLmpfCIi>O(Y_6@~ z6(R}`gDk5Z7{1rWDoR}Zm?jlgGu|T72=H1sy+n`MkE<+El1lDg{|84}Ke89Rh5_~| zl?1y&N$PCA%vMuuQKVGNRwEI!mn z!pf3O$WIk+w_h%Itlq&ZtR*SC+?&1<<%%spPwBPYoBj!IWi)&h$S$A!1Ip@4I=~P4 zFOA6=EAkIryN;ylhvu%~$IFa3P$0zBnIAEYiU=kYQ64SuK@Xh5F~Y0My*!NT4Y|MG zm%Oqw@M=mg9D5JDmg7jqnuHseX+JXkXBnAjc6S;H0S$pvZ~j4VLM&d0-rooC=;`Y+cwBD_~bo@xinKzqq_J3n9O{`$^ zPqrEx+$_Skaiz;#(q+2kB!_?Z7n@3yVy8c zVcrsj-^t_XpTk~gO-;jCK4kilWoV1Xws`f7Kju#D)#4m-Bt0=}x62)kg6oXc+|dXm zb9rhsd6efce4J2vloK&bZHXRpSpg6qp#6ZbWYC^Ufnj-~ACB)?R~XTbJzmSv3zJ7Z ze%H!J|E}Q<_KU6e;V2RCXIO4R?_s&|ita`*jp9s}KSm~bt3tpXTZw&Jab%(AI|h~8 zN7%w@ZOE>TTPLb}Xl>U_TvTV|T?qrj@~2mDW2u+D<|aJasOdVT&h zXIb1qVlqFaff@dGGb2hS#x0upbxLt`qWaOvmvwCcdAik~=hcnS&3BG`N1u zd_@V;*@GnwZU?wcvvshHic1o^l6HbsObgCFH2g>=)CjXSGpt5O2vy&EmG2w${JWra zwe!Gtsi4%(yccQb!eToEjVhhFt!*saTORM%nqt3dH`S#2b$Hm`wjKMGPoNN-g6^mz08fwW2J%+S6FTt z<+O4=kWrNKw~*bBxW7J2sim5z1r-CRZ4Rf!y2Gs{+K6}&QY_8?ax+>z?{ zg|s9_{)RNSHD4Blnpw#Oier>De_JID*~;$PBYDW5Sz%|LKITRDw2U?x$Pr;~!fg9) z$={MpFD>Ux`uO_luf5DyC<1ot#Yc%A*USOtWDi}i0M2Heqvo5Qb)MxvEQ#cZAvg5% zX(pq`gYoy_>hrJsu0fo=)O^nlGpsX5f-T?Nz@~x9{EvIG(x!Qm9YE|RosIjA%NSA| zE||KSabeHF*xFRNW8RWV6#PsUa^%sLj?n`w6n(v);};F-_Dd$EP0+2GY@ZEv6tVm< zDlO4%8EpjfRo?b78Gmrhz_h2b!2ry{?2K2LY{RBzZn`N`o~DIO{iI`4v#`N~2Fl08 zk~i%{#9y&b-!Jv)2b*rl`m{&b(5H`f=+oY6=so6v;<>GElt^vnU@t-Ie4EvrpT^A% zqq*E>z1KRuj?pRHY|2xrU`xkHUAIxG?Zl#f-9dh4(MjX-b4}5I^Zqb4Q(X}9^KoP= z$g$DI6!?!cECGr-tT8FSp|erzXlVu{tuyzD6qOHn#U z-W;vfVGF9owrNp8*x;k>9ihxw9Ey(VXtt3AaHegZDJnvPwg7fm<_JyOsdcWJlc**} zZ!@uUgHb9kdXq^|0RaAh!yN0M#XM59V~dmVz*dEJ4PQe6(%XLrOiEk~urg-Gve`oh zv2OXKYU9~d{uXEE{Z3MfNEkANL!-CVf(JRa6{Gr_EfUam1WIrH!y^u7D>Wk805ze( zzv=F;={JSy((NG6YE0#>3N8s>Iue zxWxBm>=ad$611;klSTy6alOeyFcejZGY%+%eKyU06WHSpcVItB*JEH`Kx4rVDIb&H zwmwl3!wl&hMg_et634@c(|~jI6G#_|$hO&>7KvjnVz;tfb`^?aZG0$+;c@S>d*y*SV{?xi(S$1^12n zKQ)N74@;yz8mRrlY8fOcr`#KPOmDIkLB+l=G_z zR5F^NguFJ4jv!+S8P62rHn+s4klnDMBW3dEjE@j4j;Bjlm~vLL#5}>vZHD009VJ6Cza)QMb^DZ&T~o|?NYt3jk_l@z zD#q+IgAC@2x7?mMV_Cj$K0i030jvJl%lxEw2t9YnjP=*OVcTW1`&(+<@VphhPQ4so zBt&O;+QBs&kNVs?3{b606R>)S1*)&`A4U?1oAMM#KCj^;2IjfEVHgV`>YS8%4FlBR zpia{D8JnA!buO>mhV@6tn|~d-hE=zFg?nMHqQ*`Hqmt5ovqNgZHi#v1&koCdm6RyA zP34eHeeR72%-r5p0L?W}XyRrY`@J2wnHNxNO5mQw8;mS)iR(M7VM?+;rvikOAnsp3RFDA$4rF*yRl>)NcryFF5!Itq};8cL!dO@k zsjfIkDad^V7)%wMW>($jass~ExSM*E#sqdI#PS_QYH{M*nms0QC13+efUwLNd>K(^ zheY-&c0fr9*p5O)u&Vn^`c=f;@o|dVx%U= z7|S(!_EqasXf!{iWnsrUl{T@*hHKsE=saC*TzB>jO5akO)w)pn7BC@oPXrfMOr8`` z0gk_zUUmzo2tvKgo7U1#9gpL0zR)cbEtEYX32{P55+^bViyziO1SOJq)<~kH7fwOp z3yD7Fy^7PsevbM#9~1L)~qR8TS)p1}?cuGX|t zyw4|^U_y*1QrympGEELAaL8X$hVFbDs{O@-TD`}avSBs%J%dv2+u`&#(oO*@JiFYNg1 z%n03fJly;A%7L!$Z*D;yC0c(A12*_Q<)d}D5<$7uQ|)8;O{u91H{F!6mF{a4pI_Xu zsb)2GfXXXg%QuLwt;kmtn78L2L z`dAFqA0WJt#ZwN78tFJ3$^GS%ZZD3=OW*6DQVy%R*?jHZ^w%+)LS2RGChrCto9q9K zb%`^c$Uih~9RpfiUzkTN9mU15(rTF@x?Nw8jOD_Y|8jkyWuP0Ls}YvSmt_=2{rfSE zgfNESspng>D~WR;p(wm-h8UPOgtv%U;^O0H zn9f?~F1oW})BkqAS>iZnWu%yI-F`E6ZzNex!30_$7hJM>lJ=V=AQb`ZMAwlG`D8`z z=|uH9@5&FxLAVk#^4ec=g=gt_v^hOYd* zYg4&4#|F-o|Motv&kNoXK8xOi(3L+HSHA95#+2&N-PQy~)u>ADe3CE!Lk)OhV_*I@ ziRz&hacBNeJQ84|xkAD5@7Yb=EUCa-LbU8j}q-=_H*mvfUoS4dbBUwTRn|X54zuZX%?4gY;CH%YN z+qR3(N3J`a0k*rl4eE7xe21~5|EA;a%!}}I3GC;18wODb?%~av`2jAlJC4|xVKY>28OQeh)LxD*zt5VY4q=}Gat!^b zDCY`PlQ(0>wW`6?fbyUhFX28U8*Qfb=`%roqz{?l(!QeT<9IP@F83&_D5@~GG^hoP z=v*3L7_Ssg#JlK*CYZqzO3{xEGbRSOqZR|~m_;6s&;UD4f!FEr#DIJYWRO3mA8#uX z1FpH7xA@r#_5ryKL-XVXO%zUyomAE_z37y(j_J9a5WS`b{RI!A^($WI99~lJ`K|oA z`Dp|~H9YI)&J*|JJaI$tmQ7$>5!N_sW0iX;vS@n^cK23XFzqV{cBc56U5Z1d#>_*r z0)N|~yc?DHF2!K|n<_snU(kv3;aYq7F*Ujq2a9fF4t9|khBI>6*FNE7HAe(%4W!xX z+x@jC6K3^c9@BoWAzV!Gs|sOl`|tiiA4_31)CUz{VJ)FMxO)(9uKI?{NT3g6Ew~eXNsR}1byZ<&_!IXiML|$hq3k&nw(X@`Q(^^@`Rva8{PZu`2R-OY@{)z`d+ z?5pL5CvGJfw!OK=HK3`Q%i|t^Cr}zSw1o?3uXCUA6~>45L_EWh*t4N6P}qice+s)k z4@81$XuY=mjn5EF8rN8V2eGsxYvPkzJM?$0xVyWt{m0j?zlW>8zb#iz>tonKZeHQ6 zB!@P+$R|~EUc7(*9;p6(>J?t*AtHJc@ySAcxjd7cSYV|DtjT$q>sb{7G1#B?+1JH* z6V}~ZRfRw=@Zh>T2-y!1O}*O=aQu-;+zaI!M#0N2WHm2qG zMa!=d7+#vse)N}vsGPP<5;$lp)(nesHyUrQbj???Pq0~1#PE^wIS-p{pR!HE6iZZW77>ED5g0tw4aquoMcmd@!M1={QmwU(IT|e5vJMT||cLCqJfH$|) z4nx&d|C`+`CWdow`jejcx;^T`HQjb$9P#6Y_VYz%7`-y0Gw_W1F&y~_H>LbIv1ws{ z`cv2=BC+WgA=aV}M^lgct~zTpc8LYS^0I@~+3T5OI>}2nUQU#-bIyAIV?U(7PEzD9 z_}`?+053jXBSMfW0Lja2%{RNlAo7^9@uPi3m&5gs$4kR?ZC5=oihJM-H(VE}2U&Vh z!cQ~|aQFXA9)1WzTTf2g<{RbVXT3Vf!@H#kNL3qS z%Qf2_uPyjICJ*zb6?T#b|J}HK2FqJ-e?e;{xiI~B2T}tdarl&P8;_gLT$IGZpSuNh zI|H@ps^IM}WBk-Hki?dp-zR>=+r8pIY!L$SB+afv{D><<^nD*TVc+y7 z;zzV@5Yn2i4dyQpv9~zB4h?-qEprx1Ig6FDQ4-~|TJ@8kCG&;1neI)N4R5pU&E`}A z6rA@r)oAi=D6`3hmH9-61>4O0`PzC!kSZNDUwxF?8O4@p3jm1!B2oRgm%g4nD8ce~ zlrIi)dW$*54`UR#Y{(3k?RaJf(&K8n>;>|5vktLTqcS$W4uJ-H_g3oHCN$Wk@2F+1 zYB+D3RT8%eP_Um8^7vzWZt(F3${$u3ThIuO`zK_y%A3BIK#Xjd@A2Z4Tj{nJ&{nYP zr?K%UuBOys6P0{{ArN)d^k7Pd9)vn{Y;Q=g#e14IKb68i2OxuO{w=-PW*55{@UVAj z^)DnA<-1uNM4~g5x%}JGl~*JRo4>FNEQBjpBh(ZR$>2Y0~ohl zdDCBpDguZpy>#y>j);l>+fu6GUQ7XJ;HhemuMDfZ~cUBh{J z27T z+xuFVI~KwSRadZeG)dqhVRpvb{|X@FV6THlw z%+(t2yEX3G6u=&ykPML;0gtl5Ik2H>7u8YPoI;>KpyN~^epE#l$ z_uUxLEvJMI0VAU9wm*XP45^YzGd?vS5Q=e)__MkG3<5NNbK`Z60KfOUE)ezj9{>L! z3MZ{idx~o`U_+dmwx&OuM%U07e?BRX39>_s+lih;Otl|7j2*aBjF_&cObKJ73cdC% zq6}QA7Jow*`1F6ci5 z69RT3wJ!ISNPaA~M_Vtg|5UH`GSj}$;5!2X#?v8>u5|Hr3yIP(cuCWfMVj+^qY zbLA#8^p$&I`y7P2 zb{TNmeW}?0Pm8w5`~JEG>i^QN`){DU&P9moe{dn1ZP<7b?@9L2;OsTjZyVVshW{;S zU-;)*DsE`_y8Q*GqY2lmyXv+n(Gy);3vIr1lUPtjpX+n~=n!=2H4D0=kTE;ZUkT96 z4I3PvIGv1mO9WB3cuODQHP0@>9_PlAU%RkgPj>}?#a{XscUsZeJA!Rkc8dBl%tc%r zj{1-t+g9{{&9*5UJ&SA4oL4Xm;1>q(YK>wmmArzwr%$ehm@7P(cBjxfwL=Z@2#8Gt zPAk^1gb=#Q+4fN9M&m^q^KCb#I0TPJ5V$x*4uY#31Qp5h=?;RciV!%zZ?gO!HkBhc^sy92$34d=l?^w^n2{abpw?QO7w@g+Y#ih6|j*I1*Jd=f`;c)oNb zk7f0s7Yjb_EaS02ic5*(mmvk=-Z#3QOO{T!+$98P!72dyDFE4ZFuGo54|>j84HtM! z)xdb!LvVw!;`5NO7~Fr2B-X?F!lzy1pKiTbwM5IXMN>a zh5n8^WJ>+YJsLcXY8dyN-^07pSkApxv0Ty8f_?D3vl&Xvf-Sm~AdfB*O#=?-Zg*p7 z8_JKFF{NkiMpdz`7^8tO=%d2y3v`>`y~0;dE03ZQ7@@|`7xgDU`4(CGWBy)je+7== zO}76G8mrp>1K5nUzY@baxJHF{Wg&sUBa2b->?qy1nO^pfyl4~$Eu6IVcE(+4pV7S}h!rO2Sin(*AknYOw$oXrEA zS#R8yntR*q02ach(js&3s}X%kj!4BaTgk{%LU!CYQSSX773kqc6b9UF>av|OIu&r}Ah(wF0@Ic| z+ohBJk|RWEH2NE+UAdf(7+UEM9O%eoA49(DU$EQjY9J=$o$E|xS?=@4%vUS}m-mn( zPT?>&Zk3l+@z> zwcs`Wixepk7JTr6TF5Gld=wlc`>3UbJEz#fnbQG7GP&UX4v8_fGv3c3Ko#FNwRflY zon=SsZqAU@dv*H$pBq#@HoOk=HoS@a#0G}=F9$1&OONpM)PqXva)|$`8fi|NqdI)6 z5m3htPqDOEhtn=oti!>#SF4E4^`K6k2IgyVz#mhEHTkaY(&#EX@+5TIy z>M;MtbLiWA8ios(VPabhA$Qj^mj7O+s%@adA+EnyDGs-G0<%4sWJ#q)expX>816`g zmvzBFe|ttny2NfOtSz?Rw9;gpgTd`LeUIsDlN0^BTe^vUUY>?Zdp_6xhED#K!YEpm zMUr`$)R?%?j&~Cm<$F7Eafhs;5C_4&iQNc+LiyHt&%{7B>3mJiZ+VuCRu%c8dKgt64H_8_Td(ehq?O~Dqu)+evF z$t98&UiRAf-oxUdmeRqa&ZGxE}ng4i<1Yx3Z*;xNH4*N&B>IRR5 z7@O$_$c#i`oD;89?VTmm#@x5nT^mcOdki~W(#PJ^%8df6a~oA20agP4`A*=^xuY}q zOXqhB{-c=C@y#W_B&$<|&!Fv+KQ)wFn)86Gc9BrpQ5fuCX`#T-Kz*$BJx=@w+wmoi zvLDlCL}`&h92XJ$+4s@_?yC3BDDKF9H_Y7_z3&@9U846N*Q?ieII-}dm%Wdy!L6@q z5^(n1M$Neq{e}r{-QU!)E?YdsTC{5;%mSQG*5F`T4E>BD<8_6ON{V&^4|j=ol$zVj z?G}QUvAp6Y&&vq7VB4?N=UNy)Vp7NJ+q_6U(T-2Abr|cHGU3?sdEtcM%}+N0&_n}h zL{IO!M{2(1U9)JnM+P4W2aS-O(=}>p4Y1Pwrfta@e0P-qg9g_6V_$ZR|J+rb7=M-t zDJL zGRbUQ0U~{yRmCJf>c!#^XBdNP>`NCjcsB_BL-!D^mE9TZ_iDWteoKbEP&t$9lOeT7ap>W;n6@TN8i70%$KKi z5BWhr8kZE`?*{VU4K70d>fgJE{7>Al#r}=VWt}1al?rtfX?+mJF-;-66^42+Yo(|V z|DwihooPZLx$*9-IpdpP5~g+}nWKvF)pqF2X!1}@rbD!g5@HPcz-pT5)(4er=j&n+ zY&ZHUm_S`Q&x{raMDTZD{3giW{8b6E;Bs+pOa%=x%ro6JIX-N1ukb*?N&pY;U-8XN zUOxOwKwD?7oo&cr`a=iPF1aDe9bIMB~1Lp)(239hm`smyJNgt@Y#Uy9PN zBi+e4?VooVYp~e#z*xd#IC(aya5a@Xg=?f>E-74-e+jKr7l9bixkukCe%eN#6j49y z+vyACStsI1v?cX+TP_Z!W6DN%XIam@%=1^6O7Ijvwz)f%yGbfz@Wlt6uyHr@g;ROa zc(XM{9Q=xs#rZ9czA2hu;tA)I;PCkq%9K{;_e3bW^buB9EgRqC1-%&uQZo3%vudaX za_Q)1-$Cub0V1S$vAC={U}n_BTP>ZSTFE>SFBU8#!GZHY=e)Of&imWW30EuO8-V%K zjHrPVIyW$?bA5-9fM&E$=Zw2|&bV#ogfbFbH`Yz*)Wdg}TUdVzj#zD#ui(4Oxs)eb zd)WQVE2iJcliRh4e4mPDAMFUR4U1>8k)haULJ8zgWE1{Bz4ZPM3Ku5$&6yDMJ}5-Y z!ZT6y z#8LfEW*WzWkMZ5*d{8-I_t9r7v`eOH4iLI4-ZZn*tT}~)UsKd|!QAnevYS~7MW1lD z_!>%SWPJOz0C;hC{D{ySKO%I-j~M$u^u?ciwfOd?eo(4imbuM+5jg#5(Z7tHuWVY7 zn93ZcPqvMOX`&dVvp3nwMiqKau};(%4xE~N+-0kqFEN4r+%rZJOXuYjGFY_D6 zeBI8b-1?lZ9VHN>>hLnN$x@#?vm(gNji{^X(g?BV@Z|7hF8yPuTzL8eB_oE2mMcKl z1|`Q_`rnABV2oM)a_a9!S^wj3^VE|le>zb<$J#MEZXFHp5^Fo6D8(LgL=`;h3&^-< zF~~wTjv)SWi9SX*TycnH>?}T&Q*khzPmX>vJTZgZy~<{o4n%f=rafwF4^9hfnoU{V zKBN;dmq)x(%I?qi?QN84HI6z3+CI|te)&BZRoz90Nh zRQ`FsM-xMEH~vot#6wohDHRq%#w1Y~M<)2azQ!3yK4=F|non8=%jV~hWOLI5lHAic zJsHNv6w{6=J|&7zhw)^UG-3<6qI;1P%?TD3Ed=P6c^ZJNRn&0X!;0d8KA%00uIRdp zH5kSt!AE~nHINBANc_vMUtRU-ziN`G9w{;`(aN^kh$mW7oX#|QaWmV1P7StAqkAYT1V zNqEB+4_YGbRCzDSG%Q(|x`GmFeK5~sHNo;sK%=Rx;d3SVmylMQdwh!x zlo^h{LZP*W)#nTa$z@Z0e5Cs0QB$=3_;{=PxtpK5R%=m$dT_X}g#K5Mmp84I3CR}3 z_?SV@4O(9E$K_UV>-QXLAQp0YOiK1s$GD=l_;s-&9S+%~V&eQndY(2# zlrxK%#AiKsF4X zxYUJlp0`LJ8xJnpFIL|Q2Z`cA_wS4Y>*Y)pn@A`%ol)s}Mxk6k)vY|0j8hAB+I!d8 z2QAY61mz*GHoxeP$GgMFx}{U?jwX_HL|uR5>T*+cIeF7I;YHhQU+-mlD$K*WdF`O( zVsvEvg#P}}iPDmws=i)pUov@_Z}C4{P5Z*N=QD4$OsX1A>IP$~NmZ4+j{taM#j%O} zNX%P{x-_!49ws#Pg`Pxd(T0o6LY2&Z*vN;6^&wTwWhB$6+1bbNX)52pu4O^UrrYs_ z>_n=h)!ld*v`RZ)6@q-ON+S{av-PfxXgiEE`|JAaZcu-#<840oGFw6qx(O+n8`(dR zTb9h7$eR8|yk3kl#Px;gN7)L=Uj zMUC6|cbp(M)fn9^HnbudU?iC#E`Os08sXDHoRG;#%U%KTBgLg61~1ct88H%pUS=2c zz+~>UW|&=I1n(FG;K$krgSij=pKk$`8zvifoXL&lgw6&P=_LdGwa0`gnCMHdTf=K7 zkTL5`)1=1>#KEXGeKjS6sWc(FQL)=8R-5^duJ-jZlbHnk(~ollm7T!bp!LMk zYq*HX=5*eWXW+sp8^`8X%otZ1na~dc(SfT+{R4qbH+qExl3h(M?Q0-3!VqGnzt_`$ z(-A@77S;afxzIEbL%Yu-qR-O^3DDIJ&xAh zo|5j>OD4XY$j`Sg>N(psMemC>x{UG{4I7OzgxOc46A`8WgT==nr*duLNj?bfx2w!?C3GwT#M7WRn+ZeR)VQy{sD(m3ssg_hGUGA#9Nof zBawR|ksdOlta;x=deVrBvgSRL`CjFT>dzqx7X{2f8pU?!tS5lmIUwFatHM5&o`zDIX=*( z!TzlslJ@@0K?QD`EBw@tA!z=DQqIm@pErpjmAnM zh`X|Z%-^#E1OrJ5^8vvVM*%?{a7L{6cM=l$?*F@gtW&e&0QoaiE8QpuCHM9U?Fu$MYhx@WCLyfuRk(qc z`B(5i#5l(CTvnOLeLQHre{eHh9;r2o$qZ&JAa3i z=Il$BCG8-6-x^AVZ!mVaqTeG z8xAk|eFXHxYO~8mGH$lNhp;aBd*@J&orQ_~W&QkL{z$!A61>ac75fvFK9JIh{N}Iy zad+k@Vmo%|y2Gc*Ql!iR_V98`fRlJ1^kxzhAM{Kkd#X+XXEjSnzX8FJU2v(BcfmuCF1giz2K06 zBM*NcS9RM>MR;;A1{WBLGSo$Q5JPc!SQnnA&`*W?GPqF;Qobfce_LyWtBS!;@O)7) zq;|>$U&|a`L0%`fKB(|N6Sw7-C29^W{9$*lq6M23A|c^1yx31 zsa#cz#eZ~`SX}&S#34=*e~VN2ZPln^0)3juz2`rL{Y<8uks#ZP|SK0L#js3nc3x6E&$v9iXKLPmtTL@E*g?6@esX0t?LSZ``G znri!9ksd;pSA01-f6$!bsKi*`=--GB`6KAPYmIDzV~g|>f&9Tiq78K&+Bh7xfHsE2 z=*^foxE~IQ=;4D3OY{Fo8smKLjSSKjHb_pdj*ri_u(Huoj9#MQW~`Qvo5^b6Nv`s6 zd>MaN{}HbKV>ea5jXxP|{F65RFLWCJ6BC84r!L;T%*_1bj!($B^I3v>8VlRMGq$Wu zHva~C4=#h>?@nAJZh1@<(4aH{@Lkf(cIcXeQCbKeQAHHpg{QH4qQ~~NXBB&*=Z~~S z{LIg6QeX=)cwL4$nn-V8G#~Xc?}r~oCl-Qd{Y~-z6lO55;2U9v@qRnWBEWv6499q4 zHX93w4^_1YE-WemS;;fT_8K1h>5<>w`sH9Bj}>~D zyp@s5n!yPQ4EC?5S?X+BoJ{Xq-n1phC5S)u8Dch> z-n$C(So5<0+7E!>uqz%D1;;!~HlKz=RpYwoUF-T7pnYq;4ab$?nQJJJ!&O~|l@+x3 zMY)?WArt;@nJ+?AXJ=71Xr>D#`7cuy78oMk_@6p*{M-uCde-}plo6P;E$i4@iT2^L0yO4he{MPaBSn)5b z2{HbSxYjsy$6<~`|3h~jOL>{ii#(S<)Dh|Hd{r#B7H}&+<9bs9LqSLD*?mHWU)Fd~g3W25bvs&4 z=6As0qUGhuoY!<4!TLmu2f`ceM~fH_WOn{_sK=aF2Iss+I~tQuCv?p@Gh;qeY8o57 z7wJj)8%iUg0oIVzQd?O7gOun!!d}EzUY3(oV92n@8Nt{6BhNKN2KT7gOdWTR21ZL6 z#)Bs(YHl#DWJG8o5>LT)6p8j55Fb%pMg4btcVN)USM-hHs8ifxgFAh#zYX0C`T}i{ zAH%xJgQeCn&gX!C6uce~Skz7={(?V}C+bksu@VtRjIJ}U`z_~`Na6*Q*M>;;wnSm-$Z|E^(rs)NZh86Re7@VCLL5w22U%4mjo??hot)dauKFTQR^4DC%UGbE8Bq*h7@ zk&(%N1CKW8lOO5%uUucEIUT1C5PE*Ke?14VwX|nkR?rb%(`Lt@zEE(ysM!DHT~lnm z%*VWOW&<#C@A0Ve%iw(`J|-IBGd9r>?@dPwme>gGGIkc|tsae2YOcmw!43-v@bGz0 zZ>njFd9Iwsz)a;{N`Uym-t=d!U~?s@oR2XKa>xO)Xuwapp@(uMyv%JbiP>*MPbD?5 zuxUxPgPjN*?Vl-IF+_NF1|R<)_PzwLs^Z*#&bjy8dlQn}EI<+x$OUc^Anb}P0YZR4 z0)a$GScMQEKvJx0=dj_@D*0x}) zod56pX6D=_H=)}0z5jdvH_4ot`R1GNoB3w@W;y3}v`j%WLm~EDi4c_9BJ={xdmT$P z{8|ammvBsXvh`*i!?1#nd$=VWwfx2c*1n`3a(X}dMA-fT;$J{~G2bJ^pmmz|@gn0N zm+2{TE=Pv%KZF(~qy`-%fgc$2C8Q`lFzGos9fh@A4q7&}a28K=ynz;1x_=H()H14C zw5FHt@8N{gS_`0dV?ppN#)E2%2WS;ED9js4STw_iP}`s|)6FnOp|M29%jD3{kG=nB zcz)@;Y)<>DSXNc>T>K04v_DZ#JA#*RXuf=e+YGlobff8@TSZrEo?9lHAnk6@p*3!T z-NEWz$9-6V=&IXuC#9xOD}q{Bce&cZL3gRgOgo2OcDomizij;5_|n_Q_>7i+--8@J zS>~U6vKYe_ABXw(Ud0)DqkQm3Wl--(TfCx~$~dkR`v!kT_Mmj;#qqqCNxg~VTF28+ zRWp$U4b=CCIQm}JWYw;!(Llh3)3l<~eb_M)=&X*BEW&z;To*wa;gidUn6yg$CC5qf zQ#!s2s`AHd_WlKVplq4gi1%U_CPWRu1aiq->2dHZR6`ja5gUZ_!Y zY(K>{xA$7Wbb0YE0@UINz!{! zQVdcYTm&T4#Tz6ChwrNbBmm8kMfJE`u{f^9ZzvR+=uuyS#r-id*VkzqC+MJA$ovv3N7c z!`lXL8e-wy3=ZSKp?rT^GIgSZH2I8rvwZ)g0fz>N_s8-?MIAN`49Y@-Oj&z1QVvJ9 zsSvMI_Hl~CUqi^FGVCwOn6rN)n)v>SZ_u7l`S`Q`J=c>^3azcz4?tS#haHphWM{__ z36a1W=L*u4SPax6SsYl@-2>#1NX{?^770|S7dpJFXpDZIe_gJG=a9)I3 zDwFMT33;Ipp>NW1Vm5+@N_TtlY3tT?h(S+`IZ2=cve{n_quH)r;UTy4~2Kkrn z#=?Zuz5P_xGy+nA{d-0b8K`_D2LGPZs2-?d*8vBgBqVJg-|&Wl@-QY3-QxG)6|WbG z;@&q~r%|0zYk}hNTbeCYd-<_yNZekgBO6ieh0a^4GQUZ9I48xnAM40(6J63*Iz~K9 ziJ&ilWXCgg2$1%li7j*my89f385v_P4PM^6%rIc>V!L8Mp`LLr-X; zI^gwT)9I&Z64c`<@7Bc0op*5tQwjjx-hLRpW#f7uK~Tsnb7E za48Gcv`?*IVVwQ}wi7kKj-|*M)%D(Aqv4GD^U+UGUmY`+P(i7~9-x{%(eeC)1VG6< zUPcc*okgbxtZ$+VZ9yH41~aWz6l(KlHmu? zWE3r6QjimFsjMZApjy~nfHg{Q_^4~{N#>@FilDn+yVp{G4By+>ODBnH{SEo5^>@?h zgOT!O#TjR2YMsz@`VCo_JtSVpH@p!2WFa`GU*fi{ClmZi7QSfO@vj%DqM(o7!P!#? zIBBz6XJQ!n>iz*3PeS$E{x&W-(d;-N0FjZ7h279I9n;5>fOX<$(a@)W13nKh{*5g! z6Z%hcfldo!$a4S-4e97KwPQThAS6|WpR(d}6xt>6@0p7H%8tJ$2VRh2N>MOL@bQ+zX){~m~Y1;icgkGLp&aE3)X^wS#b|G>A>5V)6 z{Xc{D9uvHvz)qblg)PwubqyOuvrlUowUW|~hlh|3vbB)0cxGuoslNJ-4c+1=Fz{eNsG^G_t>6w49SKyn z-Op9>5zchV=W~^#jxBvwkEc|gb@xS<=MQC0d2YVuA6uSfI4cg7=j7n-%R{{^syq`v zK7V-@eKWE=BSPhQ{_1~hc@B&SFOUB`<)L;LRi2H1IDdIc?~N=^O{r5qf7<(xEzkFd zhnJ^lPov$nq&iRMBcz_u zGM2tV%U_C}L;>{N4CwDGX6>JNmM_Ac;Ux_4GujS!{HhNL@hk@8*QvRH1Z&e}_<-nD zFDl4E`cA%7bgS1zD!FZQkj=MuQ#PM1rIU4JbuX=TSvlE@TYJc;GYqdnP?k^bMhNox1)ujP;Hwrvti<}JFdlvM(KVx_T!}L7XLL;t8h-zT7boPWDB7E zR*D&nWlFH45}2pyRuIPJuyY4&dAt}lA7Vt6=MnF}6gHps1lRZX;d~kA6V?_|jSoyZ zc8@-$z^)EoC9(b$ARyd=>ACcTH4Pnc3Q7KiwF2G%dE2dbB+ganiijxsHkKuZN#53n z9q$hxP~LVco_g~E>jEBhtqW!7-^ppWhRe|7Jb+n)WN0xCSP|F!ElxL^T3WkxoeX^+ z+z`4&hEi_e(2Fwktw%ZZ2N`-+Vtyb)H-CrY{zHal;^hNSseA~)1C|R5Nraw}p{2B6 z(r&#aL*K_L7@?ob(1$1>La)ovl``~_3_ZJ)(_KPy%?=sDq)jw` zEkl2Wq!4;bh7QQk&k^eQN&$^c{(W(zO&*vu`VqhmC>XB*4@_GAAYj`R>>czq;N1s7 zcho7^j~F)Q=U<~-O&Tx_dcY4y{iOJbKauu+!n)Qy5OoTzam*0pp1R&0lmG+Fqr=YG zM|(ax8pG1_9q9-l7CoRf8`{#ZrxFe}AV2JwGZ-k+x+|beux=$`5?^IuLt5 z+d22~@B0=KmhOJuU5;tY+ORWr7t#Ow%UJPw*SHtl(uaDj^{;33QAXoeyx5gr3{d1oh$}oO2-QA#zW&cJV^d{YF4#aqBw|e+e%82sE|z=i7L?Bg zIit2GT``3wm8$1SryWX7N=<~gw`-HYadPsYF;EM<)4WHKym)ox*A+CJa#@5^MjvnoQ+5PTL|6^|B z_orQ^Hlg6|LNgW2?;dpfuJ{$;8inSU^KukFH|3)Jc?~_@VIJst==dp9 zb3BCT_1GU&9HCz`zp+nu&F}WRL;U>Medt`i@ec#qRrz*&+2Ix{-^@FiA3kGpydxn> zp8K)?dHj^c@;rK*OiU==SQ%Bqbq5`uvV4z2ErL9Ah+ks+U#9pU z!^Rd>AkHNcCtMw3I2>o@BpYJrKmMLuGrVPA1jA^N9^RuEt~tc=T)R7>e3AUF#rd43 z`-3Yr-QDlz9PhAXgYoSElm*Jgdp)XnaSe(a?ejCg$2T#*om4)5`(I?!ktM_-P2$## zA&%uhm7=3u9q;fR;5PFoplFFwE>Hv1W)f1+U>0vc@^>ubc>9aH-|-&rKsR=qKRt`x z>t|JY(}CfC9MqCKGtXKZ5^v*r%_V~Q)_M(=A_!-G2QDde!JPF#F8@p*h4Dwbl7&w| z;h(Av75>AOnh`{VdEj_QoGkt=P6Tpr{MT;d8RUVAKMLKySH_Ai^C0W{L`~QHmo5+S zZzMb(AENm8b|PZ&KYPh}_}>GBuF9XaG{nDx@M7`*GmxC>?^OOb7N3Xz79gNRUA4a_ z7KF0!!6MCRN_hJl#cvRCcz7xTO2zja=S|3;w7l1A|V6HpuhM795I7oU%R zIxxB^{~Hw{{tr}YMiKn09dPIJKZ#R-F1mm!|3YAN!#`tAi2n!h$0+~J4!AS_PiCKw z|6yQs!++eY5dWb-jluuBK}{H&p03dGdPzC z>wnM_LWA#Li;20M&ngIy``?uC#=mH~26q2{gT`~`q|1glcDgUA&q4Iw) zO!JD!!q0|kaOW&Mnb&0&(Et8|Ic6*{z`qDH%6m!eXW`{0&@%<&~>w#XHS40-79dPF?jHl#X>OWNf zXVPT(-%IAohn|TphRRPw+)~8J%0Et6tXv|mq>r*pNLqiEr9yu-uOkH=BJew9k> zJ+ag;><_X2a~LRL@{iDevM9M)pHvWDtogsU6VaLf_fpQwe+y8$;@^XkEB+%0FBbnl zC+mn9{1JDa@^7K!A^kI={I~nV_&aP=4QT!E=RlGf>&*XGN$2H%7${xwe={+}zk={$ zmLEu6@t;5h-s!gf&m?rszYuX+{tpvgEdC3eh|cBzUXSzg9}5&nl*Ye~BwhkwdrD4$ z@#q4J;zC(?AYNwytLWn$UfDJN3=Ca zoTh|N!DAe7=l*}I)nx|M_`eVsRR6L1|NCy;|N9e`mOcb@ydz$gz5^(_^j_}$UZ?l( zK-}?nys>*ft>0<<$tMC`@PE^#`TriinEYRKBB(-W@fXG)aozH#{gHGabu<2E7$NyT zVCqan$iJ5Zjv;>=vg&gDCH^yk(N+H|Jcrb3{P_@mM*`vNzs*iW=k|ZwXT-kS{k179KoQTfy|K6V{2i?kl3sAb^|JOf;_>Ukwo`Jdi@A-7b z{tP6UvCa~>p9sWmetP`bLdmXHjy^pYUSxcOuaKI_6zSo+Uw#7Q;h2EvNH{#n3LvDZKE{o8r@-vbnC|FQUI zAx`qYl(1s+zlft^^S|vk-STJs2Poa>zgyo4Rl#+?rcB5qqA>jz7!u0WAEE!=c8d7N z+d&rG0n)&HM58Djn+{4wkQF(;yP{ZAkQUDrRA{|w%5?TY_ph;!N>;l*lyo1KWx z{QD4r?)m@XUnBTO=wENXMf~OdLnGla|0&^}Kf?ic?tGU}@~)&mU7eq$11YTh5&SRv zRfzw?ZxVlbytEU?hgvS_442K%rG|f;vh>99gKWA#|D{a$tQ_y}d4t=VACx2lkbZgQW#*Sd{5qYV{py7f!{5E6NvrcLX1Mi- z8XEIF>zB_t4Aps7J|O5%vH9KiREXaXo{>qT&+BF!jo^s>6mbOVeNu5$g}cz#UVbFRu12NfBT{ZJvK@OF-c5U1 z^RQwl+soq*btBL1_lD%z@Ssc=EziyO5nM8iaiqNP9>q?{GyfYA@{BkypM7nJUCviE z+3@r7(}w}=>OA?CeTr51dHLaMBKSqtU!SW&0{z|I5W^hm?A$&V?bc8nZu0JfOCOli zdHN?i9hRznp17hLenYl|`1QM7Qx5MB`?hOn%>EG9+KFEaAYHVVrSOa;vrhAiImG3!QXEx#J+l(wkbEP?@4qe&v8y1w&hy8jS`Cgde=H^Gb}@Tn{&)h* zAQAR`8{W_HA`#^$mOis#iPmR+3||-e%+(wv`)l-i^1a2Bqi)yJ*8rs(efHie5{VoU zpI)TPPQA{#Pw@4H8r)eVaTj+f5>+4fRCde%#n~bLZ&heU5&WN@tHGW5mzAE6|GP80 z<$v$A5dVoljnO1>XJ~L|{&7>z$NxkTQg_iF3nmkD+1-i=FNQv`7C3sij^0kae^Qs+ zssEK9uue}TwWj?O%=K5kLz8g(WW2xa7VR(jANwKh%mC%;@u5uorBE?@5u@kvUt4r{ z!i5AqlSjR%#@8`2oBUlu(8p`r@TiZFy8$3jZVMe$o8=v(o7@eNB~DyTp&;7WF)5 zA4!!i`J-)9n!-_Tbo}QHzo_Vxg4ZM9OJU99e6%P{EPK9m|Jm`kDS486R{6<2hq96# zfO5pLI_`XUlvd;ZEp#-!a5q-Ea9B8QxIY}{pY1P)tjJDOb|_r36egGA!fiBOc--IX zkER_R?v8#m?&l3h(+*Eh{-MfVn10UAh8^0wv;8ArufTpSMqDiXu3$U<&h%Z;{b$0< zk>`o9Z$UPX!d?fv5w;5UEc((CxI1AxfD_A(>mn|_3wSIV=Y#z@jQ6wf`+A+TgMHDy zVOPWMfxQFvQP}?j`){y+g#8pY0e9eoux|KY$7ft#`X||p;z-(qqQc$rJr$LwkD|gN zidJ$|IGXkmq`wd!R7&_K+3YB~e?)%%R$e=z(oT;GUlJ95| z(-F{{_$b;G>^sN@xnI;~tF*6#(IJ`?-uQRW{i6B#XQoR~#?81WkKi@3?4Ct%N_9zLSF zfPEeIMOczScQhYC{65%Suv=k2Z+IN|lD+On=j=;i%VCRP2f=2+Qk?zDIs0d@<;{q4)=?31w1!G06=dRU5UQ!e>q*`j^3w(?iF_)WOGqb$W~OSBdtKH5_JiZc@L&>vB!e*it$*FQREQ}}MY zhem0mY3~9&-1-PFh9!O<{qFCx;d!R~J_35NY$@Qe?7nQdp6UykHH>- zf;Z6v z@V^Lm5!_^?e-U4!jFpC9_abg9>`2(NX~2d3yy0<3L$osB9!mwy6x;T}eGzggg?}B~ zamdfM8r!}KUlATuX4_Szz=b_kXxqc_ecGpHArJUkly3(3!yWEHD8) zV4oa=e2+z*F0$>rVdFrry$W&2W9cH>PQmA(56nmTF1GEqd5|aQuUlx_Z&o7jaPLN* zK5w{Vfo=DK-3Pl1yg!0HJlD39F0t)d({20f%TX7|!>MZ9er^)#6}&%zI~?VB60)JP zlNG>Qv;?wTin1c#i{{w&?-BoFeBWQ=v`@olS@9L1U9dK6QI2hY2X-+0Q}DT;juGG$ zjBQH?pe`ZrMX;~KAB{(G+7cb@k9Nl?yi=e-ctnd_3KNg+@}PO%i;w;vDv*}^jsO@0B1MGygb*(kE z8#mUhs%@!j5p`Re>Q=SZtq!!bHrF?-4Ky|fR<^BKQ`an{6R2+q%&jgj*Fn$?G}NuF zZLQy27ig*9UZ*3-AJ|mivZ=Op)jCnv+}zkKYMSfT)@`j>)!1AoS{oY!o7z^b3#_bN zwV|~c53m!f8XH!%H8)%B}dMa7PaiiV1c2`#H?8yX<` ziXEWP(zLO@wUt7Mf@!EgtVVT)rQsN&R#)4MsvzPBt!dl1 zQPzzD$bcq?s&WKYv#xF<8jhITASx&;M5}FOL_k%om{UBnY?_!>F}%s{I;nY7|n9x*lzpf@r_B4XbM!8)``6)TCsi8(vvU!fOCS>2gJhs&#c}I;cBY z<<#OiVz_9i-Bh=_W@CLzD+p5)gIw#jiUlLZf>8p+U&D_E!C9@RdLhZPrv_PU+E!B| zYHC*3)ivpWY$@|~H8#|3ZPl5ZuPR#Qbq@ELh3o2C*VQ!#>Ra<$0=2r;$&3yc8*5uy zWtPY%8#_3lL4`G0(b9^xN@7PoYa7I>+NRdF=DHScWl~hs;~}v%PMl1Gk)UC93#V#< z^jm9Jt*enk0!jrzqoA8m!g(b%6_qtJip$EY=as0?{OW1bO6Jd3q2jrVL%y0~j2toz z;1sHvSF#`s5*exvi>VIBtg4uUW+n+ut*D+my?CDHGId_@+-apMZkpsULkCNX=M_(@ zDw!7@t|^;2Hx?|6=QN!*3^u)FMsam{RZUbDG`M8$^qPtpH47`|O;^Nq%>1h2c~wzy zz*bl)U3uADEz&SZjTVZ6&99nQHg{%ZN(rm!Odu>Gnod|QXH+j)qQyCLUU6k<$()kt zGR~Y=QZjupWKmgCT&1|roL5m@8Sbwk`9}as7M0Df(oLhhcu5q6@`{St#h~JdVs6PI zO}%nnMPCIm}Cpv!`6h$>097WiPilkjVx2!^UUdk(nqo_KtD3TH$ zMo;(4u&(3uRf0La#(_rkKL;Ato1ze?w}!P6)g#et!n4MGI=l=Hpfgr@?wL4*p!%F5 zPErZA%Sd2ndR*Vma2SRi*)+ob;aDSygoj2G3U?kY zB2v~=IHM)^OcboDdY*0=VTr>K=M-0=Cs8g{{v@CZ)0rbd8mMJg7g7&^Qi|!bt_9j_ zOKV_d9Vw~MAevi9Q%TU%{bBB)}ITDuu|Mqn17KzfmyJFNyNw06fJP+M>Xh5Z08tO@FLRMoUQVE(HYBvU0O$Qd~L~R>un*&e|pf0r3H#P+78rIfB4JSid zlhUJ9i34kz8#e{EtgDAc4W&itR8qGNY{42qX{oDm^GBv{Xxp?B%1z^%fK*CI^^$rq z@h2LJ15yw_*2e;@j|JLVus~V4EyRhb;s+W6q}U*{wawe0CpAH5Q$#s=OQ5w;@(4)o zEh-(+ms+68aqGI;)&Mli)orW5sdXI|JzD)%3kIhg=S?S7yYOUTT4&e%SRIc@rR3h& zQcpz;AcxWNmQ{o*p#=(xE;WAm!paFP6%`FFTvAzCx2>^Zbyt+OG&bb7Dl(u!a^gBt z@}t_Lnj#HU>ZOoYRCNy33pkaY>hbfYD-N`_HEnc~kt&PcCV5A(<0_?msy@UuNexiS zqHeX5pFsT@sMY~mz^<&TYY0dsw~kt96u(eYh29UXyS0rf0G%A&3F~R{2cSZO!bT{@ z2q|$>Q}5mwolFQHcg$3*c3o~E|19My$1OY(?v;*D#E~c7Eqe68jlP7$B>4OynSMJ! zB&Q1eN&x-!#J`YkuU-V`P4Q&Oq`TF>LOYB{?G}Ce5lT*=zoIaJ zg5eYgieNA(az$QVzEf;nG`y?~Ge{D{Q|E#KgNNXLpBOq!3?CuH$We$KjrgprtP7M0 zVar@ys52*BA;!csn%hNVBa9f!5qQevB^KS zGeen~%9JWori>7?W|xaObBl^9Dk=qT=!$vst3>sJg)q3{3$qw^ikDteRJ3dv2gUN5 z6{2=!QPHYZqZxp8u~@sVzJC4s4H5xQTn!hS8e|Yx!(p0~fj1;7aj9e6qPYe4-(_*z zHgDNVXb$GKZJdrlgrY**mG3e_-9b=s`4u~NU3t}R^6uGt^)>t2l_5YZW0+U4EjqjTkYKk#M*5?>3`hF2EI9GGSblcg#iMFtosNuy~H2 zK&=tYZ*tL;;;GZHewpl`~8JS2>WXLdGZp-5suj3<+ zFU}M1@$^uzgowD$6G%+@JlG1?4>y_oDGCtF5h%RrGTjz6!~a4PDb&bN06{N$Ck@Qk z;3x-2s5ahV6R*Pl2$tI1ORz7)z6SeK*dN3G3>I&|iC@9~68244>S}j^#*465z!nS< zVj0{)aB<9JmmnTj`US=yfs5LhBWP@;VO0np?5~0IF6{4N--CS#_I23jV2{Cm0*kj7 zgddiA>78&w6mvu%5D@*vfB~4jqY9|fNMZwnRH1qKVi4}^ zV=i}zp@>gUPamd?#vZOSAzd|4@n{wP5F;ZDS2_0$6E(t!i2&?f=e?I&Lq6tL55l++NLt_>a4?C>=>88P%Xvf z5;SBJnuA$Z#_1?b8J@)vE-{;e3Ml;=;2(B+up_4(w$hz6r)P+w1v zrx!=}_M~TI@@(5R1L^}%v_y7a!|aE5QUd)4AT6phmj*4Fj)>){0XTmUla>!Lc*qb| z+$7%L`y2{0Oexl3T$Fdj$Z!~He>5yTFQAsd{!!vW!Ih4=6$VNjXK5m;7s}n=U?xNR zlV~WIQ#6{E!+EDq4>+_KK7#ARfoYG|qh~Eq;+c^yJTw4?naH{gi-4Ea$VgCR=>OgM zkwijsq?{zl6T|#>m>*f-dek!wm-4!mE9=8j#$$Pv&!^l_eZ{GDUc4sexO!0S!D$jy z%8(OHPrl&;ac!K&lKwk0wv=B!7B(l3!$G_JI!reZM4p+n_HxxkMY7`Jn?R`Nv!|cHDT3 zvZ7GX;3_6i7o1!qrWA{*2o?((JxeGCW(Mm9+&iHAO68XZOKmV@5;xA75dHi2*Aa7| z8_$KFQdxPiG0!mO8%9<20%IY>yJ)dkVi-#e;}XMIwtV^W8f%4R)mqldRjaK!2z3pX zRF<{gvNl-O#!Z_V8k<1#Qmm2MHVZ6{lKk7i4|CUcWiC@jmsaK|$-g5c2J&4lu83)b z*csD^T@gm?;*!zxO4zG}*u5v50mtqY;%YkCXVapL3<)8Fz{9~m|KWg-{;s)ZA544u zwb$<7f8BM6ZV(5ET1(5pgV&2gT^9Zu_uTtUO6H`z z?>?r(VF|oH!if8s3O$L!0}Am$3O*zm&=cT?m3c&&P^9$9Vb)73DomVk=Gjy-=w`jy zgNe2ebua9V^cs+wI*@_E)ZD!M)Ir$Wz_g~;nUYTENmCc}m@ocPhE$Td6*1{lMnl7Lk$N!)=FJa>p&u@+ zs;1|n#Z}cymXg1!`jTbX-Kbr;YWZrSSGQ)Z5bK19+}nue6dp!T-Gr9jsOHBq6dXlw zLca~?o!iOHMJo0|wArCO-M9w!<}ANowVg=B z%gOLi5eauf-Oca5xOiIp>UHlITE+65?B{iCjOn>M5G{LC2_dZ;tp6VKyY0FH0=J=_ zAG66-K3Z_XICT-r1LaMDNx8=onst1)_5uLo7Obpuz+wzeCU?MMwhK;14@X5X&=L&j z9F9_8csyRi?F&NyiqDAi7-$s<5#ZPXFM&OY9*^PZG*O62p)ezZyUP!BWwZvQ!-hf2 z=}1HEH_BKZ2jKO&68ST4;#Z z(9-T2e++o0_~68(pJ$w~pFJ_@N^XzKha- z`hmUkQ zCsTAZ!0s7)(#}aXZQQVDC%Ldx&KzOi1@8$%*eBt){cscEUO$q0j~K_41h~T#3EOY` zkFgiHet3`rJa@w0wTt-rk?JgHVBbav+QHc=cCr|0Bc8T$PS(7Y^P1nzc`HZl0_-w) z_r^qWJIBTspZ9z^Vshp8?T=4Q1BCk;ID$hC(cL9>k>*93)hX~hXHQ0&o&RwPoa`b9 z0?g=J3`7YK{}+ zAdj_ONNMk+%_)?6r#O4c{%mK>n+OO&z)#`Y{+%L2W=x#4KmGL6Z2Lo`vF*n}w+QS4 zej8^JXacr<^aebRHGYH_7i>Sa>%1floGovY&1Z@g#UMVUwg&n8?T zu72BoA1v&n@18sf=dzklKck}9U~z^Yui5r3=g!3MdGD6{ZaH&ix&2q$|2tSDk2L7t z!fl1^(9&e!_2GfN2st(J{w!85iL|lr@zB0R?{rUw$CK&l(9UbI>*Dyfh}9NiS+H4?YP`Sb47&N=~?F4wU&}x>6z=fs$utTkJuwI_FnDx zT;umt>}&UUuAL&%nQpD#x7pA8H~U5Uoa+vF4qgw59J;~d`O=NzCeO{ti|3ZZo+C?U zc|5lYPs44udpvjC`Q^KauIFy1^Ob+ehI_>0`KtKZ*S~?(_jo*W(mnTjZvJNVefK|r zxLK&4Ri3pEiiaM4gm_Is+65r+Euu2Zvt6uBzfsKbe4Fzz2OIILQ=aEvIN^EmhcAJYGB3YU@zhhhcKzr_uX;|r_WF;1f(>XH(}2=Q zA1Y0y=Ww+OV*cdw120r1xie;<4H{6_SyMMiRnH0JNQ35=6U@!Y2~B6pm*+tEICGF8 zRe1+$7$X!3Bpx}+&}uw@tjWVInnD=GM0@Hq_$cjkc1tK?#!PyWDJ{#vN#PtBn5*(q zp;=X4EF%C{zIhVhlsDR=%J20#CqIw``4bXh=&&s@H8G9+iHSX>lbF~Gp5BRx>4}L> zsxS|o$0^J#okF|W+M`@0e^rr@j@%WC&T!{2h9xpPVRw9_=V>`dpTi)Cmw51`QO%o! z(G!E2xxyZRW zoAQS7+xCag%{CP%hf8%5CGqk+9CHrlnF?b*jr4jB-U&Zu8=i-GMslI#G*3m$!*sTS zmv!_!d;%ei_L$8v(;z)m7yB&D!Eo*$7b z;tAu&%XS9Oxd{9fvHnv8E;>g!q-^tCOF5SFEskh*^7MkR?aDbu`S$NZT|SGFe2jVZ ztTU$;VIHNavxxYf1z9f}0QQpTgX*8Uh0e&QtNk935w1 zOjILFq5)msZzN-Q6e3OZ1XzucayO%QPH1kXnR)0)nwrO4}Ko4l@!fc5l{rrcP+fqkLn&_-?r#wL^C4aO9saduOa zVT{A}o?(>BWb>O1!)MUarlr*|HYFQvj18G_JoXW#+05nIVr(^xZHBR(@(y#^2C>7q zocvdeGmM?c_by?~z7qbcX7A?t-`LCP+pY#zX%N1~FlLHoT<%6K{07n=X-%j*+Lk#Z21e77Tk1z`2 zzh!Riwfk z)(SX0h@OKDxziVhfemqK3@8VN-sA&_uX~It9yN6u#ZMoFG$k|OqqH;GEv1OES@eWK z_d(~mc%BT+A0>CzmSBUM3^uu?S+-mvfR6OltdIZ|U#p9+^`lt&0jB)(=m!}w^@B`r zAFUTes{@IBqx6F?wSv4fenlFozeFkyD&+OJeeUjePnZ^lTy1v3(@BT;|6PB8d~*J? zbqJoSci8`{N06HG-$9Rv?3JMq`e)Q090pTt$a%37X+pnHdvl3ql4<(QWK-!E0RK(; zg`xBd)0Fy!BsT?4u?hXcEHR;9m}V)#%S@Bhi@BzW5z;j0ne)x688~?`7cDlIn69Oj zmtYb!7tH|bGIMzi=EL}MN(Zx|)?8U(u3C+w2-mv$)C1z*k@op!la`(7}KO9I5yCpDSZC}rupDQ=BkI`XO%*j^X?>itVzJ- zy$2ZrJ}DKP?mMnW;Yuxn=&-3WA0xK{;l~wTIqMguxyqdU#FOUto_bnh()0V;`vdby zXcyR5c+Ome%6R?-F~8AV1pVT~i^)HfbY3!N%rRe{Wx8IWL_abswp@>hS55OZ<^>pU zDM*UtLbfoXoUsmfAtI2uKvgB7ia~nXohN>!y3jLvb#7^KEv?X ztCkvCannaJyha01Up9$O=7d8DdCj8nJ0HzR#Hg`4dTl6`W{0@;@cBv1vy%X$M4q3x zcsWd3mpVgXoTzgYI&*jyDE5ar=iZTLDdH4`vCj35#2F11@;O*XLowlf8@a3Sp?&fl zERmgamEYX8IO1I8*=sT*&Q*SMG)tYUWJaB<^o=@K=_}7wPWBBuQ&|>urn0LBD{FbC zvNI5NrV`*Y72ZEUsh~}rqs%kz}2kO2szM0}lvn4AKibFRrbfSo$U)KUDMzyXB!cXob+%@#`4`8?$*9QUAv zm_I)C$(@Zev|pmnRNOc_9cSAULuV@9urrk+P(`EZ>Rd&{I8Py6H`aMd5z0XOHxN8F zQfwEtRp^|DGKS|#;`5I?HvvsHn2-fdNS#w%_ISXWcC0PF36@AO{aS?8JKeHy%f!mE ztZa*Jnh3g>YdI$;^4uhEgx-XnFsg9;#7Twft%Br|8MrM%cSUF+DTIZ!GPK;ZEZo+pU1_aaJsZc*b=DedZN<9!_11=sVw2U-xUmUzE^QW8 zi`8na#lJE=$6-Qw_9uO zsIag{VqJ6B-BttLB_g`k*E#t&?%4$QUd#HXz;OxW`JiQO?qfYZ!LH zz9qi>okxjR3DV+}M4AfgyP~1bVX@hIjPtP>SJfVW0-1wZ3+>2yQi$)>%2zh5wQKJn zxTQ*OSx=37zvpN#5et_O z;KjKr#s!Z@0EP5QJ_G|Go&oWoLTPE=8Q4}2;^0LXZ^(GaPw9kPzUd>p7*q`r7blXK zB2ngKg2)IX#Y4o|PpOzP5P*d|kpmoPKJlQF06*PP>j8!q;Sh6?1|tlM$RP(JJ_&p% z6)8tvuVKRCE(zYhAfwNU$OQ^z7zQOa(lGWU!Ju3Opz=}3o0b-j7siMQJpAeyMa3tP zzzCLxP3$zvCg{YYsFYJm?eX^Pi5VQmlJ{`p0Q7>b-*3<*JHMZBsZJ!b-Ff$ERiad;=!<3NM-nw4Pu>1La_} z1o=YV)M-sLU5=zzz=I+}?IL6J$6O0iMC+>Ed-htiWpE9$(guLF544a^ z^b_l_BDo$@0lVtN}s{3?|@)iBAj)CJfFS zLaw`D=l~y1wA?t+5*J+P#%&X@&~E}0x5;k#Mke{)ZmB@c!dy=VS`_rC@=CWGdQ_DV z)kO;y3iqPLZugR*Q|BB*VVh->!C$CW|QNChjy46 z-A%&H_tD*(w;;ULz0JM-G9h-j-BO=&<2792-i_;Vd-jT}uL)0&GbXYBI`@Ha*ulAO zs!nl(+x;bi-{{6c6U;4#-A8UEk21HpZ)bglCMGso&@vQn&}|A8g>%Ed+tAgZ?upQm zBppi9Go2o6FtqV*np^I_{Fgno+&a57?Bc2>26~IVg2n~fJaW4|G(%b*%V$^^OtEW< zTEvf-dxg*Np{K=}ZUf!Kz%+@sN-+PMBFVJk;@xJF@ZjLmXC)b)9^M2qu7|Kp4|O;~ z#vJOwY#YNE7{;+XYj|B474YEzGLfS{;`yEo#n4oUnM=ea$E9G2V#THUX(hxajqrLV z_M!kL9mjZ6;zjR-^b8FEFS_JK`bQjV6ItHO)a(++)4W472a56TxCx{UDU(kwB#gEw1!KA_YHwuXJnlicDTPW* zejg#Jx{mAa)QwgYlpbfQ(pAW4;~YidC06+(e4ND`ikuT{WcHfI-uIL-QaX^EhC zO*c!r^vv$-`1|DuzBs4=xp<{G4}XH*P$Jk66(I_Sl5ZG2=<5=W!DlAOjHU54$(&=M9~!GS5C2*D#Wx%n3!H70W+k7S4O2Nm>8I&)eIJoEc&_btsELpXfJ7KtAOLQ7#v9qZ66)E^%VYrdEjv+wd6uizDMG5J|+m0{xz{m@0j z7a44!Z7bZ`L^pVG^XL=A8b!~H&6(i(=mPPneRBTxkxfGEGDbd~Nqd3zYe(t1vvNn% zz7Z2I67rt3{ju)ZSBxZ@p|aeYNMZR}Je&aeL5`o8L8Kd9P!$_;qSv3Kcfn$^;3qVB zmn+WY;!&R=ctDqzUU?6K{OJLJXsPva!(KG&dp4Z(wP}VRaMB z^Z<~rBso;5-G_`7^3re=5#j*r1L0bLL#S(ynVy-|H>dx=TpkTGvuG6P;m4dHLNP8+ zT#vNjL<2Dh460r(kW9d3)ZBc3MxX3{fdRohgCcVC2aTRMgErTys@F1Wyc7vHH$R=L z4$H2D)cB<2p1xk5#FXCYP8P7}sjObSeECYG>R-8`3H2;r8-sQ#O#KeosL_%KVnZqO z2c=_{V`e6}i!2P1`REloC(v#~ZTEE}DXJQ_g+laIhfIvW{ox%XmLm)FN+*B62TvrV;XEJZ7z89TM4p6B6o@WZ zV}XQ%GYM+ss1#F5oZy_3K^!eJkgo5)=r_vf1Q%PA8#dxq&K~~soXW*3H{=W=iLR8+ z+6{y7If6`>oIzwJR>D*-Tntm`_oq^=rvprr#`l1F z;fqV4fd?)tksNRMDNHknVbb!7OfQq}P{YIXGSSmC4KtfD`YL|dqvo6a>INal!9RFN z=m8kDa#POBScwf7cmXwdZRmY|HochUMeH9rR)_%u_0hL{L4YD?wI-%9ikL1PJe}#3 zn0<||iJQ6t6xa+9Byv2Y`h67^2K@DT~dKnsUaKOMr^7119Xa=_&KBC$uA)pQV;zr#% z@HX@IJMN78@?BrPn_mv5*Mjep1kfH1-EhD31KThkP>%;kJ;YG1eDXakk+c|{$`!J1 z9>Eq4FktHlQ8gCbW_0Clptx_*gUq+36Zs^?0;6=8alxpu4|pdT0n--r9tlsN&!yvfPt})F%+bkxIM3LX2~PZ^oqp6NdVCFSuCw zI0gq!j-Ll%(!jI(@k}8C6xCnH4`2_zz$N%q9;JX6&_~_a498P;bNK}y2GZ0>-Cch+ zi-CBc*UP>x0rat~kQpz%SkFjPNDgUw+Dw86S~(kwghVx5bbdl zyx1620CZX19|57QLdWQ$QTOGRC}W)Mq)ilNEsNe9RaabDzv6Qb-f-#J%P_E|!W$|X zz~u|CaMhhxP91vW1dRU10K*t)1R0o{XBhc(=XJ2c83MP!Fovq2VGM(BxC)IJslj}` zRR`dXHb^xI19bL|Wsu((XN;c!FTEgd7)8dEVuDAmPNotlWTwG8-3gXBKK9V%bT-(| zRleEmsvF`8MvgjUni~cRdG#AQvI@eUm=v|>aYRBN=i##wekAuuN$ru=vqz6!8rEBT z{-?TOl8Nx@Wra)jPsGs{89Cg9*^4ocW2Mv;NH%Z+F+kObf>H_v(Fo4kAOsKfe2t{K z4T3J0lMUpEjN~i*Car52nLOI)I2joh6N-qUf=hz5k10)9c61pra46z3XR@d=R+SqO z2m{Ya<9I_rL{dOuvdD<8O2R&k%>1YpxQr5oF;y-ln6X$&S}-B@VLm!5bh+t??M+x5 zL1Bl}GU6y4Zy7y=K}sh!DFkLA!%V~cXY?eYU@GdJ-kV7AVP9GXV$v~4rKM*kVh*Ai zD3IQN03i$v;*smc$2qY5Lli_>F4Xzlw1M#E!}1OR0)vOZFL#52nDc^i2Q!s7%6O8( z6g8s2nVpby2&JGEM~WE5v*a+jt41KC7?#hwOv8`{CN+f?5dzb4em;;#iy&t`kxGz? zQi>szOztxQGbQmt3SzEH&rHMYj_o^^Hc5v{je=m`m`pk*JW85h0Pcf$@ic_%5>g5? z)JIg6a(5vG;6Fvb@N*`>nz_pmKx*SjuN!DvFJfPhQsJX1oR}Y2&Io+SQ}hc6(H~w} zy96XdwTxQDSNrHqVT7n|Adr8Iei6P0r*sYIAkuJLxH>`#2y=&v7d`PDrxXf&Fyex#WK`U_?ejN{TxrB^7&>3D`SHNpR!C**Sqg|Nf~7rm!+n z&8l_>HO^YAZlYcCJiA@JSp_=Fs+g$E7{UBQY*MQS?jn zfN)-3LLBB(=>3?iqGhMUdS8daT9<|Fkf$U+T|jXRK1#^x!K?65TfkTJG4B9h7YHQTD8A&! zH{+A?gTt5)?A)Oqx7tQjmQd0JNwGJ}GR30>yptRnqAfT~snYNml&Ov^4xW z5a$e8p~)VGl``3BqyiwpV+w(XCY_g5JTob&v`keZpqw8t;z9-UgR_+3FRiIZd6*%7 zRA=On8}6q#7=V@N8l6GtvS=wVG#J2laiQ$Ip;4_+o?A=W!;&z%h+!-+ zK%_u8*WCBHjKqab6Uc=DOpBkQ^8ui6Ag{2na9-hj{2D=FRc7^q>IK&YR^jrbJkCT?kVfw0nv86A=i*Go14{;nSs|k{moz#fX*5yENLs-T zCF7YOo7~K7HZ&K&5CTjFNhFgHlYo$vk(rT{k&%u>nc#}aH9MOk30s6?+^~;$GUFuVkuxWW%h-(C zS}F$N)Ml@$t!2)u@l?f30-cPy%xsy}q@>j{G2xS0jTE)Db=hlH*RH9{uFb|zB@(f^ z?CdqQwQFh-TwA*eWni)yN#1HJ2{YIXX;khdCDa{C%Z6iBFX04Z#Bqk=BLe2m|zN%(wHFz3Q`T&QY0rfMDU7;&(+2XX_zF5sbN>}NAmdk^VdqondR5Q;pFiK1jiX6&3g9SyxVzVQ-_v#7P>;tRX+IH1m zH??m4LB6w}>(%J*;wjX4tw*6px(~M=;Q=K2u zETp@X_=ap=uy^gXHvq(ALV@^_%9a{lq2v?})`PWniIC1mnl8r08iroL0wW|fGDG!X z?F=~D1f^d|MOF*xDb$AYNwb1M2>J$fG|C(SFnv&akvst;EHWyd=NPmpgYp0{HyLVV zn3H6q1s$|QhHJpEq^vpA#|aG%>11q(?u|2=l9EkHs#!T$poUfOqYeN| zs&lB((|jfgvWluDLM2o(CJ&2;hZp8U5R^)5hk!}7h%ye{QBHoq$j=99=&m#!GMs#f zmm?JumJGp)r3zP#58HXryvZ5=^EfQ4?&feKM+G^q(E!1N1Y9&UMQYXR+FJb6P=iQ0 z-~h6kV703#R-3gzKw&gwl`O0Z%0Q5CrNHn6hwW-aV=w~&heC*{;p8&dVKwnWVnl;ZhS60^mi3L98Q0`@i9XEr{#^i;+$eHKd%w{@WP#p z+oxRI9Y+q_;yM+k*aPBVSco78#q|#45M+1*-Vtz%8)0vP|7Itb>%}eNFlZgYQ|Ezx zl#KkhI*{Ao+ahkq-yKMKr}#3bzYEX1#a9&8zbKkth5I#7I}AMC5=M%zGuAi6J>p)0 zxBA5W2tUBB$Bm!#eo)0egyVl|QI9w&d*T@X+xWVX&KtG)NAWcRw|II`o;xtmfC*H^N1MyoteZZKQ%tN_z)AP*KOHtSO}lQU3d9M z67}MHUHER9L%RpA3-)mS-WDN$v@a29lH@1Oj8r2HX?nu;!s&OqVMu3$L9KcuVE727aizegrkL`D#u(!wmKkA>H69f> zMmN?A>RIw{f>CG$#6)9~F&Wa<{6a3JD*}%xMzJx~mX_RaeoDw%C0z=w z1DwWK`kSTFQ;kzfDSNl5=d|mM4XXa0z=#*BmyH~|3C{)<-w1z`;-T|%sS|ECS`goA z^b~EJQu5vm{}$M-4s4r~BE*ZzP2;IsY&R}5Dvce$k>SgYE0A&<+6RS489NQ!dgffp z_zR6I5l0Y89S~Qkkj|gX#c&lbLvFDfRJ7kM_OO3%7$g*@eOGfV(b0c0CR7@Yc|cr) zy1zi|GwyeADNTD+xi!9YX?`NjMux5hh5g`o9dnJW{{xCnDE&#KniH0L-PUdp2aW5E zLn`J5<4f?}XxwBhP+Vlqgy=}$&BiVKN9hh5M+|%u(74^W!?@E}YkV12mVXY9Hc4vC zkz>@`BHOqNBU~2a+-$`&K^1z)c-VNv_?Gc)V-O(UaX9JPdelkvT@@$u+{2*JoBkr@ zKvcs2`WTM^kLHQL?GLA#bngN;bnsTJ^NC>n^*`sQJaA8ye+El_np%EfVYGRHX-3|s zo{H<#poZ@>(aWLw-B4TrUr_Ny%)-AV(ISns*ff_cHKVUVtJ~23Fo%A4Bf{W^M?R;a z3^z35lUedEDK3(h;wGtixg>K%DZUUiA=OO!|^m>5Bng$y&s+uk1H7z6J~ma`N`Xh5dU8` zy+3E>^r|?*#qAg>EMU$PA^g$5ytR!rGz`AmCcoUq0ctBeeBj4y>82FDQNw5y3q1bk z6a;6|k|GdsWe2a?fq=p!G$GR<%Ay$1#QhOM1Z}<&LRrF}eDKXU%d~)ikFwz1(TE~N z1t^=~fL#Fc;Iji>59L@7d47MgKLvyYS_FMIpchPU^7zwx^}^j>Gt0!U8X+3@t%NHl z(7V6iKLGC`_y+p@0bnHtGlISSBG)wKW#v@B@^B*z=V!Tit<|#J!Tt$}{y~-)?9Uv+ zm&%aX$C)gMv&=Yyijj*j4ywq+;blR?3y;^8<#q#TdEzK4i*B#bnHKm^I5#dAzei1o z1(+J}$i*ccd~pxC#807^9-xt6@ITC;vitCA0vwhCW!1{YM-UL73x1*inF=2~@ zu;-{+-9gIobCmjwYa5IZJk`bf|*jgov+9JiJjcl%^}3`2J7A9O~W zGWnjX`W@%qCVgrjRhQk@&+lsDUIL{H!s3QFuC(E$ChY16{N!T+-3%W#a;O+Z?r4Mo zzhL-<1$2h1Z-V0o<){US3nn0*45cH(H?YEfz;g-#i^WttX=a`w@7dvf%d+fQv%`x! zlMt0D$JS2)6XfqBRpRR!Fc;7B&sPZYJr9k}x4iktOhT66a}Q(0B}O z3;y7PlaOkwZUyZN@sD2-98DxF8s47zuDHBR0R+6QAyL+cWA@yju3IeIh#f5CcN4{~ z7ADeThY3%}xk;wLv@1QWLq(gqdME*ce%Nh`_Dk1vE~0Z-<-@_*>iDF`*e0-H6=qO> zm(?MREbJg~zWfXng?EOb!Mp3q@NiFLIApHE8z!pU0G5X$&^}}f)gaYgwSyiUc0r0R ztl*p4xTU33Jj0+n@7iScF`yNH5tD7uhqyjx%KnBiKwqRs(p*lSmro9VMw-J>4}H%* z3LF+3g6sETW++|2@5V^|mw%rc1GQJn?Vsk-I2g<5`s>OahKaSnHO%E6>~`bRI{3Ai zoPh)T_s@s8di20=`--@}X}vT0Bo_>m2XT^)yD!bh!c|Z(%&iO(lc5hXuu+m zGk1$*1Npr#FYmpa-8*yU%$a)UPM51%ft#C=xZ$Uh9(+n!y`r)@R}e14n6p>LW+jtJrx!r$eJ1iR)r`P z7Z0y14hE-BA2)XFv}wh|hvS5N@u<>3-l0T@(RQc{SL z%YF>0M2>kfI4?Q~tVLymN+GZ-%snWP z2%M=B3dCXr*zutgIagKe+S~#?LNQxT91XWbj))`d^QZW=H*oPsut0Dmu_)t|VJQb?G zLBnvYcNrLgHB|maHH>Z?!NxQkF2oZqVaF9-K+OmJZrDM}43Q)wA(+DOLQEP#L|4mR zek8A=vZ4~SLYlR;@Z>A3I;!y1`QV?K)lEIx4W$zG4Z|DIAsR7~LMwQA0J@zpEJ%HM`IPdhmHMV#9D-}-E!VSf%Wip+?_oBML$D77n5#9Y^Lz}*{A`29 zs}@MaPY~5A=s7K_s#?5+=B1jrtZKO!7gtqvRaJo<$O_9Zri>vUV@Q^E5|ESqXjGkK zQELysg=ACi>!-krm8&c}PTLXIt^?qt-GfHgeTZ? zKOBv4e|7-X0g6ktzq7EQ~+1bN7@ zpsEVCLx<66Hq>Sth}R`@C|O|;tuJWEvCa=~cqaWwI1`(J2+;hStd00J-%k;BmvQos zhf(riHbA0THpH?Gz;$hzSLWDc23YA+g9Je~91!BC%F4=2^T)9!68ZIpJB&gquI9ijO<=;;$gb6}UbZ~#Hz z^bo+QSAwg3M~c{vfxwvs%w`B+?5W#LG@nI*B8*vi28JiZ(3;X0w7#%n+RM<`!L16g z!-bgxf?@;2rU#*-g>s^$AW}qRfDh!=W0$<+LGV&R$f{sQQ)UPt0_7iodY@nmo9^#f z3s8BRGjD4T7m!IF(SXqr+AXSLl8c{ZLkwcYe-x3yI7>!{UWfu`pz_CPnb;tT^n{J2 z2EBKKDu`NTL(8l|rZL~}$3t8&LB)XJ3fUYX8z{9i2k_QSkZwCU!lb~OaZDyiSI0(}yC@D~RRu5S# z_Qg=KAAS%U&LI(I0DxT!2Yw`m41(3jGKQ)pf>3bCkj6&wN)1Yw>={*4gMUrUXeyjz z&=O3VYdmipVt}I@QD({b@kntLxiF!!3RtmMR9xjj^gyke%z$gvl;BiMJp>UvUd(j( zHD=71v3PJi4Dz%ZX14JxGG$I+{=aR0$1KHti|nGvZT9-qJ)>5n%8~j;b>eUs5+f4K zlOmKUn3y5x{Hc1ikU+r_I9p@VGUeR;>pU@t3Wwz^#;O51Kpb}Y~DiHx?#iV+G-niJDqXnCJ1Rc z>)f->?A~}*H}-mNKl_5SHlBUq#_qEr0As_3i!Q$S5`BmLrI%G)egy#HE+KK^s;k$( z`u$c`Midt0Axj|&v6Qnx9{0_) z-J;c7cXj}q)6v!e^PJl{K&Sb(wq3h5%PisBy>m}T+ih)o)vf#XcI@1yg=@TQ52P_R;+jrKDpu86*CZUd=NBUP!vw|syTrc!bMbu8`98f z1jV}=JOo>UarzaKRZwUW=7?k?I*Je)GVHnL)&ka=q<0pvLq9~0a3nop5 zVG4Ex8rn3YL;Q+>r5oW4c38@-SJ)ec{%A-2tWGGJJE=9T&YpvfSo5}fEz%Jk(D}`NF zR#K5L`^qJkZrir)vP&-Ejw^vHMa|4)UFEY1B2!tpq<4$475-%48kyumxy1C;GG346Bf6@B-%eI}6GjedvCj{dqXCM(`^C#;w~ zfMt~H`93U7-Fxo`?#0cqTx=5f=>1r6dVpe6K7vIjUJm=nr|*Y^b8L9RMkn0a_Jt>T zKO3)5`3m8y&j6mqovbDr(7ySc!M~NES?pWS6MKQJ+>3;7fYASY&!-Yzu0rO(4fddir5zOl{ulsxme zaF}DqJgPBH3Wq088Q3b1I(+z4p`d>sklqC}Ug{(o`XWaEyJ>lEHODxKFnJtcGUnp| zO-;VauChZDd8SR$2<8Z35-OZcnlg1N|C8Y9B&<5n3eR{bupB>eQf6L2q$r~IQK2S{ zQ^nXHzW?md0nSrS&to7BR6FFzT-KRxQDjlB#qnSFhnq z(mAk}9P6C*t; ziIyLI(6(%C9f^czAd~f{n|N9~=G``HfJ7zZ<(Yn;hISjQ=V!q{5rS&7dwxr`aW+z- zHPR&35Pgl!j5VNZE`TjXSnj1zJuWk2rf{P=XqHGovN^U*O_cB57q2zdbm4Hho(850y)|^# zP-IPsorRK`oGtd_=U@dD^MngDcSd+#jVUU=Gz!f?vFHZF^dpOA*9w}AdtDl_F^aTR zRE`Ix1vh&Y^o%scg`*nKf<&xij#ZIke*@rbf=tA|Bc}M^#pZaAvL>yekE-;K4& z(J7EK8>D@e^*6MoSc3a6g6t?|<1#aZ8I3|nOhAW#6MR?=ky)o;C>Syk))!6`WgLd(UY|~-q0{59-lg`p<#Lgl3eR%G&IyTjMn~*YGo9n5Xcj6>u8ThqqAV@5L&dY zy)D|&8Lf>bVNMR6J!}{(+UK-&%+>a@qch>dQT07!%z|KVBf8xTy?eTbPe0~%f{_!}^a<|WqClTbZSz>@PGbvH(C@LBp zUBpnL#SyWb1Ak`1U9=W#C+rh6BXB)vlL#{z@AUlGTbO#R76q5cv&m?#)?)^Y~fmO z9WFXqx8P(z*#fwzh*TFXU4LpcT8%lzY7o{(Pa`+5q6+Bnj5$;UrAS|)0}4w*QB4h1 z6vk-Hf}z7uFkmqhX7H62Z9qYdL}v|);LeU{bYsL6BIb2bw3u47xH}%-gkS)X=**cz z@$%@!W^&*SA0oAF1PpL_ zb@tbX@fW^5*X&Nls&NL2OE?_SFv#pwsIZa*tE$V;KOW2;^03;nx&&nm4@1v*SmUrV zkN_hRg9ncsHF$K>;K5_Kxq&pSJVqiMK1L=*B9o^?CQh9Oefp%x4C<|si8DcOo6eLsmB?h|cm2i$p&8FQ3xLLz5!&^s9_K z9Em*gX;y`9iS-A;eCJm4{5rzS&!Fq*PjQ*f zF*o|)^Jj+=o71S_`^OaVsL>)uJ}?dxe(UC<$SG5%w9cG@GYx%Hz9SwR*J?wjSU`-dWJyy{UV1_m*zLRy;iU;9H;NV{aEZ z8@GVt=I`@0|Mm+md@F|%uu)cD)ZGnn*>G~16_=gwyeFTKXYNU1_BeGM(Cq_z#%h4FRwXS0lb!;$s^5hd1N8yli;O`1;>P9>U%}!RD`Ct>$Vn0KB}5EFUb5UKw{p ztSXy16$il>!H@VNq$^kNj#6Z)Cy6E}$Jw zmjIL95lZ!TgCc+ugRNm4eF>nuXi@CS&jF!>Qkc0t5~C>@RKlv*IxDe=*7M?zq@zL9 zH=8&PPdjG;rbTld!vt%%$zsYu^&ZI_Qm%pSb09weOj%|Jny~i0Kv*=mMI;OK2bJ|2 zvh0XjZtG3H`#g5;LdgZ+VIE>;vhZRByI)(uyUv8_$5?Cjg%b7<7geK+=c+qX{25J0i0i z6f0sr1(4-aKtw54gga7D8&rrh<(j#8%2<7HOYQFAc zIkn`ea}v~?dOYlD5l8vfb0@fENmsd2@Ag+B(f+hx5SzbCa2-n)L#6hxoxs1zLi%6(!!;ujEDfF$JWd~ zL6EnVpZwTUco>cjIiYI;RwhYDzucrMr5$WoBM7s8|E0Q#?Bx_JK@cc}sMK5lmivHs9Ir!W?(V_aM`xW;18u`3?p!OWrY`QUR%E-vEj{B$-X<04@d~ z>DK@Y`zG?gZoMpK-VHC17Ei>Pbz)i~+l+t#j>JW#*OeDE^FLEP_QUiocNub?Yv%tk zL4OhbTntP|`D8Ym2BdXX31iX)%YGsxrkyuU{@SjJW<5rpTaUA|E4${@ISemk2|So^J-<03_?0x}R`^WZU(} zle(c~1=p=@Qz|8ht|~OGS2V2xP4phK_7ld8qQ~wiLaZTzP+eQ#GEE}6jen+TL;>}^ zuqDE}GZwZi`+PnE$5~mBI}r81s0;`C!@1yll#j54`?Ovk%SG(V@oU69YfHC!u62Kt z_0QV)6@{My+USV&W}+wT8Min-aZG?!Ze)(bOHcfO4RTD6VPQ{bpk3h`t;3VR1JJMa zu&y=I6apz%*4i8nq>w1G8z3FLnPOo|rytjhjsJb15ZS_Ge37{libT*G1N2-|b``)A zgE{3Ph(11LGvw@pkVDBfX8m+syRw4KRHa$i+snTcyyZz10XInvX^|e0kc8qT1jmGk zQr&niklbaXp2DMDCvvYDCLQ2sn>Okakd=iJ8oxM>o3p-kMgSX#=!)}5=&hF6UMhpl zKpD|N*jmNmGxRKw_QXyQWj;t;%q}BgJ^sbk04ZMBDiAHsE^&N6{YG8|nb-4{2gcuC z{$r59C||o5nkl0_>AtXPaar(==;YwDIm(9bASVUXksWlB+JspElxNk8nLBl)lQuyV z^B(A>DuJm1er*Y8c%P|_(ChH1`@Z}V)Fe@r3Z)KWG;lPQfB|EHzWsD6`FjMpE#5N&Pk*oToPppMEw~_%3!{N)>83$h&CXJ znHeh#fk{%mrdmdojox@FolgBSeB@=m_;y<718R8&lMOO)%|4(8-TA{2;V8#D9PVH< znu{_cLmc7ZIHyKcaqn5yBl9iB?9aXEsh0|#|6yh(l&Tjms5J1jiiJi&DB@!@FbZ*1 zE(CfMAYilU5{plUnW9@YOp$X2e8to7$R0~Jm1%h*|9!} zC#L(W{iZ7ZbKU^B_1C|6_ANZuEs*%Y;c6~qnj+~!dB|`3?zNuFKAb^6{};r_)jgs@@~7qS`wgO!t_!;<@ypKB>mcL`U!bcuMVv)6H;o5TEn@ zc&}pgpBp}1-qaI zQz_QMtcLlSrDJLARRgY4h(;gQTIzJwtNK`7tE2edSu-BS_$5+0-qx)+Qo zav$wc9z#$cn5~W^)De1siu3%#qMH$rGyrL~0r0O!Y;qJ^!a$U+3g0%D%wa~)M5;!% zuX^zuUw2h?c|{HM_@KcRL(sAg9W+RuVYu9>woWCG@eO#8iL&RDvH@u_yUQt7#N06` zd+s5m2>l@0iaUv1lc&TKcH!C!ZBdZ|#9 zLGIVuZ#^o%f0J)^`gu4I;W*)|JiEO3Xk*rZV?cWu59)xe1H<<=yr<-?=PR3^)x>3KTMEMS1O~2!Rsj2HNoDV!%y87 zQ}01J>4upVXAB4jRY!C!LKiJ&#j{K5i1Z<9hqnGK{fAe99DMl@30G}=|CIgIi7R3AYByOdE>(!m-7yzQGwza-)%D1{C7V^!4BrYC}7F z7r4Yt;%6Hld~0^HdLTVoJP@@cR#;kCMw>y}+V|HYNc(XLIivKJV7)q)enY+m#X+Dz z;|W2WejlyzLItvUQN-E5&k5g7rulK^XBftJcr3_qovAFWKgQZUmUDjJSzh?TTH4!c z9}-!%t z+b!`~nXqY0;9-C^P#KI}4?^AtDikXH!q;D(Yd$#p9s2zFNG94+(OG``-Da$9dUE?1 zZ<#)Zm%yVx6JFFyKod=jHwgixq7@~Tq*Ew_q;nwE zi1~tHtLJbr$}~}t$Z{^u|H!4o0D{9Vf(FFb_8=^u<+3cWsiq+o{`8-0zmkru z*lAD9aa6wFe)IM@vlz!-`OzW4{qZ3?k^|%DtrL3Ky+^Zo_2D1t1o`{U8q055rX)I(-CqX1)2yiXab+}sx#7c@v+8t99T^qOeiPj)j4ud( zaDL{b{{qLa?EfnU4`2PrwQJSGPp8wd-|nFKyr=P|H}s~5s^1>Otn-_H{3Ry$)YF)= z06zTMxbUjqKHKqwnrGA3KQqkX>__-dhYj>7pHns>DXN(4j=v0E5(V8iqT7hXXBfa#5$EqApU^f zgNM@LbY0;6ux~$_{(1VIL+L{Y6EJo3bfi0=3(`ZK2F}~n;R$l;hQq7$A*3U{1rPK? zFsGOI9&`@Zfg=cR@FDUAP?3vQl)Uczo1kzT0}@O>i+A!&I(<+L?h7lha9SKN;kU2T zK76>2ukPu82gj+=!|7Pdk@PP?KsgTlY&*j01f&mu(wW9fKa_p}!?~AwB$g?b0VKNz z@ntM9Ttntygb7m*j6Kn#=@jGJqbT}^40v7#2lSpJeJ~(v;R-tPimC1)j&CX5@&g&k-^*2K5iuFEXtFC>W<`v-C*h%qa)9rPz|G zC*3jYuBV+aVAA6beXIpCzMAWC-rYaa(mJzkhLO!xgw+6?V^QW}4&^NGT5*zdG6KTQ zKda=PpLOdUT=4@~=Qt22)V;}}C?Ut$hU-+$TnBMg&bj9~=R4ak*m@x(3E^PJWtTfw zI9I+4Ie*pFI>t)jCLCOTLs>u0jW?}j@*HP}wxoKqbBkU<(Ccj^-O5~0&Q56_Z$p%J z?cTFTIeV4bM}C1bZ+CVSId=em&z+95bFFii88v9_OwHxsRvluz4TjgjY;$lS4B!K$ z>Vy05Lpq!fec1WPN7oIz|6|H|;K9Al#}82Y4@3VH`JB5RLZ}*Gdf0K+t4BWlDA337 zJdV3nAR6fL&wl}ib&P*cK%@jQ%(YK_*>Rp$kFTTab$6QMn))VFSao(-vTUU>1_qC4LadnnQc`tG*xRbKY}AN+9GkAAE!`^gW*&iUyx z^zS9j@BFLiVuC+E6BgJX3iJW}xi(7paC4^f3kM>EdSL#I*f`GaZXyou7<&1)zjJ>7 zhgZO6;Exvhlk>Y*5C7YraTS_#E?&m}`M>J=ozA&m%Ic3wZt34E81 z-f(*EdIA=2I?hq}oo4tq>u_kjTj>&pyc5?@bgPXS9hqy&F6WqJa&UkPLu+m=b{vea zrJU2FTo~;en~33lFu9|~r$VF#g~|vxlW`dsMaANLGzcQOZql4dbLY`^J|w$13r+w= zw`l>SK0 zS`2D37Ukak`#WgQ;wu#&`U9YI4O#WR{wn(6fD%-%J!X(uakT!ZbWNqeLqtYxBBjuA zBb46MO6qX+rFt>HSexiIU0ke{gAdUAR7W@Uz4Kb2-*9S*Yc(k;SXir(%9Xv;`{2>h zo2X(Ai@4 zf|`<6=xgQbnr+IXh5Eo#swJrsNI(1}B+Pox4&Z4lq=!C8Gg znuZ)e!8F;N>AG{HFlOW8Tn0HlSwp!XLx&}5;`I$Rvd}YfR1I#d zs8NkWFmS*M&DdsH&c-A+4^m>$1>cs0+$!o!h==5wwY>gLkdi`%RFpY$iOrioyp+w7 zT1b;!iFTGOrBM|x6HN>E=>qQHDpK4Al&Hu$&* zVfRgtX-@x-0eZ6Nm@&&(B!H&G$daFO1Z~lKMUKF5HNO-6y#Ryt5%%XnF`yk7gD&Rs z&5Z)?D>gf`t4h!gXli*z!O&P zeXjKE@qRc~tiwl|P9K`lYsR$f%fHSpx*pdC;D&&;eW)l-;109@old{HKmBHUKV7F^ zrkOqZPFF?~7|n1T%eLf&^wFb#+W%LKIluas{a2wIR-O9J#J06ZR||{1w|4g$@{*HVF1QqN7IM&AiXZh6k;?4=#=p)2Sx*o zS-IJSC7gq}^nP$Z%P}iQEEu~SDu%wNMVgEm;u~{~UUC$O;T%!$ax}%!tbQT;fd^9z zA7ehY%N&!k-Ga5WTX1B?rH3}YRQEzGUH4KQ*zrB`vkbs#y6zYF{IJg1+4W}nFMX)N z`89GNS4aO+D#bBrAGnXEXVt;q-}J$Ejz>A}LQ?R+j7Ai@$PNO7pDB(M)9EYWp0A%) zP!N0OlE>klgT@g$%ssp~WJWrDwLcC`PsjKbPGl^K)M6~!mwr=^MLD+9pCBgKUdPh7BikQyrhB&^#yB$_+reUu=p(I+!y$<#;-<%sDFh0;zN|fJ zYG{^V%`Tknq3)zJDIhw(I>`mmLD=C+Zyma+wQyiY07xLZQk~2#t3r9tsT( z4GD>$YE=h!w*M?QEYy$j2a3(?4NpUNn0?_=?5}_vJ|l&83FOZ%4MFH^7iFr7z}e8u zRjWgxHKmydt%Vq@b?euhdRi!iQDZ2yDYQAXWif=%hR!%s4GUr5crL2m(0S*>$*G}D z+tH?9aG`O2(Z!)lmW42qR98T{F~*VazNROXvT27Ny7nxxUI)3i*I#(U4Iv023GFBi zb=`bRD0J&=RU`gvq5p)PqVH5S%Wm5h+Pw!kuy>DD?SBq1iQG2t5hA&|S1rp-mg<&#js-^hMFd1iLTMMBamE^+JD&1`Uv1 zOXRC!3Wc5wL4s`v57rzY&we*K@AyT6;+X2(2&}!{< zmdf@iBOp|kP|LA^s=JR4yN^C3>g(znhSzZ{mkW))aRf1ltCTY8Qz60B_r%GX-vE)r zxDM#EI-%4h>G$k8!02|a=<{eXe*sm(2`AR^Zc=SnYT~lY2DQ9PTYzq`6`GKh;#}0E z|8E<=6=!w6GM%cLaD1>Cui0^&KYYs{(3#$+c|Exr1uN+J_}nPxn^4K2-A?ptw=v5% zBbn812lLx)@dz~?+HI*6d*M@hg6i(Y_4P6v2ZlaW{|bFFx(&A=49-PM{pgrB92T5z zL*=TD9_`!zSGMKDRZ>07djR@$TONc@8#qSmJ1A{A`C%&nzJQ&F4)z^F#ftf7*w8u| zM5hn_kAi0DusB{ z&i&RRCUtoKY>NSJ+0Gt+4;0pPF$I!4gyG&uZjRKOi)C9eHy2@etlUB6t}FGM>skT4 zC@VRQE1K5Eah!!6uW&>1geg;}&wy+pHn6Isa~6b(qK(DKcL4%%c~!Ezc!}#SbuqK# zu5eFM)vkMTNhU(4IIfFnrqyd)jBz2Nc)fe7d)fw7y3y_4q&B-JqfxxL z-D^)$rQ#2U)Y`xKqR&^Q=UjKad&7Fyt-kRl*WEEl-F(Zf?pnyOn$S zp1m%v4}Q;`49UG!+(Q^U^!K~&-RhouKj6BnKM3PF39&n;)ZOpK?gR6OVBUav!4IEv zrL@Bg6GMI`RKo`M0d-~RAa#!Wpu~p>{`dhz5^&nx;QWMApIocO=DMeywu^Mvq^j-f#E4)(LyVnZty3(?06X+~#0N4GL`XKZPVxsvW7eeFRM<07!qA$v4 zo>=nGLswk!+0X7#pB5SN;xDW=Blen&am|7MZtbTup$ix3R&lXuKbP3{bLld_{nVJ9 z9r=5;kA6dG5Qd)vIhk(_Z#jN#|L6Esw~R?-nT*WP2pz9I{2wxYJ=(_>rW2il9;6%f z{NH>0YTC$HX8fwxQ2#l8{pa}gZH-?sZhbIx=g0p!ZnbrNp8j9Z{yKJn9&M$pLqhME z#fGz!?P+p0FgB=q9LrH`-Msl!2@6iB;~Ks;EHUlxQrrG6TdplYH<%g5=A}Ag{GUC3 zZU3J=el0fRSMHViUpam~l4+a&%f_!51s{^VKK~rQ{x2NA4lr(Y|2K?VZ42_>t^JfH z^u&d_nOtPr&&9U=T(Z<}KQ;E>Vf>2G2`1zcm=EjWXobK9$JelP^HHvUy_t?-?(k62 zSvyB23hP{O5?;uf+r>g)`iWPw=6A7v2LRW>1bI~hOv^L#j-1iUtPv)oE@oQoPIAoT zVMfnHr6-*}uQ$fI$4=1T;~TQt2k&R-^**fEfi7VjLoxGn6bj3O|J)`foV-$~Y!GKv zFd?U>v#pCBew2D(M|dAC*Jj(yD?%*NC?Mw?XlhB63Z6j@>v<4L8O%9(Vh*U%J*f9r`FB( zP#TVP&ct`nZ~h}^GK7W!!ptLOmoHp&N;q(USDvn1`H3Gq|INeb-8sM#6lR{2^qPpoMf(TVVI-Z%_tU43u*U9FGA>N}8VgW?5UgvT_M_H({Dt z)B{jaKJKl%w+_?bP+8XWsR5L;9_*6({fORz(XLvFBZc(sl$G#!r8;}%=mND8o0g?~ zF)GIdyiZwT)mso^g(*(fsjut$mBmCLr+kGxoDUDNhzZzo779s8i-9Q1v@B@8fBDEiQ29dC zQmn%cXgFo%Cj|LkQ(5DJG4(4x{Nk#Wj~_TN_P~P&iuT@kAiqAlbq3djWFvmhFX3<$ z_OG&j17nn;j}Ia?(B5;Pv`8JmG8fC64i*kIaDBmFA}wIGC3LexthxqQ+v7TWZUM6{ zv|dY%5;W`ZaDAa(?zbIPJ=*81Zc^1_#=^R}W}GD!=xc0S3b6hl*VY;fU2jq7LJs7W zFDXb^`N%0(vcZ5hxWq}9DHbWIyf9DC4N5tXeHPK*|CGa#G5lxNPe|8s%TM=umY;F| zf6Gt$P}fVPQhrL=CjKLppPGM`pPZs^4Q$`=dH0~!4uXd(3vt zv}s9c&9d4wnCtLEo2K4zo0i*M;&+WBB&LQ5`U3aO1={7f#ynUV4D!Ckd>B-t*aL{; z;Y}&HkqrGJRo-CvhL@{BjcNp}M`HC{-`v*}#3>UnnCfJZU+-8)d3s*`@($WBRxzw^ zq!G*WHDmk-XuncPg$}Th;r5}u$Qj-4q|+_#!>~A_`&eilr1dd!j7st9)71_Z`gLaZ z9!z(DImI)3*wxLAbw@hkZ!fytlH39I&Ij=31xjlZ`fMc|`n^hQ>;yp`zukTKNKQhvtWk-2xRz}g9@=?ABhy;~B!6%I$lSg8*ytEMlD0DJ zhQfhA=0W*Yc*{AUcl-GVSkaLIi2ORe2LYD_R1~1Y3mF8|z06 zPmFFFK8Bmao5u}TqsI?NcLxs#GU#ZcV=!f^;P)k>UK6pU|7=`Uk8OhI;m-E5^U-bDj<=@Ng%_!dFHu7;h2zUEFXJ9T z_^~JhB_st!6UPAUmbxKVwUv&BkJs*K6gzcOJ z<~SI?x7=UEeNe{+Oc>bxMFmTnxJ(8n@a&F^0=;!IVjokj<(7&z!$L5ef^Z{>}F=|#Jwz_(=kn-CY4uyoXr<&D-bLe8LxY0yYD3Qk5_E5u%(d>R|X z8P5z=F`9ruXyUTLF15-!D-9j9rcIyRi7j{|Moz<-Xj{IF^kkGT7AlreAF>N8%4)<| zM5Ulw_y51kC->(fU8$`35lofykF?=?+qTsCIhir*wp;`p`+r2n|%MoJeD7^sfD zwO#t0tb}E*WI~*UXP|i!%#j>C?i`5x|@=S;vZbuP=V=@+3`qEhX}UKfo(-W|A%K{I6;dg+QMeT3yTUA_;+(mkD!Re@e* z1Qy4J{_``ai|r9eH8@rrd4W?ID8O@VL2tIPtN;iyC5#t{x&TG=scVO?@j z`&?cuxoG*|uDL6+I1Os*XI-ct5}>dt2_F0?o~(m>7yAX2gOS7Q%BLOqYdsTflhg{z+X)t`Z-Fbf9C9$ z``4x(=4i&8IeQv%Wj9c=gE@2d%Y#F3t_X41AMXWU)|s~(ME1Hri_*P z$=-GJg^)^p&J2f?9J6;Fvm|UmaDL3ud)Hw^mO+i->7k6<6w=CUdKHmR|3$rVkPLm2 ztJu4~9d^gvyN*6v=3E)SY391!yAFfwUuPhF2&8G;jecx-r)>&zjj zhZx4&>T4cgJ#oFLccQb75{nKRnjXNn+&IdfzB>==%7+a5ZDlYzRWi$wNqSvYTMYrv8ckglCwR`uuF3*$QS?X?Z-HCS%-SXb0?)z?3?)C4# z+dUh*+CNBN-8;nj{`<~?j{WQ(Rv-E3{m9Rcx$Z@A_W`%`K`?zBc1tmTe!xBZ6AHIU zGpu=VyN*5(mbwqAv*UNDi!h5s|CsPcK8?r$wtg6#kK$a}28CP(zIE$+MK`H;-N)6w zMEn{TRM*9UGvOib?$mtl6QYX=^aM?`|LoZxgZ?=&(foP$3r~L0{nEi+MnS_D!3nfB@J{yE zvHj!J>p%4Vc8_ylDv75{m2&1Jg@;{}i&d|5Ba*;}LQt#Adg*GOw?~a+Wg2%IDU<~oaRn-Q#oXhG>*eJRcV$3rhR9CC= z5!yJ?r!vEogDwwXbaizTR^FPcQ5jkZ3$Mx$PsxhuH?3z(=NwonjbmKvQX<|b3cY=i^G34tMn$PT=B{7P7iA^bcVEusHX zeW5_0bQeQ3Qwd_mf}#qLFUWmlk7OE1$Y+*2T{`grv%=NubDa2#5O|o7P+Cms*aUss zX1NmUsz|k1*TiD+92g83l11V1>O}p}x`v_gx?y#R!NVIGht~N_wRMIyR$n`~Ivy84 zvy~CnFtTyf=*Gq-#3Lq)23R)8g7~=cqtt||mINX2D*&`?O0vGRW}gH(A=Dyt!Y%}2zNM)A+9AZ zXg;ACjdnOJUCw384PASi>=NUO=H`>&A9#!{{AoH_hqdCA=H``Jl90B<1||cm8ynXM zYCLN;uC=yeEy*iET(K@3?rQ96Z0%}XvP3LbH;x_Mw6=Nu`coCwL{@AJhnc^vUG3f0 ze)XoNg~`*_uiC7-#wyq^+Cuxr4I7O6)m?BubLJ{WfbJO&__qpcDdHb@a-81PK6-W2 zrq$hR+W7{zCbuqJwdOQf7=HM-8fgGP?P}WAyl~+v)z+l8=F-<{x;lg5Y=U!f(%4RZ z#@~cLx)JUg8yOS;@toG!e&%V-XEis&i7fHx%ogj$<;_Wj*Od&1&sLk3jGd;CKV9dH z?poeF^Q6YH&8t8+nY#+_1uH=3o_9VXsU0KVrCcm*T-n_0myqr1OoqhxNjbP69KKLB zu2{5U?TO8cR-!=QHJ=g=U$iPRQC)03LWF^?Zfb1DL*0O-h_&W0HtnsK6kck=X_S6} zSl~rKzl`|hLb&2eW(MC6jH_2{7rk)>R;g&s*%s2T(t2Z~EX*eX zd_2%Wzwla|oRyb&f$$N@BMdIUtDy9x~Jvd$jA@Ws}GLaPoDcm@+}c| zYfas5bZ8%9r8X*KRv56U-Me?QuVUFgg17)&kazFC((qcpQ~_$XD%NHOYU(~ZI1wKf ztB;R)-~Cg;9s8K7)LE;#VLVN6Ox>aE$8-PrgLENn{?iw&-g z#~*$qF77^Un5aG4_}F7}Bx)#f0%AaES|kXH{C0IM%N^g*qQ-7~tIeM>4y3#h=a;-) z-O)|HMt<%|rQj>;hsTAt{WFrLwI|MB(IcUB;~SpS3>hk_tDQfckF=W8{5iUlwnMu` zVlqH~{O_M1Sgb~=&&Sjk@R_oj7`s7Nmg0i-H6hD~CuyN;KW#@9BuU>F-7BU1f9d0R zn+LB{q28xHd>idEetvm|;@r#Ag{J-g%2%I}pscdOAgE#GXA14J3`4(eR%MOtY$BKr z8^z6}k{NbTB~BzYHGln9#eI!mskU1q^^LsTuZP2r(;vY6Z?FyKd*)l0>z#yd-7pa-0Tz<5 zJnaHTSGb_Gu4?^e$8*ieR#V{A)>X9H%8wtQdl+}?&(IofqR|?}s%65ridrIff2<^i z7m;H#v8pK25_w*GFtI9f&xfobhYbb^Brha!Mn=?m0@|aRSiP7`6>*aZGRra+%O?&& zOPm4QEN)uTg<^V+I-~oXu1!nMIcL)nRv%qsr8P!5?CO%Kw{fvHXES zgTB{={do$;i(rhv%SmG}m!gY`-YI;O)?9I2LLX7MI82QWo9;M$<&aOAn_gY(&8|V7v%yI+iM)d13OSKv#8F7xk+()@jOU%9HzEonuIaS|6K?QHlnCYpkIpTG6iu} z!gVEtOyqOZ{4RBs(9ybM3lev?H{m0?PF=5V5c-W!Z^E-f-K=g=x2m1MZ^I6h>1dsr z)E>20?L))ET)6}8-lOhRccIB^Qt!j_eg)|nVt23l0P;TbtA>OMz5)LB8~r}@A%)pT zs2^4LtBVWzLeE6h-{3`VjF6yj>;3|gJ|MzM2=m1pmJqA~gi`{3`6QX|> zvxe4(&jb5{dJ?(%MfD|h(8Q(}v3&|@__BIheFeX2NT+(ncSE<&s;^0&eqGcH)Hl>O z!QZ5wQ{RH^^MdOf-y!a@bN>ZUteN=p>P7W!^&N!$UG+V&`M&yr`XS6eQa@Hd0mo0V z%lltp^D}h_`P>Jo$&=JC)GzT?W~yJQUyFagQ7^0Cg6DVY_v#Po74=6@^{+|&$q%nd zy^4)$|7Og87X2^a`*-z!)c+OJYuLKR*!@*f@gKlmhhW$@)lqB(RgR7~CyVek;wF&- zOx|Fk2-jRuRHRK8^MLr3CI(U1=-wK%WAL#Q`Y?s7I)TTW>xC0@ua3?+ z?QVx+Ea_*Z_*F&W;t<(v{bd>5q2gkv`I^*V-!vWNa)>k3Sq`0hpX!{uRKlr;{awhv zhAh4&HC$q#)A?MM|D-hfoP5(ZY#rVR-_C{)`Cym>)?7_Fw$>#iKs(L8%{U*MuEuj~ zm4hi_XR-r9(9Sexx--LRb!OsbrU_0PY}%a;XBKQaouo6{nd8iL<~d(f^PL6G3C@Ym zLT8b)*jeH%b(V>*Iz3u_TJrHqq$l%>WrfYyEqA))XJe}CQ>(6U@@r?#-*L{6GY6bC zkn0)CjCeIY{Kvt7dTjfvugCgKebbow`m$re*kf7v^k!n?%Cw9%pITNnrT(p;Z0fW! zEmgZ?7I?YCVlMP~^XYH_6#@8p!im-Zonb7@GF!B)Y!T7LODw_aOPAGC0Jk;f>L;7D zpOO`IL07KIWdxt5tX`9AF>wBK1}j`pU|vFDVGQ#`ym)I+A#4nkSAbSYi~mkg^$sJO zpFfy817MGrnHYyXrz0`%$K7evvlo^gm&=;A|$fx*llN-(mGPId=}Ltd~@ zl7SmSu`5YoTL#X3K@EpwV@3?y=F0|oXcAT zybw&>csE#R!6DVCW4I-xPMfO|;WCe&Ru|RRf;5QC4ce{}OT@J!H6E)OHOS*`kw$HX zJjW4Ub=3&CX$XsSe#R*rDxMH3LUfTB?zw6yZ$z3ZLW7tzNnMHYyl`TuE)i_>Vuj#t zNCcUza*EiWEHFhN#)MA|O&ix#&9s6iJe^v__?lqTxN4kYm;q92FgP<*+*}x{8P7AA zZE!QOqNWLYJJ614Q)dM$r*%#P9vn9=6dH>iiO8ghp_1}O##DBF1>wD$M6S;US6J^B zi-8s)uh-BJ4$hey49?Pij2p*z#gIlEen6Dxg~v{-VX$}y6>}5tAQ+rKsEqp^=S&MO zfEpiOd%}qV8I2fROkTK%X{F-^l$T&(gmEbjFD3;qbbLjkK%y89RkI+>85_du4aY-M zk^FH!ED0|4I?#U(74wA$V_vXpg+RYDsP|K11c|i10$%93;Qy?&AY<(cm90*`ZZdjlt5STbg>tiOv9n66#Q$?FLU3)*HmHNy;8&rtqE9guL zefFHd++u8>5<}nw0ltfciwK%U+ljh3uo%%81{|BL0)geeRhPk5oMe!bMLz{9r1=?I zU`-&fb{*2aK5!~Xr)>xXHg;RPz^2Vxd>lwY!Pe8a13iqMS+VqoNx*9{nE?C=JG49)K1@38o26e zjav2HfopnF*QTyZ{oS-oXxE>3!=gnuX0Lb>58PzqruBlr)@(x1H;fZ(hi}%%f|~<@ zTe4}l1_C?j!}>trHqv(mcJHAM^In}lG!gdQu63x8dU)n8-vk7L4+HP_35$I!AG!M; z+nX>tZ-30|0Op)OaN=1RFnEZAzWCn)=(}?bT<`IDJ6h8i1IGys2ODsz!QZ7ZL0I*% z2Dx5kAgAWE!$4MsHf8E@EMYY**Luu!8&j?4+RFNPKr&eFy_YH~|E2t=nv0I%TfcfY zhkz!Z{T;o@IUqALGSh?wc|FZUl?-h`c;T1=marI^npviT+hcJ$K-Vi zxM77!DkZ;L8Gj-7YVPy;W8gR+VAet*9zqSQsB%Iiyf# z-YP5W5_R>mcVz@7+eVLUs>Gg@!oqQt<0~h$44H@twkd_9y+WM%o>*8}iaEB*%GTDI zt*WX}RaTC!ES%cbS~<17)+?Mesj#A~w5_s(>#ZtYs)~|TvrAh>cXrI2qr3{$K4fl{ zS2q*eqUX)`ipr`=XICZ5OXrQA*D|xbv(PIYSJ|Qx^E_2NTNRCKnS~pPhc4)>JYk-i zQ#l&*c6AFYXJTP@(VTgOt(6NEtY*$@>8M>euX6EBHMFR(sCMeYshHEl%Fdk5rOQ-d z=|WZ5q-rahF``n-3oD15=#8#yo-!4^6hySDuuPqFvcCN#g1cWPLKvT~=uJZkE+aCnj&8-xijR70ED!_Zz{-Z4u%>ntx%hG%1xG-vL-aJY?| z(HAb7?Jibxme6c2(Q;2wbK*!%+sXxXt5&PosN*#M$^|EMtpWc~eWY+*nAg#%lWAYk z27X-I(|!74@^91T1u&m6+dWg8!{M{Gp1qL%owF@mat?Cr+>-OoN8vS#1h{`-VTWv| zG%2_Mle^lyTB%Fji!Qr7%*-pRE#G=YIWy2dcqk68Du?SeSHJrb%DJD6NRW87F zqEcC3f;Cs_qQGF^wI+jlJ^hl}j4T3W^5(3mpFTItXk||Kty`_a6*s^SJ~slt$)pEw zqI}2AlA>GOi?aLyAK+F?*-3L*`Hu1(%-al5gFO{qQN z)!yVrWVqeYj11?3{BS81!HmH~TT} z0KCw*hEEDBmqrEAugbnKZ3ndsdvs|q?>Zd5UoFIU=HC&-7)V%%l?5!FVgK<%dL2y@ zAATeQpFThjcgmMajNUN}wk3c^9?`nS;q1|jQ*C8aZ(_bPTow+yj~UahJ0FK%h@%Cr z)!iS)2a$o#?8AmDKa}tjpT%bmqh{Erh6u8^{7U6sR9-&hb9{@FEv5CC zSL?-W6uc;<84LmC%G#UMNeJP6<>k*{HR)NU6~J##>Q`+p z$4wxhu68e?c~|-O{n|m>k1GEG%7Y05FAm?gnDX*RrL?0Ul@P$(WSRn}HEfHi^2xQ`_ zr}10o&G+f=6!C{Um``CJfJf0dfA7=Z8FKR53;&drfxxQOYeXKwhK;S=n>GiwXqQ`C zPv3S%>zS=*8IN!|(Rsd~=lhtC=;&>4y}+mBA~yOL=8}(TBL79cEiTdZ@na!4+yX1y zjuZ&scBEr*4Mgur3H926>@4lN*6VMu_&~a>KS{~v5XF@h5Z5gx1*g|b%f#xxu_6Kl z-$DHIzd+0<@Rd5lhc`8G5rkuO(Sp;b!`r4NjO_p~Y-++jbB;PA7zxVuYwSP9ppsV+a=gnSFGighAC&Pw2pa&fKck#~ zRRO>ymX-KdRVn@*2WK8?YE%t`Rm8D1SmE5m5bWF-I&2vBZq(K~wF)yMYV267m^Nd6 zSk=`f5(y`v#*fEfV8R47W5x_MZQ8PB%OF5w)~s1-?%dN(n>P>R!1=grw<+ji?I+*{ zny`yx>Qs~G&+qOcGN4?ghk;7fP<|e@i-NyfqO(SY&-en1q+mW$|-Ga zvu9(nRbi%ep<1|d<p3(LvqOK)oOJzsgg^Us3n^>Z`#z+flV-K&6+Okom;zh-8$?HS-)Ow*l_Bp zr=Nbh>hA7VTeogi+qU6cqQVq7_K|GavPG#a4fXX|tFdOrmG2t$ttkc2H9=D?PHSO8 zt7+%+@bQE^OgwmA5oAJIiG3&$R%jpJF~Ht8S%Rfri*wGPY*0Tax3r3K4=cj`f$oG_ zO&toLrY2rfQ!^M3U`Tw3MhpeVoB=|T6apJ&8AKmagAzli)0$Beb+vrW0uqXcHIOVA z?s~&jMK@nr=v8Rk^A;^$%s)7n zELpUK&!R=1U}6Au@nT@mwTjxyhh;vt+{@r3F2@5=O3OVD^}oQ$892rBPVvOJ^5m0I z2MVmtf;FpGdoZq{o{bw8kSw;=BIF0R=b;`nu%5~HPBm~^4s7tyCS{;oZQLZ>p0`ff^};1gxJXdP5{leO|*`JAZBz$2;2~_hrEuS#kMVEp$_UsO-0OX zU~o``t^s$2WJ8erK}3dUy9lt9^q}`5aFYRT;u$ai_;%#N&AQd3>Up<7y)_HKzVkME z4jrX_4H4>mw7;IWD;svxKrW$+jv1~!j57g%ou^`#@X{eZh!)7G?2~v zgh{sd$y}%qqvw6{Uo!A1Ixt49L)EpW=RIWMVR9LGz%!MyL`J}eMd|w6*dR}iXJoRNCJkOxw@M!~IG4Rz~@Wcqt zXP$Y+dlpI-eC=5eA_+3^4Wi%70q?nQWrOEE|AK)RvjE<|_-$N^>v`V>dLtE0d{&Ft-mi5c;VD)<+{veFTs12U?${)3J zmRrG~7n%at!&XM1hm9Q-WA+gxZ5JJC*S4Hu>94Q?{+N%6V`2X!1P}>IG}STmgTLhCTx4O7zK+QRZ}sK3}5GmW;>w5}q*8dW)PfnS?$4{AJFXP^{Kl zoipiw#>Ad58R&e8K3$S~w#1$*;i-}f&H0f_&DoJF<%Gz1p8mx75ccP;Q7MVFJtcCZ zx=GC3eb3*`cz9AoV>@wTzuh=RvIoy@IY+V&XGt=@+i|XhKOCquI!*d~ ziMF{*=(ppn$?Z66a=V;1xd$gs_~VI_+}{Ur(&Rq#(x&zXDzXHEFyX%lS?^`&7@q+wxNf~cWihNhTgzt%}&x+_T<45ux@XSaAXGU1| zd2%Fzvm^RT_?es_i71{R$pBB1@Dzzszd_9S4ZSRuzg0X-B0HAVA2RH31A9ey{s`ab zBjHb?W|UWP4ki0%ZFn}trZrptv-&emfM}Iz{r8;T|B+I(2Patg;|Z4Aaen1L%#UBV zhSz<+d7|YF|98~KGBk^&;pTN#Ox)t;@XU+;>60&*AoVYPyV>8Inxl-=r{wj>Q(y5YPHO|N6|7zeiQ`^Oz z!Tt}z-vC3MO#P})$=ElLz_chPMxB4d=@|YRoe}28GcJ?VXs1bjV<0YgEYjNSj59x; zR-rE~IL%_uv+Pnl(V~Bub1iMofB0|5hC5!(z^NCWbYZ^Eg4!uq(y{qLeRhs%j)XTC zr(vq(G>omMwa&9Kxs+_vLb$c&MZ&jOd|QHH#^(%KZO#CT$6w5~D3Nw3UoC zmOw%cX`$g(GMP*=(@rw!%%n}AU_+adN^jeyG(eF`p+qcDE<(ksRS_$qRz$38l`0i0 zi`Z4fs;E^FtFmtWZCATX+WCE+b9v{TODMSP{`dd?_ayUv&w0-Moaa2}Ip@5Wzwj)U z7zHZ-TzRUTO+I8X1{>}GYp?cs- zpB|?H=RH2ltCHseUytu9-$M1bNX75+>y9uBpy@eb@Mw^0&;lTv1l|?B7bC z{QZM(m2b5PEBW{P*6??&Z>?`YQLpn|@4Lab&JA&+??&JId^fr7^}hG}ZuV{P-Qv5| zw~@cw)Zd`*1HRjRAM|bV-C_RjbYo=ua1!&|T|WJ{*>^X#sm?t<{dceLKHrCY_xm1D ze_MPXHt`?y>A#Qowkpa;ee(A)-^Y#rHsA1npCF9a_mjR)`5r3r_i2-slr%dQytaqk z5TEhszwHV?>w5&u)^Muxxg3|4dD3&*JgR#4^Xlq2U+{g=w*&i^l>0Fi)Asw9O*%HF z!*hJRJTitKSA0+SzUtd)e7@%UM{HmB?ecxY4f{>kW}*O38rp6+_*=ej`=0Xc z@qNelwC}sVy}s}9({*Z9p^$nW^9pmsGw}JJ)hK-#pO=iU4kwac|NRrOpH(Tm?0nz% zxJpxkKIi*^$^8&6JxA=rSA4`@Qp}cKQ}p$pjsIgliSt~ZB58v zbgLoSeYD$*dl2&hHv;e2aP8W1(H(c*wK;Tm=$?D;yXc}1U39=8?3xqV&^(dFq-Ia!r^ZiL_D0R2>q?BR{a z$PS#mBSpPbi-Yq?7*5XLt`0$YU!)B3cVOhS^PLzu;Z&lCQ%%mN&y@YovoP}X0cY$r z@*W0t3d!+0r|asJ@m!33mQ5b+Iu9cUdNVL`EXS!jM|l^D9FqgMi{+ILa*`%*(rv`Z z_~9OcrZ7g%v?7=mj6Av|<1L2a+??~P*>Xk|my;*X^V>OHPjq19!7tfI6d=4X9p0eF3dzU}N{0Jl4m$G&F0>?C z*(%R6w~EQ$O(e6do@eb`tLIypZS{Ps=Uka_WzLoPR?oF|zBM=O$h52GUAbdN=3SY2 z^{gv1?+mHrSebvtc;{f5gvC!LVVQ%)c;{g|7u)$*Psw^hmigG7kjw)7tY`(Luh8zvv;NiHIH|#vaESb;M{S zS|_o3iPcT4e)2=o5gkR0Ic8P5O7^IA>{!uTtjQj^icLy6cC0;i-M?SEMYj>-Ier!E zSkZOFh`u8xU*~b%_VH}FGdlZ*9(((}yrD;AnU-Jr`ReQzh1|0$TNFqa^`3g}f zhev<+-Yk!1t_J#RUzE-+db`(XsUU&@Ss+hC@*o{g&nf*}boApGrN4^`ukO1tI=mk6 z_Np{`QRii=LhV%W#(?W@Sf_7qV_GX+L_}y~r#@n#@#*g4$4QJx% z0iHf^CXSytlA9XG^NhpTkz+=V9CxZb`QVHlKXQbhH!As^k_r9^a(FO79)TzyJ9g6B z$4xq=tb7dbBN{I^T2)Zt@nZrbP8~sUPC99nZ{kGXM8ALHXrCV)wqoMMai>l^wc^xq z6^?%tg&WPcA5NV(dhCeNBSuldiGdO0PZ~eLclyNA@gqv#_O`dab!5f(abr(AZ5(%Q zjjfpA1jdgZ85mzav9z>YDsg4AJh^;wFc_E|C=UcC2Z_v8+~q=>JURHzU^%-| zlc&5Z8*}m$!YM=I1fM)vJIl+@lTK0nTh*SiiBa8tn_5w?4u%F67n}oz(`Gv?k|5;iyN_( zAW=%i(Lha2mGZBOx5+@lwA**it8^0TJ-N!-qH?LN)!|KIq+e50eX5_Al0&JfnI-O7 z0=%Y3nW+*oQp4j4#>`YvDR`}fbxoossXX*0*^)}*l}x2ml7%AHXx8h*A*H%7CD)l9 zGgT2)h$=~Y=1huGEAbO^=gmz^Msq1$2k&FoMIXoFjJJ(nm?YxN+K!o3{MRN@XSI>Z$`vIXY;oc{K@H3{nmI z9(Jl5$c_|4ucODlSkSj)|HM2w7P4YGEM!ppHaw(EZM~6~@RXcQu zb!KgXV$~!PvTmzQ>8@7Zct&80nndjdScN+-(fmjo&m`-a9V%xDOT&^_hYo*X3+c|B zLwMb3xZ+{MQS;}AYgl-ybST`!i7amU_!ddnuE935){LJdS;9YxQEReeDj`eP+2QbI zq&h!*Dn*v~Rac~Ih)|PGrdxD5d8V|gDn$Y{EvYN7pn9ZaMp7~@TI&@mTq+%AD4)xy z*6Cc@EUBr!6_7rbpS6o0M%Y!GnHSbb?cSs6BbNoWQoyik9o<1aHmt%+Th$A(Ep6c< zldr#bv2-TJBuvQ@+Ff&r>KMj>GBXVlK!%!hT~aJHHU3V2Q^d5p>VL(s6z^*P#WkU- zKAR~O!iXzE5doF14BBK$7?{=}kIQQHxHYj%x$rmUN<0Xz^E1_!s!OuTbS>?Fg>*?G zsY<6373YPNhi72@ND)av48dgkASv$J+WC?QQm#grC45<}4R!@}tw}3(N!GCHsFBQ( zR+IuG;TasfKuz^4l0Xa-1X+<826j?L3e^I)R;5~02Wj!Gr;_S(w97zw`I72tg6ocu zL@2eIBA6s3q?ti#!CG<4zKtM8xn*rqUVaVXmM%L><5}Vr2rLIB{))3|HC>%G{KKlo zM)o57{cHNyNV%_VY+NhIi_Un;cHNC)_n*x3wtoNnm^Wl=r|~8k>80z|D;6wWw@BAy zPHm2Q_kJt2Z=Swk`Ucewwo>6+!ncNHf)3sqt`7uga}Fv3fsKK{JFCtNmvg6eeR=tW z@NFu6E@s1}w|DRZy|>dMJi-tTmxjY1oDjyMe$sKJ;SY*aj3`-IBa{&%RFv?hJH#c% zgq!AY>1j`30^=9D#F?G_fm}}5tL~lTOnT)dhl4Ww&PTkG@R zqrdg1YRR^cbR2`^f$HjT@0LqtoX))P!w)utRaKW(H_PnlF*C!eDRpXGFH?^y2ca$+m`zhMl zADeuQicNS$sFRqrwbgQ}*}|VFKUbuaB6ulQ_~ZChRq6DV#84Hpl1p*EUz8JntCD|G zK$$P}WTWIt?To4jLIq*COF87OtFEX?`TIVh;?wG)3aOujqaLZ`wlw9}vB(Z>r>e>>@Z~H|jFdxy2(PJ- zD5CVCn&ci*p29y&VW>&USjAW;o7de{BaDF8VXHnadf=yTBAD61FwTg!*Ngg9QrkD$BVtPg~?5O0g7B^o^*Mz^AO6_10 z`Vy(lp2o%WhieJfhHGZ4giN<+IVlaVW>4t_WpH1ksp@Jkb%9!*a6Xq0Uto}!vf8pM zE-HOtz zxEW?cV@89omE#kb4!RgnOMHnTswajBip#)K)rx#DNjI^U$M8MIP;>xs$RH9ORE!!> zAY>C&hai*+$kjEM6H^>2qFjh^naQ!;5S7xwMN6Si)xOpagxnvipXktA6}eyWkk2vl z-UzOzxKCo}r!Y?8DGZ^WqMpRCcS^GP;eOdep2+b2y~BLlBcPtaIE5!Lcy}UyI^^+O)i41upQSW&|qaMFYJwE!oAoc3Y zAob?kAoc3&AiOw2zC5h1G4quWNiqASkiw@p+gkh z^TiPFQyuRy&vkV2We|C?qg#C!WHs^i^Bvth-!Z^Lp{H-S=B?uZ+cayF?|_KwGwQ0p2%>!-F>&7@%3{Y z@(jmwxPG8$_2vnVCrR%|s%11UJg)5dzt4q0(=WZ>@q6kDUK|cTic&)Xr5h8zoQBPgy zZ-dBF74l4l_iG?NU(C_ZMC5)4B*4dFPvPl@=XlbgoU44>BlmAC)N%au->KM6BgA-+ z_rLI5g3u?D`Xqj%`L@Vt-`m~LXW+6ibFtDFR6g&>@t=(AogRujy)fE0MN!Tq*J^%e z@#KOoVGUSoLcfit7{2JXweBf>72chy?$+1e>9DOTDBtW5Ni&@%BjiuM-ht%cNe2BV zeIj4-xQHhkY?{wGmv~C3>#yrJlQ7wDeCTl~sW$tvJT71T5WdU$%5x6#ESaP+0o!wq zd=cb1N4^OnG_gPDXuJ67l70u8{?l&ZYF)y5o_nw~!TU|PiHdr_X$KRORO;X1o8vph zNxI?X8Hh?pKLw%N$vz8VYcJ0~)H_%D-ecm(^A3{BRXp+VB(1f`CtTkPO`dv?+}m*1 zJM#R)dsQ2XOP+v`=O5~w6)JYUW1oAFryZ`P^=*Dxlz3~&LvVmt*QuD#IM?$$g!k_T zo{sSTNqGDBJ=Z3bbt)JA^n^S$VM7V(Cn&O%TM27j8&$}sRD0j%3p#_oKRDT^D{Lr@ zck&E{olE73ihGEAFTYmzX^JhlKIeScC(o5hZFA#Ka~@P<>LYx!NB*|*Y{jLfb)^44 zM(q1doL&>Zm1i&Nd9FgYUA^-OT=kATTOkw~4-YA>w>f;9bYQT#velV>IBogMt-?@Qog{Jw15^*kAo&BNM8`{daO2`|q_$deH< zB~R3p6xa~O9I8%+*e^S@yc(&sEzUQ$2K)Ls+m^S=Bn{=#O zr08hh4}B-|j6{H^BYy0AfoCXAc7Ed9@B69mXTF~spBH_paW&)~oM4ynJt&_e&m_iw(#zJK@q z)%Q2w5#KY;fAG_7@SmzCmzw(NvQOX}Mz5-;%_Phaelg>(!^zB`|BgaGru-)PGANls zl{DlgGo4lmsAcL1e8or8W4@8brrq{B%24;Indl^yqRmaP)Qxqr@v|{STHE|BO-o?Q z0W(wx?b3RJwtvsmM#mpbx&eRo&#T=Q+GCDaHr?PGBX2UvHTM1wc`CtvpUK|+p}x*M zS-(%8O_rR8Q_Q0&e0YL;$K<9DZuy8rW06SXtj0$Bmc&RZt)420L}ZieIOeh<{+G|U z#49FGcJKY**%C|6Lv@d~y|Y75?(WDnlPAkVDU&B>@AZh^z>5iQlDpU9@%8cd-@GAy zOZ-;s8~NQf_<`GnuFMCmC5t-$P4PPn$(H9%kNYk+_~yIsaqZd?;ady$#~+AuUk4AS zeC*?1?`@xm$K@%NhvT2w&I^Gb{rnfc7`N#w+>ztL@ukU+c@w}cA-uFN#~=TSH%M;V zEPW!EIdHl6Z>a48xxgs`>H!vg1IO4?_0349X&5_pJeG>FV^5zjRzl{Ri6>2Zy9udY z?rme8z&F1IDvy(-JWKK#CiohD;uSpS+;`VI=kjhjx$v6)cTeLto!@!<#65#w1HTI# zUOp#3eKA)HF4?|}ju#_J!qen(o?K>dsVDV%Qm!Wve(DPK-0A$zm!Be?+u+pK6QCZi zdc5lKs)sfW+B9g>NMsuH>2=ODDf2YSJB?JQQO;?k$xmOn&Tytdyug``|8&Uw^o8rW z&h&a`I-3B~q%00EZ=6n`^PTB4oaqhD^b4HxXn^xb^t?L$)lXmQob%;h{kYB`$P7TN zl8{{LoCf(*of^_pmWiogF4UY#s4P z8?}Z2#6s<2;T`@-J_iv>g?T5ay3#AnvDO&Dqyp&>ZJs8%bQ66;577AObcpV1R{fgm zO2%5F5>W?eio_FqbHMA;Y%n*}nhZrreJ<0llw)p+?-bNKO(Fi{F?DIDE3ve7s!N-` zN_B+R=BZ6ni2jSy=k0ikLO&)8fQkInJj>lzuq=b@aSA*TP zg%ga;b}CL!(hbn%l8mW~N;jE|g<2!YNV+pA*`y-PW*CV**4mz62+=%j`pOS!uddTH z%usNyzBVXebCY05UBX+%BJstp;_5u7skl00<^X(|1>~yYPE&Ck6y*X!Mrrhr08NjOYmKDlMI-If z94(1B;wGQk7V7B8r7|!gN!6C#u<2Mj9x0$AKC)q9HY7kYF&i!k$C6=b_*wkVrXS(V ztW8T{*CW;xi^tO4S${()9xT=zNgyaXqA5>=*QAMjATuR?%G%|0sCrTgwKsQkwujT5YOawqJKJL|u}HJG%oWhX@J&=}$Wx7)#+~jCn2;Zwn=76V>`eL-Ce8k~p&glqU`A7M@q3 zCdfwtax50s^NneHMW$3tMd<|Ht2%O4s7)1!X6Xte7DbAI&6Fs?*q#;Y2#Fv;h$lq= z;nf}q6FsMHiS`tMnRoEkw&qBPez2|i3*piOm(Ws z2y=ZlOscbKRs!Lrazcu=()>ymN)Qq79WnZki4%8+6s}WbU28HS5nQ{{9bgqF3}2RVs(n0T}@#&CX5{Z+hubN>eggiJmq%Q5D zR+$IHt*yd?IW9ey!XS=2TCz6jI+u*YGa$TVX`N~zkxaD4 zyG6uB+7gU&INX7Uu1sDYko>|b%a#?b+@;MTAWr&6L(s}{5Ls>qX;^m zaD8in;cndCJX<4)wn$p~IU4GK32`UYrB#%7afwA*%wxAL)=EzCP^-Emm~`o%)_7;c zX%(GNE<%vW70neD8V}}XuwkAzLR!um#!b~DORZ=*m;}zXBceA)8 zsE*z_OD30?)7m+UdUPh+I%mT^SUR03r_0lvC_1mqYa}Zzr)MT1=r(k1#$Qowptj3G ziS}qD+M1w^QHSKmrw+JuDmS3#G^28;sZD$5S#9A%CboE6T9ct^F)floCt=-6*g=X3 zJt3D)UIO7nBTY$liOe%#X1FLL!HKeJViK4OD|9lMGHoPUv6HrVbmkFqoG@IJ>Lq8V zohWOlXgB|KX**xvGrALf6KhU2sS5)m+08i8Q#|Cfkm0agdK)2_Zt1MHkVF?EwL^&VX9ath%piAh(Yq<5W5HPnWAX5LfN4yR+yD`X3ceGhxm_CaDe44!-kS| zShOQn$a531u%w5*sk2?6wM#_+tePrRR#}oJTPFx4)_?8d(iW+vwI`BMqP2RxJEDnp z**H-gt(#$XsGGJX8^jC=Mp^R9C6S7%B1hRhfxy+Ok~pBSbmfv@9oo#eb7rf+bDj7U zN5pP(6rfn~P(prkLA^THfK*=-JVIU(D3?T%Whb^~t7^KWCf62rZOyLDs6jTqb`~b0 z=-HH%Gn<@psx;f3IHB-CC#74IppY#LJGYCSsYdO3cBFv3q@x!yIRyr7_%pw3UfhjZ&nwPPvVdX zzgyQ#Hq>0LNgNT;0i+^E@TG`>{-YY#X^ZerT9F8;Mk475>TEZ2md7pwD%WY{2SbAF zQQ_1@=2&$8RBW!KnM{b=tKhZ87z%AMySTwdmkPmXBW*EprP%gJ(x%E9VaudF!j7e7 z1@X@(O7)9GNk_s_y~`qzvQA_G?XBL0RB{rudHPkq|*IlPT zCAmbq9r{>P9U&3cN)r~RSp_rUQ#NKFv{(2}<|154)HNAM%}#r&&1vuCe>RfNOqXi1 zF!s42RdU3C`&u!$a*+ff4y<*gVv&5KXC*rtO&G z$S#R0c~)|=?Um|o$4BqWc5@8TWnJ^4C_=(55uq@)JDT}#;TLo0-BxwMUogglfCMm> zW(Fb-Cg+Z5JLyFe?A$AX>6yocoHwU?W>t@;%(@*UMTOv71Pxr%5l>Q>1Vy1cwdN%% zHJf<3L_2-4tWSH?ybe-K@*nZi*ok4dLX`!6R5WP^RSQ6&$WkU1jj8?dBw9)`GE3G4 z$q4<*@|vv)HGA7ptsLou%+cCI+p`n8CxC4c56PX-ld~ifMm`fczl4)aL}~JF<`&A( z$)>(s)PQFVYUcSQdx&8?+LKOdij!iGj9)aum5MT&+r@^T%=M{Ir`S4^?8=~-J1KX_ zq=*(_1(1rgsxt|9OHYo*SiTzt0M2z%tqw~|8j$!=bZyBY8k)z2C2%SVV~BDakLdjk z>`@^wyApo3!{Fu%aO$cTVXk#9#bv`Ug(m?LE$L>ZC1RD5a!Ij0Bxf-x${@ocJB+MM z&6#0HsDlkA*~>}I;h&n%>4b$G>D@Lb#VLxqXdPXgdRr29_d2Yi%`ngtCWWz9TC`J! zyt*=@vU1RNy?&5w6L&E|DLOku*km;d2qtw|H_801($1r)BwdIyr=tlsr4ru5RX}=D{kQ6gjDG{$WYEAY~C`G3;nET-a_lFb_URvvfcU z6l_u#HnBot;ht@l>N3Yhv{!vsSgbPe&vQmsSC_-xK%NIW3Fobc^KQ8s`$FdE~-s1R&oS z6A-)(k`|th@toq`JRmqxkq5}t;-pw4XrP-+WI-n|1V2DbFXn(Qh`I?Y& zm`6jYg$2V{R0=sJaI`&6J zMfb=*rGUT^ZeF|N&V8o#b7?1ja)BvC?50rWWN*Kak}5*VGPE<7&3jpHx)!TGBZ7s< zEP!_ITC^;g%eoZ}g2j9&*{YB&Ri#0xcAd*AgeY=l^H_948cjJ7|G5O!wsR>q#Z)Ig z^O_uXjv~&yS0HM9#~gV98Mi?xrB3PjcEOX?wQSCE?-bj@IU8YSxyTl@r_Xe_ zd~Qi8EloBJLMol%{hN;CA3lzMGye9Z%d<}}gV4K$uj(^gxZLU#9M>?iyh6j>4!3JZ zwZZO+b;rA-#vz5>l5&;dl$1q`Obj_aVAOis2RTbPZ(tLErd8&6;b`K*a5fF<=2_0E za7x7;{v1Y49Qrl}Icv<;Av?+G{7k3YWBu$&zvg5)l~CsR;k3?=R8qz_vE-tDzJj;R z=Qs^zLz&Ik8^#S~c7joGAJ_#R1p7c|jN=S|72qIP2W|nQ;C65UxDy-z_kx?j{or=+ zAh;Vm0`3PZP94e|0;|DNJ_H;EgWw?80B%2RDANZX0SCc~@k5zyU^TcC>;w0KTfl?h zPLM~!oURJW2ljz=V8!W_Pv{fK7u+(DbotouL2wZ4nlzNz3+@CDg4J&)opQpRK|0_O zunuep4rNw?UGEsm>=2wx`N2N0^sTfD7z78w25<}50d5ETz@6ZFa4)z8+z;*m4}yEa zfp-mM8sA1ZZ~@pbg?0o7!Oh?na65Pq+zpnVNqxX-@DLcSCSP7;v=i(DyUrpX@E~|l z+-DDE%K5fZ!#U&w4uD2QQ`` zr&I4sh!2)F5+7^;kAQt3?=*7ugB@VBiE@Jn!GqwI2>I|*rtM%O*cYW8!GT%u4R{bN zokYCZ_=AJs0&p+587z%cfAI$ofdgRa+bKWT03HGRz=k&JE$$B5=?vn{pe z{K3IRgr7osz4RB@wV3jOrG2zFxN`~Zawg&5OMifa*HAui%TmIFT`LGD?ta|W{MX|K_kugYiuY4~unRl{ZU-xBs1MixcHK;Q!JXiC@Cdk9=o{#d zTIgT{SaA#Cz`fugIJl8^K8NsNwcu^|gVlrhgI(Y@a0|E}+zB254}#@W3HJfo7wiL9 zg4@Au;C^r?Sn)y9e>e2INDtf#ZUgskrXJwnJ;bjg+M>cRl6!1mVHHhba%Z<+He_(SDB*4?GC&2OB<5`qPR3Md)C|mxzBJ^?Z!*VDxdy z30Ci--Or~S-=H4g7I2HWzX|_~8$1a1Jqdrzpg!NG|G=GlXx|3op>a0|EqJosJY z8n}Hg^%Vc_5$^)RKSR3Uk$)mRaNt?m{X+8jK70aJKSz1ME#N_L;0O3$M7e)RdBOeQ zPH^By)Ehhk)?JMIdE$c&Kc=2w^-rkhCA7zW`W=k^6n+2)e}=r9Njz{1c<@)G14a*! z&ZW42O+COZeN`{fJgjCGwfA4TSgqsYy*#g`@#Jqk7iaz zC?_}w9s#$3rK65!c7he)KCl`*2sVID3-tpl!2Ks3&Gd=8l>ERg;7)L0^wCVPmG%J} zz|t{CGXvnjYL8~NfZLxSeZk#?kAY879`Fdb9cEmc#M?)H;6ZQ)So+VT3s!>%!2MuF zoO=I)dVvSQE#S^y5)K^v73qOp2aaZ{+wlJl^#;2RQm=N>2dlw`KOD_8g4@9^u;P!D z4;%ys!6V={aNtk0m$<=w;(mqti5qkhxc`OnfJeYOasQcmh#OoW?ti6S#SLy2_aW*n zZg97_|3W{D8$2ZL|8q1`+JPGkf&>3XJBk}*2hbTfOufYot{3;eQ-5)TJH-80+Ckjl z0dfD0_7FE%J_q*^>JJ_P8^!$})L-1-N^$=u^%pm|P28_ie{qBR#63j)#SJ=1+()TD zcm%8y_c7`(Zg7FPGt^();AU|<$1>Z+4el1V?^tHPxWPl>_8-fXrf`EnaG>N^ra{~w z8<@_(h+~;P@F2Jz>>7D2vjyA>?f@G`9n0(mw}S`3ij$6Ij(~$;d75;EX$1>Z%o#0NPgZsc};8^CMxIrF{ccNpCWh%hEV4b*6IhKin z2f+nkSJ|=504Qdh2FG`O((w(H`zDS#sdTf?;d_vLSB>8`KQe42ma_7evWi)639Kz$ z?_4_JqO+$}O_rz*tPk7;> z=b`U~exbBSQ(5_4{zzHHoh6a7;2k5H%BnYw43*Vw92F{S*l<#FS>r#9E^B}gDywcP z3pSNi5TU88G!(cNdb6dIfTqt1tSO|oNc&w|5IjOVNO=~)5Cegs%timD@~kb)mvY96 zm6P(c1lATUkLrKQQ$1!V!xZE=-DTw){8v6jQI!$i8pput!vDQO$?{WcS#XZaPtAcg zZEu#mmMS*Gs$@o*_=Ch(B1Wa(=ccdvAOF4huTVMai|T*q!Bd7ZvIk&|&>w<6P&Sl7 z#JfhyxeNMk=rc{b-YNZjhxGHN5zS@Q8%NT88%FhxE~^fCdRC7Fi9aOq-!har&BWj2 zZ!W9YSkhb;+%SSzGID6)mVkeY>xh_P;z<0983^0Thcd^cRItae@i)5h?J!g0U>)%n zymcsZvcxw=>U$sbF6gF9l#kFKh2Bwwz6W}=2>nIqjYa5(p*Iwvk3rDY6`@x_uP#Er z7|-cLEx&?}&CW*kbp-06==zc9Q^zl5b<2J-qP5_n%8B^>ZC%_Btu{_o|Hbbn4F zt7oPBV}~-R%uGtc*VkLNR_*-?{vG&VEB?kvyN)=CITbo8uWN)p3Hl-EV_d41N7JDn zgdP_<+~RL7Qy+DYLl2G{%8bnmzX*CY^q_~{jC~#SI_TqE{%v>L330Shne4rxxTC7nH_Q_5b|B1vD3*EW&=aQ`aJc*y@*hH)kQVZzHE*L@OR@$GEk z`>^o6{|c8^Rl`aht6;>Pgx_Ss-{~j(9VKz;PgPDe&ioyD9Wy(CCq;H;r$n#f*H3y! zNN<@CdZeFdM8sQp2r&^3(3(%la@pBRxW?0lGA{}rQLha&bP#bZ^I1!vUt4DDib;Px zOZY<-Lz(H=z4OpZ&}Hupws(z$AA(*Ez1pSf{vF4Ftj-HB{8bA*2>nh84}Yy--i!o# z)a)tpAddfL{J$aos$H3fjXd!i8KA_a5uFGZJ1r|+X%q3wCk$o2X5!yLeJeJV(1aVM zoi`xQI{XW0WqOK~$$=TBCD5hY-KDe!U=>=_B}j6@Z?BO4O49$1EAKqzd&%whrodv? z-Wo81P?eiBgde7(_#Bxyl=&HUsplPjrcG1MurB8|AJb%Y)E0u8HU<1m-h!ISOJChW zdV`a^{EHk`{Ckauf2pR?Wm@QR;q_g_+fBSLNPQIFt9UJpNU}14V*%mluwt6lzf*7=AYnD=5m@< z_b)>@mk;Zf(U&fdQTaAuI$A_C9R!Js5q?=jdVQp~PzZ`&3e!W|%1JLiOnM?e9w)s) z(o_0{l?xO|gUVc zW=sTbbnVf=^{!nDqFSP+NoUJDhBESUe-B?GCH=qG!6~Sb-%AN{3*lw2evaV>?|3rf zzRv&YyumYDijmV~vxJFrDB(b#M_8y%5jl34{0831-Vb&u-v(aMix7*!MykKYmBH^- z?7_M7H{;tof2(<^p>7S}HFAx_vAiML+j<@N*p@0a1OWkPenzr=OS7Gdgo zw7d3}fXL5U7HZo#yHVux2K3E3e|U6RFsw!_qdqFVVVtytlu69R{Q61f z2VTqoUGy~^VZ|U?>jqJZBjub_?l}8uS^wvjlXl-I`nAkQbtRt>F7QeMJ*7#%%_si0sb<{gjK4lw z76QW{q9kvNu`{<2?>^$~C!Uf&DxQ+-^jpG>7Y@vK?M<|;@X@oxbKY(AzxJ~7G|gTn zG>nYPSFi`Ie|CJgOaCoa-L6Em8-CJT(a+vM_&DJk3C|X_SAMAUFE6V=V}LJI>RQiO zNB9oHPZb*Fy%Jw3=Y7!oUS~QIeh=XX-at7I6Mpb@hL?G^>TSp~!au>fQTV=KJq;hY z>*)nDwu&&;>_Ev(e^DRBFv8cH$mdY~PzLqXH9~&~`a$SS_pT8>*#-Ro^c#el!(Xf| zT>i@PjPSO^J50RlX+xQ7+<3+KiwVV~A);F1)uPxhAl`g89$R7?N*Gl#QEPF65H73G z>@1UX28nl?qUei^uXWHjLoY1= zH4wvzKkbA#GP4hDPSg=Ja_RJ;%q3?2Dd=CsgxkNv?w6qa6xlCn4bT_)boM8j1J@Oh zWpqe+?xQ?ADUV&(|9$0QX3o!7$>Ad9q&(rk^##GDJkn29Y=rfl=j9ixM-10b%Tzmy zG?Dm=h`)vSN$k>3UU{$P_tvsHS}Cj6dpd}wa2_K5PU1f&@r@CF+y#B*`DPza^*psIS}#Rb+6wk(iND0u=T6Ztj9v&IZybpv+%T%OtWlOEnnjI}JsTrI761WGQO5dX0x5<45w_N`5P6diTd( zUw*Qd)LdrAZcYi*sJ+$`MDmk*kC}-4xYVqROx@#P74)6ZKjV($sC%9e$v;o%VA{J{{2{dZCnS z3arTqka=~wA{gf@2IyX|~l9{5gT+M-!e=T0FW;KW8#h_f_!0_d|g>pSaxvJ-| zPwDF4NLBB;F6QcI>t89P%AU$P%2CS!=DyTW=4N*s zsP-w=Z_Q=feEwe+ZJ*fze-aP+IIo}~ROcdOGR8>$kCOj^^ibyZ_Vu0F0;|B_RDWlS{YUerS!QW;vFE~93c!F?;5KRN+?yY=|SqtJ%1MqL6zs~obsgc zuf|{LyThiNJu{SKq#m1y*Fn5DQXW-*;tjmPc+#Ik#M?%^Ph+=6_-x!e*pKRBAHE2m z6`UUr`uqoq@>x>=aoK=Ml*i_bvF>7YT>{~o`^bNwdnmJ9NNDAp;vmz6cVcQE>T&${ z;(t{9mHv)UHtRk=LaBl_N30>BqpqVfFvrp*mg3tX(pi7mP)2ys8flktlUc7opJIui zv~w-=9nfbAUG=M4H?!X^yQ6y1+Z9$P-=qoqv2(D z2!~p$N_|JX3w~c%cs@7@`sO_PBEnCHJ_!9mKMvJDtb@Jtv07)E`%BjQ<_*&hC0}Oi zG`}NQZL58F;e)N@vzvRIVI1to2Q`&jNnaKMU%mc5dp6C_Fie^M@o*b?={_bI-D81$u^6y(c zl$ktSKWFz>WpVwnqG_R4aax+sPBcFa&|AEp+v#V~Wkysp-me|XT#Y?v+^Bs`J#6fa zFA{z_;kyX`6A7>6a(4enl=TWd|0sbX{kVwmrE7;Wa-UefJS$i~(Z0-DMd}d=lzg># zN6P-cCs_RruB_1Gr&+e_#m+?4 zWY7PpKw2sw?Xin=>ITs}T)DyhL&fKz*0S~f)kT}b988KF9K+xa@~lX}7*-Ey<<6nv`T@(~aM6nD z{hB!WRH2wx+?~y*VBZ(fvSF0}=Xvs>MQ%+s8*y+soJ*2Y?|#xNy=N%X@75bW+f>5c zLgrkV^AJDFot%0by;0&nPW&kGx4H3=N#_0(doEqj?jF7KF!8q&zuc8~-B=@au zl=BeoCqh#&93GWh%UoF?VKLGlj}t$7AI~5eKKAmRsefb1wG7Uj24q;uwyV41pg(96 zY0nXLtk3Qr%6wchpr;DtKZ9?>D9$0Wl_#=hM2X)_{E7#LGWWb@d{!Mf@pXqxC(bRz zA0Yl(6W@Cutsm{#Z3Av2)#6aEM|Tl#H}P(A<0(0+&ap%|n0T>3cQ&4s_b~BFxA07v ziRa~K+Rx5+pD3$t^BiDEU_CGMWd&!D_!4hH?HfghS0upA`9-u+BgbUk z*-Ad;4;nt9R(`!b#C?{mV$gQEs&lVBgxgEF|1IaY>3aI}BmaBOZ(pK3)m#6*^V|9K zL)A3&UE=?C1dh0z-*SGrN$wMOc<zS8NYuO>6e=!LbY9Bg5NpB1rtcM;O%KX{Yr-m(evz$xF&P!o>`aVEO zZ$9a5euDE-w;j~EQC3dS=wmd%uaNDUhdo4+d8RNtTglK#IZqikii+^>Bn~dtQ?69*JXdW0 zNA67jE$J1C5xv|}=ebKsZ}T^puU);1&hYA8?Yg}h{XZydFg4@lw_;RoRj=cob8pis z){yeQNPgSCiC*HCA4Q<}`iO@tN=6l5&gk(hd{TP>{QP9WeTgs?QeOB(ZQ`;9^YF=i z#9KtXirra0@%C?a-C>_c^IuuCzgh#uw?()$wP<)XZinyRag=L_axI`-W3XEz^l=w5 z-xZpKw2P z%ZH*`z-M#xx^kPZBq0SXHuBK#ii{w|&(bfCl26A|x%<=?L*D~E3jGF?|0cgzp06x9 zmHe^`v(NOGw-oxINvL~# zi>SK8)Ac%ME9F}7GoBN2^%(T7f_7EoCRVn?Uvf(Ec2)aS)2Z4kq__UJ#qPJ1XP0Dx zV-Dir)wQFG3;$JJf<8mM^KQ58Gpt@PtL%`!%^BS^i{G?ufdG-!I6nplHy&dVf#i4dK57f7!OQ zM%AAK$L$62bO>qh>GdS={Y=NqH{Z#%oBqd32+4IpW!sz&7Rtw#%< z2frA4T@iX3dIR*g5!V_Se@h#g51>CJM72+1&gbg9#|dA3@6pViZvSTGM|Rz#+9Of6 z5`Hf-sjvq9x8lvD_x;w9&!i^in-B4B4|jdl;qp;7AEUQ)lx#04niB(;v0P-n<3j<2>n^;hl+%M33~J+NA>fjCXR$3g1!y< zazhgk`nWLbDdl=q&_ld&r zi=c0To*#Z4bmx79PZg&BBJ^$0^ZV;C^wNipW^S~J zgOdK32=|*7p;tlQUxa=!^u|vYro#t;ob5&EOQDxPTp0cq=mSOQTcIC-o?rgQp+`Sc zSl?%%?^xZ}1&qJ?%v~b+L0(~>|{Bn+Hh5w7tCqZBE`NDRa4t;MC zI&T|x>b_8z{vzmGiqO|VcfME{{yyk^Md*)0-&cgb2YSPf!gOAQz72YQKOTl&`lX`< z@81{`rM}Sf*UTfv(PDJni-h^z}QB zW_t6=Ibs&_4f?|#`U&fa7C6xYCtBb{3!G?y6D@F}1x~cUi557~0w-GF|8p(yoUYOC z?-#GxC0`z)J<2uw^`pk^*Y4)8Xt(ip4t~=3H){WJJG9#bcUp|wgmUUWuWh9|xHHG3 z=a>N9f7CI3#{Z(vYLB3C|LhCe-Dupe{>J2F0vxk$lfd0yG6|auZMrK@(Fs`hdgC5r z(hcs_7DIMQzo+v#-T1GUhh;Dmjoa2|f^iQTe>qyCb(0goooc?^4NA?f0Fi){R1(^>5SJ-XWMRVvGl<+wcD1n;=|f~ zvIaN5V;Noks0p7jZrhHBjQd$#9Oplbd$z5ZN$>x!u>S3)Ve%SauHm=E2Cp@^(ct|C zA2#@e!KV$rVDM#we>FJjdpe`j3{Ek4zQGoQa}6#wc&)*W2Jbicu)!w`K5g&?gD)HW ztHDvvnEVY+F?hbg7K3vQE;e|r!Hov*H~6r@Ck#Gq@CAb}8~m%mQU7G}H#o)M`374I z&NaB$;I#%f8ob}&!v>!)__Vb<&mAh_bH z_x3LAx1QkYg+0rc_pYj5-M?zd@~dluD_5+(q$Ds-Ps*)4yU>ehn>M6))Jcbg5gBiYb~lJ=pvZ&LFtU9!4Aw`qbx3a(h3(}<-QXm0D;QFh!iWE(Oi6)=eguewgx1 zQtvg4TN+^T(w?hVizPeMbH;tqQC_{gcdf0-@-@q@>RlzJAg9%5sSYy(Uq*WWnw3j? zgA(CAxiQ|eV)1(<#(S3aEb2WA$*^YmBB|c0-jz#x7MjLYsV(hY+`nuEOjHfSuUc|- zpLVTX(%%Pbuj)lIt?sq_bXIWrisk26j*(%X=ybDW%S|cNxM=WE4&1wk2g; zUM>D78V`}4Wwv0^#*>C}o6hCGH<|rh?#pL3&0)-O{XI*TGv(#8Q}8ueNu~Bi*vZ=( z?lfkGs7XwCxhPw?5(@r$Q`zhPm5o!#Hre*+?OC<3&lR9=L`->Ry&$4Pv>GkaQz}g) z>8cfLuI{t4b?J%~*NDK73A@Kmsy#?0J&!_LxB`7=^~x1!6w9wxJ&dGa0@g|us?6&C zp5+UB(PWGSlq_Y=TE0T3CmM^AblEYoc+JwKDwQ|4imL9x>w8zNkg6|Rv8p$?u&-xT z&qC%fG=i%cAV^fvQy9`B0`=I*mdkd)|9si{Re7%Jy?V*=o?9E7I(6z5y0TVptUpKV5b)`e<)Ue^giuNagki$uC~mqV$s}0a6Z9k|bXgl1 z9ZI*pbiNFEbfB}$$WY^aVb4l*X{~L^n6_gI>8(nx)G$dxH46eDrkIvd$B6FgJ#|*NC2>^mRnb>NQLIbs$@r)hj9NMItsxkQ93OEhE$t(WGqj)wQZzlBG9|oR(Rw z=V&E^`g@lJS29X${Jiv+uTaTZ-_^Qwsw7rGc$+}7UE8;U@@O`ol3GaiE~4(O(w8c| zI;mM+;5-pSOTT9K58LPBQP9zO9V&?zEB|m^=(g!=b)(yc!*`)6#ziW<<8`EJpx4of zIXJS1^)oy3)174OcaCiVjs(aV>S-@i6>wHD$lm)GT~H`< zZI2kaj$)XXvbWxOl2e4~8y2&@157827MmrQR}U&^a@`Ef>DlGe8fin-%ytK%XLWFq z^oQArU;N-Qj3^;yBhwmt5PsT&~b^w*$fAlp{bA9`&dEF-O}T0d9v>Jk=eyefR5vaptU!kE zL|K6@>K#yBc+R;+J5MF{x;n7fawWg>bTg`j+-rBBL>zXuRE4Hl+)gpA^m;opzt;;p zQYn~kP7kW2-asGPN>TeaqYqVbB81_22vfg($2Mbk|6E=2JS#(S<> z9Sk)EJ>u2*+i&$9G#8uuh%PYLXmGZ@zsMWOV^0}>n@*Q;50{=Nsj;jcIG z4;|1HbN89`b_R|AX5*h9f0{{u<#ol=f55~K{-JpKU;dTmpKZgW|9#_M_iG(LKYvXf z{yJRv&zo{p4;NtgBv1Ifi7l|p^n<u^hfF@(GPy}?d6Uxrv8iwQ2X#A@*lfC&eNB6L;|L%9`_*+f<&FgdHAE?s)rc_#ZI-rM7=wCtAME4}P9WcZa=UHb1}#_y0%>98Z4j z`!A03i0S9X_i6sk=Px@xcHEfjzuSy|%bz=r!=Jm~Wd59G%DwpnfBui~;c%H8k3UQQ zMf1&Y@sCG$`P0bPeEziaQ(d0_`l(vJy7SLXx%?Y6{+55&ABTT8zsdaDZTNS~@fzTS z|C`zZ3rs&Y?i_CB%gruyK=X~&AFGYGjooPY+pe#yUdSt^m9gOlOgOuKw&5D`!tFHS z?0T%s_;1b&x7hHHA^+WQi%F-h$(B?nbtG@x-f6<^`$}%OhCk08;{MWhZ9morp>-+j$pEms)R3H0t99z5HmumU(h{?ZkxAw9A&P?sU z!}!M}r_{l8|??=b0G`FLQ4 z_J7*=FHj#V%0741X#Br#{MUb7r*HMg-RJB0KQ{j5dF2nDr~Q9v{GB}i#%bFBcgFwF zlRABUcfa}diHg_9z%*Qo@5nZnGfT_8`17Yo6Y2pVBeVau?-~D@?{tgp-8t{Rmy2Ll%Fl{TCSAX3|?=aQAPtzhlZ#ZtA^nq)unE z!Qtq~&EJ&E`GL+SXt2&;hr!V=Y57xOaEie?gEI|w7`)QpdktQ1@HT_@8~l{P#|(bk z;0p%-Y|#HZo&V_urx{Eb>^69f!J7=;Yw%Hn-!=GCgTFI))ZklR*7>~M;8cSlgDHcH z46ZQvK7)4~+-~se2ES|YCkFpy@Ku9>-|KuU4bCt)+u%ZjYYl$T;DZJ~Z*Y&npBVhT z!B-8AJ*e|J)8K^$=NMdSaD%~n4SvSplLmie@b?Cf8XWrvlfJ>}1|tS9GkA@`^#<=Y z_(_9bHMq~%6QtK z+{c5ctDzaG<6MAS{8mF)4*fRV66G)tunPWAE*LxP>|<~VO?J%VgN}KO&kjrHN56|3gfOe?n{h2V$y3hXrH~C zV%&Nbahyiu=GCamoW-@Y#8+~vK|3$}#-#gugMTsjM}yB8+-Go)!QBRVzE`zpht9@% zi$SXo{u2M2M>79S(jGtjbtZEz_5TG}3jPWl4IVJ~UGSSU*3%~4ALEvOJ!0HzUdm*~ z5`MMDl7CR>D_NnisboFjzJ~vR!OaE-4NAGif2YB38a(z}O+RArRj`S0|Ech6B~K7e zYVhwKe{nx%;vY8jKN|dtipTrV6n?Gb5flGU#{c&q^)Go@p|9k(DxBl|M!B0xwwmxl zmvEZyEBOU(ssFD`_+OgvQco$*?WR00K$m*{%;1kq_#Z0#nrbHrf3u1AeG~3eFoe)U zztZ@R22J-l<>HC4&$*xcf(|zU#u57I#{JTdwY$W)e{I~qG59TmLu+)n{g-LnWpMGx zjQT!7FSvws7lBK`g^Iq!xk}+uXE`WiV41<5(V5J(!f#+N_#W^Yu+Px10GHveCeHCp z&=WxH2aQ|ozmf|k$gkE2odc#Vg)a8*iUlL~CxgnW?CN`>IAtoZ@=LrI%LVh~+cnBn z;>~FB#Z-9gR{jb7d1R24gHH*;7%LOSY2~8Wt!xy#m5*Y# zGE(eTPKw>ADq?kd)Ky=s>=c)kpJM-%T#T{uRGc?kB538SkgSXqyOpzIx3X63cAY79 zX)Bsq8EGrqb~J-B;_)SHIz(1Bi`&X)vA@p~#>#1-TUjl3E3d_Vsgd1cxAI%;5xE#+ z<+wO2J>e&L>}PoFQ$1y<_t>X-?B{#z=XvbsdhFGowk6<|uA*#9OIh%rY! z_8L!^vpx3Td%{fd(7*1npXsrG&0~L;$DSrn8Q<3-fb1M6#dw!ojA^tM@KTRGY=suI zAitT$PwWdk_6xAj=l3Z22Elg`PjD_jF{dBZbg>8doi7$lke{9RDvcXZ^mmH|6XbWJ z8P7lS)a&OS`!r8EWxSsu5iw$KR5oot9s9-nHbED^k;D_U<@t{xO_wM_KTRwcvD^8W z>D1+ap^LF$?A$H%D@>Vp8-EG&Esx#m4?_PobgM^v7rW>Z?}Yx(Ak%_M{~7R)#%||w ziTemN@e}(F(CQf{3Bj0$pzq=L3x3=9*)mz(LxS0U5WA!!D8|-F?6xdox9uTzo2S^V zo+9=Ux64(Vm&>e8%aeL_BjdWzV+y2O4@`Nc2a{K~2G#e9c+n@e_-+&1$5 zGafi&%NZX& zDnDKMaOGzzw^x3)@{!8VRX$qz`N}U;ezEeg$}d+wUin1jS1Wf_e!KFi$~~1&SAMth z*~%YQ{;2YW%AZvJrt-IyFIB!=`TNTMQ~7U|hb#YD`M1iUO6OJItNvF@ULEo3$X7?b zI`-9Zub%qqX|IldHNSo{*^uh>InMuO>pS41ESmp!_IYx7Ho07$T-qf-NG|0<4-g>q z&{3rKj`R*vl%`;zDu@aQHoyWXDn$hp6)Yg4NKpani(OC=K@`zf{xiFiyXXCXe))Xn zzB9W!v$M1HdG5IZ^mK1TdEaCGZeF!2R zFJ0rmwuFP{B4-N-RmBntZ(FOEq(~^VM8Zf*Bo-lkWeNYCw(#$hBI$NpBu%zN;0{{^ z7Jx`jM;eWE3544WX{9An#(+qQ(`1&me6BNdH1WMo2@s0jeI5^box zR6?C33rfmusM`c-kA!*w8|vp;P`XS)gKGjBCfm^H0|8|}ThRC;0Zn#FXxh<&X6G$v z{tHqU8(MTmy4`}73y|)xp!`mx2>`8jBW;w>`Vpj{gf=Ni{{?8f#)7uLThQ(j(h7j~ z;{iJCLYj>9qJ)l(Ex7Jw0r*udbov(QUkNu@7Tj<@Eup8hpy$f~z5bHW`x??87WBD*^p}9XSCIa+px~^QZaj^&4q*6$NPk%{;$Nh`03-V#-6mnwtw

F9OCFNtiGlV8T2J6Mq#j={!3XC=0MmLP-D1P^n~??r%(xC|whc39*>LlI3Ac2#Vb((cv)3XW6EG*ig1Jvhn71Cu zvfMH_8=exdah?T_&qex3!V}2=PhM}qQ;vj9&1~4*$$~A<0X+SI1<&-i zVC!mtXS+yvZoUQ2pOmoeqJ-_gN!YPO!p<8kc;S$M7Y9msX@G=Xoh{h?f(3haBK;xY z<(nnE@}&iPn*+Rh#Ddq-Y44!|2H1iX11>5_!E=16#ZHj)i+z(R5@ zIGBv|gn)M*M+(|-CNy6pN9jfP_Uhc8-+tDWqg6tyH8nAnnJHb_p4`2dS=< zz7nLTg^b^V2@i@vygrf zGXH0!d?^cRBF(U6;Y_6KEm<^5$|6U~NIcSWAdB(eZx#2Fvf2V$R$FVyYRZSW1g6K&aS ziImM3BYhxbiz7(OK(?G@%a-#kS$-SR980#Ejg)W6)&)pETe8hhNIRu$y924CCEHzx z)X|phuS42r$quh0EtIn3El5vV^1A1cK9chK50R2Vb_yV!l=6m;ky?Q4oNUW3tEBAW z+OlgF(jg(cy^Hh?$nFP`_FA&Xt4RB$?0HPcUPqC}OWAuI($7-%30SgE7b*Mh7P9XR zmhAT$(m*Nu-*3tO1Ed^qt0f0?w&cJ*NH$C19Y@>2_%)%s^Tvti&zS zO8i|~e%rGAm+{}#`7A5x4`~IyM`~hO$qkXd2h05mX@F&8-L_Z)HtfPqUI4Z=3h7(0 z?XQqFT6Wwfq^~X8cM@r(wBtM2w&U2gIx6jikp@_CXe$nF#i6Y@`7Oj* zUm+c~;_L%Rmmn_gH>CeqalV5xF8(c~wsxG;2C0h`r?$vA)x?TRXo&Qth)aA8>8us! z{}Jg%h)WuV^rjUTcmt`(@`-e$AHXMmM4E2iWiwkPs?~%iPX=ImmQGm z+wqozbWFzEN0Cm*__*Up&q+tDM0(nCU_H{8;K+B8{sWHn5z-m7{4vrt;lyo3x(OWL zQl!b26MtAZ@$XoUvkPgc?Wj>mBP=JOJJLnrB>sd{%X0jsNY4r*KOdDuas85-Pqb zD5tVePCh7=CzL7xl@Jyxp%7GJfl!G>p!|hG`6Hl`B0?nq|vN@*xmN=;C~WEi`s{<;%tx)MDpfcJCl~ET|W_zJB>wyY& z5Gqt3R8|+EvPwZ^_Yf+(0jNqng{ssLROMbmRc-{TN^iVeDFc<$N2r{}psMy2s%jHZ zxpxVb+Z0sZ-9qJsK!wwU3TJ`JPZuh`5~zZZPz6;$6=n-nm;35`O zq^i?cs5&bVH(RQtiBKi$5myLRw<*#pq~$`@YmRge(!D~}Z-KNK=`~RJZva*4Q;4sE zYEUjzgAIs7rE1t(sD{H4!=M`F3f1VKP-V4{-ax8hC5S{w00(IrB*?Ky7a_qawi4`0 zNPT2NTyLavGQoEi=@&?d{~2kdOmIdZb$|qQ80n&wknk(gIV&Nto1NhAiZsklNXoVn z0$E6>tc2uGk$$ie-0zVtLqf{$NI6y_&d)@#0ll~fDOV=SY@}g!qBRKVPe`8`R$790-(x3U0^oRb$V?-UxpWWQ@ zSGvXWS6*lNt2|`+bDpsLRiCo_xi4G(yjLuL_@L#_KVjtLGsCfjYlE7wiSr0kMuPJd|x5`R|Mk04#fAA0cSYUax0+j zL0V=75*8yhu>y$=ksc8N|0<;RGLY07X^;#Ax*`omY9#~7LZ4iO1`;q<;f$aB? zu33Rf?;|a=1C{SW%CiDh3Xw+Ift(wWCdxq7=`xTzO$PER$w0WW4CD`oK*1uUdNNSh z9BC#5iaH`~v;vV$NHwfv(ZouIhDduLS?)yI49V6eq>x2-!(6~y6w($h?!2z;7j9gl zaD55FjaR~Tt`n|ugqsjA+(e&n{hfuIR71FdIN>JWAY6B{a8s%aH`qzIse^=@Hc7bY zbA+2Ag`0W3a6{FEn>A6m*&T&jX|`}H4-{^dMZ(RQAl#~%!p)s7+`KBn4bKv8e!g%E z<_ov5NVr7{g&Ro{ZgGZit7QqddS&6($P;eOuyAV?2p6A3a_dBdTT(3Cx;2GcudZgxjdCaLd{Ww{d&nHt8VTrd{xMOb_8U?+^$oE z+iiw$yU!JFj|IZ*xmdWp0>bTGOSpZy3b*eN;r5#<-2O9#J7Au02i`8+K}&=?I9a$u zY72L0H{lK&D%=}y67KMug*)O_;f}mRxTBT|ceE?qF?EDHw!3i04HNG8X~Lawi*P62 zCfrGP3U~4{;Z8{r?$lD@-ZWCU(}KdCo+{iKnO2I}Y^A_6GDY^XQ>?8r#ja(i#9a_6 zzS?$5d_6nGDX~*jT{|V=H<6N9$4>E2uu_tS$dteUD=5AdLFj1*szL3IlR6J|j$@m2`>Z-ZdcTnGkcLoj&`1l>d{m{P+I25Z{E)W@x0 z+W&uVj^uyv-rQBBvv}|5N2IqbDc?XEfrqpqNQu(6|HkvyyH;G>exx(f=X*rN`yNJm zM>=?3a(wM<#~bc0Os zbwp|_gT6LM6YNyqc%*T5nr|%9Gm!4viR70VzBHr+ndu84CCQL49cieY(=2 zC9-}0L7E~f`6eMf0hN8NWEJ0IR*vssq+GkIuPV}TE7#Wzsgca{HALDg!oK^E23q;P za-{aMz}F7xMJV*Wfb<;{`MyEA(Te!GB8{<%ePfZTTh)A(kp^4UeeIC0mosc-xQ=8vT=M%q%)$4a|+21O;rZc)6gv84Wt9mJn?O$sj`KC z0@6*gWzsaH*JOEM6H-&FRdNHQW>#yr1=2U7jqhuuZnAAkKcpVAU9dmWdePqZ5Yi^m z!S{pc=u`4K-@VrLzTtK!-x&J_{Ydbz$IUmX#~90>F!FZB+$W8^l2JTmD7_box8SSiaxL+Zl85CO-YGWE5{2c`D->#$k9f$9e8xK&7c-7wyqob}##M|D zF>Yks$~chy8O}J4@nz1R!t%|G^BC`BT*ml1mtV>9gN%t3GGSoo6iN^j3_68OJjoUT4bBV0jVaYQyD8W<}pSX zOBl-;J27@=?8DffaS-FD?8lFc!#I5c<5b33jJGo0$+(W4^c>MlJlb^wICB`sggs~1|OUCON`!Eh; zoWwYdaW3Nm#zl+|F+RH!yBxe4BAC*RzN5G~*S`3}Z? zPndQrX88fe&5X}57V-Z2E6?+7oc=Q7SdPPCmOo)U%Xpsg662qYe=}ZVj9+j32{Gm| z)@E$V*qL!C;{?Xr7*{b?{2#tXn~mLdoc<`|7RKio2Qi-Db?`No4={en_#NXlMr(ty zA7IR2ti)KvSjt$P=7hcnJ*eBeQ2e<{oNGp=KNig5?yYmDzQzR!4^@gv5c z`Tqj`xy{%=!|A^={?6#|yzjlklnb()!5Cp&!sDPh%iS3VGtOpQ$@o0uqdX6f@Hz5T zPJe^(Fyl$aZy0}P^zr@?WGrMXWo*y*H=i&2v)qlxg^%Mfiqj`ER{WpFxh&t#xQuZ* z<9&?4<9Id8n;2hU{EX+}L6-05xWC8pQO47ZpEG{Xc#iP`<0ZyF8RL0AXERo3tixEw z*p{&`;{e8?jN=)nFwS6{#pleqEH7dFm&fy?EI-4zgK;-jPn>5Gd|3?jd3623C2^5pEFkF z`SLBxXBjUrzRlzB2A2QJc$LTLN}l)fDKqaXG1g>k$~c7Wl(XE1u_NORj9nS;{eT+vKk28ME_z5F$Ts~*{KaA%X&of?SyvFF`agoSa@qdqlET=P8 zVXV$r%Gj8(72{_1;~K}g8>b)Rb!{-qyLX!LIGyEE_Q&FRb{nVP&RD?v{6dzOF|J{J zig7RFe#QfgA2Xh1JkNNA@fxGz`#njF7ufI6%f{ajr`KXE=k!i24`-atco*X;#tn>q zj??oj-@*IN3oNH|eBNaFIOBJWml>}z+PvO9!TZckM#bqVj8zzGGrq^=>a#qa{c6Z^ z6UG*dExDiCvD}d3){Dn&CrJE zV=cydjAe{18QU^m$Jm{*592V#35;_Y7cwqqT*bH&f2=}(&vCy##Ocp49%Ou<@i^m2 z#?KhPVLZz?mdE{HEGKdQS7EHq*pRUuV^_vOjAI#RGcIIY#rQDeV~m>^^ZDGggXI?) z-(mcK@pH!Wj6NQ}zq9-&JZsqICaV+1$X!E`>m*v|S7cs72e1LH+{|gywGuCBnz&MxV*No*gjI9|vFm`7g!g!hI+ccJM zWn99zg7G277a0#Qe!{qf*SB9-j^p!an6V{e2ga_9Lm0<0-o!YAaW>;Eyl*aKc^Tt< zjQ#n0rH5I5f^iGu4#r)KuQ2XsJj8g6@pHys8GmQI%6N^@=J}Vvn9P{Q7-Gz4tjE}h z@mbzCTd>@Nu`lBw#v2(&GfrZh#yE#@KI0O`wTw?NKFheB@ioR1j9)NbVEl(sRm^wB zLdIr{O?jVa#d3SbE{r`H2Qdz3+|J|XG~*;rzm0JP&x6%GKbA2r;{1O6zM?fOKg776 zaR=kuj9)RHW4y|EjnUa<&aD}YRTv8y8!$Fyyq<9&<0!_lj1w5|<9YockDHq~{Tpu2 z43=jze)OF=hs9vkmyZ#r-^f?&JJ5jE^&JX57yB65}h3Pjda|d7WRm&b0qE z&VQHj2;(uvj~PE_yvX=pM#cUG7~3+YGlm$eFy=EBGuB|N%~+SQl(89OE5;6O+BC^6 z?mZm;U-``3(%NOU>(#2;c%~NdpA6{)Q4`N~CaUHw2j%=Sl+Z``;N<`DXUhLN34gY% zb1R;a+vI&=g-7ovENPUV)KG&IrucC^-Mtreahp#q>7eGRZ zQlt!8C{xoTC`c`otN-Ae0^)5gbW{&heQ{dorXCBU;L}1s^?fM{4$MRkhpD&l4G{4O zFc*cf>J_XY-VfyPRCNmD5$|eYhFX9x2Z;~DT+ErJ^6>2r@fpw_g#~IzI}|dZ7YcVM z{CT*D55etd?M{_U1}X#o%v&r`caecYScJt^svvn#8|Y=XYt>AAO-FnkEo{Iak)Tkb zg)J(Vgt}VTt|BDVgIcJwN4-XYD%HO2SG_PPz9IgUQHZxi!aLX>@ejoxz?Z^=;x|wu zox3PV8;KRph%oYxQ*#~X3w&us{3dFxi~ZRa(|iu~VIp-cx$VCX8A_$z)T#6srcO=8 zRC;DIiOR|bI4*pnAJS#%$-X3tjn5&|II=ckAaD$QhvU%ae2v)w*&V~-+(ZvaTDIM? z2Ibomux;`A=(nrJ=V2h7rkJfJe1o6DIh;uR>v716S*X(rDu799Q+vN1-iH3qooU_L^#^b8;1}r7RSyDrj5bPmz;otbL9ytLq^Lg))Wj z01&DZbVZ?DUBPjqZh+fS=&0I~bDd!i3fyq*LP>Lp8aDQ%#(gG+)DFklQ z6qIf^eFW|c)R%X_4VYI9?zuvg?u0v0DgpOGE=qSnKa|SA#h>U1wGh5VC$a~-+U3^1D@t32; z$)+jkb7)2PIZsg~9Uatq^qAH5YlWEW}^ zx$mS+95q>}&7|b&qpR9Ne8^c?8*6!nBAM%)r$uTj@deJ9Y~-J%h88<5Dg8O}t;9J( z^Z9w=%bdI-vR6WPu*$hxE7fPYmREf zZ1P{$!mU@mScC<9PEGtwZ}vZBg`C$O3w+!`7wC+i+Te}RLS_K`gR(j~Q5Tw4QHT~r zQ>zY-JcPTFI(45e^k7Ay?a@NorY@O*KkWQuJ#GQcN!lU4u7wd5&fl~Me?z?E+(k?E zx5T^7!79jqM|{Y69j&SFiO+RP+av!2@x{(MTtU>2G>J=`jWjyW#v@fkwoi#BXtS z(1^G~{C1}crC%kRdz{T=^Kat!J3SJR|A+WP&RcoN|CjhZ35d+8v@azC4TVrQl>&`u$=+LrA3>m%5*KY7 zKT@^2qaq}v!4H_@s*N;4(zOs$_fRV`@K>YQ|7tk(RVL8VR;4Z0do30*H1nUCh8R1+4U>CCwl{W@>~d7twKex}oInyM#M z=8qKq5=g=npOcE8>2v}!i)?0pJZq}DP+e!1;HRGA*Hsiq)!ZcX7h~0n(U+Md+jz(_n9Y#PX^E(C(1g zox;@+Xz|J1R|)w>5F~TU$bmBWT$}rv%+b;8w+eG2vok3+hX3jU7Vg#BLppJp`pDnZ zN!rbJG}W6JyCpO&n;QPkEaaO3ZSk3BsZ4X@(`6ccEewBzn%ELXqFtXezM>jBL#5J5 zBvzNmbc?ZQIozv@uC6Fb$5>O8b_X;RxcM9!H}P9>hU6v`(!tRAxuy^a zMf&GkPFZc_Ba<-Kael}}USEQ`&SzAnx;~ksi8oL!{vNbkoLE4|Nv8@1G_go`lXC>q z6C)H0$61K;CsDuA-gVBQxx{Le9!eWIWrRqqPUUmaoQ)>p7i0U1{fTrS)#m(uZ7yxh zs2Rea^euUmHl6r@!a3q<6aHi>6LN0N$76|0Ba_VaL=%}`ql;=C&`Hm7?a{UHrE~al zlN9X6>@&E&FOb<=$`I`A&(YcfCp)hdf}4FacFcm@>>wW57VH<T-gp)XFL1*+peu?W_(o(7^RFbqF=F`Zb3!tP8`k*ZI z1rQ4QXsN!&3X?YK9Jdnw^G}iVxK;_No9kiD6Z#q|h+mL1g&?RBpq~B02Y6vRUkA46m^1X2xu~nK7Ft-Pm-q=-?T0 zZmWjg6;b(IA-~4W(~VR?JMvNj$_be2bCx2TQk;_U38HRF zil^EXuJ#Oim=YqtU8gP%5yOX^L%0qa9;>|-SBaFYRcJ@f#d+d)enr;jT*gm5<7w=f zSxBQz$X`pbkV?Z;pOcNBdKs!8Eu@zPQOXbc0^a&Vx3in&X_LN2FrAv+Lfln3g=0j%E4wK8sZNA zfL#PztiV9H&Of+m1Y44ckh2R*2HOx{+1W{aTjFz_(>N!C?ayLLu`{_o@*RjTaT?(^ z7VK!;D#A4^c%5;pMm^*^5#Q0Ni%Vkg2I9Lp&2Z}qb|$``Q=7_kC4QJwN@cncKh|kU zWx5kT)v1O%L$D|Dvz$Ea!r(yiXMwXe3Hiaq-{njqekhe$;w-|`OmG;@jFlLUqZkhP zOnXc!q{v8I4n?rm@94SDxr(2hl5KuVuvadxf^Cgy%n{hP^jwDk)CkM+)S}GH3 z&@v|nVo#?6#z4r!D5uI^#Eu}=!fJ&aO(x?y6Pt@GOsYd=v+Pv02rXr=#%Uq4Kf+Op zuUmWzd)Q75?!pYcWTvKeLsq1X8!1xLnjkBkUva9WrW0=oN##>B$WD9;dSs`DenZ}< zW@%MZK3nT*GnH7C%BNO-gKX}`b3tlOJcillBvG&jVrpe%Qi&1rIb_rHb(Z|26#Z-Q7|y{NoW`zt8bby@>*aKq`WIJX_(k8H8>{N$0uSeP&Qx`=9EA&7 zn58bDC-9pV7N`J*A1=W@oM1~7otNNuowHIMsgJ^CEv!{8dI*2QYq&IRP@Sn2S9H!6 zHJ|GFOAFi8kTMjmYGIH1lG^>Z7WS(-l=F`k4yjU%F8m9L*pg#zO%krbc@!=L-5Izj zf{?T-UJ1IN;CRFrcul7$q`Gvt221{qC7o3FE%MyflAG$DCMizN#*(2__h1o9J}u>@ zx+ih}f_QDSIMr=Rv2f&kELnniaVROd4yCeGx3mRH3Gzjh%2VB+aYRF+`~annsV@CL z9Pmr(`EIH1R6L#In@6_cwM4&EcQY;!_+F8Zu*i~Bw+>EEd~?RPC~Zh}pR9+HD{EmB zwqQxhOVQHyRQEBQj1bh)o>X@~wJ%N5ouvJ#?v*%{(zSFb)x|3fd~v0`fO*GK-IX}T zAXEN<(&=(>5qomNXMa zrnxCpdlfkvrO|0_XYw;gOJma9bezRdRZC;j+()ol$ko!gG&dQi9OP+fe42YZ#X78| z32E-^b|~d*X=0j-9W9_hOOw**%^U&>wKO@+y-cw#($bVP5q}25y8ymxfoDkPEFN6p z`yR*&rw1AQVIn0vS>)o6#Jf&OUF6RaA9Cn$2?K!4!&kdz^|0v(K$(j;R5m9ob$Mu!f#ZjpVOU!ad9K^!<>=i!=+uw zk9F>*Y4JOyPj!YjNB%PLvqX?WO75pN$FY-2Cna1;sA)QfDoE`~Ir`|}bNW@}P<0i> zr%@vH+rt%!sl=fnvgdOaQ$DfeONG*AhE z=xO^mRqu$LPjImv24jG-)R81CH5MMNipB6HyBJbM=LeXsXL7k(f@Wcc{tlp{8qo}e znc&OCh^g1HFx(6sv0?oxO_?g-7NE6tfSOOCnFSP-f#^6nBgrxN=N)9@lUrl|z_s;M zyY^9NPw;+b6D$Kj8IID^2(PfwtzwZ#Kr>Mv&hTBhWCLFZHvyAEF22c$zJ^hHmf+Pj zmPN}n_!6`e4wdo4A5&0zdy$J*$dCMdjdtcGPJ{RxhD2i zw2&e~xlk4GePdi*E-Q4Pz~^cIT&1ZeAG1YY?c&DQj6>4a~QCHDXeDf_u#8npVolr{)Y3dGIlxyqO zhA8GGa0{8zom`hYS$C58PD%GmDLhPNbaDf4-!-i0yD}()OVJ=S<{)VQns5+w2Q<~% zAw|bxXr^;=jos!tr`Ysm3+-%)$SsF>n2C#79{tV*5@9cPe%>26Hz1(LQ{I6F$fxRY zlNTvLK1&alymDHua`ZUJYf5vaSodn)6?78n=nlhO6#4o(lzH@gGBnb$$lFFe)Ka%u z^LW3Bs_CW$N4a>dxMmvnfaNHJ&}JrL&Q5Hc3-fdd(?PeIp;c+r z|xho*2Q)eSvC>sP~RTMT{l8A9pvL|@GdeB%t3>ZhCJD1Bn+4|INT zmEK+lz;!rVLQ3yb19>9ijc#4d1LWFi?B!xOpv##i9@IQH@f|HVW)L5Oc40ED&s6W~ zGgZi(oDS=gQ!e^`6^&++zc2{aQw80sQw)ddCDxc3#&h9u+UsuAf}`eBK!7_ewN^?w}2v1}AJbm)KNt;CHX;Np>{s6Oq*6mE{IG7LAEjhzmV*PLj^v}hCI&sP^ z0`4@OsM^ygyUTQ=PBs|K||{pBVSDu-s|3SEpsO^#%eQMeaIQ3YplFqFXkkdE_DjV;HF2OxwQ_?-{7 z6;^3YS4GIoYAuA!+O|elkgGCjdOoQ2>8=FnW|C1@3kQ+Uc^6N-W8q=AnJT!ATKx#T zqATc4Zak`mV$+<*bOqhaa9^)0=x5fW4LWC-$Ru;H5h7?Ur+W>G?vt>aOzWxkl;(LH zZqkBdM%!jR+UOhfJFv9RA$Ky#0BiwD$=QMHLpRt8f08ln=d)fvpEG`nOezP@!%@76PaWiPQh`k87JOBGCZjfR50r(`Y<8%w&RchxxxX%k&6r25j@(p2Z< zs<_4|G?%n26{|J{y>S9aOc3Nhx*Tq(< zNEQm6w6Ipyq?{Y%Ak^8Qrr~N2U3AVC^&Ac2u5vi$Y*%f|QRuF7_NZx1QRtzC{i=+{ zZBIECiycz0(n{D%H{qCip)Cr1bg|QFD;el3Cu6ZQN?#=Q)5U&NO)00pzDB&D`qD%m zAn6kMira%0tbvj)gz>8GNs84VZ4ST9`H3zn25S@eZO$1SXZTusiamat(|`_DL-qAd zF1VZOpfpTNdEnNjd48jo!t{0hI2;K+hqhmz{vyifyo%w`r+d0i)n7?eTr4cagmk)I zjipwc{?}t_a4q^t7qGExH2MlA=tDDIqU!BkVk)f$KIZ`XizRZg1Pxpt21l3hiA=gf z0TD@eD{@w0x(jt>6GT;&rer$>WVdhyenrDUHt;Xo_<*Em;2{2X* zA=QCK_&BYTYbMWlZLGM`)G5<(qtrPiY8Lti6SYvLW>5!C(n7hKQy+!NTIgu*lT6V< zH*=q4suudGnpDqCdO!>_=YVN?;EYv0XkJd&?o3rnY4**~_X}pJd>UUfb@$UPxfvLn zOlmOPEEgc3{0pvRE7M@M{2Wif%TH26ioLZ`#+Ja7zBd|<`weX zl!SY=;Fx|~$v)}%d!IJWhy45X+{-m*$Om{4%%SCEmF}Pt6~++{t99hdl)jI#MhlJA zDq2Av)It-b=k8i9G*z$DF0xJw%|s@7ivQAN3I;FdW;}<5;0ZZ~ydFkzcv5#aK9)dB z&{JA)R0bX1HfaN{*+w>NAw^`81=u1B(Ewh2Zk2wNm4y=kp4IN-LmzP{Jf~afs5n{; zpVxw`+EDzqar^Z(`gR@LT=gNHT6Somz+Cq2)Izb^NUeN93pLdsYRZdRC^6TKFKMAv zouZiS(oU9%Odn28*e$1{lbJuz9DPL=pr1acI)3Ue4O$?Rsz3OS#!b|zhp_{3JM1)( z8bx2A!I@4^VV~lAv^$~jRi{bF<90~p;OkCpu~;}hg#1ZKHxb}5Ovs;AA?DAn;6%6v zl^SEw9R>IhOBLwBKgOc9sX$)|jY@m~aLy)^m-LgMl+LNE)jl! zCevTGZps7El7HE;ru=2=poSBv`^)#Q+kh;j?w@;8n0_=Q4?#@yW`RL`M7x$Y^4S7XgrxO_=b-5$26~lVOSCFpMvQh z8v`4o20r!}_}F9MWXynJBfW9>z^Qmrjp%FC)A2M`3daffL~|mM>feF+dQ-vwOyt7} z3E!J4e~4E3y{-~{t4o=rgM2-_p{RKgPND9-XtY}5pf@eO=+V09(YmC0)cl1PfCLM`_M(OFOQqZFmj47qEQW4Hd z2pOd>qe>xebS?MX- zl|~q)Tcb)NJW3;CN+VgRoZK5{ly*jy#(9*+$CSpi(nLC8jZ-@0mtsmP7V>e54jww> z;}wmC$fMb)GeIYd@MIc6=S{7pXv~a-^PXDI$7=mm*J=!0(8(gKXv42;JeV0ZP}$=_ z<(LOmJRan*2aU*`md3!FQ3EYK2Fhaw$~^{J>EuX3J=AZl^+h;`c4FHYb4x0kV|$Fn zX{~}s%CTUanuHUqKu^3lMK_vF+kEWWPf1v)ma#S@YOR*XT5XTD+8%4QJ=W^5wYO=0 z_cGS@M6LDmSnKVv*4tyPx5ru^UBun36?V`A zIGjL38s3kVJZwtRciHe>0)4S0!f(^C`Y=JyjB`{{FF+q^RS|xV4x|5?Tn7h`$^Dme zM^aC1aD`63GR#>$cSe3-mFCd42Q0Z6Z}3(O*}#OQfhpnwF!* z_K7q*Yut^7BQxnV(j}29iPXTs4_!4cYCIjy9h`VLnma`E_}}KV-o!*bWVPNT&C~fL zf}6C@sfVB8wG`m_rXBa-$=@~i3EUoZ;ugCYj9^YT}_|Clc{Z)_euX%ib z-T0o2hK=tBJ-)xgzSoN8e(dr66?ZiTj@(->-OlzvA(o zdF}fZkMDnZe7|aZe=q8t^vA}JrFl`~Y&18;9~(bG%~y<{Tz_o*^Jb!*w?4hhJMTB@u+#g_O@8vD#&WF0gkg>+40AaQ zTcf#4Jz-e(KVeww3B$UIFtnj>qqdrMtU%thW2>hf&wASNtfw8!>vlZrX~%P(c0BKC z$2QZB-dKrg#~x2RUgma8kLJGPX~&`eX~#)VJ5E)!V*u@HXH7e^+VN9tB>rqhqKkHo>z6&Q|G}=;j^S5`}a@Gl`hju7?7#Nt6|!Nn|#V?10`t-j8~hABZgg1)3K% z&P8+U1!BI}*L;QVtpYLMTWcPDUqRdd2gdg|qP~CN@%^aB_oE))nb*D__4t0wdv!V<{O0Poe}gxlOx%BSV{yOe#^Qca z7c_Baz9rpXMILn{^b99l(q$t0JOAHZUv5PoTz07sBJBao{Nd_V?PgNayS+@&{h>E$ z%kX-Wwl!ZAnTzcMCxzU^W#IX!UX2vpQ(CX4;k8~Z&9h!z)+;h~^-9rwsC9Z9UhDMH zJnIZ#9XuG&kP1Ie*Sbq|B4pydCKIP6DX};$O^L;6sV->Z#Jr9Z^3gag(`8JY?oNrt z>7EoFCw;_To)TLESET4A@EMG^X~#pJm_6)?*(2VVZQyp)_&TchwkKu>JTW`yjoD$= zUT>s%?)9d+793$NI&JiZ24f>^ znBleFjhbh@QLM+&S{jUvuw{nVI(KWHb?#*y5vE6g;B_s+7~E3L*m~U)t$m(o?b8KK zw3ye?LOvR;{kn{a)*GH^y=kJQ=ipoVdxIKRqb)t^iO?}mgpPY7^f7x~qaHeHBJ`Ih zLRUQz`r8|!Ypll+%GVDmnf0u|@H#?;n&${rGv8(4?E9CFhyAn&+wr(%BGfN6HlF&W z#>P{BUC>0x@MaenkgCUuUT_BL?>)?lHAt5?(Hfkp$Cmy&d`K#N9Ujr&h7UEozKcD~ zl-E(bQGcmYqZK-3S~E2@wzJ%%`67LgyG0i)D%4*q%+(fXDVq~jT%H=+bXI8ID6aA< zuB}ky3z}yIh((opb zFQml+`C^*hX7$qlk}huoxhpLe$lYnNK<+WT4&KXYdK5+~V5&>1NZxQCL3%gV!ZP z2k#VKd>4$Ny{}7#=JiEx*Nj;3y6S=^c+CGm<-2B3FbedX?UteEtiD+8o|F!U2>_W%RB((C~}KVEI8AUtqg%&nrh)^ko2jCB$C@h7<69DXiAT;Z*C2_OJG|e~qX8 zYji==e&%)i*Ld3hpr`$7J?&rTY5zl>_CM@t|0ACEKk8}!W2Qa2{p&sL-{5KgMpH(& z|8c|X_CI0TAHIZ9hAfMM2bZa(`nG+RzELm2Aqwq;Or2W;Z(N$yXhLRe5>3dAjf08i zCm7+xT-2Ilv~G-Q&GBf>@o3Fut<&VfVx#q7RBN$EYq3Xb32Uuwk6LSt){&^z8jsc* zkJf_~bwyBXlhLx;RS+h{e8YVG!D?e=KxVXYtN%JZPnniADI z=+Qdp(RzoqTH{MIP^K{;xr7_AObtrU+|(4!S(t>g4PK*(s_8r2GUw6Z)} zS*&${mXoSR>xHORRgYFxk5(>g&Ba@LP-L{uMzxAOT16hM2x~RRxIs;$RTW2uDTrFk0)PS{poC8$4PYS?emTQOAwe(WusOkJfRI)(O^XOSiI4 z8LhaE7416Z(K_YPI?YLtsgyFKYFyzR@Bu1wX(AG{JJTsm6a8nUs+kP z`IT*clNY9EMIqN{ZH{W?dbDyqT6wJXA>Al0GFo3mwTe7iMINmPYdt_SrKZtJy{;k} zH9cB2JzBL`>rYze>lv*_qgwThmVW%TUY1VRCx-eS3-z^yg7J8=hWc4gpsqQemg;nK z0%(w>PXJA6nQ54%PYL=2&?w7?^_uJCGUJKQp{MhG4n4FUei=}qr}1ja^%ZUD>G7(k z$E#i*uX=gB>gDmOx5ukK9c}SK%mxLdsyF?F|Ry62T(TWE=tytx0#VSuLR(V>n%F~L~o>r{!wBkWeE7p2i zvCh+qhdix#*wczfJgs=t(~8Hq6?<{jg%hR~`=YHl;c3MQPb)t3wBkcgD?aqJ;v-Kh zKK8WYq-TVj@{Ewvy1WSgHy%B?Y&^N{hKhJz_IUD#$CE!ip8VnQ7! zk0)0>p8U<8g!9ppjBLFcd>Hj4BU`Tqde&rQ$7W4tc5G$H%%%gmnKhZ&u~`$+>1Nhs zWyfYsc6MymRLYLcn##Jo2=}B@?k`$^yv`Ld`Nepm=j?e;?dMJH`ZSL`U4iSLBK?}( z0Cmj|d5F`Os^&TjU%P_|VL$FR0G0IB#L{RzP${e3|A&=HXxRA~%j~NSJMJ+t$v9R7_VZFx!^4bDDtPI8n_$qDJk+J{kV z=^kqt9%~sMYsiyt`bUqMY%PSVDO5Ao@_JOXw3^3Sb&s{`9&5-)t<_*_2MWVRHm63^o>ih*}uzu`tAA zVTi{9^4h|Dy80PwEL7`R5tFeV3*$T%#(69tuPvmfpoQti!Yxq?(>)eucr48DSU?^v zMD&kZXL3|q(B84wSUV84w%B8BiO1R!k2U0@)|MJ;#dC|$+TFSEXVlW&xq2k(pX}Y8 zi_4HG(7)KbNAsfi0Idq&=0ZxZidcNBHAJ;{ZG4oa5#5=x+F+)6;6=;To8xKJYVX38=Xk!fBJQ5IIjdV3yO5x`uC~uxS&XTtlL&t6!WsMh`cnO6&2}7 zX>TG$+8gabagp{wKX_bCzpW&qpGdA=L@Sr^tcI>Iq963BY0Bu|xz;je^tC|kB5GBU zd4RKZ5p_5En@KZnoAEcLZ-u|xjK4a<+lyim-tO^zyY{_6|Js$)d(dr&9YuQN>ptCS z+N7iXLQyQ*FPipgzh2UQMRZ$tnYQZo?bg1VXrC$KXrIuYqTjF4Hx=U|I?i83{T>&I zjg0Y;nBU_gv6zpK=#ioQ=5+nL+zF9GIOYm;8zw|zZI~F*{i542DH3bLKDh_Q(7ErPib+i zJ*CCEJ-Q90#kvi{=#syIDf3iN^Rc!yD2}zQVR5W&jf!J!D=Ut*t#NUzZB2?}ZELDu zvlP)!tv55g?ziT}v38Ct=5`L$EyD-({&H|}D$(oK-`GsEZfV)9TP3k|t3(gcVh1A# zr&>XJe~ik$QY{dVGmakg59iYe&Tbp=A+)11i|R!aBJGH;)Rvxw7vXEPH|%MrOOBwD zI(JVy;?WxYx+8qLE|y8{pvx?dmPzeEJeHv!X@oD8VVS!6)iJO&TBdF%`f-d1r-d;0 zGxNy&XP8Tm%o~v&nP+Ye-YC^Y@H@A1EdP}$pFRM~;}18DNSe%{=GVGNK580H6qor? z^I#X~iCP8veI*CGkPi|4`>l7n(72$-hz@n3NESu(!uWm{>K@z=UPXYqU12t97rR=Z ztb#f*UKH1%GvO^=VSTiYTe?ym1^U<2w{+Eg6sFM#m)hv4y-Ou^AD9Hw2fw$`eNbyO zc9T3s)7JV93)UVwbOg)zr5W9jxyPnVs6LRNlDfyHFNq5D?TLGA`XZ?)GKsz*TA>RT z6_N!OP%(TD_4r*{2}V>HF)}MI@+uku6>Ck$o|j)}&*r0^@l4C;Sv(qTVSW|xG-jF| ztA*!R0WJ7f0fXoc^H2K0eK=TAy^(Q})8LwBp8ii8RAFYC=js1x`ssgjF+IblFQ)%g zs5H|@jzzZ9Deq>@i}3OQ3eDnZRe)VlYt7?I_=DDP5NDw-p-`YqCRY|({VD9>yfY?7C)1Rx8&*s zn*RCpeo@TS$AzdR8niBQ2shaI^hQoDX z`~nuoPMDs>#kzhh!^C+eqN}hjxiceDC+#e5HqB-|-&OqEBpr9RmN;xelKm~fgG5Uq=NS}{;?P#8g@Lpqt>cADlAHF;yQ1L!P5)mOh$_@PoMXL8*C4yccO{|4I|ce*VbmGjRJ)pu>Is z^l8}9hA)bIO_Q@x!i%|Bu?VlhWgNN~8_S|Lx_E4KO`xCI8XJZe;f(VC$Jlp(S5ZB0 z?-B?JHAt_9KnOhn10h^)ZrV*CH$(_Y0BaCXL68VYk*X*HHb79sNMb<&3&9FfM6qMR zibxA0q5_HqkYM@Vch2nQ67=`~_IYyi&N(x4X6BSVd-m)uq&|`7_v|uAF?NPz>KevJwqj(^>n6BMJ;!12;bM_-NNdo;(eHkw0)c8+*IseHl-7-7y z`g_4`MNr7B3n0BO%#o*{Y)QAGdPjokDsx}vGgtFfLHA{@3c4?IwceLm8%x!#$J3r; zBb_R=TFZ=2R${HzvJ$(JL#^GKE3WOg@RVxGi56V?^-!a~I0NtbtP5bw5N-VYt#jc!T5YDw?ADR!i>c%PdR zVN$ffu90jBJjwB?@2Km0!@3Po(mJ+|a$4(#sLIy5AxdgkhSlezWZoxl7kfd3Vs55_ z7iG|od7cB&O9n?K0>5mqJQn+k!H;lk*eJN`YRt0iI_yJ^M}1>(4K~ulg4LlDVh4meCZRFeUc3>>^}{Qx0_~+0dfPG`eqVYqcz3o3Z$?|Y z{%FVNj3C|&!yEN82jF+i0Nx9n?D2+Vk2lDQ+T{n=R>L(|xeRG_{DK{Ol*gXxmNUvD zv6UyoM|t>q9INB4=xLk%afT~u3Fk{ia(1^rBc}{cCc!+PsaT%Ryh#|X zsGl+X+o9%aB=K6u+fX?zn8`_~pN+GpWjMpzYs|D{21}7C(3+rW$r`bz-Kf#mTJ~CDjFIWkI-R2Q;yBgMZ$C?E zIi>XrI;DAoPH9PcO8bCiew86pp~G&OUuDSk)YEKRCeu7BwnrE-VW@$O1tuPKuX8M2 zAXjJYMapDiyp0Cu_eOt$%V`pf&L33gU9G`+kI^~8&yfxCzjJcAgC#T9V{1uwJogzXpQc7wnFY(O~lqNi! z)}{+GqtxWo4ly!}4L4$^d5wRWU>%39O*I3n6_v_qZbpjObU$rs5-tg=(bd~`;3Og= zMewUlfHQ?L=4Q?n`x`71=>dXqUlGH!-9OKa(9|YU{qwd0o29`4l8KRxuThBonC<&$ zHD1joe}ocoAVm(lxY}5}8A&$G9<8^8;M{ql=YqXB=X$Zkh8`<~p;~-_u1j5AhQsl~l4tz!U8dNf z=#h2}c~wBEidP2oURS(^6yS*0aKw8K4TE^Ckg^LzzjQ@wohMpLMWrrkNx7_xX*_|} z7tZY$c+q&A6A{DVm{H#`BQ}S1(MUE+?ox61C5K&{M{$|rHj>vI*!giXNo?ebw@rrl zH6mWF;N zHmkpJ@+isX^Q_+@!lx(_dx+M&FN;WvRog{q#ysp||BaT_ORj+4ug;fQ&Ww;{&0u1>JiJZqx`>3@YJuEu)W}AMzVNMwa+oJWBFN^_A^1 z1!tOnFyL((AnnB??PU&XwwJURkF=Pbp!@PY9UrNv*xfJ06OFX$=so?KGg?-_@*Yjrk?@p#2}w9;bY$1v%{EhDA=y|BI5z(@zMYX*1UY9f5SXshr;+i`ijN8zVNjZ;N-aq>;* zf1YIF;Km^gck-H$<3@QND7+}-grNqf@?9g25<17j{;6i#8%VeF)4t}v!D%1yADVvb z`kDZt@@R9B7X6$NLepQ4qI<~-fZ_0hIh9Z5uT|D4hqY5}&pD(Y0R#He9@ap+x}3U1 zer8zux*fXrB&TlM)#ZgncQBhm+STQS+a}V|zuJq2S(uCTk{fu2?vBdpB~#S)bveD- z1Ug=32+?(U+8aHG(CLN9xOE~jMd7wN_TC=XBIY($O=u~Pxq?%!p9QF{S zy$}qdeI5a|KM7!2{zwjQVsnx_!umdvjm5V-W=GbfdK$GDT|!0kw_+ zz>#SUHh|4iLHneF-XJX%v|lQSA8AN0Me$K6*f{&0RLB#^FwPzo`fJcqL7%A2<#hJA zarQ4{inEao)!8%vXpTTDoa<_?F3+9LMV8TALuh_FK`N;27nH#hC*~g}GxenU_fRRT z|4#yj^5RBh@fSk7vH6r#NE(uj=F>t?2Q4<=q?*ehV4pKK7b8=&zD7W;-vHo9yazw_ zIeB8BR0Ri04w8!}-|Wm_&dDPLc5a+>(sS|; ztn)>J*|eUyvevhhw6vaEWxekJ=uGyF#4nAGat3Hovx=J$685~NxaN=`^&?=AZU(Rt z9DbZqYW!vo?$HV=ro%t`4Y90H)#baEl}&NN_J&yIgzXKn%L&^KvC1Bt%2x;7t4iuR zN{1uZYy{HrYs9sxQjS(TO<-PX`) zC?D6GA+q@OAXxknn8C!G6#z+W(+ndqUu-j0WicqoVb_lOU@9uIA@be^lM4*{tyS6U zM4fZk|90334Ev_4>=99&r>W9*&4YlIN@I3aWp5BAsf^DG>A2QdT$>A? zczM5O6QNUEs4?}vGTg4K&7)p%jF|=|DT=_@9$S^YMbvi=dzr&dVA!v%${rcjc)BY6 z!eJ*cuHIRdy{&PzE+*Sz2my}RIvzBf_Hv)4RAmNB4w8$XKndnzslD8ILF17Zx3`ZT z51yV-(O+)GL`QR9MD?4$>QE9dt*e9FkD1FdV*7T6D!)irdyMKNw|PEvi!)yMrG(88 z=_Pwg{L##7fqvau+Gzj@Ur zAq(#mhS#yfQ=#Zr*_)I6wQ;?P>-yvwj_be5cAzcLXlothHmIJHqU{0&;1TBNE9Y2eP73dg{2 z+Nps8XkfGUC{1L}s0_cPZhsNe9c4=(mV%=aQ086Acqc3Wzc{rQ=OMd88kX@O}+eBdQ1p>8ZIVEh9 zgk2fN9Yl`1h9CBffm<(BwWmd9 z+AWT|7bQV`8&SXg0`i_5i^$D_-Y1aknUvbqZ$lfN$ zdczO(_rS`}s;ci3NL%GtKcpqp_Y?Ky7pQMC$FaVjqh72x{Hp$NRrTH=^_vr+K5ig) zo1Rp@#c0?(?Bd#YphwCnKW-pT`H{FtGBdOu19<^QK>Gz_PXd^x-O;cAU2dq2`eb|C;|4ePa9R0O87VD&kyqLi#uYNb-^ z6lHZUxer$pt*@|rvi?L?D= zZ$efI4l#&|RrR2QhN+puyJ+Btj_TbG|2gt|9}kMK6Un5o14d9P0q}*}7)4H_lO#%Q z08LbVLg#@tQA{>bWLTn9Nj=91|G@dsBVnO{gk>rL!?F@Un#KiU>Zgb>Bosl@Xr$`d z1Xe+>(=;6U;HHrjr_6C`%kA^vfOMsR7`zoaO;^em`Zv(Vp@EeSWjQ4}4&@FU3O(Ww z1;n8yxabgv5&^`a3&hkR5urmAfkPfgJsg?9{_C}9AO+}i(IP~)NvfVX<+r+;ST%zG6+aB+X!IV{Y%R3 zR`BG350IVhelOYC?*ArW1-HeOo3wjJET|!mbxIL2#)M)fd|R~?cc{?tr9+<>M8&Gw z(su7&4NMyNmZN&6!(U4N!0kcN-VYv)cA%xIVDmXuneOczlrob8%8MI1KQmH{ICz@v_!% zqi8w{P4Tj=W`fW|V<8yJ4-(l&FXdD!x!h<J}Ln&UW;@NJ2A3?mAh#QXMD6y9)FmyEf zA@2~>9m+BKCQ$twQeXX{bfDUj!v4IdvLlqdKCo4bXpDOctDzhdTExF#x{zN6Xu$B+8Xoe;AtQsx4P`ZCNE}Wo8`hiTu#0=#3BzR) zYB(N-sl8;9Xz0&Dr-U3b>=$TT&07p`+b!WI&s#2}93eX`WwG8 zy{@RCh#aj0Xsgt_?M2i7MVCO1D2NB*x;U6QR zrK8kj$db}Ire-@Sy=Klp+24~p^d0puy|e~i-n{@;$enbbsBMBtPGFsKWS|n4gMqzp z3Vw0%H^=h6p}7}S0wnV_kFDohBk8uD_p7#^kR@y8SUJ;Fy0PQoT zgok|3{)PillzT*hnaV|jD_nym$T0gk&869sAQt=Z#V~tCbr!N+^OjK`4%|_?OYi%v zko!}MU_~!!N-JdR{GXsrQ+r4h+}I0rZWBnZ6#h62P)Wb4)-a>gdL5yNmo4{CiO_T~ zWmRSBE!*%7!#*%%pK)x1SKtpnY_vH_jlyR{p`GwA3`U`07z~E&da9vJ6k4(8I9wHp zf3Y- z>Gy*ndxL6FzY|AwK#4cV9mSKH#kRo1E`AVx%RRXp#1A_^eGm*Bi&XQ_#5gHfJaB}` zV2`VwK@YIPITz%4yfm=)x6HFFW|Ei2;fOtp_G5n|H*^b?h0pKsu!}d{gP_YT?Qi6U zZd;Gm$v1LCcV|C@R&HS*md`Zg;Y`jG)VD%?0xElx>fDT2X8#aOG&o{Pk(|U}Vnh%T zcuk29pkNTpK_`+vmwh&fE4%G?LCQu26AuOx8-s~G!Nj>>BJyaZHY@RwItWF&)K;=) zpbyG{-g+-0BsUS#<^J#3RM2wMAYJbNz6{zsR>fGgu;0D^dtU=+P87{^m8FKO`6gz|=X`a`0$i;ihH!QFAbVg#o0zIE)pj?jKuo-|pkd`MBdKZbVEc3SQgkASvb za)vq`%6q@hQu{iUI)u=hum@=$5CiSsiuUcwS802<`&9e4qWvtjOW*xgwD(Mh_P12Z zzV2VN*J=UnoojGl-=%yoSZ$x|XzyHuTd{6{Ht!zgYFVibjXS$O)a;e5WQE@w@vW|! zg2k{(rVM*!PummF6Q4_oeIn7-4_Z#A`-OfOH1A~`NbLq4XF!>=@SmwiRCjt=sAV;W z+W6~}q2_ohpAad?fO+N0;htyTac3gglQpjgOb;v#V)R23;vOF2GAFeB!I+O^EaAe# zAvn)VxiG1>JYS630WsF&(Cud6=P}2YsnbTYfCy0CYVkA;$zBLzbDM92e#B znU1@mLvPoD(#u0F>uQwI|HW#s;!Hs+)JC->*=9H2A0n5@$C_?Xfry%5`?DY&BA$at ze;i6Zp8@<#@D2dqiR7KB>=~vm&04kH136b~&N$6+Co)zbUb7g*sVIOE3cKD)Sg+}% zr!ZonocN{nW78_vytixseN(YQw6{RLV@AO%P+O|9n3V+DYdVX2 z%@M2a7MG&g2hT4KK7>r#1@UP?YR?3zT@aLBAJJt!pg8ZUpyFV7c*rToLM!%ZHtL3{ z3}~6MeQk_JqfT7LMvW|Ru!`yiSY;fe8>QlmV`YHuFICn!l@FVREGeHIFVD|4N#*l% zbCBO#c4jt}5qV)l)O(QmRjC zIII(?BuXv#7pcHIS`K?>N3cVk4&2n5&`xD^_GraMc82Bz*|NG=^F|qC5RJo(hHQdO zkd3d8px9pd7|9^98eCt3j{mMBZ4(Vw4Ft_^P1%V;e+W9TO4YuHs(-Q4A}g>#GY%l* zQ{;lRyGqg%>gY|#MWdT#$Af( zcAko{0VdB@;w*^`!8x9vjP^#?W4N551RKSzC(}Gi;Q(mf+thi&^ zm#o+u*`98c4cleP*3h+n>jSV>P82uF_U;LTK+7HE8)f%)-NA^dY~?TVaV!4{(y}al zlW6>iw46vL3OywkEf6E^BwshU@*OC1A}R4D|7?8AKA}eNqAB3fRGvJB!xnMUJtqV% z(`@nBlf$&&bdplKJzhnL^>UfHZ) zu1uBj`D=v}pS|+X#!h%-+Rt9u#y_UOiO>Edwx8cgOZzz>8aoel;&V{wPeHT&lqa$M zqz-f9Q`5Q-H*Oc9|l^sldSGX?~Z}yr0Xf6vW8>S<)gU~ zzZyr&IO;yzZyL0Cjv#$47_!@H=EWExtiELLtSRMWU*Aty%fXt`Cx{hc;W!M%J;NG< z?_=*E%^hh9gSm@V!n_ER%LgmF;wq|_Y(m-PrMas>vuZvO>Mu}YZjmaA2!r0;-WX^R z8?HbgvTqHt!5Tnwos@8=+^@U^5Xqp2*^7eN#k>18C7IgydPVd7(46vU5NnWkgJG$? zspfXgrN=z%;>#X}H`jS2m(MUBgpy0-k>*YEz;F`IhM9bp_FWY%Vu`QTJVSpTMmhzu z>-}c*#WDQi&*#bxZaM5NH9MmyF?1DlX739!)Jo;^yiN*2ZA7-!^xTT{*U5fD*;818 z6<~VPn}e>ls>&xb0-a?PZY== zbDmE$u%D*52EJGGZ;H^!`&dr{l|hWm?yFQbO^#ZggfeDIXSOecf#v}*lh9rs1e<9d z>5>P*W(hVgxSVb9)JQ0plQbs+UPdkI1>!EFZH=qVBp7XX1!=oGNZUO@+U`x_e8Gy{ z7Y}X4qOC}cKE(_icJZsL5KWmM8;*D3X)iIjSX5nm6 zz5574H4o{Jfx$Bs;46X~0O}QD34?6D`#@a=%J(q969AcyjIPuaf!<*+Nt#AYZzG+Y zo>u|hA$Shp9{?lss+K;8GE0-5abyA`RAxB=Wj+M3vOiV+p{T9oBT9^u)|SZz^}Qy| zrM{A+2M`rcFQhlW2A~tbH3Y2zRsi_P=1T!}29$3gKput^@y5}#otkb-%Ah8CLr(E# zDmcZm^&EvnCggV@9NvYRUZe0tMa30_=bh{i4awJ-tY^h&eiOVCnfyKFDnThjj5WMuSClNZ^XY~*6|C}V=`P%)1( z_Awaacw!od$qwfEL|+;&kog{itJ(-pb z6La>#S#x!3Bs>U!KMpa9mj-&7*f1H1y`_O(F7!Ik@%KkU-xX5KhoA?rmCx7m?nYTW z?5ol)Ek#%lBCqMS0G|O2C3pwmL4d5PBEDnD`4Bn2GXNpi0fZog9RRY*R6Y8S9KL$U z$s$V&fZNFOy|OfOSfY`$2{}BxEwodz!=uJzVcCjp*#efXmRZzdWf<%RY{a8Zz*fsV zZ9jCGdB~G8PkaA*#6sq=Psuzje~dF!t`UuQk(P&y*9v{fSaY&lC-bz&L792lSH7O7 zjg{G-s}Y=sWOvh4njE-H3FdTwVQ74qb!5*9;>meciA#!HSK~q*q}~+_&y@( zq%xEl6VOn;r{8j~XoL)FU&B&!ujm??kCB%1l;@0*so{u@P5KnFa-Pb*0X->M8DwUW zGES*2m3;@jC8ib3IOw&TJ%--$cA^m9Mgz-6%yO9+@Da#Ef~-L~ZNT!gw^WrCv0LJ> zi`za4vt?=VXD=T=m;ejR-rAF1e%7$gIMA{?<`*w_$6QZ(Cns9Jdb#&@73q&4X#eJ& z4g)Gk%V!LK_wqA_T<76j<&+rmJgB5yYJ}6|&ccUyxu^QK6xrZL%r`kh`C1v>NZCme zrA#nnAJj~Vl9gorVLWPU{#ma)?kKI5L_5bqMrKJN%2-$nHrGuW2tH9-N~IB+DN3cb zoD__la@h5f<~kxfDAGJwM9g+laCR{w^^Ms_!R~Dv#E#ZzdQ?&$O+~HB(f$d?`o>9& zYU>Hwc(Rqz)!j0w33$bWAzZ9#V`i3Gl+S(|Hcus-oPJpbcoW8nXS%(~HErV3gVz!o}-Wg7@ z;Wwe!5$6@l7VD(A&VBD)2N5%;9vjRqEoFkHxV3rA%&Yl~lXq$mJ6p3)k@8Lio=`5-Xsu!#cBVo=T5vNf#iQxx4N`;l)LbrE^AWpqT>R1U@TP%2_!uK+|iC zsb)1m!BR8uYLce&4A{}6W8XmFO-<$r&adpUVvL2DoUb)=c#xixLHchBO0WH=F^r1t z3s%IDEvJR%K3*x|^#)1MN@t-O;oP5&V1#AMop$9aHtKPv+OQVklRNEU*{sB~2v0Am z#IS5u;;mB8y;qHQnraN7*@_YHn$zM8bEPW*mphH@1L*7mI->HE%7P;b9kd zdloKApEMj>=z>f}BeVH}g!E~kB_wS{!w01AiiBvC(0m{wzA5^+-A?GMNJ|TAFClo9 zba^!Lqb0w|EudvhsDseipv`P+diKSCiBVRdx&pSSTh>X)ctfD2CUaLyiAhF`5W?_~ z*PPYSoK$6c!DX-ld78%VvNI_Cx*&xo-E>j7*HIXl8YCR{bY-(&6eQfuO&8$4R?2{yOjxFA6qp6;V+(tt&(kMnzb$3;IFd9MM;%8PB_Y`KvOgFB^_SuD-dVuV4oBOJBZKH0&fTXN%i}ZUh%h z-<>CYcOL0LU6gpc(BW{2GyXfW2f~NJa_?!r42;}0HTZ_nc;V5VqKVs|`pdw%K=&sOYMu9~_Ujy2V0=u&ht6zb46>t=o`_zM z$z`yzTWA`)A2z@m2KKpcT_#j9?+67ZXfDeLUw>W$Xzr8|m>>DAM!@ zw_6py;B>1svcGN{8?SWJweqlt(4W?a^g7vZ=bvq^N1x^{YikUs^zF5;S@=8E11ecKglVEmJ#8;YB$Kl@`$cEn{^Acsg z4VICsH7CUt*%p}Nh~MDJ2)B9hKmPQXoNzJJ2|@ph25lO0Vjs(Vllnle?-j zHn(XGmr8lq#lN!T^~f4G7hp5MP5|FK07GuY757If(U|Nw4uL<7Z1#{eirEEORau5m zIAN~}YF|N0NpK3HnfDp^PHN)iMm;PldJ%?vi!6ECw80SwkY0pfvLk@c1+C{Q=dW6 z#?)*v^$*w7fubS(4#(6Sp>F{lI1yy37YhHksptON)VVY@MHEMbnx=ykIqc$)R~%DQ z#MDPnv@tbBO#OkTNmNrsL$CRcscAyr06Nf3)iSEz|DUFMl>5S{=8i$+2WfV9*Tx%R zqh~&{?nPl~w*Z7z@V6uw=Uk_91>ml1RNhINT&4ZRX8947P}x8@S6M2f(tM*6mCzbo zS$ziuo2Z1=U|VZ=rxTT$qTy=N($>O+UJg3&h^l3X{}!YErLEBqX=_g_H{V87rL8q+ z1ydV{;_b>+*H2iZbZ?>)COW|^#zWp7m0>Jq{Y;RLeB>s*dJu-S}6S2w&t38 z?7vOz*aN1v62(?c)7C0Yov_J?YAZ2yEs8d#wh~iMxu&)j4Jnw!7*pE_Jr#7IwW?)Q z^Pup5o7zRWFN|tpcq5qlr6^8Tu9ricZt>4%$J8&y)RidOn7Ug`?X?K>Eghj@w`dr6 z7fh8sWM9cU*w>T3vIX+@Nd6zBk2MATwa|HYgTDA8(0gTz>QvG#n}FUYbTMgp7ufz9 z7&xuk_kfl+!ygbjj`d-kDYeK$U2sszW99Y(V`pV0%D6ZkNQ;b;{G zb;aAgmMMi>pwW0W*@~Uc)-p!k+-21^ET~U8?BbDIoc1_Iz9bN`#A%OXf>Y2E^WFttsV3gwTC|%M?LpSK`vHys{0`vz1>nAAm}Z?)33N(1(#V2o7DX`4 zs+v87f(apb4;~L%qtmRTU9lTUldq6W$QOIIq0s8xEbAAP<>5=ly~}a4;SVquv;tLa z$sk`x{C^&)zIcEy01~2H^{ib!r^g+kcxfU6Z->gO*o&0KG21R~@EY2RCs{b=L}T$4 zny|CK2PL>Y{_+Qe#+%n_3jGx5R9fw*a<5Us!aOvP3dCe`iW5|kRh4}R{TM3-v|9o2Gg2}D`Z5sT zs>ouBM21N%NdRV(m9_XNfS=h_oX)NYavFXlIHkjHXWE-P3x!71H4SGXn0VO5k8g+W zdy(}f3we?}51~)21PHC*Z%N-I*w$DDx6`&8!aSEEZ2%ZO{C?tX1lIv#mmB@*=ecC61OkLT7^ZUj09`__srgv13BL_hH9aS3{A|rPNUNKQvgets~*y z5(&>PWvqO^(C8fqkTm%v65t)sX9B!b0-RF{S{^N0DjF_&6to1`&^t&=fR{>ua~^}e z65#tKzz0Z6fR{;tFMS*Vj;M>hcBon7*dr3q?Z_|zUM2Kt(B8rI|3`oaK}!_OH(EAJ zK$}0|XxSq4rJ%i~|3izv6k3diXC$B#T@B9)y@nco`5zjr*ra#_c!RuFEh54gd;{7R z54-pXEHnY$Ag@*134JEO8|1}m-qoNbz|YI8)fR%z8LnzRf^cQ8_THe$Y;UHeO+gvC zH=_s5)vR18mIV)f6Wwz@vfhA3&nf`!?MPb+5L&_C5+6S$F&BxxmjLzwc%M@>6lRNd z-q^&e*jZ2=ySxQ-Pm{AkxnrbT=RQ=lKA#B}*;N7FTORv^ifM8;aQ zg_DT?t0;||LLLh123=RL!_NS|IBr=36HTzlVJ{3jN3ZH(RCxego}K`k2>24YUkUgk zxh7A8d+1;l-Up+a;4eP{PV&594IQCbBj3hTkIWkEX5FM&thQ`sF;Yfqwr0`G>zMU1 z`nqHdyGOIknP)KS(kvnsa%K$U z*vvb1gJpYl_aL5s$+vRjp>2>dWw~a&O*8z+Dn&t_D*+lm2QwJx&EzD~+zy;WaG-?R>yHc$7mL-CAjM_LXtcY&CQtdpuZPF)y`SMcwZ_Gk}6yWi^p|J~s{hgkZ^{z&D-g2%f~ zyT3b}XOYj~mFeSmhx078a=o_ud&1f7N0cG{om2~3(@SunvNa7&)GW5aUCgR%g9Dth z5#D3Wa$9c7aLr;Ht8D95?AY3{ymoz_UyGC_-VNSW@4-?T{%gwzZ8~mnEUzsewRwTG zj81h#!_?mn zo7U&~HTosc^0wJ#LSGKrdsOXZ6<3Z%Y!c~((9s&k8y&ssvp#3LI(iHJB6aj`Y@EGN zhrbLujC_asJh$$4Hi4GVz9pgE0y^EQk3VN9+FQy$becCUfJm|_F z5W4YZ$iMra@^}S%8bVvEIXmr1WgF}Ew}hPtjfA#VbIuC;K${6|t>)}+>qtvzYs=^B zPlL`$)J?om5Dq%0W@)ksgxpcIVh_T6`%&rbg_=Lct=P{#gmwx1qte@Bw>YIgCcV8J zv^?efnDq9iaA{&*%kg-)zLq0ihNLIL>0LRpGdE(?c|r>+XW1`?H~#?R<`+o6bQ{14 zfV&6|0lZG|9>5s@Kly!UL3P8dz`IAaaQv-0T=Q;Zu3X$%1FnL=@5+m&FNeJ${0Wvi z19>B%%yU1$LV`O1J|~y}a0Vc&s;sXBIdR)z%F_VX0(cuVGa>swOv!vB77bTVR8FIxm6$Zq9Nj3dt$k?T-D#!EgAEPZw&*(3M&ZP*8=^6cH(D|CQ^o#+bVHIZK zX3#P8r8wo7L1%yrI$wh}gHDzVI%6?YFoRA&2A#d2(+5T18K{q(4xcB34ChW}(8(A2 zHqhS8=C*{8{g+X9_eNRii=pF$t7D=JGOJx3lZ4(&9S{7c4u3gxm_cWx3^ISa@}q=~ zN1yN>{ZDy(XS-D2K8rn=~&&oB@C!{5`6>^Q#8lzOsL#pOixE3^? zuRG5OGoI&$VTjwV8T;H~r+$i|qzAGJIO=%;TCiUa0KoGf(fAiy!QYa!=7RZq9xlj7 zik(+50{_A)nBA_dLsGdGl&l4P0PlPgk+~Y$eX{}H1?bD?7mg`w#6{Fo+cSu1$n;zR z&=}ppb3K3;0Lz(?txR}5s<-{8P`3{1?m)ipWq>sRqPLr}CR6W3qjx9OQST`N>TQj| z0z-MBGWS!xzQs^=Ir0jM0qk7SI9{2GsBxsxI2$~oaSZ`A?h=hw?k)(Hs>FU(YZo8= z3~XnS)e2SSsc{KTegJ6=01)pJ$Ox_AZ%NuA!TdcB7qlj8UO^}P3#(u@`IMTHtkx#pPF$8z??k8@hOBI0cqc2fmlO`)FsO=#@`6zS8t;M1WHm%miP6{} zJfd+T0X41!z>#U$pm7L`Ju zuMt%I1lkt~(0-5V8mGEk+x8k=nP3oIV+p8hDFBYV{t#cRQhN1)NX|eUJj0Q-i~KhM zT>dq{EP%5F3juE5i%5z7Hj%7NW*l}0qwhK} zh`vPx)b~69A~^{9e7m6HOVB<(lUe7W>bgU9xshyYbj5-}bmbCI*DU}za;x{k3W!RT zNfIn5zJ`sV8?rW%KM|my9Ka9o7(iNEfY1v5mYjzhOFDl`(t>coV5DF~xRU<{C+*Vm zI%#=LQJQZ&^7cTtZ#uxA0O;D0CNiCs&qu!1$iDaxzy^R+04pm_`MNrMcOh#uvI-sq z;A7jle*+XM+fzm>+-$~nQopxlEdaA82H+^cB>3Skd+kC-bAE} z@+~D_EV9#(?ehR!OTMgR<-E&}}udB}4qr+se{(f?Dv3@H7 z7weA^aIwDLufm&Ngc2@+i@swhzXuY1X8`g5#E_6^6W&r9l4%T?icB$tubdD=-T@Fp zS}J?JDuz`54V*NjI{^(DMnFSm0O0WNLJ7W4Q1&V$6zm7E^TmWb)oC?FQXgZ&>y&0J zju9{x4SrV>#{Gv0`Ct$e<`B>XK9(&edtX;2{1IiZ+5-4^u6P~(2LQcJBw*mL0Kk#HxGApk;G*v-ls^ZF zz83%<0}w+RbucYpJJ{^MjUjJQ2gCm}0S#$(!&9s2gsxz_~^!;p1XjlPhn&2g%2_pd{7PJ1tgtg>kBm9hj zCWM{?pb4D-c;vp0;!9P2OEr^d7r#}G+Wiz+cE0CF{L7}?X@F^eBBNSgWDHL`06MgS zza_!ApdPdH3R>{rU|$FP>-rZQ?Fld#Abk+LDntRkG^A{2)};X9e*;_&PzvBL1CQ@| zP}TmSP3aNMacw}E^+-!Znr}0}1cG+}egp6qg2(qcsC0`p=r1EZ1N02gzB>WlB;ZR+ zFSl)+y;~r^6x0)-aOC~~T-eFfenJf79*@{3wxK(%_jxFpx8@+StJ*=kCi0c)r^L;3u1$?`p{IEq^)b zVkqncS~ko4sS4{DpYbjB29^6n3c)4&MCJixRb{QRXT%%U#n`4BW#ncqw5CV4#F>n~ z9Y(=VLX+=jfG}J{`pyBo2Oz#pQ~4tB+rKqf01@%63-+RjZ`_F^zU>3>lTCb!mMtCr zQqp1lu%ZfDd`s(U403%7zo^o;x!@At9tX&(%39U8OI1}>-^x+w9?pr^doUG%Cf{a& zhS&q)dk5e(0P$_3%15?>Z|^l2#fHUttAo4#;#&p*>unQ&pKRh=HMs%qA4K|dDC_`Q ze4Ep)if;#l>g`H!iEq4RpH-E$s&99xsw%!EJf!^rbEE2b*I+2RNmGQkw7V(!Ik%fM z;0(4SvL0u-$p8&;r_+-SkdL>`d4>VB$CYkcJV0m#e@lX~Zxm9l0E4dx-~hmonE(ZR zxJ|mrGJt`&`;|Vo71kLs$M>y9${k4YZ2)M5yEneA0DZ8YE#Y1kYiukBzuotu&v+Ta zaIXi0gu5Y@wI$ro0r<%#;jSesxBiIMpx=kW?w}>y!{e%idr(kQDgl>-`wf7ss;pJR zJz7;c;ht%FUV0%4ZI4R}Ujr}JaiGc98sH`@nEE;aEXO*Y_;y(3w}aol_oDR(hxitc zg(vatSpqhtE3s_iC!6@TNfuH3CrS5)!u_Ddx3V5pe0w6uw;U`Oh;KImWL0IY>f07o zRn@oTHgFQH#J3+oT?S3Q9{>&!oB}AtHMRJ5Nl#K?F*xydN8hmSk3pw%aS5@c^0k;JCHW*yu+hl;Os;pIg`&(62@hxGm_6J@< zOo0`-ei$$)-Z;`R1SvT1))QXT6(9@e)f@4T7p0zC0G`DqNZNd63{SfT|3WMHTM~?Y zOOY}HR|&pV09y&x0W`-{*!MC(5!wze-LXH}#jNA8JaTx%o^=R$49m z53S&D$$9v1Xbr94Z;3Ahxi(H@zFdGrf~x=?B^V3v3qZjXfRH5%=J;*{=!8>^?_PjA z2v!2r!~pGk65wru=K-=XEc&(q+y+qaJ^;s}Om3`9?_6p+ zwzXM!HCQi~;g8u&tiELN9FEf`U~NRAF>;alhmik@%W_YXR0NpjMFHG|anjQrU@bse zUjPX?{v+i0MaYBj-_VMX;};=E`XLAn$p!FTg`ch%mwaOZRuD`9_?zH1fZiAueD?y} zNU##%B*Bva>(Q%x&jVa?3BWdh`v3~w2XMoEL_OKXaKG7P6Wpjgk2ge5lTZ%;@ROx# zsC)J`5pY9&lIJpO_(oML5&arUCAtWpM0bvL+1oAy!Y|QX!RY3lf^ns)6tymgT^x;N z2~TJmt}AF!8-Sev85aRqxewxZmx>H@MJ7^Y4YI1^9-wDCz(|0!7Xd;m_*;@tp+YDg z8*lS^pk3sBh@41|ajK82>@+|`Z(PSuhSv{LM!-NGJwnV_f#$E^`;q=_FvgGdHHe!2E%*$sLL}Ms7vJnEr(s){3lowmI=F9L?eKu1d#v-0OW(fi&d(SW({ptlOpm# zU^L1Mev4T?2HcNLG{NDmEVmm}ZC4Hb+;U5xBrOS9sJ<-z8{LzU z-dHR5WAGMgN@ZAwah_WixcqK_Na*B|9ub9`d??$u9H~)hHeOw=hCVS}&QJO%8sEHv zN29pcY7*p9XZC;>$_XfkeInYk5X3O3$*P*^TaKI=$iZ>NxnVF$O}NnrBL<;Z=u8V6 zF8<-SBpCY#!O#q5$`7^-ZR?IY*)K1Zvfwd~zg$%}V&&4jmTJGemTDCWPM-@Ey^#_B zVj@J#MYLbKt?vOjB=k1Wfmqe|44!413!`wF4t_IDhGxHx>=h=P^YENej#y<{ph(kL zzn^NlyfLWSq_BLtBMS4=RQX z7ZhO)-K{KiD&Ob{aw_F7&DKvvIK^AJEn%dEcEh8+{33Y8??OXbS7h1w1%2dSRx@R) ztxTGILHZE#4v$h5 zs1#o~B(>fpW`Kpf;{jZj zFlF)8gYc8ckvLS*!a!d_~hHFWSso6po zgAUviWa_s6)6|Fm)70Fxh5AwL5QIme%xS8#a;XAH?4kqs`gKL{Yn zKC+gB@{zsCKmdxY2N>P~ClMaFV%~^y(Dd1!vb$+=jj{Opgr|~cpTjf9%1#a9fri{h z&>4vVh{uBJ@(-i$_6pb)jjSUm&eH>6Z4RvW0t^|zpM3s|;LmveOy|!X{8_@ENBFZA zKmL<+kn(dcg(7OKF$fMa*+*?tL5W5mHEsvxqt;D>0jRlJE&#PZLckL49s&uL;$ta) zf%37W8}ksCo754UzjmFijLS4l=A+}oZ?EL}U3q3Ac6SBwFz(wE()p=} zUCLC)=!CMT{=^U@AA>L)E%VW@9`EEZUG&Cs3tVrB=m96{5Zr!p%MygE9T8q z{0iXBRQ6b? zL&rz!k{Dsa8a~JB(SD8<6_1Ha))-~Gl;z-ve-x7rdy#nP9R{yHgF^c*p%;Me``$2I zqN-3SOmrAa*#w9)KYL*(J)F4Kr}W<}kcFv!bytn)5M(Oofi@fd@m z10E%2gGd55f)O54o`Z`l9@*I#vv{z*B@`*au%W41-i4Z=?M*l7+i~#cU52Mr{8_AA z^Id-u{)RvPp2ESmb{>RT#>_{>%u!dMnJ}R5s%Rvt#4bxe0Rttd+rc0~t$(Ekbr=99 zB+4(Yy`}_RYmO4DxV8|Zq3hb?N|+V_`wQYx;+OKJt4NHNJa9oO2fl*q+W)0|!tO;B z-s`niuEYt@DbXs%%5%>!u^%!npNQVL3-lg!^?o9HJ6r|5@&R8XaW&|aUjM51G;Fk^ z8uM~FSs7MJ%R+MTW*d4u$-=>B&{j}yH%hc?%%_FouLk{WqR`Z^40QZA%|N$r%xmn^ zq(`z_M>h_Q#F|Z^Z4JI=1TL>TH0DPx8h;KW*OUH&hIEzuBc#8s1-hHKcF8r6pJdtHC3hPsJiiz# z)VPu0ZHCrl#|eD^bbtB!VUNaq>PXgWIriMF@hN1ZN^CsdvT-X4=~kGZNiy@+m6G7>}s_ag{2i`o4{KK~RRax1rL{L@A)Y2R`B1CL}UCmkQPN zS{vUu!+DzrdIC>_xEIY=bUS6aQ+#jZVJJXe9G3$z?`Ac|d8yxQN7Bha1<7G2HD2aO z-bBf_&X=sdL{_MC)~g+B!OWoYjGM5>HO?eh7qKa_RWxLqZOHZ{KUQcM8+2@swg_-k z6E@ItEoVT88d5x@I-0b6Qzxp)?i8GfV2(EVCT#MV*MXL0q;{fV()FO_*+WB@i~;TQ zpajr;@lg}d@$!I1`z9Q6zZ{F!H3o|8Xpy%E$=7V^V6MX>85Y}dO&+R-IPz;Y{u?mx zp2hrzhkT(YlV7umSN0;Z_i4h{7s{7xUL^Z!WtT76WL}qq$$+w#lHJ#&4Se+Q^+P{` zy%H27C1V^?76YsyxE)~Pcs4%>`qqHzcO#}+F9M7p*bcCj-~)in2>@RK%p&*};01z{ z09Fyep8zWX(zz11ECeYta5eJ-v+e}A_$Hpg5h33)Q2C^aNR@&*1`0<~5$1n97RxU_ zYd|e^!O(jmKy!d`0RA${bpUlAsd7?1K{cHu(pi?qr&P80GLU&GGJUxKcL4Y!aI*AW z4QdUkWKuVP%ARb>$2-lk_d>7#}#;Dq_q(8t0b zBg5^kh8%8V#-Rb)pETr98}oj1;7<*fk@YjfFW;*Eydg)rnBrvce9@4jK$k=q7$eW2 ze%p|b8OO+TQ%3}Mh~`jzOnOy^Xn8^I&!UZj6J0^O5uXh{`y5_DNrg!}OoW=IZhfC$N`lp*Koz-Y32Jc2uD0 z&HJS{pCv85dB12Feluu^xS=OZ0WG~5G=ljQXw#byNN=t=6}0r`gCc(&Xz97V?xoJ*qrytROqTO!XbvuT*x^pE*FiuI#(Wezr+B zc25{v?9b_*IZ`F+bky${M)3UK`lfM)<+BG?FU)l7gl0bV88 z1yE-ez&>UH6nqaLyH|b(*n^a$>oBe7aYBBvvK|KhNoWQAX9LUum<`~M!0Fm|H>j6E zr6+^>wkGmdAf?6}-PaI>X*`cQs><%#NbW#;z#w;^rxH}hoM9zER#o;YH<7&ERh`}< z#g(#orO~X?IV?c-azCrq7r`LAVv5{?f4RO|tzS&nYnxgh$WrL~L;|`_oBd=F*Ow!iM?wQ_G92`|P-g}1*AB_k zK^6kR9KKy|Fusu#ct-7cs~mShB-7dLkSphmVKTkxV-K&6*NcbdbGxP4@ZkL}ND}iM z-6Qdz{8sEzPGcXFDep;@ecz0(7!2>Ki@{7zA&)iY%xDw*F@xdbGMjIHJ7}5BKQ0=k zgEq7ICuFwhy#utIURKL&ego*}YdD*KQs(bwF8@^JTz-wr<;Ts3n4EFeikhvU&0Kz+ z(C3&hbNQ!bF2CbW&@z{QM)J>+mbv`1Vpiq?Gnao(a*vY2Y<0a*H!cLP%;n33{tdL5 z%WpV;E+2<0VIJFA|C<^o)~TG!GfAe}DT^@GPEkhAhTg-SmYrGSXLP{0*I1>9x|s6JEX^2@81VA3&{kAsFE!E5I7?}@8LQ06Z} zhMCKMB(wMXk;v$LEY!=O5`NV3*hFX10h!A?Wz`a&VD#3;9nf54E`I`I-V!xN=knE; zlyc9A$U0fB?6$_&IIY2DcDV7ol zlwq*Ul`pS8!6$TxoL9T14U=GE?8>B)xZ{xVkzYq~oH!yKy4 z3=iS*3cqJa%Umg3G}O5Vw9J(Z{S;}LD}lyb=^$t`SE?ni1oYhtTINc%MZN^I%#}{5 zDWzz!aOquJi>MvbSAr8cF3`sWaAacmDN-cByGTh-hO*cO;3+}MUCRKT26!F7U&L}Yf~vP1@!)3o zW>^K{QAUebHrf;cv$$Jy7#QUIw3vYBCyMyVW@aT1P|iP>^qWxF3ACJFA5ewv`E^yJ z%8h1);F4*@Jb+$yU9C^fwtr8c+-j`cvvPePT?3$PEsAAw5?Ult8| zP(A!pwG2XzUD)VhL`FQk8Vus$g9P-DB7U-ohjmtnhmoWUpfC=!csTVc6S6vt8xDI^ zkcZcSOFUczkX4nns)zGbRaFm@9@dQCO%YaYv?SkHSn({>`lbLJ2Jp|Naq~d6d`P|h zRt3wDW6x@|5K$6u2ZKSpy_taCQp8U-@%9T)m`=oLlSUJl!*?H)pGBT{K16d}&ux3u1(9|O(|8v4q$&a;hUe(6Scv7UYQSMsK-;FUM$%qy&Bia;1!Hj6VWJGK9 zFlZUkdWi+x)DOe z@$6%;XAc-@Jggkg-cWYFb=J;mx{T}`&$^U={nRyv-Hc~tJ`AhMo=o<^P2Yo$p4X8+ z0_>IG2vW8(Wet1t=WpbCIxwl37SR zjYMAoK-VYP@X0$8)HS3|l9~W&2Pho=NZbwg%|k-lryzA7z*qqPASQF+qLkEPQfol< zStC+ts+%=nY^vX(S6gt^#drY*B4lHgao{|PJ!-UGZl2PXs`?9JhxUAZHJBas+zN!pjOx}Zdi+oKCPLi zU2r}4B~3X=_R^Z4lAUYD?}OdXM43Z|u7mJaW#uH*TVs^*ymFCQR-dq27G=GqoQ)l4 z9y8zRzL{#i)J$n?R_qt30sB{Zl~;u7-0g@JKjg;X*YMpb*m(~HmrN+4Kwm^6@oA^4 z{1(n>+MA@ewT8mq!}&4P3eZ^#R4eR~qrZH*^qer*gS_iBo86d0Pp!y{z!sauJ0bgH z#si;Jj&%1L=jP^4)$EUhMHIMOnoxU3^g@=)*CO=VNIT`R4NL+ZfJL z*O0!y2J(-@a0%@I=__d3cS0wXfxa~v^wF3}nE9519ypnyXxy>=wQw0n=GTaQz0rn< zj6>eBm`H@sa}4P;$j?OI8BjYQ?h7fz&EySaPpYFTaJNT}LWr5KYK3)Vq^<&+mv;|% zOr9a*Iqv?k_wkz9+e@?9nK0DLwMeXwbGnJqluy3Si2h*yp)Vb3fx3`xH!+%Zy9_0m zx}6x!x{ZAvwAAgSXx8l$q@`{rMPGpcH+=!L#D9{M@H}W!0h6Oy0exR|D&Xem^DAIV zG%H{p@=XOyjb;VBMp^`lqSG@JDBdHlvoc_E+^J=pe~jVH`vXk zCB}_0*49Te;(lV_FZhslH#JYv_gR`V1)-9wT4Sxl6=EYED z@;8x|e$`SsO3Fs`Bk5NywJ%tvr?k|b5@vdelN(_ws+IJV_aJO~O6w{;rH%BIi#9nG zb+Po69MaNLBBf{CPFgCit@MoVL7R%piOCxqRB<^Pm$|IC=$O6;ic}m8@H0^=uJ)^1 zaaRJM;`*ryr)S&(F;j6V;_H+DkFhHcu(AC9?>l2J8I`56jhQh^)))rk&YfX4bH|uH zB1VOhtw`1}%2JXD5hH7sqGbPyh)6}I6z!B&RMO_F#qaYu&w20Mxud?n`^U^V&sm;x z&U2paU7iqbd1;ob=88TT3!UorpCS~oUEbfvZKjX0Tz zr;Jd8X{~!B*fSn{8Mw68&W_x{2{06S1q2#-9}?vryvyCombAGWSw8zP_r!Y$Lxb5HsFiS3~31k4-l6raZw1rtNlE1J{|M4P=5iIzDX{H&Z ztlZV!r`)T{Tp{iBJ3O?vbYbYSle1-inF$S)7YT~wV9Xf!(6{jEv^W*t87S{UpeDDXjIHEU4ib9nsQ$^7u%D=F$U<3*x`AbkS5|rK>f!@N&gZeKMM{?^M!)Q`gsS-1)dLWg$F80sK%M&m zxV9?0dF+bMs$-E4Vp=^m$+unVG{wKH?p!bjXk{Iopq}m00PcvPUqM&8KZ6+E=uPya z1}aLUD?tX?YbRK)jy~qg^BO3`j@&6u(TaG5^}GaZD3r+u1qZ8Sb;p(;yGY}{1%`}~ zN|dmJA*mD&t!LzUTQ$v9I|z||3vaz#yw8Mhk(eaUUc_1&5O#82eUbLLew1OfaKF_q z?edG`b`NMtW}&$H0I&?b3vNmK?DcUFs`yx3M^)8^s^04o7pCp=JcOlv-Y3BJ`7Z!h zp0fM2k66^kX=bV!_R1<2ov3J$bJv}RE862-M;(jCLs%?Y zO@J012H@(a>ijL5>1d{!p|1KEbHt)^5K7+XSaictSoDOlibdCrsgT3VlzxG#M!Nb_ z6?3>dgvFv!1ZdGh0IqGy?qgAg(>LWaigncFMMyuZb@Lmb^(7aF$~Ic}cTO6W)QP}Q zCqv~+E)JEuP=OgLUvhD%yhvPz%FQkgl{dfb42_#z918CMZiYsKze>6cjhm&$kYgAs zWo+EyGGim2wWL8?gv_B*#zqGXGGn8I);DA0R%H%JlTmt`t7RBBG^It|&-b;g$`6`| zavJ5&-tT&%8J_U}FK9UCx1N%B;5`*iBYb4g^SDOhk-2#M8O$J5n!8Ef4km-^veG#V z3vH*qIlPbm`94ucyO-Q<>&-iJILo>6+`~olD*>ujX|5$eP_?;7isswZt^}jBJ|-^w z3qdEtzbM(CM+%h07RiIo^42Df@gbKdSveP>db!eHH7$tLD!3W;1op$z zG4BJY1>h`!1^`|?fm;oc0PF&HJNyef2@hQWZUfM#JAgLhOmoSAyj69Fw1Y%!X!B^O z;eb2`+{rAIDWd)dm<@L;D~G=uzz0*MkKL~NyjPZ3is>s0((&MP=b+NX&|t|2e}k31 zm^CJcj%JNq;FN;H)l7+cKT%eRvNUpx#x_NMc6#Uwj^xjj?06N)_#`cKhLl!}8>1Bc zAppj$2LVQM1AugY{#*t!mto9h2>UU7iM>>*_r0!``pIhaK)(2ay@I)1Xt^9;ug1!O z1fK+9tU68VhFIhjaAY2-+B*iSqb0emFcweeoMJdG!P54->U!~8KEggr2GraFXFxTd zIm|0~8vCe8pvSC)I=n8&vHl40n0Vj?1zSNM@iB0D0N~aF-V1$;_!}{x_Y(fjpFscg z!N7YLaLZx$jgc+-Z9*Lhs`;3CAF=-na-R(W+wDTf9j~G^nR)sNJ#g;MqErs|*N-=8 zxQTf%wxFmv8iGT8{ZG-FizgbQ4)%Bif~Ocr#;#Vm)0A6V@CN0Wu`b9Zvrsa2FtCjE z$|@7~6jf;!ok>A(aC8gU{#X?BY%5rS_4uC<;;L=CSf2VBJdr1UcNBb@$cbuSQE~#r z%&qj@1)K=igQ)|)Y_dnNBfxrBonUOo&5NQc@u-4Zr@4>7f!;TGNsEfA+-gXeeeg9e zC9qG)A?{U2S$KDV2OwD8w<9XIDg&0c^0PlI;MpBiVDkO{tRR@qmggIl;WDI+$e_iUvaT$(h2wacJzREV<6#LVb*CTTkUcPz*|bTyuhGfc zF8QbpI=d|F28MEB*9$hbe*k+Kdr&Bci?*Kwe=tOFcFre>x5EAcbawXMUtnQ3bl`9Y zuX+ab6mF6R3w;N0Gg#am%E4mxm%wFkxF?i@!(YT@a2OKG!6Ei5;6HFreQ)R#wA%sT zrjrZ}bsmdPT8_l{xiuJf!9shcxYqV-)4-1jHW^s_j!CAYbkepsND+DOWUes11*Xi` zl<6@L89;L>6PGGoUnqs+BO3{ieVd-f<4ZWOqIu*7B9?g0vsCPCR^||uJms(Rwg;7h zbse*bDW6mdZw{atVq_FsCSkX~aZFt|u4*&(i=xTHZ_q>ZFumZV|Sx4)HTF8I@jI(kd*fFSy80HJzrk@%Vz&~U61#%{T)!&2iJiRaXk|J& z{sTd@B6@GO<*7E=Gz`OZQV9C87DvR)Sf!r#6-m}YM!yCEz>JWd%e;u~r&K4dIsN+K zrl%Ix@kVYK1aoJA)NKO(RJqK*%esvan17eK=BSK!1?+vzt`0i9ZTIB0*yYNU;vE_G z#300BybEae5a z0iK4D(6R%iLOa)7qPn@~t5ZzmWcJ;uc7(JCXXT!~+TjsS&c21oERm@<;Cn07YTPr0QIBJ|CqOcprEa##a$p%Vm3I$J&Df*%G2v+! zuOOXPh7beg1T5JZr}JL-2O^g>2@dZ!R<^=8j2LL@CcoB8x3&=|?50olx_j0?aepYF(JJ}n?F`EzGB z6ZR+IskyhAr)6157Na*I`wmnSSBUb=pL~I#D4B{9%hUKF({%Hv;Z;#E(|q(dSBjRi zLz%IeqrCY96Gy{dyg=XjPfRBE6y&i*KVsaj`guF1EbrxHu(; zF3uz_E-fF7h6AUOfII2B{|8cMqGRb3}paad=Dj-=QAG{ZwIsE zVinc%&n{vY(7GyA*kg0)VzCOiP5r2RN37%G*j&0;;}_tgIA4#=<)x!1ftzL=mrEbt zA};UdjTijJUo|8Xav74RfSM3Y%w-6w|K@~XQZ7T#0yvj#MY$Y9mIISEkDh7_+Qfh? z$}NCV5{HvuC<7Rfkl(?XIv;&;q{^J8%(C3ElzA5A^U2{kte!F}=7EHeRi3+>pB;C7 zQ9f#>n7P3>Z+ZocfnlvfuYuCF60?0;Pg%^GbaG<0R${gTHA-5nlNh)!IU!pwAsRzm z(&9OZ$p+$*7SBses{I#uX(Lp)LFg-p%Urin3^)l~qIBal6Q!V7@b1l>*inNMa@iMP zlnPLSPhY6zjKO>`Gi~6V$5K5^n>|v_b#Phl;D(|Xt_^u^S4Q@Ok5qxIHuyaHP9-vf zE_#WGyq0smsewqbR!o_$544=)hL%~ao5D_eY(7)Nnr^%s4Uj*adjM%OV~x${jI|wJ z$&58NpSf1&50E7l$K^Ad1`xl(Rmr&gDj|3%8@P%4_GQEBaYKr7Fbg_wI#DurnLzu%J@=wWm;=E!!(9YYps*f_3aPDwGbr* z84kF1Bo3wrb6fnOxb_m%8P`4(<2qddzO$Lo>FTS*B@~9gyM;Hwr>I&sdMXr}WHn*7 zJWnZ=QM}iWY7*D-yyv6gQ9mBb^OKK;4N5h+j0Ti%>$<`pF)pzZlcA{IzD3Da>n*rk zYCkW}Vzp7$5pah;yX3Dfa7ymmK40}@BEB^Rr`nAieZM17$qvw`yEe$vU9*6jr@J=# zKHb$t6^~?#y;!vmw93<60RdQS%vPd#x{K?UG%Z<9_Lr(2B|95=0N7>yvJ^lvsnXEr zfq8OOh7J8Z1WcqY*HSHKo98n@xQ)%HHdzt#pv3+-AzZnT5c0FPm`A_*1j4|fO4LWc zCUJq)Uv6|SSIT>iSP9Q!GXd)_H@fFTLHo<-J9c3Rv*b78f%MDZy($Ihjqm|-BYYR} zgNU?!M+gs=s8<>IPYr?JDfmOc(>p$DniM@leldeMwT+Pqex$%_6nHSCPE#CbTqVFt zomq&tQ&p&xm5&ek0EYH|7Ue;4OYk=vY?iCH@-X+2Am&y$Ue2u688T0qbK~xc$4ds1 z5>GW{N|-a`p7J?EZlRnZ7oNz$f1wDO^W+x!oG16R?|E`7ea@3xrRT|org2f<)71Hj zx6YnEb!M45Wq8RF70s~2&o-JPB_?@B^B3{Zm9Lsxujj_UR5TZ>!#m+Ue|E`F2~Go+ zN>y_Z7&C&Eims%pz~ym~cf`###2eOx=sQi*kUp)d0T+n!#sR4J7XIymB{0QiEy z0|4T$LoH-;KMia4x761Z*05k>Q0+7L%aQHikPK;mIZXo=jWiFQBXYXv9l7({l)2%NcJ2%~* z$$dA<$3vx95jD%G#U&>B*`tgVU$Amo(Xh5!(HlTUOJ!FpAd<5g<3)lNFLSh%@Wi&b z10c<({4oGku17pR2Jkq6ZvY$sQ1CMVyI(5DwmGULgiG`}Jy%f$N261+|qYLnqitA&g$mm8jrX0`faVz8uAbq9H@!$^0cx)>5WCBZg8YFNC&95 z5rFn}5Q1m`YYDUm@F{?TL;xC#@W)NN%%Odrp4+?PJ|~^1JjzOIyiB4IQ5Vr5U82zs zm?uW17>yE$z{cvMaLUXmE0m`^3|F#mNYWa^P6>%ysimy4rwPd}XqAwBNq`}#Ru3WR zt*jc7YbTIhZ&!yAZ0*zTuT5i0O-~UK$Xk< zyUZ6(vM}P#gorx@q_Fxh=LJ=1#%4WSt1~;!sB((NicO_A?}e-_C5fKHvyOgU^{^L4l051U4E?{{^r5Tb{7E( zE(KtDf*k=kGyu$I0g86h1^TFJau+%%pK;)_+SArYVqSTPD6U*aAt`a+x}!=&S)QRP zF>^7V7V}D2uCYGlre17>X22?YLk+H2iZnz*7`XLHhnc|Rr)f3QO)b{7DOh~N?x)1kKfpq}7Yf$4G3>57r<~n#VOXwNJ+Fj9X5iEs zxlkm7%{`Ekp7kUF_N+IlXP2`3Jo6!HUeWS7R5QKCVn@yQj+%N+R83C+uJFK-=AoV)9e-L& z>#I<0*yy$gpj$!6^^H<5WAufKW)Yn+TuWab6ky%DR1uyo84F=Ywd;x!YTfH2+j{d& zaG|i~8CVqbq=`3{L-MmrUg++0#=@HHjAvkj*<}r=$?iKm9JnmU28f2X&49~mN(Mhe zTn_6RP?KG2cmz6v91n6w%|)o=Z{l$Yu;9*`yt6YR5=$Hl@6N2)zcuD zPZJLlylxbNF-PrX_hfsIvGUnya(^W$0b1_$YMEJ+M|X6Bl+p5-;3KHz)W2v+o&zn$ zjtMn+V#t$T4HE@FObu=3nSfo*4y$!bj7j!V2~UHqaB6zG6X5j{&~M2o z=cqgc0sp7{>$q&l>c(Ojpe_- z-KO&2?YVRCuX`i>NmCV79oxSM`Y-BF=?Gd%EBrBR>-^c?4+_bs$adVH?Ql@)RoKFw zvZXq2r7s5!zY1HfKidmI3$DUe?9aA3X!ljvw)nFx4mxucwsZb$bAoF0sOV|^g?=tf z54z95S+xS7A%@ zXG;%ikXbPx_xZCW1a-X%8{ZA)&)f7Jg6_Er+o%3)ErRA;g{}V6e%eBVc3g!m)}O6G z&}Ua+8=`D=#X|Ix8-psNKl${9uIw^P{I%5x@?o)ZmV)Pk^5i(GN*;oyxEDY=i@qMW z3qXg~01g3o2ta1YVq17egU^{fGumn)$9StX-yOA+qA_t>SxV6Uh9PH2o-?K=MRU@8 z8A{ENlN8NK^GaK1$VraowA-x%Ru%mAK(VUYhcVF}9bG32cJea=n>xX~Pyl}t;HL=E zItN$@UoA0q@&gD~DnF4jM-^P4g0$%2RB$~W>zWUC`98`~0{mi1mAC*aalb0yS8B{+ z0?&=fIwYS`yi|ulhhJS-r;5E>_z}@>P&q%c;D##s?7~aIHa2Ld1Ku-x_u5*hrq^j)W|P~gvSG@2H~Nte_%_cn})-7^rm5;MrP!39YB<6s`>7B>jxi~1m<4v=y`O5{)6Oh8|dRs9l#*~Z2@3J-RnVz)9UxJ`VWE!6`=Z0 zQ2s1fygkYdjMPl@C<=U2*`T`f&etZ#^2o# zz^woZq5$wXpYHrdUfX3RR^Fj(*G*5*Vz%sQa7(=6vH6#H4FHhtFXA7s1XZc=sx%kp zVCgsW0O>dLu2&}cX5Ko~h=C+vGQQ>(;w6|5=$VsLkXkpO_xDudNXGVPa8hqr+6LuQ zX`ln7bU}&yiOU1@Hfd=9stg4X4j>yqGF7+>fz1Hs9tz+&0%HOEOkgU2mcszd0Wc8& zOjr-_2Q^_iO*j_3{5F_y2<1P5#S5goixT-0cNWm#;h=p6;39!t00xYJ2~^?!4cH!F z?f^7h>yZGi12C6BFo1gZ0f+!FjzC)gCkVs?XnQ|^bO84dC;;#{fPy;!c$;_6a=+#s zf75VU%;v2>3dZo1mN5j_9i9e|?l0osyl<(>e{J5C$|TJ@12wXFC*fU=O{c7;{v^E2@-89kxQhK2z?k@bfh~n6DD#uDj;i7o=wV*UxVO+1~D0@A) zX&)%t30j@e7~@|95Lb#n9f4Wh?*r6YWxV&4UkjcKnUvXNU5r0{z#8`ufFc0hPj~?qQa+{yqkkPs7p2rxe!d@Wf3)#Tl5Z3tdQZCu>HOKtq7nk?*prM8!qT^IHm2OphJgMFVeUF)>in&9Kq z`5b7?$3W+H>fDb%nZV3W;3t1OmIg=O4jJwQ?xPHM00gnaGgU*!C zK#MzzKkq|T+`9lS0gxW>kcw1u!j)EkBF$hAXf>7@>2Q?K$nK9p%MP`hbU?Ay{W~mJPpNQqr{>AQFH!h1 zXuZLeQiU?tu~r*XA-njU1hq*&5n)Zf(Np`#jI}){xlem`ep-&2M`;k>@w~`q1*?12WVa6KnRBZHq{eV0IstAuKX zLPOknU{3&uyoT9$t|^PrxSs>N|jx=(-n1g0{azZ@_O7ScnWl;6j0S2`12rC#iavS z3?TN})h3DjJm#)EN=aT#`N7AiiTi8Wk(W{vcjQ0Qy3We3J94#7W>0RzGn9P2(-J*{ zue}q#a`zoQ35pybh1+o1f@h%EY{BnSVedeY5u5QW4`C^6(&a9zi)twax<*wS*3ET|7Hd1 zCragZ|Jw@G^GfCZzsgxGB)#)L16`IiBfqDp{N4& zv{HGQv!nv`vJaJ?2Pw;(q7Zp>03|utZ{nQB)y4*1ocK)jARk<*TCSHQWSx@p)17#- zTbD5IkL9|%5S`2XyR2J)!2DYdb_b*6x*{yCBLE~3Xba#Ffp`F+lL4dy zSW2J(K<8orcK`^Q5@7Wk4j?JWjRA2GZpKakwjRauUPiSw#)~Xa?KeWd8Hl9iyC`Hx zW}&>7aSE8Hrn2(2lXt);$95o-ELZVbql9m4n1I1Od0^&Ir4&>B(NMXqU*{oYCZ8ed zNPxHX`vPz+R#xwAeTEy_`H~8x0}w0sqcD9knB5BitR%1kz&QX(RsuFJbngX}#5@dp zm#DoZ*p|)$1(xaiZIb@HYG8RbDN{JMW*ZEXoE6SqFd3uo4@#$7z%9=MTELCy2_rzQ zmgilyKM#Zpj;5VB$~m_4Iujl>07_z2$q?|~1jj((v*q2jcruD_F~wqJe=VnKk14M- zm#Q-xXr+awR4mDKY2j#7$PCQ9Q_CJHE6ey&%YH_HVr!KdDJk3fE3BvOd11rgbb`{_ zR|bNgT{3$puARwaob$p?CZbUgaC47fepqrSX78!MOPYaoei(0@KLOl4$G9Mj*V^h$ z11@h3KNYqDcea-hKLPdj!Z5xgjeB#g?ium!Hqc_G(5+=*Jd*1(;_G68 zFBjQCGl5TS2YiL#RUZT14A-FTm4eSBem~Y2_A0>}%>pj(Hmnx?gNeUe3-o6N{}^}& zd7X5P@DF|*^y`v9Un}?xv+)$PyfeKn>{G;+JLnjBPjG!0UsqiQdW^g$_?+;!e*(C? zC-}VJtAY1;_ZsNy6Q1-xmXb1l6V_}1x3Tw^9wE%wxsr&^{T%CO?N5%R@Bda@~VN6q6O`{bT0mJrFEsvCG z_N0zOuMyxl6h05?@>N71+;fgXkp~%7cl-tAVJh*LdM}s|Rd6N5@Ps-;R0_%Xtm_nUjy_L2@4Rf#qvUZIH1R)Xc(R$o9DZxC{RWXd7cFh1aBe)wKTHkYz}{bljOJ$&U8?+$5s z0-CCS_z#rh$+}}9moZW0H4hdfzkuNqN zcPvkVrX?@d-!9U8qnNkgib}0~&XgFI^ErFU3%i!<2^G*cnnC^73am~8!r;Q-aE^1u znx{Wt;Nj0M@r-oFxxwKa=a#}hGtS)|&T+2C0%x4NJDlU(U%<^ccTYISxoJ-Umsj+M zg!2{smx;?bcW*eyIoCqqGR_SR=Qvkw5pWsjhJ|ySyY^||GR_Sb`W?h&oEsr{z+z`y z8yQ|UuH7fzJP4W@$L<&2m?gkv92+J0S>iH|jTSrv3llSrJs@}iaT&+Ph`w#aWgL4@ z@E?Giacr#cKd}@z-o6ZB2PM3M)QZ3*WI4EsRHJfPX zNf*=$acZ1%4ivjEKDQ#Bx5Fk|`Vl*CFnW?%RF&(z6U%kpp(@~XUg_!oT!GcP9R_y0 zo{X|1wYhMoL4J10z4tqvx1KCga^aily!B;~vW2)TQtHbh#kC44DUa^nB#V^&#HI5E z%fxz#xOBb-f)85_Towuq1^pnCtyUZKw(74ZR zF`TB$FpEo--RcVV*svXBX9m-L$>8Yqh-r6@`%X2HCdT;OYS>w_Gj*ncD`T+QVNxeb zF`mG2BU+;@b(khxfy;x~SP}13PNqt_aOPFUx(A1c+1XXN)(y)tqrE1K+~9Rx^wIC= z_R(tP93O~#N9r&J0Zoj7qhRs{ke-9daeo51_BjC623gh=0NuVsNtMg|yUZ7M-w1}^ zz~Bx6Q2acA769G^5Z`gDiE1USqy?(z#wse|QITccScjd{pEX!1R4jke{iSkQLoT)F zQZw$7Ra3p|O3a7!;3ZtoK~Ite33d&M?R;32jLE$d0S*@c zSVrIu05@-hKf?iR1CW$}T=<+}B2VE9$}^P!#rFV6CQmLU5_n!Sf3y5Gt`=tbq{->2`59RT*OWY5j^U4QlUrOKyX@5hF=GA&5QS>74C7ioAi-tFW zn=_QQ2wry+IvXFOPrxq0ng%TUu7QK_=BQ8u=JraP!gSw}z>2B|F7MV%DmDi;98DO! z&3KeFl7SeF<=qAjHLr^FAJFEyLpc~|<{op|9G>B+r=$h<23Sp@-n0sjzd_q&BcrPa zx;_t(`jG!+m2>ekx0jU>uJX6w7HjMhMOX*7!`D2EKRu!K+PMI1D`x@>SguU1L@A0( z-ULV7BOoQcgp8gKpvqdMO23rcth4)7kC$l)0OugP#t;YU*=+4-t zMZ4gdl`~*4Mh`8S<*j=07*u^fNO7ByQbh_Rl|t`eklc@(Uw<*FnVP}u`9JK&DA^C|(1Giu=;ZMn> zjrip}i~ofxc8?S>l*1o{Kiffi48rdH0L}u4->i(z^jp_q>%A3q_)~K!=XynDyq)1U z>B*?dGh9hu!O2!orG8{QuI1dNXDn2N9($H4@)?jqABl}V5?0PJ)LW`0zj%FGI~G2j z2WcXVjk^TkCji|}1E_MDf0y~f?n-xKfY^qd3F(IC9Z;9MHcFmGi4~u|!?ezLRXzo( zyHTTkdkQtlAF1mS_|yH_MR(qIILDLC`4i{vR^&3m;etkXE?%%1tL1E}d?}Y#=`$8+ zxrFIiA5F3Q6=6WJx`K}L8V>4sT6I8oMzW6%t92??b#_DP@TE#Xr;wjrGHIMMJT;Wz zX(=2qFM1k@W;^hzvkW+mM8jg>?Z0RNjg1nxQ3&0M1`OP39A<(gLZMiQHCuim}nDpS*dMd}EXMmBzz@mrdWm~S6O7~{jB{THoq27JCL~RFjce*8&y?~T2T$U z+$TX?4PEXt06rq{BY?jEWNcP`4$Yp=6k$7jKi=uG%v4#p;zqUQIF~3~L9sy!z!DrE1uvS%XYO zMp2HO=h7NCv+VYgh9Rn;Y#%s5Mh&rm$@V!81o|r=<^y!C$x&d;KosAxV=Mq@F%5 zC#wwl>aC?dy822vF6 zCw5G*j1F3GH-tQc6d46%v1q_ye5u}L2tTi!dGpIAE-!d%urlMcY`>Oa4H7$4%S;2J zUw_>d9<39Pij_9m8{$a-%~Ecigt*Q=q}ZMiuf$B?F@L#$uNMs`h)W7SCwTI!Cgjg| zM!H|9V%?GiuCd=rD7Oe7YEX&rsj3j2+4)o%(A< zm_hrEh<9zru8FMl{GvSU)Tfn)i7e|sPtD!Nb#|>wUJaHfQp@L~1sWnIWzB3l0op8c zhVr!W(yh$RT9%|`Xo1ZATGq>l?~IlWE#r&5tYxf=InnyM_K5Rw>66wTW9O6JmKr?8 zX{qBf7}P)D3KnV% z3@D)g>?!7@Vd+voDhs>R^U7j+9Y;_(RW|n8S4?c2@OfM+#HIaTM#v1cWlQ^9%_~{j zJ04*ir@K~0x+;)9IbIR=$ySIx?5ofx)76BoLg&C>W!|P`1zLujjD5_rK7>O8F^ ztU%>wmptrseywRQSY@VZBVixGYXj$1jE$>-Mn;+Z#GZ50530^;o!tR-EtR@1RH*Am zZ(U2JuFlYH>M|0eSl6HbURNn!>XBdT8_|&VJgLjtXBxH4uRc?qMx7^hZSdA*B)(!@ z*Q(e*_;vb%w=Q>6)U`qC3aU`o>)yIHNL`JOI(`|6TY)Dw{P()%{OYZ1B{tjkN~tTP zLS5~qIex8_y5@N6G7@jFt``4ZR|vY9`L!O;p14TrYEz-EW!}0LNnHVNJAN67IN*t0 z{=F{e#CmkX(agiyQddHSx~`e-_%&PV8ttviNNi+X8UJ2a2*zafYaNCbyGkOLW?3qP z$u&#@LdlJd^=$Wen0d$prG0BAh@* zh=z(2$V}Dnu(t*)bBUHM)G{n7VvqRL1l-DLf-U}OEiAhl!UMPB+JMyb9b7r+0$?uy zcN&080OBL}n+Q3VMLIbAiSH`^cmV1CY`Ik6YNx{9S)uIu$ggS%ua9IxCj){NO-5xE zk&S;XMdT7fJwa>7Ra6dwAq93e47tdWR14qO&mH;IPPz++^m z-XP`9-nex{Tz2RUQ<&@x-$UxlF1?Z9j{%SQBmx#RPGRm|CO(MIEHp{s<%e$X;~4`v zi@B-j51cz^a`wm(qbxgA@kNu<#=>+vO!4KD)9S!bJ6!Y!&RsV-O}=H)OzE2@r^&}m zA{2L)c9ALcwR&KoF6}%~2TT;Wf*Lf_nW)NL94+)+K{tPm8l6pAJdT#eA=8037AZr9&(I3`lqm|CI$aqwd|E>Y@ zv?BKm!8ou^ks=^xjGF3!AsOZ(vgHYQ%{a-=Z?%N~lC1T;%THN5^y0MuxWTO+yx{T_ zPT*`kxFCN+Xm1QpB>}Y~DJ+xfXexMIxE)esZ^>Tr@iq*P~8|~KI!%Qqz#>$eT zC@%RLj3yJCdzgvikQpWujl^c+l8G%u!#UuI(^L(630&ifu56*fr5-LcO=}MIo>bOq zkDP@IO_J`OR8|r$ySoe_hKq6oM@q_OrZQzCCEa_b&Oo|Hnq#w5c}qP~(l$qABX=i4 zdu}SbK%}H&o++Qw73KM_Y`>Ke^$Y*^1oNXo%mlp&~kdxXIdkB(t^jGmMGVgM*8+7M^LUQ zrO7p=EJ;A#bGV?&B=4&pH1UvBud4`C{cWiRb4+n}C)Fn?nW-Lz;Q6IGZ&UU1>0ziA zMNE5adXe^mI9X2uv)*MLG6pc~b)ZK|gr2XB*fz*wde}2im&v0BSv;k;8P8d6n8j02 zBhQ9_p-~nO=QYNmg`{17h~0rd-wrGev}DSOeUrrLAt&Yu~$FD^ORr;KxA=4oT5nD)6Si->GU;s2UytkC9Maz)4i*7gV9 zdLrb!>d0V3#*UQ3sUs_Q0vsg=QAZBA25_{2rJkF!B^**ub5Ul6t_la!ik_Tb?Ca(@ zJ${9ptR60!SIRNz;o|p7IU?N(y|yOUTjxoeCQ(YphSqs(Q`3-b@}wa}>Xtmyc;~T& zu;Wa$p7Tn@nP^G#cQG**FI*;C;zhiH<=jWN;SrA#d?J@9imlMMc(LT5oP=$Up6l3l zP!7J1%xMDRp&Ys!c`u&rv0s-HuOri3fDap3;`4?mXx*2>DJ9i%r6eL!%xxkkL`P0zK8DCS$%d<`a79E;A>md-5MO%<%w+$KbN>O;Hl_4L zM&kpfZAAG2(>9G;g7GzhBVV}z@IeF1ftZH`j)+{F0Kz*xhhsQ~?nAsfy3^?Xfx4xo zc53^cV!BQ<`Id)EO{RUPnS48#2;y{;Z*orQ44>S4#3%P2^~t@NKDqap=HC5mj6ueR zMXW{q8)W>GMgAb;pV&57Y>S9I&Ws(}^A6)j3;eT>8cW~yT6)x{XS{8!6CKCIA}e$+ zgTB$!e92q$MxU&IL29-_2XIC_Z}j(@=S1SX(JwZB@8kUsKHmT6jj5%|e8-nHKDDehwTNHq3@mY5FPg2;;hZP?nz*&025GUrJ}uT)_i0(!!^JkY-+JODfYLIUG5Oek>05Kooz7!j@qcR62gK<~h9}B=a0_Bsykjz5& z1Ylc$xn}@4Nnjp;njZsL2A}{y!Sew4g>v@}0JBgc2c4H5HZx)tb>E*ekh=K^fEU3~ z2JoQsODM6r^RofxR0h+a{OqwgOC7mZpQxMwl*>j5ZpFWD>fy28d%?^#Yqh3wcLo!= z-PZDqR;>))N#T$O6I}bXTupJZv4y^fSh|2c>dJ_0AfN20y z*(b-Tf{|3PE9Wcv5r*=&!4OvuK&4YyyYfI*hjTeOZ|^AwunHHCWF=QJDY-n3HJ3-R z=JFU;*Om{ABRt5Ki!^h6ofkk6NVd;nHK3GgU&*f@nIij>f|(kS|hRv93mqCWqN(-$b_rR1F>yF1&7E8K$)|Ykq1*h`pDGd zT&u7na%NMGkM)Io1vx&LdK&;^*0;(Yl7=dxa`rn_%pogVOaNAK-YfH`%4AU{I_Eb> zCiH8S5kOo)iREdb;bO;Yh_++u_rz5$pCJNYP)PFO>Z)9w%X48<{2%4w5OkYxnIUMa z+Qf2ZBrjuGsay{fY7mQQ?F)I+mLM4GQ9c{CC9}}I4cKeI+^+(-3?P+jfYmCuiE^K3 zM^o+`%Da67FM0IhH~^h_z_Y`7nw&58lmnfG>i~%4N+u+&`) zgGTQV+lk0$~82BhVT^mG98C;s8k3N(FEyN>aJZoB5V;EK77} z&n$uNNhqHVhPe9x93wCgK>f22;V9&Y6jS8xp2I1^qo9S8BM~{1N%bFzj{WmUl>W3D z;=Enyo{2gKKoc@!972|J#2C7XwZ5AD3TvH?@~L1c1D-_5S_(-wE>fA(lzA=tB4yYP zpHjvPutEBtb7W?zOi(&x4rWI%*koM*jxvBUKY3-IRhcZx9Lm1Uk%>I7G6GQMc9h^_ z+v+PDegc@ww|hIwV-@Uw8Rhd(b21CvuLG;| zJyPR1fR_lI0?_UU0OtU#0g!Y7jKfyo8Jig7*^eY80Py^XJjwvTJWAzGE9t0dl>`rJ zi^`2!hT3>C?DOD^n+xEY3jn487z`kpZ0_~IUI*sh1|ae$6lbBhU_UUsw;Z4T?1x5c zF|{7=`NcEP$|J)c2D2O({wk$Nl>@`S1m-!WGCVN+Fa$7eRhneog0sTseQdOqofR(S znBVy7(H|*lWu5cZ;ystiT*s@Z&PaFTXse=bI*_pZN zjKk+B-vT+@uSDs^<%ni)6b1bZ*9QXV4M5Vg%P}KdNZ}#5Pg9sF_XHTq0H#muFHV|f zs>~e9+?#vUk(mMxkr9A0fxkL3x2sGkWrpV3ut-=tfujtd%*$SxK`Il}12V&M+dDFq zep49%C{u_MsUs8cyVfHBWjdk+_qa9S z>_W%DjOM<+`js{hTJ!BT(NVTl_lCB?VSLoiEE;1hS8J`o8Eq>}SH}28pP0tjM?-RR zBhU#XHp3l51fU_S#gI1I1E{tam@66*6CBpi*O2yVx^Lf2x`66hp|86CL>K%Bn%&iq zBHb^c!`%o#Ivm$(eRT*;$b@;9a}GM@?F6UTDFDs;0VT$zdsU{GGJoX!*O3YTugVBO zncGmJZKyK)C}ZcgT&ZE0=%I5K}aG6GPh?PaH)G1@spdP3&! zoCS`|-QW;^1fa|_l##i1n#xp{{s*}$IY%A2_Z&F^DEB+%JkOjo&B|u_8O&VPRLB6& zb|0>r&>C0ea)qm(z73e11qTWue4A>DGm6o*hPfj-60=(e|Dmo4Kohf2V!0BP-&ZYK zgBRQ8Xzp&JswH_}u7;|7luw6XG7H@Ufb9n69tPkP0Um=M^(TO70PX`&Fc*NV0G0w+ zj}jSu;@>fmIZfRYvg%Pc%{&5zGJs}g{^hh$B~%|4v`UnGN-*V163xA zGLy0z(YKB5#X`{ZXY$SZmlL1+TnLog-XpTXT6lxIP4#{&2SfTZP4)q_iTMo(hi zUDU&1UI9}XKqo`5u+7)1j2V=Cx8S_Cd_k$j4B7a+K5L=v36v*8HkpO)CBS9_bFT$( zj=&ZGsaBv>uor-|_FDi}p(K@;kHBWKrhU?AIKb+rS|*0#IhVS0-L%=1`_r_9aK=ydxukv`HZ9@q}oI*d~n; zawc9}`6U{5KplO!k_}ftwch2~aED~0vXx7_RNi?gRI~QctkHQ%>*0PR%6q|xWEQ&H z0b2pg?FNuu34jN{8UO{i0+7bN6Tnv}k%(?lmH2#%W&e=%1@nc0tX5g0BLF?!gc7Vv zz;}5aCY_Pc@->P?OVE3!T}Dz%&Fm;Jh?a&`REq%A@(fCh%uOn@oHEyC_jP3cbYuje zOs}erOp3~sQl?J!97kpaIHW=WD07lBvSD7PGS@nNtV;G?%5lS7vl`^&O-=w z4BxCAR?gx)DfM1x z62Q#X?^wR;V}!U{H8Zt(375J0u|Uhsn19s^i=M8BOdllAO0A*da^C)ic!g8T`7z5M%gS9J=w!o>U-A;iCdIF(BjuiCz5KF!p7ryG z!3`@k7@f~Pktx~&Had4PPGs`Y0orylvnALfBIU-yxlFlvX+@>Cg_PaH&h$#yJtz@* zv<(OW@=eJIidU15MXGpB`I2O$98r9oz)&6492MAYGVNJjU2UZH$bHv7tf|&SErr8v8%;YUt^;KTD-HHV0pBChwG)TP}H-5@EUZl%FZVusT(00Ti|jHKXF$)I7dFGkYy8A-iMwD-|O$S+g*3q@(oIs#uV{DF80KBgx1uMql=HNh{* zwo>HnzI^(4mC*WK2i@|(%W6ru1;j_PTRbb7TCW!HlbD?BHG)qdej~feTESle-fYCZ zxQZvJd5hIu@c5^utIAPNwFYOf&iGCdJ|&sqC?SGoC_>%e zoif(8q2B5RL$*QhT9hAy-jpQ(;&{qRd>w>bIK7P`L!mQxq(9625KkOHuOk~w5E*lVF&*jeaq0PIn)Cl?Zn0#>sgu;s+s z0qX|L?FKLo0Dtj^KQ|^|)RNx{D0TmWTF-*R^|ey<+qS%*BTwR|a#;RDiKR5>m&}t} zU``*DN7twIta320X~5j009`c(S@LpBun%S7z*ixN? z(Na^DL0U>gp3ssSYPX%5*~<~>4-wZw9}(@Grm`kq8jrn|C1pP5NIt~MqLe`@>&i~& zlz6w7$(dr?8nWNw%Z^i`wBBp58q2uZ2SMi4!7?URldcevuz%0&y%lelhoW5mB(v1r z3h0|q?d}ZVdjRRTJDIB9x|2Z(Z-6c}L@BALt}ArW)yWu##`}~@SqMeDa|)cHq(!RC zzMOfHRxAZA-Jj@QkJ8&vQ}P^|wiVdRz}))){6ydgfar#>@=1) z(nQ;26}UicK?UD9+V((O#-l#kOgf%cJwXfues<@A;O%O_&lEZ5Q<14*vksLZy}*7X zzq`X8-3aWvl~~qQoRVs$0zANz|F9#{A0n>Td_){qJoR-1tb^wK3+y16*JSW$W0Cin z$!sn`a7~CS59}=PTrvLP@#B3(e1I`m3#)- zmYJ?`z>2`|-M*jPkxz@F(i$^C&s%u)DvY znkG02RFd%@Waz6PJ%s$}whcg)%lx~{eH4FdG{%I*vv3-IZQ3e}iP|RlBCL>eaB{(r zF;Ize4vrkk(@9H;$=)`(DJ$WjJe$Fu&|isiD37PUVwX6MfX|rgax_RWJiyX2bQ#xx zlcM;5fgP|5`wuykaZ=RDL@d+`x}mfvN}igQh4thp*=5`lit=I+ioBs6;3)z(e;##3 zy5mqVFN!-FtN9*p$tEp1<}Ep*C7*jszSWYSy(N{SMNfp$8fq{+8;<$eUeZvk&hlEl zq#>;~PY;$fQND>NJJU_WoPJ?GW-ypOgGKH4@IZQsz% z4Go)M+%TF^?$x|eHOE&1(;lO_(#uYCU-8lWijU@3d^Eq}qj|57=6$O9ky_APYBc9~ zHJAEme#b}iJ4Ula0I=82cU9ZLCeU`;Xj|^p_PLL?&waFg?xPK`SKAk=EwnPUT`<~y z@M^o@qwOajZ9n;F1MJmyQME;K2WCfbhiK>Rc4BBpNLx$$21GCsOuGj}u-#4O21ZEc zPDy}drHD}&_aaAfdsjJP6;_XtcXF>@C4&2QE3^xrD@s1g z9x1&mx@no#o11dqZ?raV>S%2trBiL%unExFYX*eYhj93}q=*ml!i0}W0 zp$`=wv9Y4`droylN?lj^YSqObS29{me)A~&wIlqaQs2Aos>1iFD^V(3O5tZ5;WtR^ft8j>E^5()8P_I*cG~LXaN8DmYSl`S&sG<=t~IvvvF1#G;-mwSSAb zmkoC(Xy?!{ULf6{(>($#o(`B|tfYN?a3ca@F_$r&+50>5MS@YCk)QHd@`28KG1x2w zo;ndS%e6|YFL>YYe2~>Wit=4xNM@mX0kBVjVK;IR7d(zw7`O1l^-1~JM>@y7i*mg4 zgQMdCgb_FkAPWE*xc(L66mm{}39rI54^#Nd_IsLI)<&?o(v<0yc;9H_C>LJbh5_*- zl_5m6yi6@JGM;G9k+Bq7y7JTR{*3m=?d9|CO}fCW7GOvsz|Xr=#5Gm*^7HOo5RdsF zf(td?V9O4uhGE?5&M>V}HjMQ0v+rsDCoGUq4Ti#We+CKLOi*BZh=%MD74E;^iNM31 zB?4gU%3200V>e~ApX@9(l(GhYqSWxS)PS2$XsM6`P%BHDjqN$P)OA7XQnG2TOjQ}V zi;Jhd?Kx7X$=tfHJtq)$_paRr07x+cEgTyTw2zyL@)^(;Hx|G~0z(0m5-0@lGl4t+ zb>mT^zXJJMuB)l4<+pvg9_Dcq&ZvQ!;!oSA+AOU$h0aKp43`*nf@&*iB;5Sum_zwI zmeK1AiaCe)i&%QK$_-o&Y&sLmFoY!rS{>vy&o2ev)D`rZ?GS~p1b-kY&@%6@d@b@Z z@-6IdgmzCdcwdB8``cK~(GRBpU&-P2JHcnB0+&xYpN(Y{pHD|!!!QUN%mb>tXL4RN z|Jnnct`Xw&On`B=5L;6Fuh^K^kVzd;ek2QlYz5%%9C#alLD@!YOpbsrO+LnVO~=Au z(`KHkfkqdhlf;b^<-P#OL=a*z+nsf_)T(5vEi`W z=1)bB;X9A$5bX!zLp92drKJ4qq|O)VMha+sb78%7n^nq%+%{Y}o!cGMZu2y_()}4E zsdrP}N}7Y{L>)q7e^H+e(CG{uJq1$tTBu`d7vpwSNAr)J_)=cn&7cM3A&ema+yL+h zD)hvRMyA*oMaLABn$-WflaurWlsNOkI_b$U#vfe4V?rTzd+a+kVw0iC|!b$XoWxDTbq>G5Swf2jJnq}UHdS9RL1 z*wRhhWln!>*+bQ~%)TTdf&EgSo)2IRB zU(;LRpKR&^1?M1c{H>(^UMTV$);hQz*$w6F@RQ(QFPY^07G(KUcl$SF5`B#ne8?|VJzB9;&FdgAi)B)-g(=3R{) zTuM%d0`Wvni{o@%!4o*Z0V}^oSFa}zss;|0&xwYLo~%`#|LsY9p*sDHHs9el^{ne9 z9eLLE7C0sS_Ce+IUZ7stF$%2GZ%=?p2CM6Pp_#kCgn9QZWyee{KYMFOKFS}rAGG%1 ziu(w_Z3Ny1Fo|-W=TwHCO$GB+rh(p$-b!;XOscX}nB=36uHRMI-({H{$~9hmwM5ef zht;-#BkJ;l;_`ABBQ7^lzS@otMIHH|wzzzNrgMD0Leu3tn3I&bzQ@Z&n@&bb>I+H)&k=DB*txI%yv~FMQjXP4;#?1COir(QrMb zdc3pAp^jVVzk~}+60Ru#u=^==rqDM;#{ra@(e=%a-gU!ws*l^mAXNJQolRONnRZ|> zVvJmc+2l^;`QJWcf26$oOcq$V$2479O1fOzSN)%9_^ei~p^`B>vwEzzjuS zD7$wkO6_=#>>P?_lbu7+76KfKPEgLXUuEc8Etqk&c6RhiJ4XqVY3J*7zw*C*PEJ7k znB{PIXYX=2RpnXvtgBb<8Lm8B4sY_|@m&rt`hVMD#aoq3TRx((f3_5D`ZxxA`-tok z{)@15=LNbJ%7|Tz{Ok{7M}jx*bQh0gZsPr*k4H(RK`1n)fvxNMpJZl4^A?IUs7GF_34XT7`4mdWbC zKJ_Covt_b7VEnP>3<*STS2pp@k)Yvu%Xgf8P*ewR!#}A^Y}9FBaI#JxappeAwMBWn z$t6p9=OO3{dz|-_y_(i*uZ}$d&9cXN_+EAqZrUqVG1htaIGbbZy$dd0MR^@u>HZ9| z$2m)RJVH{4YYX6(FJ#1b;HshKP-F|20n;;$VsGC|?l72&+4s7EN&4QC1ladJ24H16 zG84ea>lpO<1=Zv4^;Kr~_fk!jYt`eK$DLtxknD&5rfuAQomNKgFgh&uGHv7bD`pr> z;zV{I04x0)Wu31&%>s6$=&L#08B*_)9WxiOo=$1T2-NXFd`?Qm5u=46v zIvqmgXwk|=)+7t>is(l=^a`aFKS4#-sXfErb9_t?o4Ua!@o|PSdVNfd{S4-akK@23 zK5hqKrO#H@1?7B97kxP+93MSpK7OtO^f3+w{F{%px|?|DHPHW$k6|jZN$tsb-|;b6 zY~Fz&BiuyhiVSdpb59m|UQi{{`cQz#=w*eg<@mSCZ7wM1IC@e}8?Mrfei4jL%0k@spLF83TjCZq%8A<^vHCvXjN2;`x81-@-1e5mjUQ2Y z*y9(sw>ntRY!(xvHG75vu;OPb>q?E=OSC}Z_O{g6-~lIY$Nb_}S{Ap{s)TVH1qJ^e zxB3~zI&Sn~lqkV{ifiN)FQK>Ad?GJ3OV zX@|Ptm8i@Blk}<209fhC$~s$hnushHeUFbpMC1zX3XK59#(63r5r9%!$8r2>d9zn} z^;XUQqff;jSCI*7&m$k|)RZSv(*c+y+qLRFOlZBkh&~;PsL%1RtCsl( zzoLh(zjbk2{%(>k@9nl21LU4kp|0FIY9Mxbm%eRe>DwDF;cgu==F3me*K=H$S3d5{ zW$HvwI@i7xx6f3Cbq8plb&d-~*;Wwah5%?d9zZ_;vk2q>_=P|UfW8v|bO!JmfmQ%o zOymtWsBw=0HV0V2LjX8Oxn~17j}rG{0C|%DtO2lvzJB6O1Ac7G_OBVRQ+!Ye~!vawcb)N*;_itT}0Ug5aUvCWAF@t&H!?Y84dt169@$m zHU&Uk0FM!<0pMo>e?z>_LkJo5xpPpw7g#|*01~nx02(}uxQqetFoA~voFOn9fO{%{ z#Q>HNSOeg90DU$CSm?wqLQ|N5}N7;7=)_DE@KTnnfA><-jBleac z1XmEv-={TBAeT-|O{0=iGY} z`uX|hkDK@VykGBe-e)}Loaeds*@p7JfpQ)J(RCh(Pe8l~B9XAz)8Kvs7kd#zyZIn) zfOvw04<6V(L81(ZHVZ)91L9#4bwO+;(Hw;RIEeNj>VRk;=u~xFp#rn~5k;&E(k+lm z7wM!C?rL_fE7d##K&RqDspfS^@E0>9NZIZ5;`0Fe9950l{i=q(^Ho^z14bp@uE zz97A{^dj`qeyHSmZS4?1_KR(uV^9_eq4QM`50h94;v|VDKr~(q;$aZ8NlXE82t*>a zW8VZp}xKP^XG9>cnTA&{X;IY6ic-BV) zuB*Dd|8ti0wJMj}W0ouAUt3i36Y%)3mxiCEBHf8=a^vr18V}6<96vRMxB6hc;yY!l zy2r9W?xx|FqXW@z>KzvVvlk<`1e67I)K_plsE$ccSbnZO|y@%U|-iw4d zF*}(L_?g%y0cPh{e-B9K&nW+Q6@vH<#Hi;%90lp*U>iZvDHTdl#~Qn(qMczd*EXh;7M&kbSjQdAA{29 z%G!#@H?Lt<+o=$?y`(%8FjraCla`|_X%jx2Yw)p#mKT6Xq&#*jsE<(8Z-CaqzA7K_ z6fqnUauuEWHMq>8~UE@604jg3>Z5_1+;(TsXTepNA~aig}RQ zzTwXKD2sqa=S&cDNlXOs9*JQf@O5VVUIDPN%fNL77vs>aTJ(u0_5Kgu`H=h8^4t|7 z=c~2Cenb!(O%QzCGhdqs&q5H_syo}D>@nDOHUV*hL=6zZFM+54qBn>{Vq+7*tpyiz zQ(Gwd%+`Md(G9B4Gl&i*2tLsp{E_`i~&;p*s901d*L9fZ9W#CQ(5Jw!9{B{5P?@oo| zTWDNGaIsaPH3eF!=Wt}YLTiSZ;nuVITdcwFki8C&(+>mSFo>iO5Y8(2xCYMZxE6qd zKU71wmHSk8zKilI>!7$BL@bGuAcm4S2x1`!^sY4sW*+9#*ir~)Gs=>OLHM=~<`ATI zT=fJ1lCn{rv;rT_#rQZ3Xwm~9qA$3IoL*zqK&k&PDj+_Mx86 zhau|%kaH!7$t0ct@hpicAie-$bzBE3Pxp#QV<54b^JA3%O6a#BD!c~b5QrEOTS43p z0=*&w0X@%vK0-iGqb#)+gwu3D?q1fc8YfX_6l4c!Ar8b<5`959HiAe4(GG;w@%ygm z4I`G{#?yiT>Q(0=lmbLTNW0ReNJ3yjs!>lqWrj59d656w<&15YZ25 ztl3cD=`U?^lGd(?X(M(u0u0@RzFHPaziLE2!ncE}eS{h$HAZ<-0zRCrX%^6=a1e>a z#PVl#`lF~{*+SJF(N{M@t4ObmZmxwzN|ERf@eE;{mW7)tm9Ca_8s$kh@Zr3Oj~u!@ z0-{rKY`PC4>UC%9*a2vP8Jp!X{9~7(zHhO<_ru~)jVNS&uUCBw2}#O9dD41(I9K80 z1f4$$B9WNbw?X~M`p(gssPA*oDpIrPSMMBA$2!o?(=zwi{Jm;YN0cY^$A_~EJ|Z{6 zWh)S!ieuA9qBMHnovq_%@U_6SuMcLc*qNwrIxHri=!|WKMud+=eZQ~zG7^$>4dqFt z>D&AI>-N zafmKgg6LEnoBkO}qubosy45}ht8V_8_WhOh9gX__#`-#;`=my6V||~hx(tA%z9>(c zgb(L%e8j#E=V>4kiHUs()KC=l+oCm5-|8ZyQRzfx+oQi8g?=Oa_^?X}?OC|3&m4$rPv3$7m7|K3? z3+Fx%!COG=01;2(4G@b#BoZ6@J-Bbc#hld^iavpV=ao(SZr6(@eH5mQ*guf;a(PJl zQCvKFXhb0c8ec6CfTTi{Ck66?dJ9xbK$FgbNF*lKf%3j6>NinqBI$*wXOZ+qKdpsD zN|E%(U}ue%xsyJrTGC5&xeXuA*YWWLT|Nz>Q*mtiCn$}6|IXGe*PEE6`B&nwWvxP0 z)B`^_0`<$4$A9pX%)Kf%$0MRRaje7t*yp->q08`Z@IE|zBT8mFqh5+9>t@_mcRi+o zO~1e|!u>B`z6KsWU|E$g7Cl)gW-(AN8hrPvx%EGRLpAWdQ@ECjMf1*gy{eb$;WZPz zDz=g8S+3``ir;SJ;(rBkzaFv&PhvkRz`kZtN~`#?2F$LGR$1G~|IFGptrhk)PN=-h z_fWb}Inzo*|JKlEmbTv_@A*<)?=dCG5oru zmjhmmdHx;QYebZWrfKN8qgajJ5xSv;hA!36sYkG96{y-nd3UDob!Ym;bf!AjRA+iU z)war`GN!IY1}Hnz2n~Ga8;mRg{#T3kZ!OieT${B@tNU@d@V{)I*T9$aai00Vfc5o2 zdTKJ>uk=5FF$EgfIpx2rgdx;^3YNb7t1h3|8Y72M{ev*KeA=K8JN`E?vaN*hap(w? zj7O2}Xvj15FDXeamxx^JqXiVopS_^bB!HbwA*=cZX2!N4I+CafVibtzzqJapjSgX@ zCPR{~4};uxo^Q03c7{WiNA*b{j*;jK;!oOHu2qbklRZQ>+YY=d$8%VQ!2_dU74^nHtje}Hq zzGrmf9X0SoJ^6MRe)gEgY=)KZfS(7#9xMD$BzpRKj=Nidn)H%~hh8N4~zee1PRj z9In$|h^>dn-4S@c0^vG7+7rd)qEYa4C1&tgj~DN{1Y&cYz!$bA-!!eVtSMWi;Z|f# zT4i}tw#pImlBK7bGD|bw2QRJibW^rc9(ie%XPUBA`foF>vZ86xR(V$NS0GodvQqH5 zADC8oPUCTNd6CX7bN4a2O_9jME!VR{J+(fo^8i^wy zo(B=_=TOc~eNq=e5>~NTUb;3}M?32wJ4*GpLHtf)6^N=kVW+WHF?JI2P~9PaA}{im zn8=8(7|7{BMos4kZWhr5eQo3}@RvA(n@2Ejr^sJK^mYs3+vJ1qi))r0C43(FCj72) z%Lt~=@gaEm4XsuY?7P#zC-1joC5z0;sPv zbP}O`BBl`PGXk>-5Y8I_H2R1W=}nBc4arq5j zb@_^F%Ffpcs(jyROX2#F!#CGk36}#dp%6-sP)TkU#y927!cQT z%(E9Man-1-Qri;`%f1JMNv{=iK}(7y-R=T=-C*w*x2H_;6ugJst{2AF>U)$;_X418 zlcu-O?M6a25hxFFA4=A;WHyNJXdodQrZ-_pqbl)TBrDPI6AYWIID}phSpjXnj=Vhk z_I)IueH;2I`22Xte~4t0SKSMK7x^>7*V%_DU!HzD8+odO+LESZhe7_M=JAE^aI6EX z!m*m}YBp2T-HF*TAyrg$o-Nw@Zoj1`Z+Nu(VN=MBgZ^C@{9eqr{5_ZuuE+6nF>-$i zM7U4TznB!m?p4Mi?N`&#v#pK@1lJICUC4|!0)RRgdbTynfOz@OoZmxPlIgWeuI3gM z!90@gg^6CGIkzJmQX&cGaKlseyQNKdfiCeGvMCqnoF=?LuOdH}t&!V=7wBgD!O!C) z_+%3%Z4`OAKrd^;*7yg!S~e|jQuG4-l;E>J2VRy?F`Y=^7u8kg5;v(1Q8CuTk^J^kE`y=n`bLBA}E1wm$BG>1g!1)lz92CTV*Ld@8@T{kB#NReD%$Hkklj`Revo zfaI&&r%3Rt+f6qPEpBWq-q(a*(sm|6W*vkfzLTI13BHpc z6@(SDR_he2o81XxvS2cn2o_!`D_^T0)ttRzBDA7>u_Ly#gx^nICZ5sFIcDp9VX8Z( zIeWrTNNM-aQYTrD?-DANC0eJ|A`qL?U6up9$NqpLWpCgaz<>S+z3g z84tAb`(NgpTA9X~UORo0fOUWl9V1Tu><1b>Cow?Q{4iZ7;+YE)mr$|hk`nTu^%=pqTqL$Tg`* zzfsSJvc(d*A;NihHm;t0IpzMQi8b-GzD!~d$Sz|l%p|`A z3_v0aV|RgTaTH?)Z@$@XTi3KgAr%%hb;5~r1j_pYlE}i?$>4qf7ds0?`!7K}4&p%) zPk}g0;zbZ~$GGZ#07DZtVmF~=AxdOKH`6muCDqpWA)Ff1eBp>A`Y1p$qDvhI!4Vw~ zLg`J^dcj7oY>jTJlc?+d2;`UZdAe!Ql21 z2ciaEV(Q1lPf~qh;YxV~%Dv0w!wWHEYbs&S4E1~zyQk%PSLc=;qn|Psj>#<_fv8-H;{GV({u$B5um6NNVQ+_4F=PRUh8UWcO#({X3L_5@n3B;#Zyxe$Cp2s+zUcu-e|j7ay@;c#u; zK2?fND}3~f-~HxBm#3^nuMU~@>L@jttTWqrb68=)*}sfRwwWI^&(DQK7d9#rIjrR>?a#0 z<7rRlMU?*_!GWl98d07G(E~(G@*q|1`+oM=Nx(aKtUNqLsRr;RS(+{YS`FY|WNCVn zynJKtauZy5ttY<2Qc}K1a7C7y9K`Ayc!k2>f?N%+tFk6bDL~>m$Ybj3#53T3npA~f z8RTODkU@Td1P6Kb??G^o_aebTz6eBO4iwcOAD|C??l{O@O|&Bp*LZm0aOF8l(SxI1 zUZ~MUP+s2%a~;trw(aAB@*E`w_QeF;S5>O`px6HNpid}3=(%{ZEpD zjuzZ;z4QZkS!Gp_RaU1n;AIC^u?2hZ`{31%t5OTK8fW;S ztjP^kVBgmD8 z+9mSV&TSRT{HB32qIP&cYHmFIq1ULTROZY+UYP!mX-;M-4YAt)u7fd4s;^){O+Ra7 zN%b<)5mU0UGIZw?6XZD|ayo7z2 zjn(&Y?c;x~zPV2H%&)R(mgV=;Nh&^T23q&IW*@=6v~KQCx^?%HVC&lFFdhjj-l9YG z9=T|Xs^w0RcFmlnov9h!xK@ktgh-g48f^0LzT_bqK2;vJNgl?7PsjnVKY%I^Cp~%C z&_vaxcpm=yI-?E`u4_FNR+*;CiVo`#yv@eV1=T!>64tlwu#zOK^5+p&93JT}bcZ$4 z6V?T7uy|PBo1>!5nw*u8G8pwuyy<{pmhi<-a5bCb?d}y zXDSWGwN67GOqamvzM9RtN1Z`nZQ)bRUOl3?N1OycAsp+_-w~&3opGK$Vo2njTgUsj zyXY!FwN9qiQ-QQ!pxKr(A>nZ|1|=8$c{1w0Ll7~~XwaQEGTh%!#=-s$jdEyH_RGzm zhBfCCkojChVpoEwN8(`+X&|BxYZY@@PIW@^OfyxpO2*F8<|k+;4YG%+?k4)8WGhRC zgE$2Ok6a>OJih*3YKf&yeNSRPu6AH&YJknqLAhmx+huVD1<4yKvdJX9@qq zFXpl_yVyb99M3^r2)@0wC&V<=cD-D~LEWS%Rh_#&sFSP5|M#GdojNn6g|f|ax*mp} zZCykhGWqg+D08?G05rkSv#qkol4piK>OGfqIi>GYY}a17UwA{3h~pPPf0&c=UjhSCM?V zz4>{gqUUr61m6>KbxwCs@IMnTw>Q7gcyoL6P$TYDqJG7RPwSQ{Z(MWKE6+T5)+Bmc z!gU93Z@#CITnTj+q}h&muW`Q9C>|(`SN4h=^gZu&lXFQif4m9$vzL5xarr>Ym8$Q7 za1C{!xI7(iy&10R!zh0fxrx$ydsSkrLNQ7;;^a0hI|;t+fX(oFww;`&b&y-rImned zP3tK9C*;*Jeq&x&Z;_uHhqgRbH zf|s3MAQA~He%VRYCW6C7dfQVj4<; z_>jcEK;C3N2#c+S;)LIEBozT-1_>vK=Sd`k_!>ma$J#D?UXfnc6Z1$yNH%`6wW8@r zRpgRe?hn&(s>&rd8GJ$xfMWqvd5rd4a!ueRwcwx8?uRX9SLGNiFP2~2Vo^|K##03KsgPWi@2*aT11^~D8EAJCmCs)Pq7@n~97S@#y898Lp4BvM>Fm2YU(qN!xO5=@W5s?uv{+0|&R z3Fb)}W-xn6FqnTpNHBf1%Aw-HwEkNMGXX>*#l?e}q*ZSZMq2LEAu1Sm%N>q5#empy zuh2MKZXXG@++`4|<@#hOJ?mjqVrZj8+&Gn%tNjn4Y`IhtY`JkDq~!){mEtWYDr`9- zrRA1_fQ1xzyrPwYnLhm4O(M6^S3k(!A$|milO!gC_!~sWzZ=~_ZA7563|xpxa}Y#2 z>w*aX7sNdv5xI3^foo^R8;7cNO5|U1fAXl zffK44`Y}4rEnVQrYkuJ};ia24>u&Mum|0$8%N2$vKKK_m8J$^4u(QS+y|Fdq--DHH zYnzt_=E~bo81N{L`C2C4M}u9F(Y$u|ns~zDPcO{~+_Ckl#Q*TgNz647dl2Jv^j)hm zHLqbYYBXQDYfW)l7t2qhdit(au`+hO;H4Rco3wXVQ)&ib`DA>i-?gTMJJm~d$z7{5 zM@O(uGEP7JKWWD52ani|?5cNNQTW{8rP=PTHKn4}aK$#^PPuDUX7_0?&Ak7U=I>sb z7w=vZ6&;0Zt%$I1}sdsHr^$`qM6U>|cH`NB=9@R^C zt;+6|>!n!_cU$jnG)TO*zMIAVm3h~ybegJfmQeG#yVpb~dD~0#_+4vCxK;JN5jqV) zt?#a;?3wrJTM)<4*7cR9wDtSCoEC@OwM7Z0Ry|LHJ%87#45q8rz3vieF;oxZmpR8Ba{|L{at6us=vGi7Wy9s*^^*Qy@Tk(Aimj%@A%yvggph`HY^84 zUkB}~$?ILsQ&-;S*V^(0L3Qwq z>Gig>tlqI)*IBpTi|}X%I_aU_QJja`K|)XnMf+udpW_Hfd#ReyC9AT6EtLvA}Qz3jB|vJ>rPr?uNo8)YY=Ccl0& z#W@}}^CqeMUqcc9>{Wdu&6}5|i1B+ZKmDeqDNY`k&IGUCtTa`e^svFpo0O)BqkqZE z>olf2&%pQ)AMmH@!}JW%|B`&os^Dh|pXv*KdLsCTgx^X2I~=~-v!p^T{lL#aE7`Nf zp1(i%=D6Ex&k_D_@^Z%@TWYi-0Q|3Ukk1wQ^|42hLYZ{(M_}k7$aG%oYLV4XFKm2G13S;|#`w(1e0J_rP`;_$%X%(m(4C;g%+0IbN zc9it<5DNZKarhTO(+&K(fs;`1cZ{486ZtbLzm&ER8$fyXID_YpYpd_V=(jT#4>r|D%3%3lP=IT(bi zjGxtZU*BTLkxu6olpTf8c^1UPvLL<&K|Q1)8|DIVYdmUs80;RGj$J;)Po7jiA)~Mr zI4ha+*Lod79z*!axf-{Bol8(Y9th`L5I*JDMIeoR7Ti{Fv1>uJEf3-i5Zgfv{s4r$ zV$qlje-!3^Z~G{skbX%kY2Qv!)s=pk&<&9GSa!vJ4CS0qm^%dG5{QH~5LpoQK7|sy zTid~d@pO?6^bjqFI-N67HpGD-CxUnuL?R`z^TF)^mv&v_cZ|UsmMdw`_cq5wjOJoW zt3IfE#bYp7Ri*Sd8e~eFR?sQ!0V1ubhN_1mQ~B!2CAz3O?cvX^>70y+Wz0TEotHI0 zjak0sH(Uo1M~4lZYY69SU_U0jnHG9ptJ+$Z1S$uX-N<>;sQd+$m^d#LT)ntpSFgo1 zf=P4~;S6G%&PB}CD#FoIMdp&y@c)Olvxe}0+V&)zFWBx2cp?ks1>19}{Evq61>0#4 z&rk{EtH|{bC_7aZ9ik~;rwoBpP?RAMPzeNwOhXVcH8fN`)2P05C9ecUC7wXAQ?)B= z9!#}tcaTwWhRc9*T9S6HW;kBiHfeK_gqLa81oz3Eol(A$PCI}&1R{~r*nZ$5!_ePG zfJi4X8N?J2;@DWqrloeyWZcjf$25@E$J?>IDEgXqtS@1f-O)LNDs0(fu$lI^21v^$ zv*(qVrV~dG3C`Vwb3oUqj9A(GQb}+?j{^}?O~cvyunUrQ7S~4L?jgy}TgG)RHS20k zx;8zeBYUq~VER@kr}U7wp_SH7Ye~;VFjGfh<*UnT8HKX#a+u;A$i8N@kAnCYL`PQe zHuQKkylUQ~D<~?gU=m6&4cw>Azo5!2hStT2FL-|M zreZs;O)i1!^pQ5vMw?KNdemsgWsvJ$dP(NWYoG4^)_fQXXcvU_hSML-zX1^E9{_v@ zB9YSAawx7`1>K`6h;}3zfEWTo`iZd=NlU$)6R{7JenJCj4|?|#d2Mr{cAP=@0Ot#Y zvybeAy);|HJ)=KRm$=(@kn<~}avdr$Azms)+SUlL=#f7=L$z&KRXA#>wRGFMn&?@Q zj}SIPE@TzFSKhVdj|cOX`|+{2NGt6HJsSDu`wBWapAcKe2OfLdnCny_sNZms!e#h7#vs4&+7bQ zTktcIa%L*4o!4?Hb||UlLz=JB8vMIS)wMh!2ifj~Ew6eJpyV)Px-Rbeplz*lEB9JH5^8wj&(&1>rTo)7$h&I!*!yhjCz10PCC*|f`rIF8 zxyE^^2O#;Z)BTn*kBddx3a@IpR_JQcSBu-hF>AG4HM-2yJvSrJJY9}&xvK8AYCE)@ zJ0Xe+$C&yI#CQ;~$3eUbA|W4b@+vU##Q5QNu2;ts1ghuiL<-XhMgMqTo93nfv8(sJ zwdq<4O>8H#k6E)-Q^bg86t8l$FnvrRuE3${L_VTXzXpa*fL1GFw`cGu%Zk&IE^dR* z!JxAmM1!Fj+YrPvAlheWAof=B_ZVRDgh_om6&I&dF>SV1DnFiK$E4mVjEHdd@YFXL#P0;s29<8O62zF$(m+Jxe_^~_JdbLDlO3rDS6vPXK|2F z3ss4jqmo!pSEYHB87>nNIb7ZX$a1}}V_`q<3xw)Ryc~J=^RpVoQ8ZnnrUKj3f0l(` z+O%A@cE(=ztlNyI$5+$xb+_>23?i3buyT#_(mQ+yy|=yOS8tcce5mDKy|>31^s+;` z-2J`CRh^My=QW7_LA{+8+AX@apVi@{2C_fszNjV#tIamH*sGGz0*&(YpM&leQ;110 zR!^E>ooIAq6laS^u_18?J*z;d5_9=K{aX=nxKn38BIY8qRb!UWjcKoH)XH?3N2JSa zfVGwzIc+M9A6UC+tyZjdk$9Xe8gayFv8P(!z^XF^qI>K3S?N7Nq_QFj8t6`EPU1=+ zy(&X|OqV;m!_u%*h8CHD6;CI6P!$u2+qBubR1GRCVyZu?w!V{$A1%uFRoSptJ=4}C zV|^!{Z}dboEw|x`WUcWQ`RB06u{Vf?f5Ar;pf>hvoj4X;b+PUkF=05KWD$NH_!K!i z+0-eZF1PcCdPjW=!rt782OPfj%=mk~6UU!#Zhr5m3?6`N5&Lx^SC^(dvG*`}IZk*( z^!J13I_J$!T<3JH4{j)auUfEqo4cZScX`j~dzxR zTQ$GFcS;4Mzm`W!5C<=r_!)F{ z?V5uzXRLFcnGL_L@Q0Nk z;*uf!5+?uVSZUq0ycg75>ohZ?wr$lx12T9%8LWQ!N56(fJ@XWZZ;QaUe1^$qI8V?& z))qz}UG0Os!{FDSS}%B`CIfYHI|izv!NNwfns4kcr`YIWNaM; zuf}dE_t;g}%F@NgYOw0k)R!(^M))3$%vdce_F6OsKd==-3y~3ZPZKqE%gNZC1}>@w zm&fHrx`n(fLPLfBgS@=R${~DmQ}FL_rl=tN)8N(kt|Z>saZD00}4{B#FZ$*0ZE8i=u^k!p7dNaB&d$aUj^k($l zv_0CMbi+!IDNT06t;)DObZ5Tn9SJL5ofyWX1O7*sjMCQFCBIPC*d>?fV$KbhRWY6! zanB8>w3vfAAjV8Mmg|~{4c2N)xju%FHTwXaAI>PLZY@qzdWk&?qili(aY`9g!~`a> zE{n8urk0@0wNaOay@cn!bU7{6ov#wbAU8@mzjb7FnWD>gX)MbY>awG{42yZ!le#Pn zc7N98v|H$9*B3*EGXNjKDX~B|3?i=~<=&OAtEIHoMoVceMwc_n-pU%rGpv2vyyo&4vR43ceZFuB`?=v#s5qGOOCJE$($%2 zhy>pnyL<3l`(7Y_y*&6i!n>Mb1j)5KJNXQ}ZU(Qe-E)Pn(j0QRRzIA~YxOkpBRN7J z5&b>j)%@^ivbnaa`Qfo-_qAMoSwQs9Q(sng^CkXjEzF30TzJnFd7WaLkgBsCMXHh+SxzwsByt;1aWOGC}it`%LxE2|uyS)~b zd|b5{uSFfjmRyS(c@+;;#a_eMO6#cQoCMMaY37et(S@GX3}=MBDme5O&xMIk%=VQ_ zm6{4H|J=pBaS-9TLNx;&j!T#2+M#W6;9t}g#S#m~%!cD@jbKOiL66gY(=~IUr&^Vz zoYhKOqKoBXwbqM?*`pcmOlX8Z^Cct6iny;T(*LbA(jkq)v;XpEulmN_&A*jyJ{1k5 zE>lV)kGypAQ)1x)_zpj6GrY#Z8F#+$rq&qU)fxj$x#fFR2hK^&Wah+}^DTj3j)|$l z+k(mJXvW+z38rS02}WrQATPlj7Yob5cko}N-2Crgc6bGY8KEB*WmZIati0`mVk$&i z!2s2nx$X|;pagTk9gNZlXla7^LM+6B?@;ruf;m_`80=(vB#!3WGgMt(aYwN&9y^%{ z5KV*m*cl+KRv_kqNCgo;6hukiZ?wVH@x6t2{GjZtcJ?3{>%Bpz?HM2{laJg4tF)3Gd6`6gk?y7%N^km#fiqRV!(gT1zNK3r`m)6in&dZXwJlfAAS$`PD&nUE;nf@ zMK3phDB!!Kj6x^CRc~pTL<`O!=pktG+U}Nif_e#Tb534DY7l>pEpLTo(W@!}#J=p*Gwe(^aaH@^xiu>CT^rwbFjq5YFW) zv!`{ehnU&?lqJxU%>K@5FVIQ!u6FVqbbz@}s5)2+p|wBdLu$Q(@}`~8lUA^YkXQ`j zA_#mz7Pw`dQ6pJ^9hL!n(}gpKJP0y7L2wLX(ypC)26h8FW9Z`9oI1h{1(#?o!tu0> zj)tk6>5ibV-i>llX(W6y=T^TQ6;uYmc0}sEFzf7&^1v>LB@x8)B-((e*cC(*5VVs> zeC!}_OHrJV5ALZ{+~*#HlCMw_)8R>Fmy2j*TzU_3SxdWHI|?hC(V8Jyu%Ss(sS8Wqz(bcps`ru%}lNhLU9~YWI7Q`JSr)9cf#*xFej>3-t@A_M-a#^)S zo0KydzucT&GNy326Shpn#E$s60&&5kHZl=f$cySlZ9xqVgyI^crL0a#1SEOX)xo(^ zm)TlgP04uH)Mb#)PIFy`y-b%;x}zs~%A%*}GE?n@$i?`fuQXHZ-%{E)#NAPMt*^-x z)Uvxe7Pu}K%Up0#vf#QQ(!JnayLC*=$w%5>@tmZc(I6gIxvJ@L+-4+Rm!dWJ^*m;X zyEAS)8*9usD3nK#j9TVf?$unKwRF-$w$)HenZHrGeEB#ZtBWpI*`+QI?kv}8jbV-_ zD2%(ya2uSj`7oT+c8WT1?LEc#iJZwEwV? zi+$;}(J$!cV=KTO=4kYtnqAC{HZ7GanCKqp4UcF~v~;+rCHL0bwaP1;s|Ms1ZZDl4 z8Yu@ak`1qLKJrQ*!*Nwvtm?M_M{#`DrMCk6g>#9L_Z;tI^;dFU5M0M~dDrT;wcY5+ zNYCEWk{b=CDiJeI4JZXsUKn<+_{u(X7k>T%jLOeml=IJC)wsJ^SpSmBh4sVeR%#2XG;WfYN$9dzh)>6)Bqt+Rq#G^; zpE8O|)vF@Mjd^tx`KxAAQsf7Iev|8~Pi{ALp5fp)4c-YxrSEc;X!U3HlRMaDeP1T2mb%D)K1nOB(<+-rf6!LA+?`jzi7WN(dKKAr`P_FZc_Wc zq_%V~lUk)Qm%Q}aZDQd7c$L}@B(;@$n_jy^=R>DCHfE!C-A zr&*oa^_tbG-Jnxjpbt4+zAHVct%wTz|59rd@4nZT(;g(X9W+xkwbcG{WIxHD1LUkxIxC1)5J`@?!f!h&%DDq$jbtux~4a`3o+MB+%VbYH6 zi`~Xx=F4Nf66Gr2hmW{a1ec!;g}q@ra589|?I_NYth>b@l-&R($$l zV?t3nEyPm03yONv0&YgmiKUfiP!dZ^2S5yXD7^uQWcI$W=ak(HKzJm5AHOa$Id}X^MQPY}8|OwUZGe|3ZG>iIhh*x; zO;Ak)z-d3|CfA49AzjkQ+jmF_g>XNI)xw_A%7S~BQ#+Ieu(ISkRZc6owu=tXw&;M1 ztLV!bZwg#*>CAG2vsoG7PFt4OX&-1I_t>s^+7=fOKNfN25082oLg$t%PeZvV`o{yc zx_qPs<UGlJ$)R}@iFnu_>>dEH* z(LUoDPu+UI+zYK2`g{jGF{`~WYZS%`2)v4z0s`N~=gY0d&I(9Xu(!^qT>_cj+2{)_rnNReGtxzI1=Ant@>;D6EIM@@7Mu8RwC)xZVc8QdLp_$*evJ{o#S% zX?PnpahVDvCo63k_loRh-n~P zeY6d(vH4XuL>lB9^@9r2a?R1=G3fTIMa&;~wz{m=n!mZj~{W%5D-d7`%Vi`vdo z)Msa(LV)Fo+B|rUYo&$qL~TMOAOq26vF{+VpBUnYAd-fH*bm|*5U!8424igjti;;N z9qTzQW~?p|ORUi)bkcPrSZR|rP`x?9wfY4W<>Sy>Xw2p(s5^I->n$(w1|u%$V#J?% ziT4_Dc$yJ^<0U?4#M!AvTuOJ8)$m<=psrG=t`bIbkZ-F)>q>NF7cF`QGDpr49=Ecv*QuLG36!IpSsE z{h}7ai&>bjp_@kIEKNa!d^7YC!E(LmWyu$#oQh!8;INb58L@GHfZQ##5Zcf_!scR_!tDFHV~Us&IiW zOo^$B!q0uTpM=u3UX~qflZ9i2SXG&Ydp|o-djqRzh63}V5AD)ZImf~#*fmn#x zlj09ZNcpi|Fn*C!VDA9-GNNR>i*~sDfxO)XxUB#7dbH0o04}-v}zs8&z(Ij%%`&QU$5A*Tvf?LMycLveg0vF2kZpe-F_#&i@@Sqc){iw*dD-A*hzN8KPa$_W?rz( z2KFmpyZLp&J@Km)EW!(R6h)HR`>d4Ojet5B|B;{ynrhUva`=9aL6t)`ssr_9`~^W} z_wce+Jww|nZKb$^fGUhHi=rUkBgR$>bc95M@<%QCbVrATmV(Oeu5Cr2QezDY+k_J> zfJ#poAgDFn6e=YX7a}_|;epcZ^^;8L0$$-qCA@@R`w8+jlc4nP9mZmJE2UKoP4$CtJ)yqmbkHv`ndE!w)g&P#}5tONGiaJc>4Zp*Qe<)NJuY5!pR2eHJl65$l zSRF+{z9o$<*0h&Fp`Es}1463Y^vWzv4OgD zb&VBNb|Wv;ODK|&RuakVT?Vi&u3TlTp%-kQft3ZUF3-JsxwZ-{u7MY<(7;*%wgBVX z9_ac`U{-xESfydwDIT&m@5Efm<8&3!D3J(BW;|OazB=A_83%4*H9_8j0$X*wY&~vJA6qHI+2ikXO&41QwY^YzD3WZHLtq`Sd$}k-Tvw`sl`@pJ*1CL9gm8_mak!GSHmG1L zr3AOWKf1aIYE2boE4V(`Qk)%z87M-&hJ!}?$Fy{T#%Z@Hl@n3=bDEkBGLn>ml*|N_ z-b_=y(5#J0u_EsnizTd-Qk;DI_E{?y&BA5Gbjt|w-HKGS@+XrkQIdTX3MUd0? zV}H=gkmKMDHm#4yhRq6&ogpBbmvocoFr!p#EdcB&t+F+ROvKnIcdw8mFaRn|0Tr@q&XG%Jf>1O0|lY1tiH%!NCcJmbYv(cR@So^i6Qdiy35@U;gq1ZC zO%r;Oq5WkFLrK9l0a+c;_@Q4>elKo^iIS3!U5S-f@BsfR=pwwe7D~d(`U}_Kvh^ha zER?#8EzOQ~$YyCKOXWjE0fD1X5KP^yKhQzT%CEC7B8X_wS6Ldn32l4NTAOMw8o4#@ zDI~m77v3gU3hN-Y#wVff*!1mVaRqcqD{Cxk5JH>0`!5Y+jcoU$FW zsIc9Xs)R{u$NhpE5!HqrphyMhgR$qlQ-ouy$cHt4CuW_XbM`X^U}epr@CkNM?r(HgUV!0QF_!i} zWFhlsWj%p*teC;VZ;ZMQ=Pjf!q%}Pk8i|!v2bB-~nuh&xW}pr89aEu8S;&I~T{x{N znm&q&<-R|(2?%TAzi46>@f*mJ^ibLl%@yGvs1}8z-NJ9##3Ib9g*l*FCdISe=CV46 zqi`vMU%^5Wq3zMNtue2lZ5yKwB6D7FY+G5r7zdTB z(BU>ysJzOM*@XlB(bl+s>moz<>?c5V_Kj%T@S$|@V-YPYYX}BjnTCw=Pb0C$uA=Mh z(!DE;D^jhj^bWY*)uI1*O5}sus^d!Ub$?(U{Tlr~>k!68_%Q15xWkhqRi!a+1Vfz3 z;Kt74uKV8oRC(FrSxfytyL4@w3TppDy!lZ zQC2vXHf5WV=G||Zn-G66;tx7w(>RYpbQl)KQ~2X7-}_7QcQzVV6NG)ykr(@b`$Wn7LQ0 z67N%GCvCnLjgM-6HfkP-U4<1i1f}?~C#xh0%YXAg{E~|u#Pf!L`u8C-B}roChD2B$ zL6+u+kL4R!;xY6zAL8v&G~j>nex@^cI_Q9on6~UP)Ug7dM5^qvEcUZXG0?|BiWwU( z0)Ubo(i0`YoQQ1y(u~72!)O}7pS=n$tun*14B#ZrC(D+>K(_-#q3$q0D`cc)mk{oC za`K#OpzvP|_p{2$5qpsER`90-pc)fQUx##)bK$^0dlg29@}&TujWoX6i$cXw%2%v# zFOU;oal-G)GQK(pZw2q}2BU#x=_~GK)xA9R`pWoHfVamOUqPZ^ja9x%3b%lq_$np* zhH=JMX@w5v_0nz_LSK2>*LYS6fA*>bT;3#y3h>GV zUrmL#f_b&H&j}O$imKNH7C0#9yTF7nd1-&4jP=H2no~3R^D)+1j6{zic=D6yWeP#@_}} zsJcS=dri2t>F4P0R$utLCI!~|;{CHRE|gL~1z7aF@poMmPJm}V zZwNQ!1>^6g@N-uif4>XA;zh|PE|zx33erDs^S8?QQ-H*mjlXzN$OTV-3Bpx=#rR7U z-nrKJOA@}vI{I6Z0e?ACU~MQ~ztUJ+OZ^n!-}S~{t|+)RD1T21ca)subD8khUo-xe z3txIO{Y@AJf2X7%`!;_M8Gj1!{_DoyX;JXsqWpa)+!Au)uR!=MdB)%O!hiB6{pC!A zzeW|Mf4)|{ewU0t1-Soh;lhxHW4oQ9pkU5@T1=~{vw3W-b#NFY4Ep46=;8+ z`DGwh9+FQ5XtK@t`$QC`gQvewg|j~}{`LxAZ@clgPxz#r^ml^eVRR*_-^Swg``q|b zfWNRoQR97#C?w}Ae`AIFf}G@YobXpaH2%g5ANVo-jZcO@zcA^a+MlO>?QpCi^;3X% z_85QuqF{fb`~?X2I63iGLijD88h?SpALK?VcwZ;@TQ3FHrsDP6Wc(?>Bm0fN4WjS` zc;@pp;re`T{B0C|`T^r_lkhoT(BI2ktNbhl+1el1k^Hk)Rl(9u>ZbrPhmF5WqVPC) z`ujz=az~86%fh!fYW!UhzSA-KYvh9A{*|TuHW#noV&hK%ZXP%O28crZ3FU8~aQn$g zJ_iZ^%U8zVVB!6~p}+o|U&`Dg?Wg^D+V7U}rvPt!Yy6cJg}=eGej&m=cFOoGC;Z0K z#$S2iKP#ZWzVKxCkOJ%V;`JMc{gC8S0p{SaQT5MsQP>Zj{(1_Re#ZFgCH#YDjlbT) zFaC-C7GqUpKQ0B?+TSeId}zOKjXwowbKdw{C<>2(r@uwQ1z#}!77O3vqVcyx_z{=r zZ&NS$+bIRs7F9owzqDXoKLxnwvhlY|6h?xlzkJ~?lau!QP<@LCnx@X6aI(m#@{vJ?ceF|F|Gw8?v?(TSG<0W z%jo(kz`K7Kf03f#^QZFHOt^*Q#9wpa^ZqjaS_uEe-;&P^_!}by*|+&yW&A0?qyHLz zV@2T*c;<7QaD6R*?QgvBvu%I99-JWj^S)RO1^>kB`^!>by-~b=rLpCd{;2>x{9!@% zL9d9y3*hN*t#EY%jK5cfPb*>ktrLE15dDQ?18e^&1=+Xxd&u}xfbder-(R9I4m|zc z67Cu~$>-m~R}41({t>=OS^7)I?#E89BJKBP@$q-b_)~zBA;w>dDAX;d{G|%_Iyv#z zN%%wMjX#(0=N$CM<8b>SDah9TJoC%I5S>p2SYFZina_N!Vj!w{Jkms%y9Z^ z+ynkfSC#ow`}3?n+ufx}HvU3{kEu(4$2fnw zq`-Q+c>mmF{3*c2dd6RxD731t{B;&?Cpl@qF2bK}VElCz-nTLReZuv`W+}+l{yh1t zf>Tndp8{-cV*I@>3VuzMzb(QoCMW*#gnu)__0zWZ&lRTjNgwd=rho6{64;JpDZ@+zE2xZ>8{mCmDaw z3120Z{+e-cQ^h5g@3k(@fRfg)}HjY5oefov=mrd zi`TC)?i5J<6kvRBG1@S`&5?_c)Mby8rxU%Y;$E9&|wK$W4! z-+EEV0#AP%gexQ`?f07S6^9#t8-;H zh1*F^{9O?K>}ccfqVT>vT?szMeAWnOf3dcy`g!K-OU9o9Y#nd>)f5H43CdqB;TDq< zf3<~weWLMKNBBLH>F*-1N5iBb`!;_AaT7xNivrwtzwtL*6n27VK1T?b^nmd0bCD0E(I2!C%~WQdbHU1Q-CQs z#@|9w*bScTw@A27xyIjO;U_(5{4EiF>2msOIRgH6Nvu~EtevWUp7q2y+_;c@DnR*F#^2wfFc>`j{Uh8@ zo@@KF5%J@@&f)|ay6j5mWlJb`-+}q^D zUnk*DzU;5>Yq*3*F1Z(LSBuUIwXd;mUkUf>x+%cFYmKiMQEMROTZz^A1gxgL|e03H6`?rj*Zo*r^9}I=Br-aGV zzC3;7n(?IoSKl$do)(3eca^Vagxf<-e60}v=l6`SXN9+dzvnr8bY0df{KMk)%BZUA zr2rw@jIY+BFc3WZeH-DTfr#2G9QPZ$Mv@Zu9ku@udL&?lHa|5CzvK%GZO!9VI8erU?K0 zr^eS*;jQ4+eZXY@E^`Y=r_5&^Vp>_*j z<{;;(`P^r22P^Vsjt z3Uf&N@{F-d#+L$oe$@E-Q53?yRK9)^ZVfr{bx!y_$BeJ@!dt=qoPQr_#CpYjtm@^N z?+1qKJSxDk6UNu0qEO>2+M!e9P|dE}cd?B}H*U;D#NAo;`n zL-;Gt``8L#_p*ZL3q}rf@%2xe5Ipy3OCW#-9STzhL~`BMJ+_)8D?Go;Da?;-U!e1^l{yr4m|2O*E%=-B@mHKIa z523F7vsZ05{uJQNYsR0SDEtGS_45~Q-gVe2;Tr-<5V+pN8!uKgC_Bj*aE;WpK-MZHe+To_NvUh>h?RSw)Q)) z83Vg$2UsdM1Dkp0W{^m0;n^TYF<7{bN< zObo!_4-DipFQuBm?|fh?@EMxw_{rt>u{g7%OFoY>Ja&w`&HSr41*~A-GT5@f9wT;O z$$f$i=bdh1Um`XM)OQAp>%QYEvDqcB3w90f`V)JQSjJGQj*ekeh~)^zqRsxUWDS%B z`G!BBv40wDw80LuEk^@lFO=#m*fsZQY+bO9X~Q9^Rys>W*^{)$U6t9!41Tr4@i?*Z zrI!mfe1gV~2P@&dX0W4Bm6gPfEuAmeHCY<_tic{P*!z7g$3|lJl)fa`@DUoj2drZ| zMOJW$x~%0IeBV(rBBI*7ruPo6DWdElTI7zrHOi&It{?%eh@BbSMPUbNY(22j2*V9_ z2qI4*_W9r$g3a%tvFXIJ5poQ6R~gIEpV%A0eC!P0CrQxQIR?AkVDZ{K$2ektEOSJ# z;T<)0qrsjxSbQ7AafowMjk5m;*6N_KCk)nsF)ek&x1Su_?gO@E*@h@XirQ|d9bC4zVB=b8Y=ps%GuUH@;a)jkDf_TsGomz>57mj?6$X10*k;6*2zgzw z+08X}zQKM3LY^F(Z#h;lg!quJ1zONdL*FvcDFq5U#Puh-D8f-$2`4S`smg0CsS>`Y6LxR8eDXu!3!Guui1tUSdm@?}U|uN;NFU&pb>YSbmN`^UG^!KLcHEps|*tlnc1^* z+M$5HR=&4D*BEG|fsQrMIhJF17NA?o&lPC6ferxcm_gCD@~cD?SGKsrH&L#-CE7BF z*!|`A3O2vA#=Zzvf;(-n_0T@A5__ZkHNj>FY3u>8jz>5lq=c4j#B_8sB6r~Y&ZMLx z0t1ZD&Y^7u8g8Htu#T@fLzEucOGE{M+JU>N#uzJCEXR>Cfc6i~R?rd}+MiZFpo4Lt z&xt5IK#OEVEb9r;n$UMe)Xj((rei%tYeNr480_x0)MZt97ia6Gqglw z8P!JQZriFTmsE#hh@B($qtF(DE%4Q5N`rOmaY1w~w2O%Hj7Z`-PSGEsqeYZ$L=x9I zivA6KR77z`K5 zE;(C`oJ}BhsAH61GyVY_e--)FFo}DX!8*~E7t`e&2fvkx6~`@&9S7ENfoI3N9j}Y1 z;4dv=;EvJ*AlmELC!#e*@Ze`u%!tm7vhA(pAoOIa}@2{Wh%M2-rRM3iAf4AW6+6h!w{ zSR|rwZ;|9^4a&v$GnONPR%%vwSD@LyYu`Cw1-jorzp)&n2#u)ly+GI8)X)#WI_$v^ z4XkiWL>WdTVb-Q-XoX4<(gsE(VJ1^FxS9mk~)AgDJ|Z@PhJn&D+;pir%a6zKF7oh>a*IIEZq|)>6yy z3Zc6yoK;qS(^htZ6)3-NCeTkU$ESquuTVBp`m}*w0K##IbNbB+4MmjytF|Ix{zlQ? z6%s|1ZA6liio+oCtC%68a3hkw)`p_e6=y1~tJ)whJ&u7CRj&B7h}INpk%Td55=4m= z-%wgcBvZ^}iaJ&NTtt=;$))6dUXpuNJSU>?E7~CEH%BhDMppD`CSCrL7P%KGVJMej zd=o=+EwMQjn=0%DjV%Gz(XKm0-&IT%QHBvodeSNSvEpzM6`a>v64w}t3M!eE^hl*& zMU-zulEA+xT2LvtIa3j5L=tGoaEO*wsxP990&UQJfoP9%33Ms~?VAkjE0uZ*w&0Y; zHUaCXLo;7gny5r4wMY^;YcxdF!WN2XjS)!#pQ5OC*jf>V8@I7QL;Fn$XUbM8?sV!kA|RZuQNBp&k~yVCBk<^s(> zqM@b13N+b3>!E8A`dQc@fo2Ds^Y|D*0rz?&|%|KTJD%0OA94g1oRO%|Ji zphDZUphDZE1zey>TeNH`Wrrr+fVLzphzq1GiwmR$cTHH_X#r8M7(fLtQWiJF;I3#Y zqIi|}b0*)E_UiBd{+{=FpZ9rQ@8z5C%;(IRGc#wlGiSd2Mnbv}B&&DO5h7x+OkdP__@vyAz!P=41dvh?=n+ikLF|BVg zpoP8nNT@snaec|s974R*)GjJ*aW+Vo_5N6rE)9{sf}r+S=3?)CSwiDOkX(&*S^{WA z?}(eZ3REFTDlM_;c6IL<2_1Yx5lg1py$sOfy;CGq7lN9_nt^yJRuoFWq|fxum!#z( z(sTr63GNG#_E2fhF{!t=TaxC4NQ)5E{>IP?z4uCJd@Ja><$zx8&42m@ojC+?2HNes z4m;iZqJ&f-NNU?&hCb=t;TBGH?x0dQnd$?E&i5WHp@ShvR^&Gfec5}wgm$-r)aih} z?VTl|x>nFbywvH?r$9pGAxMg`jiD}msw9*Xf}|K;hO~V=64Heru6|i@Zy;XQ@f4MI zKa=+E!(UuMmwsI-%pL?K>GvVhLJTiVI-rkcER&88k$wyc?frKGO6}86Lb?zn#oWr! z9bfu-xMdp>z9NHd+%y>-(IQP+bU;dfaIdppAVlNhqfkbUj0l_PK7H)SVC{ zB^<=7oc(=9Na)}`B`?`2zvFem+kGZUC?^C-;V<#b@?M{r!Bh=Os^+C?0pew&HK?@F ztkP%uJSa(3AyO-X+6fGO)8}akjjva@NN5aqWo_R#gQ-H09G9NrQL=a6Pb743uaZg@ z#>lCn`~D`O@({!(0&NaML;FU?$&T=vlB#(RFck4p;u9)u0h5mDnT1W7S|W9YHIe@I9df}|LcyhEz(+dZDE;JQ|jo}tJ4j*^h7 z6_m=*(|yw`+Xe}$_YWTk)CDfWZ!K;hA%4& zdFIy+oDS%-zOPB>;7bbBY!iDQ@p1yZ1+#An&n8WM{gSr)MTK@hg4zZ)KMd)2RYFrk zkgT2uvjC0g*BiEbjG`e(R_a%rYE-|QBy{ivg`r&3|HaU_ep4ls6M|$<=(YgRgnkPo zq-q5n=VqVVZ;gb`?NJy?F;3e6&F{BeLggVyE>5m+s{DTYf(%2Dte*Xo0IlkGNlSFh?mt9i|XlO1ns7NWZ;74>{Mt!28p(x8PGfZ`b%hh2$FJTE(i2(zi|>$ zg&^5%lR4Fies@dgpjTlip~al)Y`-Nzh9QUtTPars;$`2uOQoH~TrTu`RFa^&5;_=yq*yZ;>eBzXgz7?&)WIT#wEe%6P)-Pv17ZzBz59nH%C-(cQsSKq zMfZ=EP~G#P+Tn3IiFGige}aU{Ly#0>2}9}qGbEG~f}|KPGjwPF*_siPZfp}Rv;nohpl7yDFf^K2$+|xf(LQ_MK6vNEW zEB);f(uE+|wMO0zXkUMqgw8#yNGPH8oa)W~&r7H-1j$C)#n9pYha@yU1j!B=$2+bc z`hOnGD+Ea~EDQzu|3^Zq5F~5kKP<-O{yoNXZJc{X5kroReYg()=zpVxj<G73 zVrW#X!*;t(ViqL`sAQKuwy@F_)N32kP`9TkvJc`N9-y8yir)#+AdI5h-G zF|Keq4@C`?kS+vCF@{bC^lsE`5<2&!l9yacOlRms)IAa^4?)el+t0t8OX`=I74B&*CkXJf}~g<^8D3NcUD3yo6LCNH*%D3^{avO6c5n3T7ZxekLzC*XnxS&L!9#g5+>` zh*LeN8!aJME9e`Bs&tbjw6qoUUNWE;ba@h*8iJ%4UorHmu0lfNLy+v{8N32&(A7#v z7lNdOeYlq&)YVJqr#eM=Dd9~Fy{$Vbq2sNfcJ~7MQumXDc84G-MmCRL-|509a*^vo zkQBqk&_&%436+N+DaKxge$h>k(D)D}XVotmx}wXLkg655kO#KD(S^ahY8Bz-USbtP zgQBa03`3AyL9J)#hG?&Z4!V_8(jZdH&@ItE3F$&m^ETrX#7nh$02UXn?%SiABx(6J zh0A*gYCq2bv@p8!B(8#~AxPHFG~P}viykH+T?mpY?PRDh`gRGaLXfPT?F_AqzE?u$ zwkml^=omNB>gW;))rBBgapPFR$D=n%s5}HoF?QYo=$Yu<63Pidl3_0%qP)>ZB{V(+ zNrfnt$`}2mgmkT-ZBqH7)%d|68iFLlixx0E9o<(#=N?mpmtu_NygrG(MM8BUNRF>V zdBNn5zEeUuAxKu#6P)VXXugq+yh4y1;|?&?6n&qB4nC^nB`tS-G5~cS@OUt<5G2LW zlCPYOEDht zvb?zCq@BsM_Ya&dX>-;nw6O?k*D$nq;4%r-RVa`&g?_`uYZ~~Vgj6A@dE>nU@iK=b z6z>aen5zR{le7mN3Y#hfWmUW%qP-VJ&C%SeyASe9+MF_lc7KSLw^2dKL3;<&P8oC^ z_Cy#2S17dKglLB#UeaculuMX){h$O%JHA+j29XI9+V*=U6BH@a%d;;wE5+r zz?f86!_VEzy zXLykc|F}x~Et4h;z9dP@mn)>l5Y*1(Id|^h>oD)Mr<@QZJKJVn3d|qO_y1ui3qf+E zsNz&h22YZZDg?=XI3N#D!Qhz^s#~Vy#lyKQLLuU1aq;J`w5OR(>0q`9K>L;|v{nSQ z@yurD;AbRsj{l+v{_8GvHkpU1`oV8W=-}cOsbmgk5HEB13>7+;*&G{uG00|tLhD0N z(zZ=gXd^*8eHLg{L;4^NHpD!I_LmUtNW{wuJ&NOPCLKIvk|aGhPa)MIsGYC~(9|I_ zgIsbINNPecLvx0#45pgXQWy->s%peb!8gEL?2;9QWU*N`5;- z-G<&QAzg|Bv6qoHo1xgDcLY;SR3LfyWn(CF=t2pNzg>ZvPfQ$$m*qVMxjJ%<<_~>X z(&pT%&@Mwz>%SAw&Y>>`*-TI%Dc7G2y*c!K2^~yQASqXO)~%0+eiKY(P@rZ9nX8DG znM1X-u}s@;ST}SNRLVGo_D7J&${vAuNqZDplESnThE0&P=WbSLdn2eVMTb&9I4oO2 zyF-xdOIsMK8dfNw@(?5^$=wWX8CET!@gYcVC+YoSHC&;6Cq&x@ zBb?;x1nuL@_m$zj5r>iRdWE(LwA!mVfc_kQlZ3{HAla}zcn6>vF;zkbhbXCJ1;#Se zX~Y5vog1t`ZHI$lGDH1GtO@2dP=T72b1UMdT**+*dzm(M#0!#ErBi4hKv3H?70}}& z-jmR|Cu zkhGt|#fG44*WGxLbUt}*wISM%L$tSn_7|odeM3Of9_+5r9z{@l zoZEHn4V^HGK>I_G6rBHFj{2b+hDzvMHzk!ktenTtBRAX@gtRRL)kfV7$aBLz5<1wm zgS#lgHfD-b(LYMS4peupwJ#eP}Xh7yA;|fsIPpcb;b-p90tQMh4v57 zYL7#k)Td$$5~>S9Qs2%q^l^+?LgPaaFPvo#ix4jxdKVgmNiW1WC24tEC4(6VYJb2I zRoxWhmXIz4$!+3QhW?1zE1`33lvL6%fj(*X_BUzAWeDXHXA zzl5Q&`VMF^j5%rrYVLzN#LN1-j5^uCw6pa$2WkJ*V7A6;qzi)KscQUDPrS&|?N(`b zap|7X$4k<>8Ca|1Kdqjp^VPA1GB)Qw3Ii!(Iztb|RtFROp+Hi^Ke&mv#(E`G{<{J- zyQ05^_~0;sChm>xi~5b&Gm=(!S)qLaLHVuDAMqkZOoy`!>)Us+ZBT8n@mvb!2nww} z7f{B?C<%=ZK~l~F;Of~U`T9RP%P*l+yleW38({g!X~9$h1!`WlE7hX3oHiD39TROM#8NIBQ3w7nLC^u3X5f~1yURfg|JkpD@JYun&5#ajsB8>|bi zQ>l9J2jtaS{^k+ZtYu1)7m>w9L`lZ$RXwqnz_{7wGf7omqEP+Fg22o!8RNrFJ^8Eh z>Tzw`A`bOrRmjjLssuzyX1S`KKA2Y213TOxsZ=4V-$6AiM3tuM`Q<=Rm5#boQXO0w z5gQ~QVQBb z5e1UrYx@dAnOUzkEx7j{it_aBgpZIbOqG)KjYNDxFMMYml8S56^lz>X$t$W8Bw`_S zJ%UVSZ1lC_;FH*TR3I0WOQDmp4Qv}MfRt?z0upCI2ajoi3<-zMUXPe&c<41=K~BT; z>ZD%5CJnM5BWq%~!c(^32s8y)-_Su}q*BHFcPhs9icm65?6r(iBUyXK_uO);WIghl zxSF2$O23i{Md9F$*V460HM#{E^l;3zLTM1ZsRd62Z@yLujNY=&p@uHwZ(-c;z*l^G zR^5t>#$C%OB;e+tfN}lQqayEAPwQb0w?LQT+p0!IGMfZ`=^KW>trz4s3S~|V2jhr# zTznV}f^_2ntGcQ;-P(&OCIpF<(5=jyQv`Y6CV4}e+ryC`bD795D%B(g@TcWkio$S8 zi*h4bYD;#E8-wy-&=1MTv1vhxm}7dV5xG7l2Z@+u$~DIPmA&8>SE*MdrQ_ccICIgRUnRHUr?>9VSjKBGnDuoULzuu5eKzSrE^lab8kkV=)+ z0gPDw>}$C&%?#NDcGa${agf;61z7=>nObF%Qoov%r=>{@g%62kpIoB^7LI5}8_DT5iR zkq5eVtp{HbnkU*{8>Tx1hv|Qq0h(o$H4|(tWnAgpdW7h5txdS|UWXtL`8>=Z*!3EU zt3@qRqDe4Ggj$oEPJ4}%gWW<}&^CDYng9viL?-tUZ5uY~JG83+;2}whF`+jlKEao5#c~%v)?PipgDUkDZlg z%MX$)%$pUPJA3xuNyg~M{xh?s!R+{3{r4`Pn>)8iKbysvZ7W_nS3eIzs`72i^A_ih zMgU9BeA}EkbFFx9qf#+Resgr*k{~%m2)!;XUbcVJ6m~QG#5pj(=rBm z*k{`o&0REW?(!i0oVoe4m$xLbFV362WX{}{QTPsh%b?A^bYUxeVP1YKg8YSfvs)1? zEzY;iv~f8hVX*l3D)}G|)xfp0eD2ISL5f*RmMm1o;9=qi<+?eR`q*f(hpww9n@FI1^*z+y zN+o9UQ6Q4S1OJ>>)RBioL?jq!!UAC;jbc2(fS-AWH9#&YYQd;ELVM$@q8pX?3q{uR za|%Y&DYb~`bT4fQ^Jqyc{M5livl6J#LnAZ;)YL&3X|dxpS>5z#8{rod(kG?mr_(55 zrfGgl=IIp9lYX|Fnl%PEG1I?*UD5<>2vV)mQjJGQPrqUc& zGu3&8%B}D|Zx8ZzBS|kaEih8IgjUbLRIdL)%z9f;%tPTpG3#x?-$UVl7xP--wkoOo z;q`wL)6p#E^9t2Th4=Fc?~~yDk79lu>4=Os+>wWhQj^^wf7-J=YTA_3D1RphgIjeh zwmOL){rHhbMG0@x6_v4S1zz0`Q<3?0j>n%|KYu>b&33z*A|@6rpp{v5^kiJ;mlE-$+McVm1{fP`Hsi68jL?^9sfZDKfy^n)tDe zAN0f&7EI%mflo$q^=Up-5UC$Q3PUd8RqJ-(>b>; z!!Y--&{7W(A(Bo}q0o_DPjiJXPj=lfTUf1WvmM!}@k(>tw9I#uIyT~m!hIAi%uY-C z7p4rl%P&^a3l!LXijJ%Vlar*UdG&cb9H_(0VYJjm-5j()PybqJrf?S>CgBL>K)Gg$ za?s2K25aaI5>{~RYotXU1HBCT6BIC*=*5*Hf_`lyY{+BH3gq!f+yBbLtmIL?Lgw*M zTVV_e0MVQC09ZqnZ36~mkwA-l2KpI;&=y1(=wgYRF2n~So%CB9huV-veO&5W?x;~y zK>~F&(kmL*-y^q(Ry0lIqV{?!v{jDK-MXKCREhekF=X|5Qw{XSx1|nxYm-`_GF)_r z$28ZJnU-?Okef@#zb$ps%Yghe&_y+6zI}0tRP!C^f7_^TK)o;!M;^AY7-A|tktb}EAIz?Z$?{$pF2{i%=;5DB zh5u#@6Fj8e$#WDFSMuW&KQ_v@s_j(NNXeR^YV@d!MS66!s&=mC_ea{upeNc1o8>6Y*9>HSzZ9uK{!lyL;W;wok|AM3;D;hJ z0yXU%@}0A-X{XO!O}~}~292G%hK{H-gVkgd5y(VCBN{1OcxZ`85Z-;lNd-dXGf=h>~n7@Sq15Ii8|t{!m$q562ru2}^b+wZ~jt z=-Tm)sewAlcH%Kd9m9`UkXzCw@at>z{q+H<_hu{&(8AOi)2Q7)pLT67v(g9Os2u!e zqz}JQnaQ)cEP>w=@W)yUU)r^ycLW`z2AsK7{_9MjWyonQ?(k#u9Y(7pZ@Z7390s%r0{#YT#-(L4vW zw~5Fv=&u3~x!T(-JZfH~^@Ra?pq=nTlaI zi|j7yA{?~LNL}=_Ouv+7q1Zib)XPS>SRB=3*2hJ7uys`II(#^FA37$Jpx0&E zYJ-hkL4A0VP>bdK^wM-Qji{&TdK#`LXIbFC*qU3hok}IHTG4QgYnEGbjn1wh__Q-u z*}7iJFw^jQ%Fxp=Jyrg%xO!V~_53fmKD;7ulyl@MT|*ylD&q+s^Xj)MIk9q#oK!i+ zoK2@UK`)>A7TSn6E5G@uPScXb3pEOh_rF(IASTEHF^%_-r-oJgd$7QpmEY>=lbSL# zQl^9K^=lhwlnaYW(qllp!$o82X_Bph5?z$yr*%K70wyuAD3vDrseb~^GSUFe5OpSX z!DMTsYzK8o;Fm~@J(<+s%>)ZPu_q05p}i(XT}5+!$)+^%-j|oentiM?1wI;pX_;#v z%oX-Ez}z)EIYh;>Q~ZnmRV4gRDERvn2?ar|a(Gl&ec1iz)nZ_ZGeZo#R_|tE1j&u5 zVqP{Bm*yBTcX9%8o}aaJcO%8r)7?h8K~HN|3G-n1*#f}KFJk43E9^oo)mE3e=!+jz zQu832s4_$``XE1kmJeEo397xPA%7a8&%DGSYvl zQRAzBP@(^JFgu?bSDr=}tIN#v;13vS!p)~dcl_Up(JNwXd76bzSC{!{2V)&MbB&1R z=U#sBDnvscfS-KX`Gd+;L&uo@B}jUho`noM(3T1GDO#Uj9sJhFZ)SQGJZpFDdMyYp)78KW$zhS9lX^HWDT5>iQH zZ7!`Y3>+|}#vY;W#wuq_Y#zbUaB}@d=fl*o-dh`Q8nZijO$^2=nlJPeY0j;dx#!f& zAJ8T@I;)%+QW0ph`G++0bOh-$t_dC z)R!?QghPe(s8ddWkyA)KS2pWk^lDk)k{ESKuxi95<~cJAxizPRsfH6{v^hn+8>_^8 zkta;?hCDexhhdBEpdoik$1RKT9c~&N=Lgy4A_afu34x#Kv5TdFn#$8TRg~|?1WiS@`I-T}_UH1u-BpM9B1blP%Y-{} zn~4^=peG~A=B5ty6kY%BSY452t|8MK6-$e3{}{@OGDI0@H~ElUR8t3sLM7vmwn$Rg z;+%&B(b8aj(sm!OSx=c7ybMsADu3-I{wVNp#&`)I(i5JkD#ZoNn za;st(e?uJIo_0`%?eV4+F9_xRi7k>dRB88`jjxNM;8wyDRwScsVW)}?Z-}MWpg6Mw z^fg>Mwv-8T6&*$geznX)!R=$1OH#|)&)`?;;%lO*Quip)*hCXN)Tpx2b8@U#(|am+ z6TMIt#6M64nrJ6@4YJX7J~Hqks|1FO<0{!6f)^#4=lHRc3Vrj%!~0o>ZDSnHqCF`J)2=xC?$x*+Vx*N#!MHjvR03dO5C=Sx<`wf_4DYbQfswIT%`?aGZv#px?ima=mBV^CWIftFB4zxD2)GXW8iJv zPz-~uOdh_Fm4ML>7>8P!I;<_xUP${llg9l2Q(l<;TAEktTXO3FZmse%w?uovw)3~V z=&MNcKUJvs0*#@T)(XXV;FxJcgFII$vS#J*eEMRk&_yy44HW(=@x?~E$4Z?7mo8nx zpmLdfsK3|LKI(3}m)=q*@IuLU>&CGbaXppj?|~v-F0FUpN}b$f(_@6EVzU^Lm=j~6 zK8>wu$LzIGd6}zQS@u#Pdj@X;s>JiW7R|s2WiV5QjRp(b44UGhVyrKE1w=6w@UBs~ zEwn=o4eTiV7cX9fc=Th3K^vT>;LWAZTR2T?twXu-msW0 zhN|jln$eI*^~Gj76lTM3BYv%!DcRHm%0*id?+>%$*T=tzFQGYR0M7$Bi3HCV*YhtY z=;`?{rhgTg$#&i#s@ zR1mcA%7Ke~MGktc9cIXDMqD|L&~r%L*v_4;*loE7NP{TtMT&Pg#Wm9`D}UvGbAGVM zMZdJ>EXObUu@HJAJS{ofc<7=(3ti+Cf8+dBPg6`1b`Cl+n+=JzsaTc|NFW>fqcioZ z60)MFI5|>lO&41X%T1=!C?IwlLT5>&hE=W&bV!px^{WzM#p)UKhDOgd@!BdkeWpRa zv~88^B>6$Hb(KC=Y?y&)N%80^yfxl<_=SpN-K?(Gq zmBv_+KZC9YQ(Rf;rftO8ezp=kcYxy4l|jL_k<9jEHXg2*BtJ4q4M=`an5++ye8(hS z3jBAyjFR;ttK$;t1&W1w8HIYG%W9$T$-|jq-M2wW7n>=lM5=_NYi-wv(%rKnj~Vcigoj;qYK9@*zUM? z(IO-LhC!{WOivfFMV-=U!hR7{k?#k|u(1T)cBUI*rrCPxmmr@;daBIDw7FNsiy$?F zV?BN($7A4F4~~bxG4#8>%v?>^`-A_w`Y9v8|3~#)R6%4>ZzsDA8;K(ov^8H7r=|-XJ@i<<*(81@e@C;}vV*SE+^nXB#*H{`qPG^>Xn$lqtdTZT zYGzto1^Je164bP}lZW0}?l6fB^jaq~*1w!AQAvhL^5Oy*ZnX8(P$nXjgaMgw0}}qc z+{M|gN5bJUq0BFvI{N7mJFy^b=SW(vFH-YXI5p_1A3d|6o=&3}FvePf#rG~__`}W~@+?a@EVj{!&PuAu z&8a?|544*se1ekfluY&Kfzhe2lY5R*WY1p=hC!zg*V%3ynaz z`a5WrQg}ym;g8V2u{YaCyHO$MRj3A30qi}fi#W|V9Jx8DzyYIQW?E1KptR5coynAV zn0k09PgqkAi!qAwVyWb!rC8>*$I29SKG_3ZWV3UgMG>SB1A$OwRe%-XQ2)@w$R{wfzQIsZ(?xk;5i&GZlo)ypZoe5(}z#y z1x9pzZ5}OzBzH`Xk2BDG-#t`f`;wwOG}A~?3FpR(%1}-?)`a#f#CYmUwz;R)CIO%h8P-7YNUtN`@1bh)B|TD91=T zryB#JU?;}UPGBpcewc#>m^TyIXM_Bw@hJ^6FcwvR=b zD<9X!=|H-iPUK+8?LiC`Sz$-k#TXxlIUiL^4}R@&Hg5qdhbO0 zvic>>Xu&|7AZ@$2*1AxmhHQORo@% zQQMrfSRZdlz3~F|G}5k=fZZE!KSc*_!EVwf?ZIeVf9BMs)2lOJ#i@2yrdsICE$AyE zSLB}brfv|$#>4|VFcUPy8y247H7{FMPF1kI{9Yd{zN0a2S*c%OZl^qzajLB5f zroKm&Y3D9V_w}gRIf-gk!%FFGqoH?;9N6Bx+|IG!^HH>{QOD;WAIdmyJ4X_|T*d|j zSOB6z7J&bItHC2}eOi(3B}ZA{{hH;OG*VA@iG+evsfM%jlcrfNXVqrpJpLr*G{(@7 zM%IfP%{0efO9hS8B|ytOr1jHw7!y&Y5uAQ4wyal6g)O-NrxQoT?gp{wqlvXmIBaMy z+@irZZGs=!bA(+4d11GBqI&tHv8O7;v@UqsvQmZcLZjhMI!O5wY%>VlkG^M zquYh;XPkohu~jqDI_!m)d*Z zVc~fg2ES3cU}|t+6XBW5vnPeyNav$5jw-4vLpEQid{wlS-!8(iP=!&ln~j`pgmKD# zy7D`Q9vru@Ayl)EAFH$Jm&&qwOT2}uuBfbSh(5Sn%FVRvKD9m=G6q8l!4RK4y$pL) zhCysD*jiyKKy>ZpQjR`g;7aHTMc#)C=g3V*j zwA6~SDf#L7h4$rzCTHcR71hq28@;={gee+FBeO_9MgUYmA>MzgVX_hoZ)KcF- z71fs6YA`g3TI9Osaw(sYU4>QbHnrDTiJ=p*O~00k2t-$|Q)|Ynt8f}AwOH~9yFd#a z)XPZojMS4$2Vx&+AFotv%<7=2<%1{CD4*17LW8{tET2tS-F)shyI4Jyy~2Q=SJsbF_Pmi@M8l%SR73%8$aacn^XSHOQ z(y`gk@vNCe;Rzs5zjGIJ5sO9Sg%oOn+3K}EtT1Y*_Qu3?9xyP&eKku@+xrDDj-Q@o zqn-WGfX|iqrrt#d+8XJt660j7C6f0;k%hEvk*h5hTt51uM3^&prZA^uzC=qrS%z%! zOUeRrGK_sn2{sHbW3iH9N!*fooR%1CoY|V8+LQ(Ru(RoQDfDh`BfZqK{thvn4!5o6GMz8>S5=4=NckR8zKE3XEq26;lk^5BbctTU zglp#c=}M3KI}TANALoU|qj-jPBgt_j*&R&sDJOx01gANYLf@e1TR5{gx?&A{OlSJL za8BpY4C)Twql^ow^yDfmnp!EQJE)i#hUuNY4%#~#nrR_lUn{*j8^@&+uN{|sBQ?TZo` zL<0P~@h$XpGk(DtE^2+!-5k8fgzAxHE#Co+i1epNF2Ei`@_m6Zh0R zF);SgH((!1OB(6ZHaJM0KX!<{iMsi{XG9f_%yR1w@2tzRd%Xp8G9CiqD2*4L`%2t9 zEhp*ywk|IUWu}Y8;C`ZQAcZ0V>_}nz`MvCG&hrBDjE&tRji+Q?}4qP3~<4hH?@D*`3c)22e zy#-DyuCv~!Z#@hh@jkNvkKlj1;LJ$_e1?o;zuV7L9mtKzolie+EMvcyhrj1N;ny{o zw;#nBxp!yGPI{#jD?Id?SqXOP@5z`~HNLtEP7%8FWX-g0i%y+7m3ZpZ$DdkK)4lPz z-Yqx76)Wvd%!c-2@6N(1>fG4$yQ#o1N%X90vZJ$8`+$9|Sin-leMJ5|S0*QYI;-N7 z8_mzu8H#Fzw$LWn1MmpYcD(5<^vSo_ycT1zQNFg!1_tH7tNg)`1EIHnR|yB?p`UR0 z%WFp7lUT7l1V63DxbbZ% zP8=RoupHIWPV}F2SqbK_h4(n~tEy75 z!417O2V33$Okc$4{7YA`zJ?VB7ivGCIoYv_@$QMr63n(v}cevxOdqSaXB zJIgR&?x5EvYpz$*@llOb4CjG*OMY5x{wQ&~I89w`8xPQt&rA8-nci@#tuL*w#Gx4Qd87s4*7b=> z*tlc5gkM zXd}$WM9-A8%H&&P$wHbpb-(R$l)>2 z@Ln=KQj8SehAAmr#YpjCm`ve^L6^_#Y-n1)AvH}5ocEQemTnf(x2Oq~q`A5|nYI;r zw$nGlIB`lIX3m8e8~(kvED%EneuLfW&9!C5QKpzt^xAK#!1%kTup?OneT1c8FSw97 zSY0en5*E6wiY~JCr9y;*Rw=!);yL`?rDC`CLD#lur%;~)`ip}%Qnll z&Gc$hDF%f19#osN;?l$b3l#-mxQLCn8gkc)xB}`2DZ5|=C_63=%Pg4leRQ{#Zh(!( zoJv?hb@dx4)l3Ocj7e6C)5AOmml07y8=K&;np;l`>rp1Sl{C;$tULnrF3vPz1C*Oc z9iD?HG*m9jx(WG2i2c0o5TmA3PdLRn=*;a#dN$rnr{u3=UzX_vozMi{O{&enOfc|T?ZN1=!awf`c0xb^XzIE&OFzLP@$Lrj;Wy@UY=cZ$8SF@ZYzu`1yPN*CO)~oO60&zER%RK5 zHfxs&vNkQ?S>+)u_rc)%2CW$?v;<;y)gNfIi^wZZ=TVq6;l)=^Mf#iReU))n;U3mKc^79lwL_9yGdwRx#^nMj4oK85zgrwzi6(RkgQfY*1oYW?E z^$EJxKhJM1*vf1UEyO-zCZ^J%dNHC<*^EpKTs{()I7$>?kuP~-HIsw#9G7L=t!1Og z@dXZ)^93zWv+v9J7qo0Td4B;*7!o zGc*HxQn7n&S_)Yl_tOt{2ffq*Er2D%qa7SMbkgp)hpIa?7T~JM_6~3v`p0`C!4vl8 zLs{v@kpKTHXNgC;{V$y*Dqx^y`zw4{;P;LvMz^yVISc5U*|3K7g;UkIByow==H z#N6K(22Q~1sd7#N{n^KMD$x{U*uZCM>3+mkBlag)zn6i2+Z>F>Um#!;<^pIYnJsNn$SoC3N$ z2jy5Nv50~X$q8fp)!r;fM8R@;2%$?HlBApFTIoB9c?#laJFw4{5bwAm=oCUc=D#r4 zM#u4fM2$Y@g%{c0xo+Cu8%6tz-a@L^fqkxSq#T&fqJ%Y;e(H>s<~2jLv|WD`4IhuO z!oP}szQ;jpSHZtY!;^A!pq%Ovvm`(t@Oydi{eb~^Uo!*4DTtf{1JnpF`=y*(mx4@2QzIPgiBm>G0RFvcz-)Tt%SCy;f-oag|D@l{*8MCvyIdb-pR(X z<8w8Ju2tfC+{xMr%k1ZH9=g>?i8i{;SjpgIfW7F)EI(BbLg5F(B4&eC&`6)d^jTLH zB$^7M+o&qLo-Pgq(IMDTL3IK7;8>*~!D4@yZ*3Le3ROZ9)}8Pe$FLqhnezO#nJ=Ec zL5!vY*?xL+U?aTCWYVjv;1{YvQA?$SM)1FbzT^rA-zQ43`Q{1K-h#aqE7)-(vGlS+ zb$zKgtnt)leuCxQVEQZDLk{qMQH?{3RW@8z!#q$UZSe;Zbathle!I&@&&R_0 zi}&yGz6bA%^j_M7@D;S@8eE*9yZv5z6qi}Bp`{P0{%-HxUhFj4uwnQIf4s>_hWhPKGnNngWALmS%y#LXo@&*9Zc`|$?tsBP<_ z4@-npj|e*5Mw6@-h0a}R^a{*{!ME9L%!!9YYa+lXJdiC;9e_2>l0gSyIDeHrXAi49 z>|jIhU=wq@-yUxn<&3xFRm7z&sKU*b@cPLYuogRf0p}jSrf-4gpiMI{5*MyCL$pZm zqi0hcPK@9<0mle_>0c_g2S3mtH!sh>t%9D~DaVa7Ek4;AXg#ADpcNy@-U#UQZuOQ30RzdDNl-zmD6N!4<=G~h;A8)bJJ+C8v-iZHtrhv zv@`#3)-)`6{B#3)yvltzBX%D>T~_}P+Q?Rb)-zJ~Mw*W^MWJgrnt83Bu+)HiAQ~6- zR6fZ}<#8@JV$#)#P}(>vou24n>!ml&>RnqJpP8BoyZ=6TBwTz;CHJJ7>$~yfUd9ie z^)-k25%j*k3;nr%cpaOy2ML`x8mybAmAd&HsuF>G7aQ$jJI;7fIXHL4A?$x{*MCH7 z;vIAai^4VWa1g&8pN+xtm|ly+N_jxy^cBK1w-y z*Wrf#J!+0Nz77|N%LlQ_$9c%WM(Opbe#$PiaU-dt)l>!J9rdtLWr|*ysC;a22gZFT z;dJ8kn}j_kcJ%gfSF^{BYJh+DX$U(IBZapt;B-#Mac(u|^T$Eh2*x(rXBq`n?Jm*US6%cFC>9BhK;D|YD5Gq{o{dLTDh z4r`c5!jUAu=e>ZlMLwANwknH{BS-NfSuI_EaaJ1*o2cBF+u4?{{)r#b<9iOjd8vf$ z`k=#QsBnxCFqPQuMJ9PT`(z+5Ox|h<<7Ux_=R^+_DNjU-SYaxNyPqj=y)Jl1<90Dl zva*GF<*z)e3#;SzV0%jHLdCC~YE}krLS`^G*j|T1eEmO_EP#@I?939;|4=fAELrf9 zfGB7F*NRpPqk@!!i?*v2WkVzGm^8od_`U^oG^$Z7NQ3iDa|^*w&rW}DYknp{K!ela8YV6Ln$y8SWb74ccoBTYnG^l;Kdkr)#0UlN>0`L87 zVkIw5rnTTYz)hc`SL4DZQn{Y{x`$dS+bW{NPfqV2UO=(t`hLcAlM)oMOlx zJ3cw7b|W1uHgCrV_mDKN|-`W~S$EEGU)^Hn4$M1^~>58yVt}s$8 z{KVS?=shr@``f`qWtH!!DJ}g(lF)vbh#4XAE4$rU>D@(}K^)`GYBJ$CsZB!CGR^HQ z|Iv?DXBbSeCY)yOTLG^`AoS`AV=NtQ0~73zQnVU~_5+Jn1&O|A(W>!Msqq~*r4(*T zNyO$FmxPkjpG_Claf$R~apUxYCYU5TyK=G9KN8kxcRF|Gif*^A+Mv0)$IMI%bm+|4 z@yQwUZ^IhfP)@%V8BfJuB6mBtCZ^lCq+M$tOEH}~wbQ$ie1*m{$+Q;>g?9=ez-xGU zyU>j4+K2V)zc^}xrv7NUaEf?Yzw8z_D?vo(<{dtK_(J-7Wfge%G*G2gDA!?)F^yho$CVrn1KTgyeV@c;+euHs>;3q|wDjbpreH(zrJM;t z6{tCzz0`zu+_Ta~196pO7rq_w@d|F!C)=3mqZP>D@is;}y8;bQrp(P(t=i&7UI+N!RH zQ^S)h&9(Fq99EI$6m6uyyHk?WrzKhFR2X)>Y|;Cry^($|^uLdLswfn;DBI~TH46HD zy8!M?(bu>TeN@=v4T@^dlhwtwg{!z!$@TJw##mG3tk_S#p@03Uf@XXIld%K!cX<_7 z-|O&FB=kA-B<_;=VU$as0WI4{o-LtbCXEZK8(JXQum&nqUt}d8)b+I@RL{G3*;9mk zj^Slz5#&2AUtI9v!<~9$=SG{XxyB^B5OX}&`DRY_HHbIk-u1h%>e7d7`|`jH=72v5 zopQnF5i99G&z17ginCT)tq>Bts7H_&^$4=B%9>iWSzMqLj1De7qPfsk)T6=^p|6%2 z9Qc{xg;o1GvbgxLx^Wl%fB@!dOM06uJzlxmTIsTt~2gXI-9+dOOIf=j9uG=x||Qb5GAI zZf{5E4C1Y=YV3DBCOBhns>Vh}j^@0M@qGc4T|Erkbm)Akp7z2dw~x;n>gk~}hbi9D zbXP1qa$P*QF6M1@k;Cb9t}@+I3Df12eO1*p<<6bn=Xk?vbKp!3UNi-;lPbq+6^rC?`E%D)bd}YKeoMzRqR;l1?wdn%HK7@1$e(6wTX7-g926@BSwsW0t@Ok7J8F&o9}t3)?19S&f>-S7}Dv%Sq% zjVc~cyKkT!*P%sY8tD-h=BvlBzj)YR>cconzdok68Bm$u)utNu^WeUTNqmn%%Gdmm z^6+Dj^2&1TaIq|Y0Lo>ziFAw84j)p_i&zXgDrs5$6F=8lYH%3;e1MM*Kxm6^W07Y9ch6L*;C(+b{2Jn;uE{+`Ec1nuD0&nj?1Z2KRuOyCXo zxvliuTX6EaP9)q)^Wjz`^bKqBY9Km35YlL8b8675NV*m+)_vJcp zWMig3bA41b%17VM^NDU3ocD1#!~9{VR-7q^<;rTs7Nh=tw0emt_Zw=A*VDT*gn6}n z123U8Vb(DE+zP$_1Uch?L%3t?xgs*3dNh&;A6Gca&I^II5UO77sVdmsRGHh9hRIPR zXa;mkPO^VYYf;#WyVvB=qhZ2Ra~d>3E1Rukzo0$;omhJ z{W~XbE)Qn5Yr6!Gs{#fZ3 z`;!s)Ow&jkR>88O=O(1h2%co$%Adg(h9Eut`nP=X{S>PJTYT5WO8Zx$Qj<`NNmgFa zS;ZNyEnMK2O$wJS)`N1~2$8kNBO|UOXa*xQ@5iXrV1ukjG$viEtp0{Ft9X>(axuWV z=?&EL>s-%={#MUFpq^!td@H$0=nD#9pE(riDM+s5<1IDr$ezV_MBcQT#jP+@2xoqE zev%XOg23Dg2Nh2&26i?}FMv*0^bQVR(mE z!Wupdd(_J~d`AAP#PO|J5 zJHQI;^wPg-%Y5vrO#ebO21eYCrMFJ10nPPDzCjJU*jf>DdLwlc3HzuHLpQkHH!ceT2TH6dJH_aUYYR=m z-7jz4N$!4$tt3H*&WZdsfgf}<_;m=PJ>SY=5gpr9#v5rIM}Mp0T_vH@^3PO$@E(rf z%PoJxCEX-`U&Dq!THrcWxu87pbS0wHa{ns!(z9*qYw33v%w+2>!UEX7v57veEpr4t zz@I#)vavE>D)A&9sdm!YJ3Y>t>RJ)w%*dkmh6#O&{2qk0g1sMtZrw`7}K=uaUgP zjshIlkHzdhIdxj)T7fT?nD4+`>6_=xw|i@y+xJy9#An7=$7dE8R+GEGFdnv34=ZcR z&(l~_s)o1FlzCn{2Y=1iN*v1zlhZ3w4bEn1D#z^?w@YVy8x>pQ4f*dj(Xs1|RBIPH z&0sA(1$UzF^4%hdD~|8sAAX8nnG~S=u9w}UR{T;)uWK;wzc$^5rt#4mE2Rwur0>4x zm74t(VRgO%@a17{`nql4(&NGSwNnv)X4o}8-(#6P`CqY><1UFoXE8iUSB)?M^Hc{` zSj{|9A-cgG_Yd-5=jx6XGmfxNgUw;!#h??r%J%-eJ23RXwR*Rd*A=#_in_a+=zX{mxNsaSPpiS#cW9}fu7f`fu87#g zKygHBIL0$`@N*Z)fTfTD5ntn6-N4uBgx1TI_WX1V9j^_)#p4y9q}tZKn*M~QG;sH_puvITY{G5lCo&w&-TudQSW{W%*pn5m+# z%~VlAml1VeU&j5tjy%xn8PocFDQZ#H(0IK%uE zsgz&4oz~-=Q%m>Hc3q&|*9-H7ih1b7+TicKB3cH2U2aY<8^!hVewc?_HRz@I7{9LJ z2V2dQ55JWJ?N=S8@7ht0zeXlc*sndL*OI$>D-PmLm-y(_w(crXMIRM6Yug2UY>ie! z3oD1aX*c$o_M^MkS1*Fs5cuLwy9R%km0xDLtEr3QTYi^grToT(w5`t-E%re<$vG!&A?1*!NgA3aAt&hrg+igAC`c&+dbI%oAJ_sa7onhn zdbOY+dbK&gg`I(T>V}o;q0I23QR9IP8BwVl7OIDgDn1ukd|~MRbLF!W_;|!+g}-Z?wS;!-?yHzWyX>+tjr;8?L-O9iabcuv zCk=hHJPG$2-b6+eU%K;P{MVk1OZ(%`0{S1k3;CIyXB2ih@Yrq?puijk{Ng_mtkDvUo(C5OoPi+2<@opgKcW9J_GdVJ9d_{`nW zVvE%$z!v8pgZE~zzl8TCcUXl>@P)-kpFc<5pD3ei#?2Utn^xhy*-3G6Mm%B0`4
;1-Tq<2|A9^v~k&egj8}_ije|@@e?= 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ΜS;Q%;=t7*{A9~b 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 Date: Sat, 31 May 2014 06:16:18 -0700 Subject: [PATCH 53/82] Reverted new regex changes, not compatible with enough platforms to warrent keeping. --- lib/regex/Python25/__init__.py | 1 - lib/regex/Python25/_regex.pyd | Bin 302080 -> 0 bytes lib/regex/Python26/__init__.py | 1 - lib/regex/Python26/_regex.pyd | Bin 304128 -> 0 bytes lib/regex/Python26/_regex.so | Bin 1092655 -> 0 bytes lib/regex/Python27/__init__.py | 1 - lib/regex/Python27/_regex.pyd | Bin 304128 -> 0 bytes lib/regex/Python27/_regex.so | Bin 1092775 -> 0 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 | 13 +- 17 files changed, 6 insertions(+), 43762 deletions(-) delete mode 100644 lib/regex/Python25/__init__.py delete mode 100644 lib/regex/Python25/_regex.pyd delete mode 100644 lib/regex/Python26/__init__.py delete mode 100644 lib/regex/Python26/_regex.pyd delete mode 100644 lib/regex/Python26/_regex.so delete mode 100644 lib/regex/Python27/__init__.py delete mode 100644 lib/regex/Python27/_regex.pyd delete mode 100644 lib/regex/Python27/_regex.so delete mode 100644 lib/regex/__init__.py delete mode 100644 lib/regex/_regex.c delete mode 100644 lib/regex/_regex.h delete mode 100644 lib/regex/_regex_core.py delete mode 100644 lib/regex/_regex_unicode.c delete mode 100644 lib/regex/_regex_unicode.h delete mode 100644 lib/regex/regex.py delete mode 100644 lib/regex/test_regex.py diff --git a/lib/regex/Python25/__init__.py b/lib/regex/Python25/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/lib/regex/Python25/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/regex/Python25/_regex.pyd b/lib/regex/Python25/_regex.pyd deleted file mode 100644 index ad8e1c76f832426900788ce60022ac7a6f877b4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 302080 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ɯQUedWmdZk8skkI|6R57Z-wWZH}M9ke0Nw5$iU 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 R9N0POOoFT@u77?F{C|wLp49*V diff --git a/lib/regex/Python26/__init__.py b/lib/regex/Python26/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/lib/regex/Python26/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/regex/Python26/_regex.pyd b/lib/regex/Python26/_regex.pyd deleted file mode 100644 index 0616ec7da825eba630315a471dc68ed7fff0a881..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 304128 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

Q>Aj=P1 zU4hh$saH`~qpjGM(ho(y!Zo1?Mc5skE1s_v=bPm^Y0EamN<6fXL(DzgIxoE^2Y(yR z3EgTBIktx!n!b!1{`ymV*;3``A@%}kn|nTQqK^k|1{*h zWL*$>5S?ui?gNNN>elA=hePFzUJXsr*EdI2;6Z&)f53)f9YF%+zm6aY@gt>c%+r<; zj6Z(2?2FYn^TU9XJTp3BK|Ve);nOyv%>04ImAO6JXyT5m$ zpzrT*usA(whtVJ4IJvw*eE5*w`5feM{iWXcH#CbAskyiviGFakcOibgO^Dc}cm6kf z3k)URFT|z3cQOVa3ygi>B$V0Vqm+;v$bxevv|kCQ2qpZM<1dEF&U58mv~KFVW{ksv zPR2MWEl#|}wqM`{5m{cVv|Tk8m-q1QQf#L-iE~0)6X+Mz55d>Jkf_!9>DPLE0T5sN zss=AZT51NZK=4>g&0svw<+B1J)Rr2KpCv6dJp8_}rD{mGkcUvkFL4jGUB+t2a0i=R zqp;9L2-u-B;>t-}B1LiCAW{_0T%<%SJPv0iB@V?dZLk77Oj-TnRd7>U;hiJ*aAMrZ z;YksO(f4RE*qu!&Xhlb27qM*0PtQYxaL-juYJ`YaaT$I~D--~B851qdpg%ZQMuG@! zO+^;7oiw2zg5~+UP|}U#Kj^2dBT`=FNke%vdFwn9@EL!)uAsvkuQa8>42 zM)^!wi+p}EuNtqbs0mo=^~O&F4z#WMBS^7|#kn}X_)@*ti=~eP=%~+P4GY`vdvSA3 zGU6F^pi|Yq3(A$Ynz2Bc7foO*g=!?iJ?}Bqh)j;7 z8j(jv8&bi2CmJ_mEUfVK0D~7oFFdj zwN_A0G2Rncl!z@%wWsXcImwnhY2OB=nVQnA?bx?-MBk>e-XPkJGyFLsMMCREFURR5 zt4FinnLQdE1@pE$UC810vreT?&!JJ<9lb5otxta@np0_c1AJ%p>3Q%u*ci`KDpsG) zVJA-YX>?`Tr{`FGx}JSH*@xBtRv)G?azqPJ7_#S57;{9=g;3LbF3fW(Gz%ChlV9+@ zQS{t;rJ3QuR*Z0uKKi3noAO+p?4y>&o|A8kxBBKl<8rHCazT+6yN43P?@71WdqAw! zC)w%K?Q$`0W4)q#Pl3Oc>~oX5^|`z7RIEF^V!=V&YEuFC1YPgd^sZN04$GC^i3t$j zL_)v9sGzjXkiF`UU82>0mTW|~XhgkG7^c(MfLNG0snNafRJv55-d9S3O~Wd53XZj$U@>W!i>3U%R-6o=iCOrG%9p(~_QM3FB^l832P_4&v~xs|&9c zU*6gst%cJfz717_Qcir;9o?mxdE*Hf8Cl3EWyU6c7-~AItBmr>*KfCVj2AnnV4+mM z#epekPHY@I+}0RFcd$3}Q`!ACKL|TK-3dVJkP;U4pGcrUH42bf{V_ouA<$!mU6Nx7 zWCxP*nP;Vm=j8PEqV1T{U@148eVP2w?x%sz$zG^mx8VhR{8uD#!j3AZ%-YC)=3o(%(M(dt~X8ocg4k_|t4L&5SGpgSFr$sRz#)Gjnh& z+1!=6Bk?(VtPBjV!gdxcu)}6$R9HKr6P_Ffs-X2B9exyXVF?&$C;zzcXF68I1B3N9 z`6Vs4aNMCI#UGQxSOAFt5VT#eMa=6IkZ4O5$q}I(E$Y&8_&e9H)RicCD1T zNMD&Qf6lRX(iB5hHHbi+)l%Ud4IkwOxQySz^Bg>n=_nTiU`P2h3KBr-TeN@24j58% zTeNbdI<$HyAOCe|bCW3*DZj`QzNAP|4fwA^qe9D6IGMUPnR+6bdNrBapG-xQse{Q> z0q6j031fUM{JCZi*6@w-{0hWyoCw%{3Z8Qr3lQ3B&tU3&l|-~=KXX2qnE7UL4+ubAX( zG5CdurY!;N!Dp%SFz3Xrd8mwe=T0n!7#b;;*P!drlwC&oH2FInH^^5-fAs)3(a5{V zHDzzLgm?j9*x$D1H=)~dp5$%5`mVzWP|FJ3*`c+fHh1PbwBI9T!(M-f_83wwq~g<| z8|XIf7~_6q+G8@U4@4H0h-WIg9VzIqh}McZ@DP?@88{%p79_!zA!UqTpo?2xjBy2e zIal7?`qZ)`;|DnyYkbe85DAv}zGag>T+24?6FW{+>*72N#O%>0`|;z}Cs)ARZ|WjH z&+AibJIZeWZhRq|<9!15!F|PoZ^0FFP&gv|ou>twI4?B1h3ez`rVVq#z;9RX)xHPp zn>0WE+Vn9%a>n#X7HaO!c(bI_`0Lb$Yv+SSE)fn zErLVUO`7B5%UmJ1;+uzA5is)Y)emwR^uGd31rYX7^800}I zTkJ*VOWj~lh}4Z&MT#o7AF0^em{NzOyzC}n&w-uT4?qmQ>2m{`icO1KUX>Ouys?41 zU(G*AX)a`q3-AYW5%gzALvNz&dR=r1v{O?nXpyZZNY4i8uYq)4vCVHKo8KN-hEf8C zAH#}}!Fa;iq?co_1JZ{8t|p-I?vT@up+E}22)OwvnRRgJae{}N_XTmcF}2G6DHh8+ z#?hO#;S*JPzT4f(GTs>@zRVjv@CLn{z%B+S*Z~!vx!G=Z{(5Nrn=r%RTtA_|W{j^g zD)P)w5BCK60bc|T=y3z(C>?1yVw*ugIOOtUAD??4D*&IQPZRv(9rT)So#9l|eH-G( zI0A}e3An)Eon!ElgFMX!OTgn)B`cb|kKqwk|9eW?6W&!wD{W7E|AF5X4|>;#$A5UA z#xJJN75ZkF#lq-OYy>w&poxWnK}C@z8wpU1T1(y+aWN{luJ>{+ZpjBC1Iv+1-V>>M z%n_TsPoM%Q$W_{a7YQfwelPR5@z^SpSfK$*2Zt(dY86L)M}_}4Xq7z;CksU{Kul0K zO0b5D?|z|6p&~l`f~!i$70$1wn-i+Q_xUCjhaBzvVg=kM>C3@u5Z}Bszq0Md*#Ivn z%Q41z@MC>h)A|TE&M;ZuigOCo7>#)@>7WxhbAb~dVOsDV;>13Y>P^Fm?~mavOl&Tr zyu}B*wT(`Evm5y0`_V=g+<#z-Lu>CmHMo>#FJRIB<2>TLj0JaA8eFkP<>6A+M0K&g zHCns}S|x(;SD*|9IX5G<^HwlqT2F-iB*%YRvQy|Q@z`P-)yJ+!+D9KN%FTk$| zxjO?`4O5Behc&I2U(jKc!4Z_p3JgPMTA1joA4=C9Zt?(H^n%yq6p=eP$hZMuJs4D# zCSKaX<>Rw4jC08ZI18gs8Z-voAc?a8`DS?Cg2z08+{dsc{2*#P7F3!e_+7^jrNfYW z0JW7+k#s0cW~{Ks9{4@SU0Tp18~vc6R?QAM{K{WIN%TR?nM7D!5WM`{uQWZ2<}n&e zAa<^xVO&z~tOHD(!90Sks(N_t4uF`YLloF5Vav#50T{#P%_7`LhB637(RUb*hbhF6 z<1GA$&$mwVx*5`z7uYYXkT+ZP=8ebhLha%|z>3eY;SL{mP>#k7)f8teHi;w~T1e=Z zD?o6%q+y4<3oLBhTr5dn^fkG zE`3vsE&}Sn9C^e9^8%PXWd8)&kZ3*~q8Mk&D8pxtR?;V@}E7DC`jBfN+zwETN$7^AGY z0N;l)9L**Ch7{IiPy)y6AH-0JCl5Yo$J4U>1T@6p=Eh%q5cccP3K{>B!p2QuG?H5sL44|KFx8A7G25K;Q@F*-oxF00=hA@>pAH%f`X|T`h`aH^ zsCb$YG|A8JV$=ZWIigoeZSnxK{s}VkNqdy;32fWb)(WIa4qgS<&?UA7u0xZ|!Q}8z z^j-{5(BHl4^`wy?bX-(Eyq0z$pf2PX&guC9w%FX zf&QhIY2Hz53L)0$FJ2YG#3x3dM$2Zk6Z_$ceoFP-%){BlaasD;Rx>cPO`|FRiXQ^35M{w&30<=3| zqtKshXpSg1t3dkY#xUd790Z`~K5e~IA7)H-8JA!Q<68)7(92zDRae41qG|1|;PloX z#h#Lxp=ZT+t^wzX_?uFL@Qvkk`kbIoS-K2(d(ilUlhKGtg`n{gN#k_J$B<0jXWZ)4 zf9}xM=SoTkVBw)4N$F`lD22R0>&hOq?vS+Zm9)N^yfc<_d#p%RIgGhExKqhV8ekXf z>jn8QlYDx5BYBva#%W?>V-dF8@FgRLzSEwUd7~{bpL8n!leG_Et*>w0lBxn*7UVeG zz@lO)zr#`eOMKw*KHE54if|a+*=;&lZv=dp2^4HFoK7G1==!*mGCq|9_6fu-jyH~|F&jGa6!{REf_}fwpe~@Bm zg{+cmOh%7}QkH)Rc23qZjI5-%dtl9k!0f-e;Qhds zb!{60(0^}dM1JSqe9WR|=OQ7Zv7TR#-qsXEzo_acxKmpiYr3vP_HBtzflPY8Rem14 z{~6fzew{hWX!yoN@$cBBt}5S{S5K7&cZnLFeB5act8iY8jryi-=g7GugO4tI6H+

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

*=e=K<2XCsd1yL%7Eh>RupUzq=y;) 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
;1-Tq<2|A9^v~k&egj8}_ije|@@e?= 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ΜS;Q%;=t7*{A9~b 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ʊl61nj?PB-8>pcHu~9 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 diff --git a/lib/regex/Python27/_regex.so b/lib/regex/Python27/_regex.so deleted file mode 100644 index 760556b7e6194a1caedb2a9c16ffc3efb9c605bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1092775 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

6@%JOt=py=lE<6FBa=TS zX0&^&jE6MF#l(0{cdwDM?~<3zBxLhmBF@HpVc;}0qrQ}X;v5_Lq;0ebeY!}YPnmtt zMjFx;Z3H2EQXz9}O)9o29e-`^qa`6~DK-^|ws<_Ggfls;3zkK*SJ=Aww|hJK_iI2lr!r2jT~F zhb1O-Y_|;I)hdQi%?~Kwpz`7eb7_A?>yGO7Lxy0?a}|D;9DmZ;<1yp*Mp)whk1Nl`j6ab7kK@ z{T?=hJr;oe$>*;L?1 zf0#;pQ`8>r8bG$9xQY<6|Cfrox8{L$V05_~LXz_!wor z?2Hig8{)Ns54oFw4|ls73K0VQ(s}ylj?(+x!!J#!%s;B|G0)D_3U^1jLH2VxKBB$- z9lhVB!Hp3@%KQk`XvQ@EqlwjcHDY5_yy)bToG_=nAYC{$mTFnk<}5#JAXS*eR&!l4{&ePmbbP(D zxKU-uiU)1SN`H#zZAWb33Fh;^0Sv3@Bk_}Jvrm|_rqaP>e54_t{Cr9zo#h8X0SA3M z`&(Bj3*&#xzCbWw3&DVjVyK2MRTzFbFy;+_IqIeh36i4*Zp)g)gqhpZg_-ZBk&lJe z?U_T;@m0>^&r?Q%JC!Tds)RmKLi>N9bWNGjg3_-OkdL-|PZ>B^MhWF+ZH#*h4V_NNiJFNWY6wJ-A57CwPDeM;fTWLgMSTp~&H0C@=Tx`o;AwK*#~ zb^y{2KuX3R$sE)!nD3;Vlm|DrX^26pogV}71WL?17Y<^;B^at?!ChBMKW_Lh>tihvnqY+3u|lP1b~8g$8S# zuVU=HNBWOKk1|cO(w+%Xi|{&~!&QHPF7Gs zm(bAqw0A*MhrTz8p%lJ!X>F=-;w%)pcG9HN$e5J(C)@;vrwX5E(QIQKoHEcou<)=6 z>84roimZ1FXVhl*DIHVZmsoj+-t|iM&2${UNoVo)p`wL;97--|YK+OVilMz1bC%BI zLs-VwPY)Ve(9|lR+;;C}d$3{iF!*1>^V7eeX^c|Bw$hwbxxeDRLB00)OX!QK!ni}o zbHKB+{L=}41Az{)`4mZeY6a9xxA3iZT|jIWP6}sW+yVu7rCtNt7R_oWDXZX5c^hz#AQ4aJ zcAPQcta>}11MfozqitAe4B0rXK4Rr^Uaq>UmJxCnoj{%MAgvP#S%>l_OHQG`9vejop{LPB+H)jz3UJ!5=f9x+T z{@(jw_*1%|Lgxn!dRs1w4i z7c(m>{Ko<$T;cjV-aP`ktX}A$MJj@SQ2p$e|3+QyTXj&)`thD+IjeO==vT9mkRNK2 zDHMSwUw*@^Vx|6w2QI*BW%^Ga@uem=wQhUy)WL81wht+OHhk4#`eHhZNAjkO{{;Sa zkIRUj@*cDa9z!cS%yWfdo(pc-P8I;MPx==R#lCJ*vhi#6^0*^ift3|!IRWI(th#Hs+%ju(k;D; zU6|>555Y;vcqUvz9@ z3!MBkSfRUhZNi@+Au#SkQ1&A_Jo@F+hO+z9IIY21>7@7tL*99M224N^9&Z$ST4AtV z7|22a)!-~ntJOjRZN?xH z8wr0DZpfVVSL1TO(kCkVx54nv`0RsPz-Mjgw;?_^@gl_ME21QWPhl~{XN1bBg^6Rp zWvcJ>A&AW(2IUb}L9h@z+O8)PQz*PXz>HMm^+2^B;?*Cw7_>erv`&A@pp|6VWwf3J zT9H>4pR*%;whqE)lUgez5TpNdd?tl|5DEu`JXb)Ty$cT;jM9BdhnM*-6uUD%r7?rg zA!U3n6%|_A{Ruxqe8M!!^l3>`_)M*PeK)v75Ij`cU;7I~pP3UhUzRqpn+kuYLzgQu zZ8c!VFg zqR0>b?l68SU1+)ubl^`p$-m%Z+tH>$*%@2K@_U##p@Gh1)++Py$Uh!sW z-{s9)^*MbS*WdQSNT)rvtsU#a;>#)AUO0<Yum;?Z1u`^ zF38CLjBk^i<>%DDccOp6Rewq0nnLo%>@QOBhqD{fE!(P;?lk#E;qyz`A1&7YXmN?U z>B5=Y0hExXTQHKol9+IWyY*qffJHr-IiNlMj6;Zw0g~<95#fg{S3$6w>oA|c%;$uE z_Vz^l(CiZ@6%P7n+t^;SM{@g0Y^m5J9UAhL_>?e%jn=F4e267l`BPq_X$P20vkoQ|VH^?lk`U?DHDKx@xpDcq?E06^5*~INi!MCbD9F zigIGM`0=kW-|x?UQ4S%Zx^>%1%PaE0zs7ujI6Eo&&dM!5RIbmArCZ+6R&WA4zVnx1 zI7qj=T|C-s|B_5KAGL2hxN2{BnE7boOPtX*mUse=lBb6!wG42JM<3eiGD$h zeHlM(@xNShHvcR*Iz8b6vPBfce-&UV?Z7Z~03ux*{BaE1Mi@`Sz}kejI(6QCll;tG zHU9K`NBqsKn}A|T@{hJlW6lqIQ?XTQ^#<+U#xMGjDz*~AWK+JSy=J2h-#5F8>Oy*@ z-@0JlBZfEs0!og7AFz}1o&k{R__#Fqu(qCb{O4Ujz3ArL?=)Gl>bEI3B<(cmnVJv3$Fk5n2oHiHd2A>-|YG-^Wn6NMAm zZKj**lB|VmH7%%Rn3w#_rQ4aH6B2MbP0)Qz&{pS1y{Q%^Xvc!9((ykpx+0n$@*3}M zYP26`Uh0Dl>&(2|DlZ|XgQ+p|vZdH&Bq#Jvka9RHi|$Yzj(EZa^vl0@Qj8rFf0y_Q z#U{Vc{ZSmZ_A;S$c&(Xzivn@HckKNuD-`4w-oL`!5pMq)i2y2hPYteX*W;jjOBnaG zDgfSH^kHSO?V?ri5yg+W;iW451E<+jML$YzVq=+z|CVZ5=)`D8In7t*EFa6i|WSS@5UdRcT#yh6l&w`exlx87r2FSt=Qx? zyAwuTa-iL%%>9@fTQm66fdxLa`9cs?}$?v!_GL&{4vj@9Kb%hHA6Yf9Ht z#*aU1ef51qvLBduJr1A4lV`RPKdU##&i1MrkEEYsoGIt-=}1<8Hk=bHLdvft+djh7 zxqBslCMKM_&uQA5ydmc_HFtj6&Hd_e-B}YWbnM~ge%+&=y0fG({c7yFsg`?|@g|k~ z_3irL?~`h|rk7u>`7Op`l;IkgD{co-c$>84dwZrgwJPmujgx#zuE&@&>WJM_uL}<> zO_V;y!8g2rVrCKF!%vGwkA0XFhVs!I2wuEaLFyM_r@ODCO4hL-Tv9{Fu77)jG6~5f zsccBg^pqunxvNI62`%0;<(ZPH{tpQfwKK?fIkXEUdJt-Y#P!EDnH%P~@bcoQ<;*Ezt6!osjANx6L->Qayg)vMdsaFpFAV9sZt1!h7+XXFz#~0}w=gi~OeYw0j{;&~VqzVUX^A8SYep_CkHGb{2q|ITLssg`jyhEyA zoWG0|`(eFdL1S3&pli|ZLO9|7##-hLj>pE@eKIlF!SO$q0`vFBBmbFjZ23@q@c8S& z@yIvW`hQ3K_278qFH?WF@z=Z0FMd7;q*kBQrHIw@6>`CHyp6NeAVpK5Z8u#w4_Ytd(x9?)7RC|pCA`5Ei)>zfnO6iw@6qa9wOZ%gSM{|v{;{r96<#`=b4e{|sarcPjTP=hxd|X)F0=1E^mz zUA@C82m#yd>B9Kw+{Ud+$3T4c2(HI5KO8xTW469%pWX?m4=H-7Je14@%aeipqqN8^2$kmGZ3tJ5PWSD8lF zs?i4qRa&#Cp}3f_SvWQDc9!^$1fQQIm0!UJ#-o|1B9l zx?k-4Xws`SqhzWE7}ViOzqZNA*Yep`I>1yi0nzzOdCR=uy{WT*i8!*3mvx9FArTK%u z!FbyO1F6g3?{rJiQ1E#huhjx^>ari{RX2aBt?+be<34-UYA64ZsCxEX0-nw!2z>@+ zNT7I;Da}n(>T3soh)>IHjurR8prQH4|KE_*iPwo+TKsG@i%07;iUYQ>Q0No%Sf4pW zO=o{zMtEi~;^RMzqLjJXtk>S1mQhGAppiiDI!4CTOS{r*@hU({dfcLEzIA`gio08x zDTl+$-`dCjDEI1gD~%5V@jGB8-)nxG{b#95Vd}4iFIsDgUxyKqK7_wG_PFA2fFV(s_ZG8-KcyzRyNBXTNxmy=u%>u0?IAA{g{&!8r|!PW zS0ege?7^85ww{S{XMB3OEx9{cJ;Izv^C536gB&zD( zD=x=^^l$28DlU9!znUPvNLeNaG8cdwrH&$CUi`@92u3MeMOxPPGN+{dVQG_YXscRJ z$2cZ!hbt=25E+X}RG5lAhG@^MCXaHn+7H&zE@}^oBzaox-+JAW-32H{#bm=jhy#zk zzj&PRqJ(BlwaM!yd8lwj_PH{-)#cvdOyjCmnZvsuUNoBE!)|jv=sEw8_o-o5D(ml?`L3G853p zY_+W;p;l5C&mzr|sp(C|kkoD4nmoSiu8Wl1Ba1%W-OCS3w(@h0{ps@adi%43pEuf{ zGlhn-RSjbYFh(_0xz`qROMR|?mvTG>dDa4YC5_K^x+Tj^*0MdJZN)bl?bUnMW_|rP zUcihaeb{?E_{{ZY6==~&?%MnSxkbu-JKP}m_&>*(gI*!MaP05+tvNXLV$-FQ-v|IV za-4wI%Z9}50>|mrMJKIW`dO0i*k7c>sHd%@*Vk7Zn%L4?`<8n{_AC4tl07-WZ93Uw zNv9935tcXv#FO&h{sr-Ro;wS?XHT_w2~4tsE*i$wWZa0>o^eie9)!ozi1WRXTr=G_ zM9pS?Uiy>PgFixDd5*c=k6_Qo%XED4>_G9B26=6>vp+Pqi)7KaqttoUPPVC(Q#-nh z(E{-vewBf;8ia7{i@O9{%ek?{Z?5U74=)(vz9lwH{Tvyr2AqIv>Q32F6t|1;@9T4| zavSiu);nc;@hMGDS)bqezIAI_uY6COVYHz#$H~14MSae7J<^h5%?5k#)-KYe+isPr zbWcqkvEDMO`U^XP;w5JEDXuN%m6JafArBXNM(9f&Frmnk5}8-&FR9)1NLx{yI#h~Ro>EDtFxTEWDmA`NA9>}x(*XDa3=f(zuul| z*_3}cv(ZK9)9FZ*02z5n`b=7gw9E(eJaXZ_WAE4L_vKPQ;%jJS%c9q5ZozHo!cnoi z2-Mw^AJ>X=7QVIvE9y{$#z?4Drg`ymhE`*53k&BB&0}FJD-B<*i-wgx&H2JcH}*v5 zQK`bnBNP6(C9XfQNxB`*B-fyWBd_-|yJ{21S(pXmeR0tPM9_84qr|VNah+X3^R+&HBSofwhZ8_dIv~Xc3Fl2ny(%zg#*K?V}%Iw+MmJf-=rzr>_ zx;aJ{b6YS_kT}SzE#miQ`*xi+jUEv9F~}%gE;=?~lrANCXy;P5rE*>ow)X_*PEjkk z=nQ0EE-Is5@ZL6Uska7yoi9MiNE4L!1(*3A{3m#puOg7*T|8NRFL6dYwsV`$Ddnv< z>7|H;&%MeJ4^7~Ew`I!AF4=?XvLpqMa?m4(MT9oJ2**|4mSA5snYeW7%r4%y)r5)Z zo$j+K*zQklY$p&Q{|)nSK1%>>wEL&SQoq(oc7|pQ_3edonuxfSWrUp5xJ3L=1b(7l z`#s$J&=D^br_%*6PExs%>#*r9!%g?XANeEe5{Ukwo%uOzl0ULJ5g(QIp2{YL zlZMiV{o&kOH~e3-$8aDA<9TNwyUA?{#5LZJsi)FaWqu#Q zc@!Ss+-bRutmrh+jzw$-(M2EGUfS2zPYtbI2Y}9HZ^Mo_iyhhEEdPCi;I5ZAf#^I+ zZ!D;sJREhtW<7sEe?);?DHX*KQ#P{X^m~gttU&2{2 zykj@;aVl9AxgiSNcWxUHjvdZs<0~ zRwJs}7U-o$^oVZ1;by zevmCvpJ0c^N|}Z^(OiQ+F-OvdS+W$m#^^zH6QhKafmxtRx@H#WC+z|~N(AO+ItV@ z5oHIq`6Cd1Wc`K9@42v9K4O`q8b!hGtu;XsAwQM}8U8rLBL(DZ5=lU^u3x*BYz0en zT3bK&R&$&ety8*VDIIoArm@T!6tlg1BupIR#y|j`Y$;AEO)ju%JY;sk!(ZDy+x_SZymyn4 z^PdF?cY=VT@qhiTLBKNx0aJ&L+gAEd`2%d0V`F1+PjNy}!z@pn!z|+nYrL=CE)AtG+rj?IWx=CLRcUl>XucgvM zi(aGlqSbh=%kK+U_G6E`1vS<&PkLK8_I~MFD6h@HD!uK{8lzb2RlQzW_vkzI6Mr{? z1J0B_+p-N$@P$*6N1-Dm8J9$N`V{CBy!jQY;ez^f%PTlVhFb1pk(P^Pf-Gi**}BAH z(JHkQ|I?yN#B5>NM&+!xDkoQd8I^ODR8BUlQaPJR-{Ta-6%EY71UabxoGx?@IG4`| zS1SaD!;DCW7G3`Dl(sw5Xt}$c|AasNCOorrt233jbQxf|B16pqtLZ(9D=^)w*I22? z{<$<2e|6zf&3+@=uJ+ToiyIY}yP4R8#9z&BG7$;EfhKt|lN;=fDat?=?8z^5+<(@( zdUq4#tQ^gjfA2;f&o)wbCwYuhkk%CPxOuQV{!J)ajociwvpjx~b+a3J{PnOBn5&k@ zOL%R4VEvh{VqRFgoVFsAU2hz=RTB*?Lt?6BgW-W%cC8ZB4P3fl!h$i8pEyT&V*f3z zSh+oo(EXGZy0TqX3EgJ@JJ$Wg$scc}Znevi<{VCmYz{?lPbhjDFTB(B*(Md*u=T+i zk-keLeP?k5XYop<26+?Tzi>26v`JDHLDP|~FCA;?IFhsJ__i{?4dv`OJOK%)nRjPV zxtVNx)=zr_izH!IPg&1p_S5nUzL!svL|n++n-Mu|KVJ@}-fTGTQ!26a$CNNs4C@Wr z3*#1-t~CRc)2urbjVhEljm~A-!|yb}OnHEo4?4>o2)KbmP=x5=gT^?rG`1`c%)rqn zi06sqN_yx-pL_t7kBCshL5<2a{+thKE>ZxE_u`qieuafbcwY&^U)9 z@1yY{H!JgKVAOPRE^f)aBHh#K*2b&?i+F19f{ND@n%-5W2`tm zSK{|4^EL9Q1KIbUD>b5UjzHJ*+Q6P0ScKb+x+}vqCJGN zxmR}M-!-Ivm$Y~7#&-nAveVxUUy_Orf6*4f$&cls-Typ_MBAK{|9SXOJ6nJgo7-VN z@D~45PX2UJoc7$~Eq5^&XIPcqzdB+padn=H%)<7pue|>vVCp}o7KZ;g9sm8@eM|Q) zQ+74Kmg_@CUY3fln}3TxguJQ9HmK%se^PCHGImIXY#9kt8n!IyPrNJ{pP0+yang$% zxL5n@-@AS93?WwHqlO$VG{WV5`sb3&p?I>esTp}$si64o;s2D1{joj%$GHa-$5J!W z&xeldZ;!v>EIF8WC;{lsYe{4p7|4$1#gv$VO_x0-j1;i((k$89QIq1eS7r}Zh-`cO zk?gB!WLL`?!bpneXmSm`anak*Q-+SKFMZEGgO_hkEsXp^I{xt7LyI@UChYqPekS2f z?JQX;2C`xZp1*67gv@TV@Hi{*FBYn#Oj%UzZR=BT_@rcfcrJTzgfRB^zjxQYBYcI| zC`r$#;AK+j>I(e@B`q8D(uhnG|xZ(OWjMb~N+k&Z?}%;@c>c03*#p z{0hzX41(bjTTYZ#`wiA^@l^f^@qTh4JsPiiHRgK6C2T0&d^-lpn&OEJJaLElc^^OR z%aer9LFf6=+JJ#X%OU$I-C1<2#v$Ev75O2mFEac{I6wezKue19?E|NAhzWjyAj@g+d3`=-OWXzt{DyG;Mg@^2 zYym^+k>n}Y8i%I-E&*YB?e7v`t^9U93tFyQO|`oI_f@EPrX^B4U-o>za);(@%z)C0 z>XQ6Z%iv~HHSN#pNWefF-FQw8PV-0Tsh+1Eo-RZq$T#WG74xAP$WF}K?1%i^8p=|o zR}DM}N2T>4@I8(`F-g)JjH%+%U7yfphf1q%EpPgEBVG7=qaCIFtD1Uw;HR~i=z2Q^ z!cFi62JRD-Rsn2~OOu zVV;;>2pZyZ@-_CONJl}h4U~XmijK6G=Dei7bWp_KgtRi9B%LeTX$iMP6dcy#vqAeD zODmIkEm~PiJTN<5l*&101;1f)ACbz(1OXEvq*!9vTSUU;kqn}qc~7?X%-*}FL%xT} z-A(-B4>s{kG;<0zQr6dOm#tjLSC~yV77g4OZ)BS({)y=g^{1Q;P=!3OWf0w1yxUIx z;Q6<~tM7%*r?bnG&kCyyRV`PzomEat^^gF8ilSI#i(w4Yo0{2N8v}TQ)2(guAd)Yy@5@as35R-e{w)&@ zs@FSatO1s7Xc&-H{n=n9dl3l;#rbN29|#4+RwE$p*jkz36U+qTNF2?th0)clhV#oz zv*^wG?+h9LZrA?@WcDoZlpIEXCL{iSo|va$8O53F~`@hyL~U!26yn`q{293mgFEw3o-bq3j0|M()7<* z4wZ8CQAU;avY1!wJ(ihcQr^Sd3l#>RIwF zyjXaUNTbBYvii3qsQlacCQ~skn%W)DYVAA3ufO@Mm-7=a|aRS(Tr^sr+19 z`T0cU=f=v1YCo#rnO;@)!M$7$|SrEdI{qFAhz*>cTDT@euo6roz=!6!utW zpE~T*Blc+~Po;5{{Uqh?A5`msLA4&N)Y4pU7Am}4tD59OwzNn5hTdF^6M;0nK5kOm zh9h`m9kjmd(+;7Y0s#B?M_>t&ID*@8SU_PjhgGvt>up) z)c)KP;ZNi3(g|K(D_@%?GZ3e&>qJX~g5WYAW~r+p_AkM;I=6tHX@7Lu`&u1P*15Qi z0%=d~Vm_!0moW5ZkW^PS8SPWl&?tKJt`upB6!c#I2@kqP$*h+fOy5IY>jX!$1luH= zX0x#JpWqXxD6?ZuxAIx7&Rs%Rv95_tECktgln%d@!RChspwo;t*UO2*wmDgB?)Nnh z;;#q=E7$vTLZV6+bs@qs4vV{l8rUX^H#~i45NAUPaQ3(z6yZ4guR}DHoR*e`*b6*3 zNqYTNH47vE6|csj!LZX6f=^q*Zhi4Na{vaMg*_5P*jK1)vV97vtIa-%x{8mm11r-% z`gWbWwM+U6|1}W#K)8`Xg_D1W0TfI8!#={Ir>3ZtCA_3^Mb^wOMF`E>eIrLaT`5Q3`6sCwWiK996~rT7j6qD zSgM4H+91XuOz}{4SeV#ag(*3ou2(OEar_0_p5Ywm3*&c1@M)&mUrg5yMK^4XXCogW zIvX$M-!bz!?zE84N#IICq85J!9$}?&e{xI%9l@9B!dcuwoqOte7JP_4SpnFE*9GG& zfI6vQCV8#tY{*{kdLx^HGadzcAB|6B?$N~9O_4lwjjIWTOd^ZEji?BrI?&1emq<}l zkNEk=is~C=wSt~yhVXhJ9gvclC$tJiI(H2k2+cc0=Rwfi*Ml%n7V802=`Y)6h#Rv4QE39WfmB0O(Z)JKc`&&ivc$dB^ zM!}jETHV4qoC%?q!guA$>OC&A3rv^eAPz?TUo~m(0hZHA|38|V`JLpQc3{B^m_hTs z!Z-PIsFU3f0d(noYCKYsv|o3YQ(5M%R+2k#5jS1&<3)~1HzmE{O*-vq#=RxUVQQmJ ze%igwnpEJEcPL>CTIRtNqr(~wfp`41-0Ob72A#Rw>~BbWU%D)!d&M1hZ|OY4oiKma z{8Ob&9qIaK%*O0Bj~J<|zDg90X1S0YvKCW1+TR%9&fQm695PMoiL%I_`AqWhvnd;X zdx?W1%a8E&29|+fWL9dHDh`hKkx%n3{i|<7S|@ret7!JqR)*!H*8c3D2tHz#$+ zA559>`&S2jkNUp~qtO4b|Gux8{?~@>e`HYm;n;sjneh87ptk~F)c?r$>7V;(i2ad= zH+tn;PTu-CZVj#iyQ~#7;xKP|_tOjGWGbv};@Du@K+SwoGTcA*{?h*8JnBonMUP)QML(Yq4Wgt|@Cufkhz zmg&9gz3Gzrsc`(OSl7{&>!=-k3M(>p&VFO=t&CUsdAH)^e4i;=cB{3k$SrV`=@wW5 zL54QOWfwq}TQE`#$$s2yV_hRDrEc!BHmqHvAiobS3v+vMk|Q1M*SV?&|L44sTvnaJ zSmfky)|$}yNF)E^lenDcXfZh5bC7xr!NhSOzn&Ay4Tppuj&TbIZ+>!g&5e!OLvMuq z4?gdy(KXqT{CJ8VT!rz7K6bf8#L6s0`$~nr!}RwyYAd%K)AQT0ED^v*eTJ5|+}G;l zN9ZkJ-p;5cHC*S{oI?gb({#v(={|hIC;~#pQd+#k&Ha}tO|{8$1RW_C?&rO3l5Uj? zL!B1(*r&_<8P>rf{V!u^Ape1oT0gKB4^Zu^sZMH!^8zl}+kdh@@@~SL4>cL!yq9sg zO~&6_g!dh7#@tv*rHQ$>z%Ke3Xp{0)6C@dR z<|c1~x?o?vne2V!oM9XlD4|n)J?a!U< z`aiH3g}I(}OGm5Ci8u;-{HcR22g&Bsg^%~~ljL2zJY1NP z?hL&&^Smd|X(zeS^)a@@Uni>CXy~GK!pUbY*uS_+Gb_7Tm=DlddMj@@sYGBT1|Aj8 z@ZHWlr<99JuN47^uIzW3AiR=nL0?h|7IyBGO%+Zd0mmky(UVQaa8&Os)pk+t;Z|(D zDx(Wlj#WyRDt+$0STg>lrY2{p=xee+{f4mnf%Vc)uo9zgayn~{e&ibfGc)&rp-`+W zom`o(+NQ4CwY99ta=t^7KzP?{!PU}5IPK9@E#EWX%WB7UFu&r+%Jql2g;QC91fK7k zX-7y^JNsKXMpJ5MQ_8ecT3+t2u!je`1pOBpMhe1mD<*Ov-IpN6HIDySm;31IwgW8zrPaIN3tT zNHcTItJi}ydNpW_ak{NHET8|n%5MvbMt=M|-LHrf%GE8QI8LE};4LOUS+ zikdR?qrB|{rRyu}uPWZF{_8YlHGs1G4)v{s7v&d9*z4ZznZ+#WG@>r>#AGB2iB(z; z4Vh4x#2qT&baNqY7$@`Z_7{h)bNH3?){X5okuocZl=-F8t^81lEh`DA5q%|c&$I7R zP#6whY42j!>HY-|gd}zFhuRwxeJ>76_RKwtUEuji@4T7p3|o72v)|R0{BK*P^6@vF z%gnv%xKXn4&p)V_Ubp!s)!e`9dfo&txn>AXUMA_N39nn<+`>s5e-uok-a%{SR|Sfy z2*TnWFjw!%iU86)YBUzHiFZ-ECivRPVbd?GF>i85@dQ4X@h_#MpRkz|cbFmP#k)$k zROEI4o@zxgGzK~O7nncN4VUM~?Kgv|r_kM9{8Q9Hn>p9%zFv>Vo5$7~+fE|)O0C)| zDq7Ld14jai>q*@5`Qi-TEgSo=;GrBaow1{Ma#SvOq2I7X-O(<75ZnuIWGB}V{C)~Q zu-dNVFFbPt1%l-ij^=9YKy~qM z=)DS_%1PA4^|$l6CSg=&-8tp71xXzd6@#+`2ux1nFD=wZ~EPEn#mj@IwC!VKXC-xhYmF2T5sZa z&8|7Ve*R0E!bI-Ap{c$XhoobpHIq*M65)>7OyoA5sOd~}y%(Ezgd6*s4Gv~T8>*Hj z^LYNH?#!AYC2ZMNew+SX|Kx@YhVl1?+!9+@@7{6x4Evv)KDWN&#(r>wT>mN7-w!x~BcFHTdKdFZ4&{-q|;c&2Duq#|^GWhW$2}Y8z#Q*S1FWlpzm1 zPG??-(+HpJK9F~6x{mRqu4is69R@z04Vs}~JztBzu%4d?pLX>fnJhxKBg#IBYL_OD?$ko< z;Rzf92p|5~BtLmLtv-=S)6}qK2|wM%xb9j23ND{yp*`Bo zwYjlW>^`u}Y5mA1#7Zi*K7q|(l6TOJmf$M}N4p6^YbX|DyWn|Rv%d3Z#XuP~K8U~-2!TYufJ55&yT z8t1}lh$6DDgKsmty!>2vb6{pKXT@Z?%iLh*-%h0gmm7*~dwzX77S&cfJGG(O1515I z4xQXMmSZ2T7JN21#x$M9_a?NdaBog{Zr205X*N>2Ovc-7duwU0_zkLCRV(6B zWtSy(n-Iri!NGV5+9jp@K2d;A=EK2sJP2SItgZVRtk+VcFUfC77PmJ~pakZhy3(z{ z7rd|q{{LUg(C@Hz%#gVQk0spJFO?>M&wR~VK41~tSljhG9UbxRoSL<|7gh%a#8t;v z&OOVlXekhihxbnALzcyO2|bRh$4pgUXAmizvbwrxgs&_}oiq3+voS;SIMtRxn#zD= z@FqI|6k2n;q`t!0i7BX0JCim_C6wj!age4ZvX59K;o|V~Y4ydqpl=y8wQM)^&#KdX z?VOAIWEt++NW%s+rRe&mlb<2A2t4GT!{R=E3x{K$ z)`<@rkcZv)Q}fal`APMC-E~D8OObkOb!tM3a(6x8dcU80m>YX?@TUcTPEGhqowM`| z)BTw&uczkUtu|4f522;A-M;6BV)_~pr2Uz7?S+#$;C#@@ZxdR$Wxau3&gTEsuFt%a zZ$ux@rY#&An@C77|Fdjw+GCrrLr^1CnBI*o?fIce>CeHHR;_UI6HNuiWbzhc)gUUj zDMcA(a4i9;jtyKd90W8kaFW11AEGDMJMs`6Oi=2A2K)^8mF!72)TgisG%yo3%S%PR zgy#dy>l%y9?pv9~6!}aWWrw8&@L3!}MY9g?=mM<7U7~;@8YVBTd`lkJilfdB5dau) z+}IyoGFT~X7x`2#cD>nk#cxr(tbYoCG7)m)g{yI36gEgO0|F!95Ogm%gq5>8cQv8r@68T{J|GxT%(>uIJCmh9}|%bo{^?*xz86W*lnWs8m2S&Z*^daR zbwxQmSj2tpVP-H>$3GM6g7Z$WuT2f9Gm-6p2XINN_b-4ZDM6;5JUXvE7yw5PR7FHQ&?^@Hb z{@{BQY4>hZt(5mebzizRxZzF1zOSn~?+@X-QRU))nL8N13k`hxq`a?NXMi$b2$Hjb zNy`m@h6WQW03F3%M9^&1e4SjV{ZgthakU6I*wccfN`RyuOE(1jSdeZo2Ep?FLC5C0 zQ$%9-E!Y2~8~@bYX_AAdOFK|L4}WgGY4kFyt-x13<)MI)VX^YaL`I>Mj}L}=zUz4K z)jzpH;302=O?@a#A(7=yiIaaq58Y3@ z-nkqtN~0h9urj+YVvwyV|28u;za8C|E3y3Hqi`-6g>%VpB8{i-&8oF~VL!8XBOdRt z1pUaZWOOHvpWmy|fv`nx4VSh|Qv3oqVl3_P`R=?=+R>(lUTx@kXckfba-diXBC^(7 z`+P+C9JUy{lXsJylyX+LvL(jMN6NoxttO3ebvHvDcQ-R0wL1C{vvN_cGe0HfM-#7v zk!Drzsc*QZ@ZL4=bqF?&LogOt>0uGdC5#Jgm~}8+g7g%%z)6@+%OqfbI$q4^M3;hS zH|BL=B=uPVzWHRZA33@hg`}+}!|-9hx(6O}yELikyGc*xpOuF&Xj> zKpqVbCQUHO3%Jsv=KQU-9W_I37P|(}4ByVZR;M&W4|tEUs*wrBX;^vTpERcwY~#c4 z=vd+R$*gp~>*Imp$0Ks@ESk6BeCX|}-qL?q{fg`>-aaG<3t|el`fhLO^78w=_b0ia z5k`aJH;}4fK84V~t*&yv`@eL$Hpbdq_h@p#-zj3&{qA4ZK@Dz)WhL4;*rJu~LEiBN zdvQO&yWDTu6zN%t{ENSvA>e*r;@jaSuLswIWZiN4g4zhrTnHu%U3D$owAZcn3SoPr zEA4T`-?Q^fW4i18_2AU7xfgeB&Rl^d0+-gZ|$tg}h%RLVk6I-hkq^wjas&m2d&F$U;7b1Axy;6|~<1=;!#c4A`BXjDuoCZ584IEcP*h-m+35o*V3y6mN2v3 z0n5g;A%gY~i)r8l(?Hiw=-GES1gkEkciH{WQ|^V*%J36;?<_u?57DK9SM?Pec#Ot3mP??k?GJx{KJ#j} z`Wi->o!RQ({f*_Xq_f49b?RAg*eeNLanBpxL!$73jpr{b9fz)xyYs_{5EWK4JUeS{*gE9<_2>MTw>tyM0{1|L6#Cue<)Le>otdSuKi@Y_ZRd5ASbgha9<|# zx{mk-?IFuBi#Yi!X$9-A$?-ekHZ$8x_XqaL{*gbmU@AfL;{drU^6p3%(RuxF4Hr3Lfjvv|NLW{txaJSaMZE}2NHOnJK;JzSs&rNQdV15fo96mKLf0X93d}J|5pAz5?Xtgnd%`x zNTk&i@&T=bMxbVIYci3r4s5%(&`Fzr!Oct%V+j`lPJG4F3}8Uxtuzy(K0nyJOj19Z z5*(|>-p{0HMs&lB{A8kesZ0u!VI~C~JLx@R@8?SBLN9J1(uBNb?;%RZCo&nU;0($5 zUl);W_E&ZUOGj!l1iZQL2udm6tW%i`a&n)yT1k$=dAQEb!}_n9dH4>)JrD7THHItj zw1)BUNDN%nB>Ky3Bdu~T$2aC&2lu${@f3xzf%&$Y)X;OWQNZAKlTHSHj3dpDdP^jl zu(V5J&vgdkDOO3!p@6OvX?>t;-t>y2Q%_Ay@D4!-sHm`izK2T zsIuCGjXZ+gfZ=0vMT&=-1qr#6dxotu9Ll#Q5FwUN!$JJ5LLzDmFJ(cSc^Ib ziXeji%Y`rh9v@{VD}Owz^6?mbT&a(?<<~#Sv)t~(XXj0x|Gm2M!IjEi#4onkUH!49 z@-h2we4MS1RR|s*VX`=Nr!NiVFXO5klp<}gAd8%^Fsl0NKGD~;;n!`jDpR~mFMilt ze3=*30CbeQc~D=X6@0%bX3}f#LR-b3?9@hcxeafpFJsDI{$-~xjfvx?gm(iKr|FwT z_n5IDX>#Rx)@+_XrRR{e3O83i-g*rmM^%56KVI0<>H7FKd?9>(jJd(g)culJMPVL1 zwrIY*9Q>DNO$oHC@lsa>->s&V4Z%;oOTnM&Ap+)~On)1Kl)hXZ7JKz-9v1On5N|}I z6rrb`E56Fh@>($0DiyD#^Kx?!N0kh_`$2Cpt|p_-eya!k+s;w@hw_m2;h>!M)XDFz zzPO)xC27t(L=XbI7}GoN?KYe*ybWBwrMq#P^?i)Kk9RItXk?i`VmreB&S-#rh@9x~f6`i}ba1AXGwimW=8!d3vtT~9%-&alhhHdm+!%(L4T*k`n z(wXmoSZkcNmBnvS6@g(ddW__EWWSy<&DgG+F+$Ei&m=Oy@zW@tM4|hqHMstfE0IF0 z)R>O^PjJs$oi2>)M}l=CwnBf)+{BMqZ7;*&|DcGmVDwMGP5+cm0}c8upN%hE73UJ4 z<@OZspMX=^7IHiDxGZ^Fo62t*ocv1y0nfX{$HKQt<3Cp-6Wu6yS8sFM80o6ax47f1 z)N1r$`A_OQNy*T(f~##^RGG{SBN246ww7*E{%736RQkU^hA44mg8z2^5l>J zOP`@{4nO}>Dy6ySoV=5DQc{SCA2@Z4P8mxN82gZa5afjCh!hx|v1vd!1l}i~k7BA-=`n&uU@z@zE^Y$EzHYdM` zZ=6l1yeXX~oFq6O6iY+b>~S{BDQ>aV)^~N1gn@ey+#kx!7Lpo*KQ>lS-d&(ZaHK_~ z(|xp<^WPki*%nZ$j?0DoDV;7Jedf%lD28eAHif}&W$-qSaD_hIOJ9|+O6%gE1q76$ z&UJcMHAxNaxvDA0AFh+Iief8YagpcQ=#l(x<+NZ9Q;0Vk;bl&~4GoybS|>l+{)%az zG=NjmrT3|qK^G1hxC(oGN9d&bEa`cjiLQGTkOtA=FXqqq;D*RW9wbgGVFcg~)Lk7ZASP_Q+9VdF5*(R|@l0^TtV4fAGsgjnA~vzPSg2 zPYiR70pwRkNhQ?o2R!OO^tRLySBPncW+hzhlTO7Cf#EsEu5==v=o_ zFFIzH^1nGnLTJ8G)k@SCSC?Un(AtB^6D7RxXK2~<@8eC&(M97zv9dN^<0}@>m530$| zQhIG1^>kS*o7VV-g)bxcfUpr%bARJOT4dTtJZgUFK6GCxHR`+WFw`g?;5bVuco8zu zNLdMqx}t6@wfg~uv9XxtK7g|w^VDosHfbD#9}}@6CTDqR4k;Kjw`Ev+LSc_L#Fs_? z#di^e(R>&7_<8yL3svs{3fMa9f{y}e@lEq3X)Z0v-^NnoY*tj7h?{GJoo?-65$i@` zaf6AO7Z$j}#8fWjpO7k?j#t@B!AWo1>;#H*)TWX7NS*fw&UZ(cu`w)ov8E-thEvlb z3~j9$Z_xLUt#}g^HO}s%_z}&zD23D5->R<`vz`nn#V*Qd{ipmZx(poV+t^LvDuXCk z1vbY5Ma&WdMGbCCxZcb%Go@Mx%qd<09)gA+Fjm%3Bb956BVO@zED&{$!Q^}b<)0;l8b8_*` zwBI>fzayRrW;KT)(`Gr~5s_H5Z^!iA^>KHytdp=+#%)WG&s2f^#N%RhohVR@ecR7YLQ|RHh)# ze=`SCM}!NQK1sej8;tcrRICXlXpOITol{;xk6D;u&!|cW@C%w|rMye{nVOiR zh|awYW~(V<0oDu!e2|-iz$ScWv>-)4ILeGW0BgWdG{#hXlk#SW)sTczdfqIC)R&4q z$j!QApEje&K%XUj0-y_scpRobW1K72YAjSmfT0=e%4^0&yk<-0%gV4Yo0yeFXNu9_ z$UzpT3z|M(+9!hBoU`&}k;(eUYG>)Uv-D*-z%TIS;1_=gm%UQMDLrs&ep7ahvbCCQ z(hJvE22>{`1?S>fqM^3#%67Iwb-~vUv?zwcCe<0+P6!8eE=Uk8rJbwOeTZhFdy`pW znIG%&_VF6X1u37~5X?H?5q$BlTCSZryT%F3Iq#upkvB5{Ko1u=L#ZtCKRsX8#*p_!`w^ioBNN*b?eSIZ&eT<7?{D{3r(0Gjk?4op<9~Io zxE|z*gj2hc@R4gt`RnABDm9c#WK^wNG)`9#i84t&@^a8qtZ?I&FteMV#g= zD*io!Qey1ubZOi4K8u7=3G3Chn{cZvA?N!>@@pQ z+~iK2%|1qf*mcPJF^ZWck6$YuSG}ENraPq()1JZ!>PT(rws1M!%3?i@o7;czBjp3l zYyF)_$uMTSTm%2e)y3zIm;Y`Uul=RZ7?Xsm4LVPgzw%xy3ZrY})UHrpqRL{_ z1ZzR0d;I%XMq|82o{3k~5p4YPeMD9n+?y|%75o6~19Hl{5AVC&C9`TW?IufjsUhT3 zUh+?9ujkIfEiX22tlSeUd1It~JrF%nJNslRcVts6gTLi{^)`Br!P)uY4MB#XTVN~e z6CfaBZMfF49*p~ifA=i(0eN2y3l7{*NID{x*+Z9NgCDaw<)pZEjLz>W{u*Rnb#t8n zOd!zwnZp0cghc-bBWH|%<#E;lha+Sik{W#t} zN(g3iAg!MkV0|t3ezFcz`hpWM{5K;^<4?H#tJKJ%y3~Y&*f~upnX8_xV_i6|Hf$`9 z82Mi~XK2hwof0=B)C6}5THyX=id}lHb7oEEq+oyE>Cs?zW-wbLm(p~vZg=bt0#SvK zk0WshUmkV|<0K%0Yj+k0U$gBw`A#4r|HlKWY~d?@nO70rl+6vL)ewC7yc&FOHu%PM zfJ7yWZxj=#={g|uX>%MgA39ycl&^P|bC|O-cu=4)e{zfQUOD?*%r3pIm>xNj%sSe&+OCnxenP$jWpt zj+}r*-Wx8sR$g!k4v+Z%Ik6yCZxoIT&4vi#UwC#f!eSCP^~~AY7B`?IH#IH%blN}m z=`W8atb7^9BojjWdhkVKiDMZOH~o5$H`IrZ+t4r3!-R918Wuc?c3J!vgHmJX`cL{> zR{R_`gdmh+f(iWR@}zd`H^;_?bm%e2KZUorGbeWqE!wdwOx$pd!d{;?+j zo5F@!KPfNy3~Z16bG($f5GVF$8^+!b#FDQv`OrZ2>6DgX<^oO3pjcb8?&h%<*>BUA zwDzKKJqb@PNISE$6eD_=tT#t_7Nvu=B;=}Gn;lV2}% zK5PhnQ68p~{{th$ZiE)wIg?hIBquNXCJ7b3O*Rqv(FWh!D@4nE%^aU=>z&{ zw(8?`nc;jcGQ{_dJcyl)TYGT!yUx-ZOb6(2X@4SjCJpHR=KVIG$5ewfd`7nh!w`z$ z;`)@CYu>&dbPLGp5aR4liTRMuEK*l!Grzds`zp(rTP()q-WErx#D7^y{dr5_HKPp2Ed#85aDj-7dU zD4Bv=IPx*%#0{bis9ScWbjE@YkEkHjW+1y{)<9-L+CS>?FKP`~`+&}n(cNAT&SLqR zb4uk82o|Wa)|^PtTmk>&{6|!5UrT%@YI%v~M(c*Pv^BVhsD+)`m6N~K%nbV>%fd8b z^iuN@cU;(7h=@^{k>Jz>Z_9Bsl6&kTmT_Kg$v)esmFabGK51u0Ixk^EYy!Tk}1*;`s zsDm0I>l`)_d6I8r$ia6b8fUH^GB`l^nl-W6tckmL$C{W&yJk%+rm~q^A|3xt-*RS6 zJg%Rt3D<9ifn+Y0x%}f+u4-M#X5JqEGRwlm=ipa=l7Hkzl{{5S2aLoxOb-NGG0B8$ z;xo*ndAl|Erhpu@CVsKoHF2%6uNW3IR>;mAXqH8DHP0x^o60<}KAzP2i1>(^r&Xm5 zp`IlF6UajM_h^00sL3KRb$KUy1~Hy!d0egKv0HgI6?t}PS)L(DIbJWzGmU*^uwyGj zgu@wew%SN>xrf4ctq}X{QTDqLV&;9BznjbIc4hGk%nZa+UMMR5)$nD{NDGU=Yf09K6_Yu?X}ikd+oK?-gF<{dneup@%|a?Z~AuIHh*QN z58o=i`}26$J-N~MwR%?!_2~Uq_wYV9dha@43<%DRaR#k_1vb0R7w-wfZTlayOT-%| zbF-822J?lsw<6y7Qjf+P{k7egyIxhbjT|tTW9;=0{#lO@1l4PU=zx?0KFR7Y?9vZi+mJuJrFsvWG z+?YP0hDYm%;7f<@rUQas=!wmawfZGT^J~Ft(Z}s#rTgoF(vFT5u|@LKnent15xQ}c zIp|Q@vqSw&{l^5iMwLnV-5NQPfB9IPF61=l$_M8~P5hfCn94hX-_ryugLXHMnS8!y z+ODxYPOjo=2{DrsfF}Ff71f) zbc-@T_p71|je!DQ=NEA~yx01-C~<7C?E&O19CYXOT@^85O)yGh)V6;M?^-Xc=*4S( zkxk7ekNk{FY3411jdaRNab>8I< z)%*KZ1q=Tsx0|M2h%$;DPz8`T6K%OyJXRFR8wjHeuxu)rm=HVBxCeI$W?@N=OA9$FzFCiY@OCgAsQc;(z08x4xl&@S>Lc zf6FkGH6KR6!8tq;OYkNo@TVm!;a{V-W!d>WMdQ_|(J1m?u_=*pt;Gp8Iql*twsUH| z#ntzEFi0KGKGNu>BWhrttUHQe3<|Kka5J*StGl+nZXh0w*&^7rz;eUIWkgR3KBTow zfs>%aEBS}YGrS^G9e5W>KdIwLWOm)5-t=esvVZ$&>V(5D=MK{MI^MK)(rrf&LSwmi z;UD;_!;osTZay0dIKiFYdqknRVnpGzKEVuHFtR$<@-?#MbfBV|)ca@lcE2ZApv7S7 zP%sceV&sq7LfG0U9K-Jf>_ZZ1-+#c-!VXm8=vh!l&`v*$(MeY?!QlvOOpa+A$1rAR zl^(FbY}ZZy2w(Q%^1x4=7T{M>UEv6TQ6K8eG9c)KXPFj(oaLaG`y-i{ynuR8hJ1>| z(ol2G5O4Z!TWU_a@=m(ViB%#P_FlZSb`ATa3U4xm-s}NJGMpU#0lzkmz|(qPv_tSC z01rnArjkAu<8^o!xY(a5Te!2K7vT0!09PIXhqk<|wl_Ht0z`^&&JrwIWMC4f*_H5; ziaO0tN{R=D-NdTQND`-o;e+%ro(B`V6YE=>swNT%{bYqhKcy_tZK_#q_RVH^ym^OL zos7oV=rao=wh6lI;iZ2pl*RtMqHRg5)|j7?os-Um`ot?C@eIF#L+ZlnA4UG z6IU;V<2<=yI0ysV6~k+a{m#vR^fUg%%5?U8SEkX+{hBm~9gUquSvkY9amievS9ZuQ z+_a}GD&pnV^4Q>Wz;lt9r+j$-I?@@im-;BnlHLS+8j$h#2v=cvDe4E{mvA8P$z9|s z@wr6T!kzd}=nih2TVj>7EMJmUDjI6;SwvPZd$3yK7}VNau>RZTnKMRF%!M$4AoR{v;#V-sg~C&G)!JGm33{C-R&Qg;5|I5a_59jqIn zD}}@*xH%I*i7P+jZ8fes_;yjIiIFP!<^v|`UV{T5Q| z+fe=CS*tVE?|B!B2s1Tjq|VfO1(51e1gCFegX)5nl$|i_f zGIAR8@{dEwB_es6w-NqY5rT>KjCV&wDU!pn97l*}%13jAv+Jec%MrfiOhpQF0yZIzk&|mmU%P9JR{LxemVEZa|bSjKOtcM5BprQ)@E* zj#Y)N{J!y*!ePDrMiA}tvDH;XH&at1Qz29Pvq8D5oO7BScaYAJkx!w8;o2D>GyX9M z*BZWXZzaLNC99+tm1d>aHTwR^u?V(ocU!g*mEjE=Yl3G^tbEpn8nAy7?3>TX;DCX+}Cm-=ue7i~2s5*o^dD2Qpht@1_bDO6HjH z&%aoY*kKy|jkK@tZ5n~1%PpiCb_7G?C(FD|2( z9pf^3sY;d^;5Q;BqB48>jjYb2mqC7Gzv9b&V*G3`v=E&4{uhOwNc+_CU}IMPHlwZu zmnDK;XK#li?I39<)dr*pgJ#qXJv$Oz!Ps<_U-y&NMSjh(Y?CT8{#gT-4zD4W#2(?} zpUI4Z-p#nXc~U1@VtvvmHt=t=0rhfY4I0yRE1a%-3R+?40ef-2mA-lt6rj%Jw&hFs z14?z$4_!OET4he(K}c0-@?#dPGX-`bqOmOKtA?SnSm!x9qOdi$Mihq5^9XX&DC~Y7 zH1H*z=YMmU%7PRA6OGVOG*lX)arTxNp~UEz)`+x$M+m#yH(hhZB6{Fu$HENh!bOkr zqUaS%>-$!4^32{d{+^I?qbdUs!XY@uVM& z*O=OIKoj3ud;-5PN$^n1Ls7--qNBH;nxGG#i_?(Skvb^DwJ>1TjhGG$^#9y!AbPpQ z^8CvF7zMEm0P$%iv#b$Z-#etRnU~#&)a=?_y!={a^p_GF1y%9g#0*95!~}EhC(%Hk zPJV%+YiPNnWzG7!t(1GUoY%RUwEwLV;Q3LcXuYJh)4}!}jYrI9yHb11XBs5y91IX_ zA9qatHg0LDNQ-|3EL&2r&J7pxQd~bce$sur#DB!7vMKh#xMpfC?1!56Q1I|yBYa&_ zthSfq;@mbGSglsHgjOI<5z(C=s{;T~;y((O1?R=}9HM%%y?TdZ>0Xil=}K>-H|HN4 zud7vbA!N$_y(@3a(oGDMTJh{MzPbATw7hu(n0?JIIc39tfQ<+nnq=g6GliIlhy>oi8ST z&3h}k{I>udwP5&>$!1cC%>v1E0o*0ss4zkP7nZZ&WgN3>w{E^G({^(2O!;}ZAMX(^ z|IpG$uw|M*6*-+8Xk)NTZd^Z6vf*5%N3ub5Z?fSa9vC?B)&H*8egA`K>{eo@D~+AS zY0&E3l>TUej;PgjFe#Ryx$Pwj;7t`l8*1dW!9TsS#Gxk6oM?$f+QDR!NRv1Vj|D$6 zCs*QdE^=6zw`G$3KS9pZ??=dS z!G9q=vtT^Rkc)bI(i-A(`m_eZiIS|Ei@=xC_jLe-%3?HXdh~aoLT>HH>1| zx<*oZL|Hfkfq-C^d=5{w=OJN%UlCL1slh3GiP>RXdxUZeZcoQp{tAohn?B@?n9_Em z_Y=(_&W73)RR<3wsfqe|_vo zI>{>P8@>lIHTZkCgVqDXEEKQ3({QNxT|(enUj7DfOO9|3zoM80_B$ZFo?mV!t@QE_ zzz9UJZu#P1Z~C1)r{*6#w5)6$8;mLM`sH5sYSL`2yC}PIqwJ!wb*;l)s7|D36SKou zqf5XX4$&PuAbjvWwQjq(UjE07x^?hPhBxEy9)4G3ps(15zM$r`-z!|jZ^qv~eA#~c z>!_BSkK_9{F8Nkz%bjz|7reiQVM(>Qn<3>OG+y^`jMWy;BpLoEN`Dwn9vDJIK+ZYQ z%K*Jx6}?pIWp?z!PEYJ8Ynwf}s+Q=B?e|Ph`L=V=`oTKe@5$<8fwnS*Nqv9Pw&&fv zL+l>~H;O5QefEBSh8~6pp0<5^ljyn5?|rq8Pg&6XL%CRFs{hk8&gyV`mqS+s7gM|Q zgIm)4OfcnrtE#zooxkVR(Ei|;1Kq&JW*8&f5wvXqE-!e*kkQGbKgM4sioM5qDtwX_ znW{H+i(ofbt(SX&sWX_)rBoobXoM^r^fn$z!Acrp41 zs)cTIRIrjC{SJtJQ_=4b`}IenI5Q+Y?{GCYC=DW(oc8KUG`tLi0{IEN(BTp{0sd zEw@lVhcF)JXMPLB!pX4w0$y^DdAUc`cH723Z`xIe`j|J$LH_P$k%scOGyV-0T`}X| zYIl)j{JB+&REUE#Dy%<1*=%X9D%3N-?^#;*<8tL$sTcl8Z`UuN^7y_UTiqRs!QbAN zsKz6#p2>~%Xw#w4cW}$Q3^-mTUhbh@G~vGv#a~HUxDA4i_%7V1a#j&&J20;){Kxc< zPg|7w6YilTMqki^`JKUhIiVH{SBOIBbij`{&w*FhdQm0cm3_H=#cyCy`*%&hKC}{H z)%2~FbC21qsV*wcM1+Ih^0U&s&!Ir7(1&9sTPovI%GmrUuF;icL=G=(6@_NrvVE@Y z&sh5WQu?8l?KjhoE`rVvFseIy01;a@YuZY8AyM-IY2T&D@HG{~*ZXokXyP(C0o%Q=;PD$=K^;1E5hrd} z(KDY+7pCGp5&WKwS*n|F)$J;`E!^)CwWJC|g0q#U=62;d^Hl|t5CFn+S@RFV{pnS4 z{qYlj&ozn{5w)Z|UiK;eXMsJ3pG;xTpl;QOqsyD0ClEO4Tam)ucm`=VDzA0`7YMnu701jdqZK$2Xv_;IQvWWa@5fq zHNT#2n^qZ2;Jy8yhz`Rcc{$!T4)9&bWZTkg`QDv}(OE!2I5PZZ#cr;^@uoo2l@WMgX(CGu@D76if z9AbS?%lXG_?&Zdd?w4I8)`MwL1l|p9pepm@(bbVquFVs3$gpa0W%K4OZ#}3JvU+cM zr+3pK3=y|gUCL|fpp9z5_Gua>&J#$<_Fq~!nlIv-g>$5CTqNmRRwoPO> zHklzEWmt7>u^-`qWI!DNxgEjOZ_xuI$zQ&?&hR*n-|%0klsI)Z79{tCWjnq^zr#g* z35J{i%j^ZqAa8U&;6M1xV9v$ke1Xmtlo322y9u&0Rj~KqD(VC&16eagCwQ8NMBm)D z>p5gdeB7KxGLCCF5Y!^i&Z}^*;osg^*D*V27qt;+zI{RDUr=dAHq;^ggnQN zE2j)OIQ{?twa%#0L>8YP7ia5~uZYvjzsHuj=1a(T;vjF{h+~F+$IJbh#G&iTwEWrmrbRSu!3j;FgATnzH>2a_Bnnj|ZrT?vdB7lM{O#PSm-{D)IyBv)EH*A^ z$(h0c!i438orc1nHF4tnb7DiypIdo6|E#(~UdI9D#PbIrL!w;ph{h*j;+P#H7bw<8 ztCzoClZ;SJv9jo5sTLl~Xk<1&Q@5y#1L5U2U~M`{;1Q@2!*VV>w0cX;C2k zq`KY9b2TC2=FL>EF|{dneDLq0IXfX5xd@K@yZM{6Du{uXU%}TH?;@u)K%>}V5#qfz zT;MvwsaAhOp-p&76TK7LAyRh|4P|`1-7{5VgP#vZF4W{(l!Np7EXl`CiLr!6^)*_1 zL-iZptRq$7P%4~_Qnr%ZWfQXJj|D_qFPC|(BaDe!HSV$wOjK`hV8bx{VX)m95KeDM39k<@c@% zRyLFx+6Kadh^;O!pQ2e|I`>xw)a(gY+g;7lTG!B8*s1~5zDW=L+s)c<6)M;3-(Ly4 z6Zh|#smcC*uh_qh68&3AC7t>Q{%$j$neOXf`^!@Oy*kw|2S51mdUhI*KxUo6#>MWpHBO)7*B^kwEEKAOKI6kc`z9AsVErUWc6Yw$-g!2 z8Eat;5QVRy1u~x^bksh)Di+c?*^h#oegM+VJTP@g-0xY63L5^ELeaiKH|3VIq;ch@ zJzA8-%?ljGOe(e~dg#>N*xjLnqEwjDCl;|yOG@%>#&ESiFxmck_1w8zr+OZV>uJ8P zbibdC`+N;d{#V+%CcNpa=WxV;p~98a-cYz)_;B*;F(<#?;AmNcznpOSh_F)*h&xFf z{i?CvOl_1mRKMxXxQ^oCbn4Q4)g4|ZeJ?KR&3pyIF5>nim29A-=%YlJc&RzMY&xtH zO%5P?tY61<%=}VNuSb_(8#u_BA~`%~`MS&#;q!4m=r>=nxe$EQA zYFBn?e*qa|cq9BxeXuL;-U%O4 zeG%Tyzqae#`c8OV*Y=owx*e~{>$m64ME0?4?J7qaENgPScC~z6$7{DZUy@!bduV?R zN_3b0a()d0T)+J%Eo-uUX+&N7{$}{+Vm`+&C@04@_$xI>igm;{L|ldd*fn{^G0ySK z{Z2YK#+kJYDOD5`US2y`PE?G*ULC{h%{zj#!Ob|oJl0Uii#72BmykMPpSU`2)=|iY zVogo=MPusC@_;h@T_@-s?MUW#|oqbN3@={^chMOM2}^k(`=8FoD-LZ6+gcz!Uv6w6f&O!nTJQH2aE zqSvDJSa^Wh=#M4&i!AJ{KdvjzOr|?}Gf&z?!uJj8Q}dhAd?XKg(yPdyDs-S=jCvhu-pt;B={?=a_r^b#aPt)m8jr=S>68yoqbT#4qnDoNmoN8DBFeGK zjDMqe6|t4OMRki*_EEjtsNN!dcL&!Hj`7E1rhDj$aD7D4@Oid0I+YhacbcCkZ<_?k zn=z3(iqPbBJ~Qmke=%OxFVAF`WUT?6%5SgoD`I()q<1{9yOpN{Y!GsQY4eQe#hdx1 z=8E;`{cAdBa24s@Ci|}IBtt@v@DKSzm;M86qW=;y{bTr-UZ@2)Qt!`;><68yv+B=5 zhz9@4NBP(?`50Uj-7?$D|EISo`AVmnY|5q#E7d71Dp;Lu%$pV?jp<&~Rco|J4g)*_ z(!JV-pcWV&-wu{Gx1hXJeJov^vE}eBd1wwj~Fx?p&6$FZUkD`!E=P~5oJrw zXi*j}(^OMEUAW=k0Cfw36}(wQZWqmNLN?z7R?3_9*3OYW*0oGK=4amYqlTNJf0SZ~ z@ADRAs126B5la^GnB52snI1~PyUCtOEoXHIyT_F?FlF%bP?h%TO(2GcJIqw(_9Na8DzIyt65}JMm7}G=?P3P1S!6wftjlgf8x8i^ZdWmMe*9bTpjH&hR+zxwQ9lUv&$ZG@h@U3Y@Qc4 z+1w`mcD}kB{(({szwW(Ie7B`~rcl{H7}PWts_{Sz&LO+IWfdZvhnM>iJ@V#_JSH2A z9J;YLeE_e-HhJ&gN?nvXfzamVi{ta6&|C{GPN@v{Vbl`xO7s}(i~ac2jlTFbP(?I5 zw1pMH9CodJnNYo$I|FIKxNzuWP*$&(fHS3KmCP zl-7vWF@gJ1W1CxkHL`YgxP?jFB+G^=DSELgl|K=u6E~Uuj3?1aZGyi$TQI|KODTk2 z%ECb^W>4SeDIIN`F|B$2-`aIDFWkb?*|3H<7fmCg?vT5eE$}WqyNg8P&S;5}g`MH$8+|1+Y!VI_d z8+}Z)IrHb%CgmahxZT*@Z@sqn=)UbY)L?nC?P&z~G+yel;U&jg!@ntjmsNN>2u2Zj z+<^p)n~iZW`WU)}#$|Gj0BsX>r%D_aO69HNg|p27#?;)q%6MGcYon^8Zk|mQbaN#w zLDI+Z7Na-?a)k9XAy&H}*S94`guL)C6zbHxSZu@1k3BGIULoU3&9CI`ziECBExLUU zvxUm&?rfoew35anL(>nhafYVL&r;uRB$w0;N+0V<}BESmyGUonN zVRnC=7i&BG+0}$l#!hi}Uy`|3qn3H`A6OchY<^OUXua_@vYpW9Vs6Ba<*GKjCcnV$ z9)h@{H9ytpp2$D>u{$1A|7lzM z)vlMXXTu*RYj56M+w4fSMYR$36%AXg zbLv5ks*XI04iSl84NK({P4=aVy241DgLI!Emxaas?yY{)%|^O;B;9PJn@7^k#_?%I zZE`e4&jH_5n+*@*UlHWVUi?n)Q7_tTY03BiN8gmYDpH}Pql*(EB*?6PS<^0zS3km4 zo~`>Bad#TLJXJUYhn`hU?52H)n#&725p<(>Eqn95QoXVo!WP1Y0CE!%$TlLrTlO|l z9S$dSg7X}Le^_Ps8~7Na$O$vhV-NUrbRv{)H`JlD*O8r2`gf+1a6!DTMNHWC69F#c zK*?V2gr5P@0^588WwX_sH^Sz4?mAnf*N7Z++t~qR*0tP2$9lP^z|hcRyxdYzaxeV( z(oV$>7rzzJ_y2qxIUQKbX6Jf?8LpM05#yt-aO9xGpcA_8F#cT(yb+5$jtlr$X`MHf z;LjAs*EVp{%Ddyd#&r3M(phHqZv=F=d6OFWOsX)cF;$S?Tx~^RD&r7&q*bpayx7{b zLeV)_9B9DWqzhD6a)?%mMQ7@a|ZfVU0PPJoSa~z0>8mID8Qd z%Q`9UnTf^?cqUR?6k)W`$iaa3yxe;SKnUI)ZxqTh<^RqUCKz$5uDVtARYzAckxi*O zmM{*(w4{5YVIUXuIFd-Oex-q!TR_2GK5w&+(*7Ov_3F>O+|}eQ(HMIm!1t*T{^QF< zV@>}ml9t+uNb6I{ny(Kq(z;iqHHU8v{^}BSrGQ>!n~KScxTPG`)A6|J(|%PVFvFYQ zGl6l9jLxL~y=MX|ReYh`bQ|E$0y|W<+1wQkUic7;2K4p+(R>nqWz$$K=&}9xA?d=k zQZ88dY8pk5Fs#ElMS4m_rm(N*Sb1AOgPd z=im@Sa6H#Uk8% zI+`|bsJUZ4$gcG+Uz&fcwsmfmyw$v!dyK{-;Mt}M41!81$1@IRoEU^zPo*R#ZZKk0 z9Q7gXxOF4NktklS3V#+fGy&VC*p*fci)csiI7~^joTuEH#(&-MPlPXI^B*0)E)u@L zz;+I2y&TGj5CABmDu}cTzPyFQci`iWw4MT2{k??`#b7Ty@4JZC2y;(4%%#BG?Gff4 zOSkozQK(K2T<9=&yTjb3>47tom@}=a>Dvv?GtSFh1+M65>kLCx5=|$La%d8%IyC9Z zs~At*ecc0|_Of!|X?3u;6P|wYT8yW>z)ua#U&W6NB~$NYmo!H|EWq8{P4;FU0C-zv zh0jdkdSMs&lPTOKEGnc%gMvOot_X(947EbB0I&1z88vpoZe_I@Z^T`#BurqGM{M^& zUH0vbf-z5`1QVoMO1UfM<=!1k6V)#GK3A{smbR+^Xx$(r$|H}$dCI@brA$WGxnC)T zVf|C(S)o6b&Cchi+@%Qr$S6)Uv}T>Qtq4B4^nruA)t9QTXYN?wxGD#+`yum46N1jH z&^~qbva>c>YQ@SMPWT`L4XmIWNJD}RW_sOfy^PqtWr1pE`hBwoF9TET%fbhW^UVLP zKDTA6dRRplg^u{$15KN30jyY_bm0#!r$>$;Q{aX*mP@jQ_$*GYzy_RMUAVZ&21x<( zg3wgn)|g;}XVY!{E-M_^l?}E^54=Ld5DSp|;IOi$&C)gV=JViPzF0hPnel+l79~cQ z`onNJM2}t%*II@4dEdBm$aBw7H90Y_- zk;aw5zEf;E%%6un#f9eHo9wgavsCE_cjXbrcvMAd@&nvVAe?+uS%^feRZ@jR< zCuVYSb;C5z>L%FoXs4i^P0gjHP5waa3*l~NG6qShf@>(c=5NL#)IIZ+b9!&s$E*=? zo)&(g`zBl93MyUX!@W;w6lijQ*&>W_Nv&K5;0??L#?rPTR;dGV% zo*ENAA}s6Gn^BKIOTu@mTiaV6R=_ha(V`>5?yLnRkoMa!NE+2(QXBZaX|LknRLGnYOCsiWoZ9?wivx|Bmr0&%TAu>Zfr4qb9Q}q^t2^^m2y+ zYfM=Z+&Z-XLaO=`@4}~{vg{XV|4Vtmw-}dgmw`LkSzUP--atBfxS<`|!;z7b#3*cS z1)-4mU`y-$j{1t#UcP+54iF>@;D-gx6liR zqw>f%{|gLALgq?Zlf2Z#p!dMu4T$i;cS>SI#JZF5j}ry6?uQW~{+TZObx)*IXCf%r z7qbp^v~Ip9?Gz0c`EfK6j#BxUe|q5E=k}mn%)76Y+TMJ_ZA(f9_Z;rpo~1fUZLj3O zM)(h`z$V9fX!qD;yW4_*sLz+GT+e;Bb`Or)-L`YP6V>jRxLqeNgxwoC0mZ>Zjqp~aZP0E8O5kY2G%>7-Zdg`F$ z!7rjFm;SSpJh)g*Hd~X(g9&xnX=8C9{K}T)&hxmT@avS!f2|iXjOoI0jhVK&=8~Lg zbIWUO<9hS1Hj7L97-#Q`xM@|L1on+kyLR-QslLJgIJ&Nzbs=}^tvJ%*;v8}@XMYR{ zlzF-9M7$9Aa^BKJKbv`kBzbWVJhX@iZ*`UUTSYtWR#Te~f6?wfQM;RTZg;HO9Uix9 z>RC)Lxz)^hQ42e7s0A_P@}IhH?f*=t0bIM1>fd@--Ky=5UbvjJL@#YDVI%%miJlN? z{2w*9ba|)dE>?5R)*Pb}WHVGKD|4iVj&}s6c9&(K}BplFZ*iynd6uM4T?Gm0TjOBF!`)mIiZpCfrP6L8Y4Z zovAqLd8TmN3Ik|TW$@IKu5V{O4N6&7+NA7%L<@IX3ukhCerfOEqy;*U5;q%N`-jcb z0E~)de1n_Soz?EU4z@=9Grqx^>ELk~@vXlt=N_xIx!Ut`wFjeDX{ZjDnu__5P*p=n zzk(Tz{#t37CG9C}u~fRR$U5tShuEIcK>g(@2q|}heT?-C%0vqLu`KLuuw0=hE_H>@ zutIzHQ0V({p?I+rTo#q9wsNbOgJQ}`+D$)v)oFCPWmDr+=pWqQNy0`|)q0PXVii4@~vCN`#ssDpbiF9Nd_4Yd??f z&1c7=Bm5zRB-OQ0X1g!8iPF2+5yFjmtpP^N#J#a}Zz&1b-!uL6 zC>J6g9XZ;K;{B?lBw&9{6X7wGFWK{S@}kpclEwA;Q3RVuPk z+J797Q=|lpCOaLrg_lMyoV?BaP6i0F8iDZ}z7*B8Yzc z#wbvCXKV?jv6GQJPc~}`a~YDzy1vSrbsDeTG2)44J%Bn&>#H5rYESE{B_kY{R+$p_ zf3vaBu1;NKdg*aSG~s+S697wwAIyXlT~GJ>N?+TwlC;fd+w6Ke7OH!7>Tlt5g z2)o6te<%XVOr+GQ*-B={=&_~rD2rp1Iy-*!^8z3tSHcHb>6ZrRXB4O}5dCpt@4B{; z9jxDLId@|6sn<1WdhiM7lst|Z%Dp?O# z9MabNZG)=U^gH?0Zg0f1P2Wyc_tM_5Es4>uk$)u&)EADg;09MOzuS*HcVOL%$eL&c zazw4ZMf!i?IJW}Xi^OzcS|c<6t+w1KEk*t;Hqa@}v8n2Zr%sI(nVP#>NKdR34*V|J zVny^-sJJuZ{$W&4OO-e4IefO~A&wERAX{mzat?1Xth7Gu!q|B+$!tmCy$u}&Rkb#N zPIJ}Lj*Hnx;STRG#T_Q>tU5*Od1i{DBxFo@EdjSc4l?oU4*PZ;9 zfVc~7p*Uk4&P$}YPTWvq(TveAYVZ9WsH4>0L27S6=k~gGlH1*roouX$JNYql#|Arj zE%d5R_U_!tN1vzByHr@~0LNEaY@*c2W_0v#T&bs)M0)H*bmkbzSmq(+NVl0rMaJPp zHRXdyC%S~PUhb!~Q7Tx{iAGUQJKuvCQfY4s6^T&C0t;jN2KS*QNT=O;jSab(n({BF ze7NXx+vQa-&)lnnU5UseHpr!2shwG-*`6^QN|V_M28t!hTDWBp4cX4{am)e@g%d06 z?AP(U=-!&KCKEX_%?+XLJCx?{barVuXY?mFRIl@Lry}7oFap}`}ChOF8C~rug#P@W-h5r;agf$chNm2frz55_~?C#^m~&g ztDaUu(US7;VU8&7eVBSn^m{(dgcEJD%Lzv4#PN$eCLt@x%oCY|wZ}WFj)#b4_TO-m z(i4L>>Rgi}J2$zRn*5x(C0egLY2d_`H)Ae(P_d8A7>=U`A5npC=;NfQ!RHru>f`UQ z7lb)$u-4}DZk0|shv4JZdMp{WcfMT6kZ#*+ESLYR@>)NvW3<|Cun(Cw+lodiJ4dMY zqe}87sTIAA4x6+Ctt{Gs-mAx1>*p*margKiJB%-TuoK1$G!vdp z`PdFI&VnuwruI;*g~Htk=+6SqvJD-)f1pb|(1_dj*`H7g7tHFkIFlHyi@;5Vw$0qU`G#(#dSS#Eik(73LVqC{CPI# z#p0Ta?5!-9gGJ(6juj;pJ<0PALki1BEm}t@2ajq=f4ZGS+gWYy{^eBRn4-DdlvDUdcG-0G zlitjAg1)mL|TZDsIRQOPIh zQ%TRi!K!8Xr5aQIGxh%0X^D38Xoqqd{5N7S{XMGy8W%YNW9*19yivW0=hDvCXfrQBjFJ@E=OQ+n`%- zJT2}-y!eIZAk4}@)E7ijTyha0`toyk_x502t3wsWMax1KVq z*vEvWBRR8N_1J&W-xFl6jtoeh`gf+rko@9x5dMOL%jZzNxcPZD#^!ahr=cNTNK%f;eJ4HxSxa?SG-^ z{G7&x9SsrQ*p9aCGE6tH?X$j-4o2Gq*Nr~75ff9-bZ}P1)M+sxtf#Ww$Qg!6W%FkI zslU3P#NyY&cmj)}3UNe46~ALj7GL~uXcCKC^On>ar=bf*({&GIaltYnr-bI6e`rv( z(vmkzi>^r7NXum1v+Aw!4L;xB!SrMw>L~H*PBam2N_mtGx4wucoL^}lI3hR30BZ-V zRZn6=;T$HASk1PMkul-!3OYf%I(wJOKD`B$=oBYfgip#v2BdIwW z@uR+}>Tg9=pVGPNeN^@K6fUj5lLYnz^GuA&Vgwj3cbk$UT6JA}ktt<^UAt&s*R}S! zow{}h>-O;X6i&9^!_2hnW*X&af41=bV&9M5P}|XBdXuR6*Egk(5@rXf`5jc={LXAf zl>9nC9gKG>UMw~BG4oK5-Hg^vSO3uUw5fAbOITBfcm6l?Sb9E!R9c9Z0)q^;DoIcfQZ@X+c)hv#QdJB9>W55cf=P0c^dOV55sX0!bfUkJR*I* z*GbE)uerf&_UMo-)gTrV`qj&(?u-nPF+X*}$Egz@FFY{gV_u5;6d&xQz9wbsY$>|* zzQ=tE30m&V`7ie=Zrj@p&oaa%Guko=qYloXkqE{JJazutI6`ssBvK9Qs{aXPd`r+o zN`^2si=%5D>#1JL9#vw5ff@Jm7V}GTn*SS1>)CESgieG6_;3B&t~$)EI%c5RIR7?W zMAGcZuq0X_lU=%ciu~JJAr(Qpf=&{gvayh^@SjRmf9zd&Jd2&|T11vg)TLJy{bbUTeTXV4)p|}+=o~;1g zOU=@%Q+HcaEV4#da%YzI0zS}ar`F#K*dkRuydt?7z>R&v#^efJF7WBj!d^*#{^G&X zGHfT!ik+C0YsTCTp}$2X-`KYo11Fb2iw3{kzz%`tOrcj>e#*jiLnhy~LpGOpOjt9g z^(rf4XQZxh_^hvBn8Mt-#x1OxKHo?{Arx%Y^y0H_)wFs~r6$=&TfxfLb=72Zot7cY ziX7K?gA1LaO}>iYrF|Tad;x8g)*vm^gqcks3$!Vb79`MRD4ms|q8R&btyE2UWxbXx zkpa#uzbIku@EePx^_ET8gD19cm7EV;ce(;>cb^;7A7de|$30*d2X^i|s0Ssmx8kiH zq7d98^3P7YLl$S2+7X$=I%X%8t2EYIU`vYaE^xuZ!`0hDw6a@9c!6NbKu4F)vyG=i z;kNwu$5v!~u2!w>OMZFVUsffrkc>aMf2+JT*+*~eldit3ss+{I%pc%wuNUpCow+?O z_j;M6mv7^9pRUeTX?N|cP3y39sG9PkYyJ1(z}U5Z43k-`tlefL>%>%1S!*Q`)Zbv+ zQdkS{ioMz>FZPnlKRdP4TIf2_SUe5(GlEN!)*BF8Nta9eD~fA}FY5hwg6ktHT7VU- zw08I-Z$iE!n`fuZ`lgMj84uusAR-O#xRnmh*8MkOd43h9PZLfNgL$(QM<`x0g!A+Q zBdD2ZogdksEVS}N<*fQ+-sBL2YVu}n`jKidy|O&~>O-jowE$aEG#7#VSRWEo;k8#Z zc)Sod=ReGDjVkn)hP8lE^h0%1d8+Lwtd0%=;jA^q?~>zvQv=<(j)8Wjqkx5IpdH=7 z3iW7eU|}|7P&lkVZ_85yFI~i2@*oHPMY3L|3iD+hrJck{X&noUPf6=opvwu-YiiJ6 z*nrZnc&BrC$-w6~@vHuG+z+7|ovm}{nK^_wyfHihqdj`lh(gol>+9P~z5Kh|2$r6g za^Z}xHJ;*YTp@>cc7WHI-KZp8A;WoZs(gK+O-J5GXs_m{)aXt&WN&5yc99`Q zpwZ=D{SPO*Ig(gwAYG-t&8t0zFtrczm<{?2L z8HoJk}d9ofvVZyF(5lkc2JT7o*_S!j<&v;}%BHqYXO*`8uR6DQwt7DzKp83~~ zj^@|-=;hamQlY3pYHtppMf3L;n!g`g=Vprran&rQm?U2Q+irdqck@!3`i5>+?AWE7 zOX6-GNnzK`_Pty;`?l|E^I+W1-Aetu;277>zuXk}6MT62tv1xxSHE_B#i6MqyxwG3 zJe-Xwcw57!xEj?+@+yPz`Or_I-=%ZN+}?GQR%NuHU!c823BBlQDV^;~NreUY2u=H%QI$ zczms|QAfGKhBKNR7Ue>uOwDaw`Z*9#8>&CYup^iw`ZrOZZfhu)#gfAkY^H!f88!Xh zRS~TX2^M_5t{4HsDEiewQMVWK;JQ75IRH4Cw-Md7@8{-M_I&C0`%R4Zd(k=U-;Qok6)NaE5m(=^B|~34D*j<~gk@_$MBnC{=(cF?N@Lw}p52!% z8sd&wHvgqN*o`j-8|=;b2LJQ$CDsN`A1sNV{{r3x1}~sYM}C+T`mApf-XBNsp73YE zyMk}s!0Ruy6IpfDpW!8A;@N*QXnJ&AN8E)=d+fsL7T?OtpDxnF=FowBHv~t>P12oq zWM-~qi6T;)c|BsTE2*KFZh+L@{HzP9-LK`23~fhImm{^^u#t$=wrU?7??18aBRWHV z#&kCDNJnQsxgn;r{5A&7`ut@y=C4ig*OkmUUF2spPP2`!0!LRrjp=HAsqzZEY*Hod zC5P(LBOFxouh&rR#W%YaBDSRBJJPYd+mU*FX=$W>+v7+*vc`4dRE^Zd)`=DXE{*{# z{y&zF+au4cC)2k0M)}xp^Dgr7RcVGAy<>NXTY`c*W zZvI=H7{6JjqSYq)9m|FPcKmik+p=E!G+Gi3&y8_Vt+`I)cN*W;A3vS>C`pDJdW3je zgSa^xzVRhGkI9A30WG#F&L4s#x4KUfl5_;g=?2NmeA84V&975Di)SM=j$m@eM|%VD zELv9yfz6kNdn^#~7wJY-Y6x@7?vXNixz;eL^2@KX$?9?~Z+M&I-n8=J?IwFGZS`Dp zr)sR{8#gs`8n?2L>a@X|+v$F}G7(fuN8deE7}ocV>4F6`#J-WLe$>l;!EO>tvg{${ zi^KQzmeAsV!BB9SQ@pVGA+IhXrD^Y7OV{;`CpszxA{g ze)X9USPN9eEtfjhOeI^PbwiU9;9uDZ{7A=6IF^KOy`yRLb1eww0Acvyf23F2EMpfh zeuwXI(AAv!;8r9=)H9WO%S})|<}FXPZM@r+AS#ZCsI?AJ&X(XmuF2P~C(W$MRDbEs zXrqCYA1y;zj$Qi-A|1l2FefeE+ z-BR5m=FQlN%n{`fTjQn7K(zOFUa{QWfvIGsA185kHwe`*+=RrB9~T33`G2Je495fz?a zMpcm`1h*Nk)8(0MQ3S2)@Jme-SV@?j^$6Jw;?ZsW_7-X#Ubn=!)D^GqT@Ae1DOD*5 zRMx9P?IaGlGI2|u-O1p}O>qdmKM@VYfrB#s+c*rS{D;#%t_8X!dDXDO&^c*B$#guI zx+-11BvXB2>YTUI{`P*)y%Dp-O}84>TQoSH>GM)`-p@+O5^$5$MJZ^XJm@> z_i1qQCyw~0?vNn9>nNea$%rbuRgoYlH(lWf@!mgl zgRqsm{{Mq8jJa;rKs=X$Ym!u@D32S)*>E>cIr>*_WQa|vo#{$MHRNN5vCQ@fqWU#u zN*Ej6)@Sb`%D|OSX7}%P#h3qk6^j_RTZY(ugP=zurna~rqVfJW#-Q%`;e754l@Hc$ z+43&(!(6g=!w-Mka(#aI*Y6y-5VRAqb^h04f$^+O+WR2q($%jM$L|Xffm>L>h&ox) zosPcz0YZojS?$LXsH>{@3+|0oY>Q zdc67-uF7M86oU^&;t)D2nMeg6%Vr?`Yh{SVJV z?Tz|f#CsYi9E`(;`Yq$}H~g=~PAB|x4H(y9tm}B*DQ?2`>)mzR)Xd{uTMKRebTe8w zp8ezo|H)24pTGc`|Ko8b2DhKq@xiJiiqbYaJy>J9*l z4fO_hSkl?s!Y$aNiu+UVLPU;0m&gxlkL_h+s4N=i!bQ%C7zG@Rf{V4rv7bs-M6SxR zoC(u;_{wcU>-0`FBqKI96WFa-!x91mD`)!y+-=umk)}fX)fjoDpJ7;)t`y$GmTgf7 zI_F($`o!e5z{)nf0V*esO+MRnIE#b7p0AsbJcC#kAJ zSZueJ0vW~Obav}oZV|w4BO{!!Vm;^!_c-W#{R_w{Ka2UIsFX{uHusV)iagqTJOJZu z!?&n^m(ByS9Us2PMv*&H`P!v$Fwwvkmq(Puwt&(1v^Um+>hpOHs_e@^l?JMqpY1Ll zUGH-}orm>W)b}`s`AJv|*))29w6bvDOC-b|)F@&_%OpSDjg3Ja6lo=PsHGh5iBC?r ziEI!Wn5VqU9}16|OYY7dHl;554~Ms-aVCxLvv_yP%=>`As15!gd{14h$*VyxH*P6$ zh+O2HHf-2Ex>(3bW+;=WrsV6WD&fj;B5VJ!k-}7};pgHdZD?5N1S8z!;ie&ECZAZD zATjfcjraYg#veqZRpV8i8xL4mhtFY^Mt)nMl*Ooi7AR%HY%l*OUTpVr;bAlwjQ+OU zFuci<%^!Y5uET=5Oku&QJpzmDLLeI+*epDpRVT4syxeQpfJP8%C3h6YNLS;rs&Q=} zSL2aZV{}H4J+^?4(TTs5&!*F%75>qLj?uE%uOoJh9OwNyTF|=IuVWSESlqAcD`NOq z#Upv6_k;F$EfyuHg_0&K#q&fxqtzQUCoK6L!$Xr;A1g9LX-S0 z*hk**k<6#AjY|4m1Vmy*z;b6R&aR_ z9Cj=x%Dw!smsDg}Eu*3CCY?*JVLjieHdj&>99u4P!u7xo0CUMhq6!biDAq%T87hp) zC@BN?Q$t+|u`}q;piajv#h`y`6K1!dzsb_R-tCx3H019iYk1n58eX&K*%&xqqjZgK zF3XSCWOfbz#flXO3vYd1eaR~Lek(7D4CUt7P!2U}XA z!^2&sM2Ex2EvYD?!{b$Nk`QA^4A^KDBzU8 zB%VHFon4QKmtn%K#><_%im{xvOjX-JM?-wg-<9Gdik#ZbOpCI0$clNSU1|t-0G>sj;s{B=#cnS{p4t>>eNK38#O7 zw1;PfR(_1 zp$qtvZs`hs_5D49{~Sx|q;pC+S)CUA&U9N;ID2_~W`}t|*WfIAP>^?)epgyrv?ri} z`c#{NL>ve&;Y$)_$I)hKz@p<5i4$Z8+xOA{?xXjvDDKRDr~Z9?^foV2Gu^V^t5>Mk zw>h!!ftNpstl`90Gzmog?b@6h(QlaGhX1X{7EiGj?cNJp4sK4?aMjDnb(<|~Vo$#W zItEd6z3#^p)O8OTqRzwXR}jFIDAIW zniRhI`33+w)5Q45-rf}t)qKmlbkWWa4LJl3+T^Jo0c$kCO8!w#Yq9$340!WjRV*ef>fAWALy1+EZU?NJs+lvlAl$|OGw5JTogmp|1uCl>Y=42c*P=1FOK|206|INnmHR<`ArdsTlF;w-_MJmeydNq z0U+wzMhj(WC&EeW(t4}yC5Ny55pz#;MBjSm<&LB%Q}0i$2Asn){`G@c7KdNI-=(#W znJ=8mi^iK@_d<+=Z75ls-;&@xs0k*Sa61VOpKnZ~E)&h#x?hW2bLo$fE_`y~LZYBI ztBI1~FP_oI7BN=xYj~8}i50a(v81dTJ}Yiw0!?%(-oGoDn-sx3uxsA;nNvCyez|MH z<4X7jVCKz?fq7|am--4_>pPbOhUd<%8ISLp@zAabwIn#Kp4GMRZhT@tD%|CDt9%UK zUCuO5v^LEB)D+VP^JIH^lJ8fd*~dHE=H+-Ijt<2>6PloK6i)pA^sSZVYEERKrmx+0h0=@#a-< z{vdsGQ=5WvEa5m1aS)i}W@2&asnjS+S?(C8lv);^tF4A)-^bf@+lP=cCcjoJ9Ol)p&|9)Q2*xGI%hb?SGPPZ~_?fEz@9u|y-ThoF zcG9`(rVarmX{n#4O=H1Pe0MnyQcl=?#YqYolQS16cSW5vI+``3aQG6Fl5C#Z(q8GpQ@^wHc;jRC^_G2S@P&hGYm zcz;~}NWRCjLRf}f*a2~{6>|!)g`~0ZjN;OSJL_wbfqqx4?^}G*Hdy}UYpLrK@!WsT zj-Nt38OB~OrafPL`bY8UA)c&~&sYn&N^U19o)9byTLjRbHMNDaRn%~Mkrl-PefryR z(X&WGtrL%gQ~#!FAQL=Fg1uU}e(@estgR#7iVF-=Z3g;~V!eCwgs(<;-5c?@9gDfP z;t8i&FQIx9a8JfUiikn^PJJH>#seHSF@Ll-=n2GZW76A6p)UvX=Q)-pfBgxzq)Z zD4W0H*q_yntNU5q&+CqRn4;Q%q3ASjjC)wEG-d|=+wM8%W-aB{Gq$xRT?#a^zbtnT zz1PQoF8l9t|8@Ugt>daj4t_cNY5A&0TKpB>h{Y`nD>a(;@vqE(h+tf!Qu7&c{Y^`G z^@|6;Jop1$01f6jtTtUXOfuD{+orFiga8=Av+YgsOqitUSCLiemE>Q-Z>|66rfVoO z!t^4A?y7I_4HfBS)7M}t)gOCKXt9vrUdqo$lnAc^d~QGvJ4B^7F_v| z!OsqUY&Mtba?AOhlq5EDc|uC|SC^7s7c27eATmmZ*6OROs!65Jyg!wlFDHqzrbAVy zTj#oZ)wiDOwXcgCyRElXHJ&-&ZTJmWOz5cIM}hY$gSV%6(tRT!D~muj4moqF3oAW; zkv=vZP+Y(Gs&A!(MDeKybj5-7a<+<{Nr*PBaJ!#TD5nVs+0IxpKC`LQ-n-8}c#)hF zl!v@>hS497i=xN6rPFozRY}^4)!&3Vf4VMXZ{8xhP8>)3DpOKn9`?;^2R|l8N7hdo z5Ij6dS`zfs&uiV2OkQp${>K%yA6$D8^H$50su862wF;(GRq{R(;Eff>rwXH3-dYH! zQGN9=skt9?vG+2O?-GzA2QWko^mxcyY(?lnkfvZYgrKS=f}G5aw7YG)7N)WIOdvJQSYhRYjk##IeDYYb8>J@CVZUU!RbxO|cP=%kxa z1$*aIQFBiJb7rc=_P;42FWpV01|lt(GLaIqDWvDd@cA!`>rr{`4bV`7?N|;qZ4vBs zxXe`JbQjw2ig+EY2O4D zd@e}B_W+_KUkwg0>38B|g@Jv|JVf0KBs_T`!my)%)59obAFLyfgLh$sVZtU{oc^kZn zaD5+~#r$&^Z$$N<<1kj^mQ;>QXi$FTXTaS(b2HY>QC3WLC7D=tGa;LpH!=hbAQCC z3ekrG#$^hJZwx*6+sMoBOTJ8D+{T1N9k)@1m)}+8B+{~r261;%Gw#_Ss~h|nt2J){ z5x5TKi~-0D=^4K;uA+xjp?}N$5s&zEK2zA$b&!iNiIVYwv;W${L5Bvp&6k*;S(AW; z$peDIPjpAAq@sE$>=X@AOtAV4>yJZz`EFh! zVWLP`UncR;ckl-y36X}Z1O1Usb9gpEyKMSR@nd#!Eyn29J9+nV&w;UY;U0%u3x$?i zhQW*z${Q=b|Kq9b(2-@6_fBP}jI1b|{QY#HPkE|(?bPpbr?2X+Ynf8MB@Fm<)8?e8 z36n3`Mg7y&jkT$^L(0#&FZ?xanB0I%M5y4_m}SA5C|w;Go35EY1SXrZt-Q4JOCUoy z&22O0?%_>cqcB4v36R%BuFCWpQ@xkpna*o$KOwcBm)~BmYd*pFy#&XgotK2V*1g1^ z!4Ae`kwggp1TzH{os#;jc7zCyCszcwW+2tUrKDK4czGX4h`?aH9~h(60d?iA)>ro4d4YA!Bxdk4+oGGM5=96e^U}Rk&*o4=wlqmj5BjahB)2%9Q`<;8nrWW;(%P3AFg!D>mX;tF17mzw@bc zuQkJJ&)z(>%wEVvBm1$}`+6{a2pI8$RQ8enPWgPeD1V~{i4QHx&3GejnZvJ3EpOQF zt-9=68|hyA_CpRZ$)FE>>$KrVme+CV%P5^HY<$q1U6{iNB-yF!^@8|PC!)@)3??=icEf9^Xz&L%gs1T+9=w#_ za6JE&>c7jnn6+^$kI>gNmip9H0ILl8yZUUj_6Gcx`wdkwlKiZ4HXV_w$*QWRQzNuE zA_}KaqQsw!zv_(0BUr%vM4#KQFT&%$5dPXwT;}KXsj!%gaq*)q=eDD}vQ<3Mx&i=AaM$xJ#Mt@qDC0BqTg$_bG4M z9!&3XZ4uLaBQ}DAM~YfUtJ9fu8Se_nJTcusOvj2AFl#K6SuaS=vbx`{9w8!uKv?CyPpgdf5#6z$@R;Po*$i%9pVM6L1eZLvu46=wGgV8Pj&HetHjR}v9UUxmxQ*WOjQGVL(JcGhygv`GOMV|eZd2ZO5Y8b1T zhjfbfH_@5G#R%=e%#@tCQ$3TFGx%ya0w^+H{*DZ6yR3yc%2Oa_QmT-vN|Bi2ZqGpt z?jmK2>rBifEtkDn&r?T=H(iA5&CtrzSs-~W3nqQ&x^sX&=5Dr+=cD`Tyf#TG0)%_{ zTP!)l0C2LPKgn(nC&gjZ7CxE&7QBE7-k@CSc~&S~ zOfLGeMr?;`x0MM}y>eBxG=b0lSNb5x)epIvsh{3V30RYZLR{mStOfj)VL^37@-Ntf zHXSHUzer`zuch|WDRe)@%i6b{job2TeN#0*Ls1-F?q$V*P=SKB_0U1069=oARj9Lh zaXPzqdGltRtsuVDYQ$_hyJr>4XU)$7=)p5Y@)({(!3ndI&8N{&)wnKtm$^QM=zf}S zqj6<;<{AoQkX4sqWkpDSL53)nn5ke7rpgG_`O7IAPNoYb`LCrcEHG5?9X1GMZ)n&? zuHt+hjIOuxUao=}hxJv)Fj^Mu8>eqcddLjr@T{c-oqd>t0MdE z|Fg0(v*|_r>tE&gcf9zQ-G&7J#$0P0`kOk(p~B8ebJFt_56+ z)wn?8vB8f~X(b6_vQEs#yK!22J}~QV8a$^Xbf`a@MrRghP^0+m)Fi*ns5SI3D{#dc z8RBvA@)rv{7_Lme)UVOeL3*$aF|i!N(?TypGBuoE^xDQmT^QoTbFX&Sk6sk>atH8{ zs=svPe^gYpsw@(K90)%op$I{4qhUV{u9$z9oA-`zysb&|b9#>WCUHG|bgelOo9M_u?7zsLB ze|wLJ;g>b-pTcB6=wz-algwC^?FLNGuP<9_f)$Dty|{g|D97wIvlmBBf$ z(vHR?e|q2Sytd#)HSCYOXe}WJG8o7Ej?;6p8&2h`*?=qW(L++b?Y8EBeL= z)G4CkVs8H^_#@04_5<1?KSp(xhfA$v1e^o^D0safu(+LA{DpraPu!vAF%l6*jIJ}U z1$|vlj3lmBFMW%T_0qvzNTR7uJGoe)5YlKDJ8z zm(qXC?F^2W|DmXzS#GR!fLh6rA?T%uS0+2=dfjHt6LY;px8J7`qYRC~=_CtRnJ8r}L%e6IZCur) z;Cd()F|;SK(vU<7zgj6FL`Ek6H9Xp+PkyB5Cw@OdL>;aU5a*utAqU;H^=DkxrX#Y854 zmGW}90Ydl`R8a2pkgxzxB0IMpl|M9u^z5CuvNZ!i=Bq4!3;3WaVj;sMf zfIz|)galcX5FqR%F$s+V=Z3xc6%n zY%TZyIcH|>Tk;ZWm+$ufPBM39&YU@C=FE0xx%VBI@GKIxy|k3eLCc0F&f=-IF;s;8 zvw^7=LRF$UqilZ{C!F3~2(=pvf@d%uRAD?otDr$)-cZ7#88(dC0)?4wjxh?2B{E(n zhkkzI-Nz#HOXq2`TYrLORVB~GzeG>_gnHUBs30_7KFV!|+a9{nRM4%Yt2a}Z$RupP7vwb556F*y4k-z}{V)q1R^h|EL`59chbKHBuSJlwsfCQ)CZHXMO_Dd;O_5 zaa{9Q8mf+uB|!uA-2slicLg@ExLsADfq)CAX-22}uBAf}>w1^L%6@cl&0Y|t#uA)7RYP_!OEX0@Kd zcSQ*T?S&de+u}F4=Js9(m@aQ%@6E^>Z-8`x7|M3ju1Q}^*_p0a-1q6x^xuWY@F%I-EtDw(lYwc>o=&S z;9z_o`8S? zz3W#NDr$SE8E+kL0(p2_;7vy?yqmyb3^>f%-;zR|=pao#!(N}Yf5NT5i5ytN7`2P4~5h*v55IMv~=C*)HZ_LpYP-oF7&eE;~@XisR?*mHqBH;_<@ ztke=__p?9;HOk7tjRT=B+@0wErw@q4T(joxQ-GWQ2HqRCZv(rxi%q`UZAE zN=HHQ{0|&y;GUQdJ)wc>fY*l&XP%@

-j)TSGrag(9>a$6QA;?8{@pPRNKeg0el` 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

EMkV5y+x&B)IWxcga+-f7lF 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 diff --git a/lib/regex/__init__.py b/lib/regex/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/lib/regex/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/regex/_regex.c b/lib/regex/_regex.c deleted file mode 100644 index a40d2091..00000000 --- a/lib/regex/_regex.c +++ /dev/null @@ -1,22557 +0,0 @@ -/* 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 deleted file mode 100644 index 33dc1540..00000000 --- a/lib/regex/_regex.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * 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 deleted file mode 100644 index 5adbb524..00000000 --- a/lib/regex/_regex_core.py +++ /dev/null @@ -1,4086 +0,0 @@ -# -# 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 deleted file mode 100644 index 663a6bed..00000000 --- a/lib/regex/_regex_unicode.c +++ /dev/null @@ -1,12748 +0,0 @@ -/* 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 deleted file mode 100644 index fa8114be..00000000 --- a/lib/regex/_regex_unicode.h +++ /dev/null @@ -1,218 +0,0 @@ -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 deleted file mode 100644 index e5e40d1f..00000000 --- a/lib/regex/regex.py +++ /dev/null @@ -1,684 +0,0 @@ -# -# 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 deleted file mode 100644 index 55b14c4d..00000000 --- a/lib/regex/test_regex.py +++ /dev/null @@ -1,3230 +0,0 @@ -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 bfa0cf8c..12aad199 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -24,7 +24,6 @@ import regexes import sickbeard from sickbeard import logger, helpers, scene_numbering -from regex import regex from dateutil import parser nameparser_lock = threading.Lock() @@ -104,8 +103,8 @@ class NameParser(object): for regex_type, regex_pattern in regexItem.items(): for (cur_pattern_name, cur_pattern) in regex_pattern: try: - cur_regex = regex.compile(cur_pattern, regex.V1 | regex.VERBOSE | regex.IGNORECASE | regex.BESTMATCH) - except regex.error, errormsg: + cur_regex = re.compile(cur_pattern, re.VERBOSE | re.IGNORECASE) + except re.error, errormsg: logger.log(u"WARNING: Invalid episode_pattern, %s. %s" % (errormsg, cur_pattern)) else: self.compiled_regexes[(regex_type,cur_pattern_name)] = cur_regex @@ -116,7 +115,7 @@ class NameParser(object): result = ParseResult(name) for (cur_regex_type, cur_regex_name), cur_regex in self.compiled_regexes.items(): - match = cur_regex.fullmatch(name) + match = cur_regex.match(name) if not match: continue @@ -185,8 +184,8 @@ class NameParser(object): tmp_extra_info = match.group('extra_info') # 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): + 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 @@ -286,7 +285,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 = regex.match('(.*)\.\w{3,4}$', file_name) + ext_match = re.match('(.*)\.\w{3,4}$', file_name) if ext_match and self.file_name: base_file_name = ext_match.group(1) else: From 72b4155b0b66f9e0879ba70070d0372a05899a65 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 06:43:36 -0700 Subject: [PATCH 54/82] Fixed post-processing issues for anime shows. --- sickbeard/postProcessor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index fbe1057d..cd99dbcc 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -494,6 +494,8 @@ class PostProcessor(object): elif parse_result.sports: season = -1 episodes = [parse_result.sports_event_date] + elif parse_result.is_anime: + (season, episodes) = helpers.get_all_episodes_from_absolute_number(parse_result.show, None, parse_result.ab_episode_numbers) else: season = parse_result.season_number episodes = parse_result.episode_numbers From ba2a44b1d1e74b0584719964a12e3539f5ce63fa Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 06:47:27 -0700 Subject: [PATCH 55/82] Fix for searches of anime shows with absolute numbering --- sickbeard/name_parser/parser.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 12aad199..a1d9cf1e 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -466,10 +466,13 @@ class ParseResult(object): if self.show.is_anime and len(self.ab_episode_numbers): for epAbsNo in self.ab_episode_numbers: a = scene_numbering.get_indexer_absolute_numbering(self.show.indexerid, self.show.indexer, epAbsNo) + (s, e) = helpers.get_all_episodes_from_absolute_number(self.show, None, a) new_absolute_numbers.append(a) + new_episode_numbers.append(e) + new_season_numbers.append(s) - if self.season_number and len(self.episode_numbers): + elif self.season_number and len(self.episode_numbers): for epNo in self.episode_numbers: (s, e) = scene_numbering.get_indexer_numbering(self.show.indexerid, self.show.indexer, self.season_number, From 0ddcc3b58a65c302d30fde8d0abd754d54bb0986 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 12:41:34 -0700 Subject: [PATCH 56/82] Fix for show opt not in __init__ issues --- sickbeard/tv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sickbeard/tv.py b/sickbeard/tv.py index c9890efd..4a23f144 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -581,7 +581,7 @@ class TVShow(object): logger.log(str(self.indexerid) + u": Creating episode object from " + file, logger.DEBUG) try: - myParser = NameParser(show=self, useIndexers=True) + myParser = NameParser(showObj=self, useIndexers=True) parse_result = myParser.parse(file) except InvalidNameException: logger.log(u"Unable to parse the filename " + file + " into a valid episode", logger.ERROR) From 925141da40d86c27d91fd498581481ae6852af31 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 12:48:55 -0700 Subject: [PATCH 57/82] Fix for anime issues during post-processing, TypeError: object of type 'int' has no len() --- sickbeard/name_parser/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index a1d9cf1e..2f17b2f6 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -466,7 +466,7 @@ class ParseResult(object): if self.show.is_anime and len(self.ab_episode_numbers): for epAbsNo in self.ab_episode_numbers: a = scene_numbering.get_indexer_absolute_numbering(self.show.indexerid, self.show.indexer, epAbsNo) - (s, e) = helpers.get_all_episodes_from_absolute_number(self.show, None, a) + (s, e) = helpers.get_all_episodes_from_absolute_number(self.show, None, [a]) new_absolute_numbers.append(a) new_episode_numbers.append(e) From 4f32ed262c4c9f955408f5deb7b8b05c4174a2a9 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 12:52:09 -0700 Subject: [PATCH 58/82] No need to convert from absolute numbers to season/episode numbers twice, fixed! --- sickbeard/postProcessor.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index cd99dbcc..fbe1057d 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -494,8 +494,6 @@ class PostProcessor(object): elif parse_result.sports: season = -1 episodes = [parse_result.sports_event_date] - elif parse_result.is_anime: - (season, episodes) = helpers.get_all_episodes_from_absolute_number(parse_result.show, None, parse_result.ab_episode_numbers) else: season = parse_result.season_number episodes = parse_result.episode_numbers From d42b864ecc254d0f5ff30ad0cad42ff1ac2d67b5 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 12:58:43 -0700 Subject: [PATCH 59/82] Fix for UnboundLocalError: local variable 'rating_text' referenced before assignment --- sickbeard/metadata/mediabrowser.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sickbeard/metadata/mediabrowser.py b/sickbeard/metadata/mediabrowser.py index cb441b17..caeb3f3b 100644 --- a/sickbeard/metadata/mediabrowser.py +++ b/sickbeard/metadata/mediabrowser.py @@ -479,9 +479,7 @@ class MediaBrowserMetadata(generic.GenericMetadata): if not ep_obj.relatedEps: Rating = etree.SubElement(episode, "Rating") if getattr(myEp, 'rating', None) is not None: - rating_text = myEp['rating'] - if rating_text != None: - Rating.text = rating_text + Rating.text = myEp['rating'] IMDB_ID = etree.SubElement(episode, "IMDB_ID") IMDB = etree.SubElement(episode, "IMDB") From 99d129bd414f26ec998e824f007c3b0d55edb423 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 22:39:24 -0700 Subject: [PATCH 60/82] Fixes for anime regex matching --- sickbeard/helpers.py | 19 ++++++++++++++++++- sickbeard/name_parser/parser.py | 32 +++++++++++++++++--------------- sickbeard/name_parser/regexes.py | 11 +++++++++++ sickbeard/tv.py | 6 +++--- tests/xem_tests.py | 3 ++- 5 files changed, 51 insertions(+), 20 deletions(-) diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py index a84cdd8d..5007de4d 100644 --- a/sickbeard/helpers.py +++ b/sickbeard/helpers.py @@ -327,7 +327,7 @@ def searchDBForShow(regShowName, log=False): def searchIndexerForShowID(regShowName, indexer=None, indexer_id=None, ui=None): - showNames = list(set([re.sub('[. -]', ' ', regShowName), regShowName])) + showNames = [re.sub('[. -]', ' ', regShowName)] # Query Indexers for each search term and build the list of results for i in sickbeard.indexerApi().indexers if not indexer else int(indexer or []): @@ -680,6 +680,23 @@ def is_anime_in_show_list(): def update_anime_support(): sickbeard.ANIMESUPPORT = is_anime_in_show_list() +def get_absolute_number_from_season_and_episode(show, season, episode): + myDB = db.DBConnection() + sql = "SELECT * FROM tv_episodes WHERE showid = ? and season = ? and episode = ?" + sqlResults = myDB.select(sql, [show.indexerid, season, episode]) + + if len(sqlResults) == 1: + absolute_number = int(sqlResults[0]["absolute_number"]) + logger.log( + "Found absolute_number:" + str(absolute_number) + " by " + str(season) + "x" + str(episode), logger.DEBUG) + + return absolute_number + else: + logger.log( + "No entries for absolute number in show: " + show.name + " found using " + str(season) + "x" + str(episode),logger.DEBUG) + + return None + def get_all_episodes_from_absolute_number(show, indexer_id, absolute_numbers): if len(absolute_numbers) == 0: raise EpisodeNotFoundByAbsoluteNumberException() diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 2f17b2f6..01e6ac9d 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -93,7 +93,7 @@ class NameParser(object): elif regexMode == self.ANIME_REGEX: logger.log(u"Using ANIME regexs", logger.DEBUG) - uncompiled_regex = [regexes.anime_regexes, regexes.normal_regexes] + uncompiled_regex = [regexes.anime_regexes] else: logger.log(u"This is a programing ERROR. Fallback Using NORMAL regexs", logger.ERROR) @@ -113,13 +113,14 @@ class NameParser(object): if not name: return - result = ParseResult(name) + result = None for (cur_regex_type, cur_regex_name), cur_regex in self.compiled_regexes.items(): match = cur_regex.match(name) if not match: continue + result = ParseResult(name) result.which_regex = [cur_regex_name] named_groups = match.groupdict().keys() @@ -146,8 +147,7 @@ class NameParser(object): 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) + 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] @@ -206,12 +206,8 @@ class NameParser(object): if not result.show: continue - # Natch found! - break - - - if self.convert: - result = result.convert() + if self.convert: + result = result.convert() return result @@ -385,7 +381,7 @@ class ParseResult(object): self.sports_event_name = sports_event_name self.sports_event_date = sports_event_date - self.which_regex = None + self.which_regex = [] self.show = show self.score = score @@ -466,17 +462,23 @@ class ParseResult(object): if self.show.is_anime and len(self.ab_episode_numbers): for epAbsNo in self.ab_episode_numbers: a = scene_numbering.get_indexer_absolute_numbering(self.show.indexerid, self.show.indexer, epAbsNo) - (s, e) = helpers.get_all_episodes_from_absolute_number(self.show, None, [a]) + if a: + (s, e) = helpers.get_all_episodes_from_absolute_number(self.show, None, [a]) - new_absolute_numbers.append(a) - new_episode_numbers.append(e) - new_season_numbers.append(s) + new_absolute_numbers.append(a) + new_episode_numbers.extend(e) + new_season_numbers.append(s) elif self.season_number and len(self.episode_numbers): for epNo in self.episode_numbers: (s, e) = scene_numbering.get_indexer_numbering(self.show.indexerid, self.show.indexer, self.season_number, epNo) + if self.show.is_anime: + a = helpers.get_absolute_number_from_season_and_episode(self.show, s, e) + if a: + new_absolute_numbers.append(a) + new_episode_numbers.append(e) new_season_numbers.append(s) diff --git a/sickbeard/name_parser/regexes.py b/sickbeard/name_parser/regexes.py index 2fb8c796..2719dc08 100644 --- a/sickbeard/name_parser/regexes.py +++ b/sickbeard/name_parser/regexes.py @@ -280,6 +280,16 @@ anime_regexes = {'anime':[ .*? # Separator and EOL '''), + ('anime_codec_crc', + ''' + ^(?:\[(?P.*?)\][ ._-]*)? + (?:(?P.*?)[ ._-]*)? + (?:(?P\d{1,3})[ ._-]*).+? + (?:\[(?P.*?)\][ ._-]*) + (?:\[(?P\w{8})\])? + .*? + '''), + ('anime_and_normal', # Bleach - s16e03-04 - 313-314 # Bleach.s16e03-04.313-314 @@ -360,6 +370,7 @@ anime_regexes = {'anime':[ .*? """ ), + ('anime_bare', # One Piece - 102 # [ACX]_Wolf's_Spirit_001.mkv diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 4a23f144..6519646c 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -198,9 +198,6 @@ class TVShow(object): # Load XEM data to DB for show sickbeard.scene_numbering.xem_refresh(self.indexerid, self.indexer, force=forceUpdate) - if not season in self.episodes: - self.episodes[season] = {} - ep = None # if we get an anime get the real season and episode @@ -225,6 +222,9 @@ class TVShow(object): logger.DEBUG) return None + if not season in self.episodes: + self.episodes[season] = {} + if not episode in self.episodes[season] or self.episodes[season][episode] == None: if noCreate: return None diff --git a/tests/xem_tests.py b/tests/xem_tests.py index 79563c5c..c4ef196d 100644 --- a/tests/xem_tests.py +++ b/tests/xem_tests.py @@ -68,6 +68,8 @@ class XEMBasicTests(test.SickbeardTestDBCase): name = "Game.of.Thrones.S03.720p.HDTV.x264-CtrlHD" release = "Game of Thrones" + m = re.match('(?P(?>\d{1,3})(?![ip])).+', name) + escaped_name = re.sub('\\\\[\\s.-]', '\W+', re.escape(release)) curRegex = '^' + escaped_name + '\W+(?:(?:S\d[\dE._ -])|(?:\d\d?x)|(?:\d{4}\W\d\d\W\d\d)|(?:(?:part|pt)[\._ -]?(\d|[ivx]))|Season\W+\d+\W+|E\d+\W+|(?:\d{1,3}.+\d{1,}[a-zA-Z]{2}\W+[a-zA-Z]{3,}\W+\d{4}.+))' print(u"Checking if show " + name + " matches " + curRegex) @@ -76,7 +78,6 @@ class XEMBasicTests(test.SickbeardTestDBCase): if match: print(u"Matched " + curRegex + " to " + name) - print(parse_result) if __name__ == "__main__": print "==================" From cfafc0a39f99ddd182437e48e31a1cb7f3c4b11f Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 23:44:44 -0700 Subject: [PATCH 61/82] Scene exceptions for anidb and xem now update once a day, thanks zoggy for pointing that out :) --- sickbeard/databases/cache_db.py | 10 ++++- sickbeard/scene_exceptions.py | 77 +++++++++++++++++++++++++-------- sickbeard/scene_numbering.py | 1 - 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/sickbeard/databases/cache_db.py b/sickbeard/databases/cache_db.py index 52a9d8c4..3f047bc6 100644 --- a/sickbeard/databases/cache_db.py +++ b/sickbeard/databases/cache_db.py @@ -80,4 +80,12 @@ class AddSceneExceptionsCustom(AddSceneExceptionsSeasons): return self.hasColumn("scene_exceptions", "custom") def execute(self): - self.addColumn("scene_exceptions", "custom", "NUMERIC", 0) \ No newline at end of file + self.addColumn("scene_exceptions", "custom", "NUMERIC", 0) + +class AddSceneExceptionsRefresh(AddSceneExceptionsCustom): + def test(self): + return self.hasTable("scene_exceptions_refresh") + + def execute(self): + self.connection.action( + "CREATE TABLE scene_exceptions_refresh (list TEXT, last_refreshed INTEGER)") \ No newline at end of file diff --git a/sickbeard/scene_exceptions.py b/sickbeard/scene_exceptions.py index fd06412b..e89ae6d1 100644 --- a/sickbeard/scene_exceptions.py +++ b/sickbeard/scene_exceptions.py @@ -17,7 +17,7 @@ # along with SickRage. If not, see . import re -import threading +import time import sickbeard from lib import adba @@ -26,6 +26,9 @@ from sickbeard import name_cache from sickbeard import logger from sickbeard import db +MAX_XEM_AGE_SECS = 86400 # 1 day +MAX_ANIDB_AGE_SECS = 86400 # 1 day + exceptionCache = {} exceptionSeasonCache = {} exceptionIndexerCache = {} @@ -228,35 +231,71 @@ def update_scene_exceptions(indexer_id, scene_exceptions): name_cache.clearCache() def _retrieve_anidb_mainnames(): + global MAX_ANIDB_AGE_SECS + + success = False + anidb_mainNames = {} - for show in sickbeard.showList: - if show.is_anime and show.indexer == 1: - try: - anime = adba.Anime(None, name=show.name, tvdbid=show.indexerid, autoCorrectName=True) - except: - continue - else: - if anime.name and anime.name != show.name: - anidb_mainNames[show.indexerid] = [{anime.name: -1}] + + cacheDB = db.DBConnection('cache.db') + + rows = cacheDB.select("SELECT last_refreshed FROM scene_exceptions_refresh WHERE list = ?", + ['anidb']) + if rows: + refresh = time.time() > (int(rows[0]['last_refreshed']) + MAX_ANIDB_AGE_SECS) + else: + refresh = True + + if refresh: + for show in sickbeard.showList: + if show.is_anime and show.indexer == 1: + try: + anime = adba.Anime(None, name=show.name, tvdbid=show.indexerid, autoCorrectName=True) + except: + continue + else: + success = True + + if anime.name and anime.name != show.name: + anidb_mainNames[show.indexerid] = [{anime.name: -1}] + + if success: + cacheDB.action("INSERT OR REPLACE INTO scene_exceptions_refresh (list, last_refreshed) VALUES (?,?)", + ['anidb', time.time()]) return anidb_mainNames def _xem_excpetions_fetcher(indexer): + global MAX_XEM_AGE_SECS + exception_dict = {} - url = "http://thexem.de/map/allNames?origin=%s&seasonNumbers=1" % sickbeard.indexerApi(indexer).config['xem_origin'] + cacheDB = db.DBConnection('cache.db') - url_data = helpers.getURL(url, json=True) - if url_data is None: - logger.log(u"Check scene exceptions update failed. Unable to get URL: " + url, logger.ERROR) - return exception_dict + rows = cacheDB.select("SELECT last_refreshed FROM scene_exceptions_refresh WHERE list = ?", + ['xem']) + if rows: + refresh = time.time() > (int(rows[0]['last_refreshed']) + MAX_XEM_AGE_SECS) + else: + refresh = True - if url_data['result'] == 'failure': - return exception_dict + if refresh: + url = "http://thexem.de/map/allNames?origin=%s&seasonNumbers=1" % sickbeard.indexerApi(indexer).config['xem_origin'] - for indexerid, names in url_data['data'].items(): - exception_dict[int(indexerid)] = names + url_data = helpers.getURL(url, json=True) + if url_data is None: + logger.log(u"Check scene exceptions update failed. Unable to get URL: " + url, logger.ERROR) + return exception_dict + + if url_data['result'] == 'failure': + return exception_dict + + cacheDB.action("INSERT OR REPLACE INTO scene_exceptions_refresh (list, last_refreshed) VALUES (?,?)", + ['xem', time.time()]) + + for indexerid, names in url_data['data'].items(): + exception_dict[int(indexerid)] = names return exception_dict diff --git a/sickbeard/scene_numbering.py b/sickbeard/scene_numbering.py index 4cc05c48..648adf9f 100644 --- a/sickbeard/scene_numbering.py +++ b/sickbeard/scene_numbering.py @@ -41,7 +41,6 @@ from lib import requests MAX_XEM_AGE_SECS = 86400 # 1 day - def get_scene_numbering(indexer_id, indexer, season, episode, fallback_to_xem=True): """ Returns a tuple, (season, episode), with the scene numbering (if there is one), From 984768278112d5a68f0ac465bf243e1aeaef79ea Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 23:54:57 -0700 Subject: [PATCH 62/82] Changed theTVDB indexer api keys to SickRage's, another nice catch there zoggy! --- sickbeard/indexers/indexer_config.py | 2 +- sickbeard/webserve.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sickbeard/indexers/indexer_config.py b/sickbeard/indexers/indexer_config.py index 1330a1e8..af94eb75 100644 --- a/sickbeard/indexers/indexer_config.py +++ b/sickbeard/indexers/indexer_config.py @@ -21,7 +21,7 @@ indexerConfig[INDEXER_TVDB] = { 'id': INDEXER_TVDB, 'name': 'theTVDB', 'module': Tvdb, - 'api_params': {'apikey': '9DAF49C96CBF8DAC', + 'api_params': {'apikey': 'F9C450E78D99172E', 'language': 'en', 'useZip': True }, diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 839f6f5f..803dd427 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3325,7 +3325,7 @@ class Home: if do_update_scene_numbering or do_update_scene_absolute_numbering: try: - sickbeard.scene_numbering.xem_refresh(showObj.indexerid, showObj.indexer, force=True) # @UndefinedVariable + sickbeard.scene_numbering.xem_refresh(showObj.indexerid, showObj.indexer) # @UndefinedVariable time.sleep(cpu_presets[sickbeard.CPU_PRESET]) except exceptions.CantUpdateException, e: errors.append("Unable to force an update on scene numbering of the show.") From 0e989fe90fa7d00863e84297eed72da14ea140e0 Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Mon, 2 Jun 2014 00:05:07 +0200 Subject: [PATCH 63/82] Limiting search to English-translated only (for now) --- sickbeard/providers/nyaatorrents.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sickbeard/providers/nyaatorrents.py b/sickbeard/providers/nyaatorrents.py index 793ead15..6ac9e208 100644 --- a/sickbeard/providers/nyaatorrents.py +++ b/sickbeard/providers/nyaatorrents.py @@ -71,6 +71,7 @@ class NyaaProvider(generic.TorrentProvider): return [] params = {"term": search_string.encode('utf-8'), + "cats": '1_37', #Limit to English-translated Anime (for now) "sort": '2', #Sort Descending By Seeders } @@ -152,4 +153,4 @@ class NyaaCache(tvcache.TVCache): return self._addCacheEntry(title, url) -provider = NyaaProvider() \ No newline at end of file +provider = NyaaProvider() From 7047cf020ef9ce8971852d7936428127a88d5922 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sun, 1 Jun 2014 16:18:53 -0700 Subject: [PATCH 64/82] Fixed naming issues for episode naming patterns. Name parser now score's all its possible matches and stores them to a list then once finished performing its matches it'll pick the highest scoring match and return it. --- sickbeard/name_parser/parser.py | 50 ++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 01e6ac9d..aa596cc2 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -113,6 +113,7 @@ class NameParser(object): if not name: return + matches = [] result = None for (cur_regex_type, cur_regex_name), cur_regex in self.compiled_regexes.items(): match = cur_regex.match(name) @@ -122,50 +123,62 @@ class NameParser(object): result = ParseResult(name) result.which_regex = [cur_regex_name] + result.score = 0 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 not result.series_name: + continue + + result.series_name = self.clean_series_name(result.series_name) + result.score += 1 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.score += 1 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) + result.score += 1 else: result.episode_numbers = [ep_num] + result.score += 1 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) + result.score += 1 else: result.ab_episode_numbers = [ep_ab_num] + result.score += 1 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')) + result.score += 1 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) + result.score += 1 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() + result.score += 1 except: continue @@ -177,6 +190,7 @@ class NameParser(object): try: dtStr = '%s-%s-%s' % (year, month, day) result.air_date = datetime.datetime.strptime(dtStr, "%Y-%m-%d").date() + result.score += 1 except: continue @@ -187,28 +201,36 @@ class NameParser(object): 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 + result.score += 1 if 'release_group' in named_groups: result.release_group = match.group('release_group') + result.score += 1 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: + if not cur_show: + matches.append(result) continue + if self.showObj and 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) + continue + + result.show = cur_show + if self.convert: result = result.convert() + result.score += 1 + matches.append(result) + + if len(matches): + result = sorted(matches, key=lambda k: k.score, reverse=True)[0] + return result def _combine_results(self, first, second, attr): From 2da18e65ca6faed2ded235922a81a60e8f6d516d Mon Sep 17 00:00:00 2001 From: echel0n Date: Sun, 1 Jun 2014 16:36:21 -0700 Subject: [PATCH 65/82] Change code for returning highest scoring match to use generator to avoid overhead of sorting the list --- sickbeard/name_parser/parser.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index aa596cc2..6c2e42be 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -28,6 +28,7 @@ from dateutil import parser nameparser_lock = threading.Lock() + class NameParser(object): ALL_REGEX = 0 NORMAL_REGEX = 1 @@ -107,7 +108,7 @@ class NameParser(object): except re.error, errormsg: logger.log(u"WARNING: Invalid episode_pattern, %s. %s" % (errormsg, cur_pattern)) else: - self.compiled_regexes[(regex_type,cur_pattern_name)] = cur_regex + self.compiled_regexes[(regex_type, cur_pattern_name)] = cur_regex def _parse_string(self, name): if not name: @@ -155,7 +156,8 @@ class NameParser(object): 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) + result.ab_episode_numbers = range(ep_ab_num, + self._convert_number(match.group('extra_ab_ep_num')) + 1) result.score += 1 else: result.ab_episode_numbers = [ep_ab_num] @@ -229,7 +231,7 @@ class NameParser(object): matches.append(result) if len(matches): - result = sorted(matches, key=lambda k: k.score, reverse=True)[0] + result = max(matches, key=lambda x: x.score) return result @@ -571,7 +573,9 @@ 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" \ No newline at end of file From 44d45ca760acf9305db15ad82e62f0d7823eaa53 Mon Sep 17 00:00:00 2001 From: Nils Vogels Date: Mon, 2 Jun 2014 01:39:55 +0200 Subject: [PATCH 66/82] Fixing UnboundLocalError when attempting to process nonexisting dir --- sickbeard/processTV.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sickbeard/processTV.py b/sickbeard/processTV.py index b722109f..ba4ccd09 100644 --- a/sickbeard/processTV.py +++ b/sickbeard/processTV.py @@ -397,6 +397,7 @@ def delete_dir(processPath): def get_path_dir_files(dirName, nzbName, type): + path = "" if dirName == sickbeard.TV_DOWNLOAD_DIR and not nzbName or type == "manual": #Scheduled Post Processing Active #Get at first all the subdir in the dirName From 41a9e08155cc561803cddbb95fbfb616525619af Mon Sep 17 00:00:00 2001 From: echel0n Date: Sun, 1 Jun 2014 18:16:25 -0700 Subject: [PATCH 67/82] Added thread locking for sorting queue's --- sickbeard/generic_queue.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sickbeard/generic_queue.py b/sickbeard/generic_queue.py index f426a222..8be859cf 100644 --- a/sickbeard/generic_queue.py +++ b/sickbeard/generic_queue.py @@ -41,6 +41,8 @@ class GenericQueue(object): self.currentItem = None + self.lock = threading.Lock() + def pause(self): logger.log(u"Pausing queue") self.min_priority = 999999999999 @@ -83,7 +85,8 @@ class GenericQueue(object): else: return y.priority-x.priority - self.queue.sort(cmp=sorter) + with self.lock: + self.queue.sort(cmp=sorter) queueItem = self.queue[0] From 2ab436b764e1c9a4f65ccf16d204d98462289276 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sun, 1 Jun 2014 20:43:37 -0700 Subject: [PATCH 68/82] Fix for saving default options when adding shows. Fix for default provider not being passed in properly. --- .../default/inc_addShowOptions.tmpl | 8 ++++++ gui/slick/interfaces/default/inc_top.tmpl | 2 +- gui/slick/js/addShowOptions.js | 26 ++++++++++++------- sickbeard/__init__.py | 5 +++- sickbeard/show_queue.py | 12 ++++----- sickbeard/webserve.py | 21 ++++++++++----- 6 files changed, 51 insertions(+), 23 deletions(-) diff --git a/gui/slick/interfaces/default/inc_addShowOptions.tmpl b/gui/slick/interfaces/default/inc_addShowOptions.tmpl index 96c28e96..76013a1d 100644 --- a/gui/slick/interfaces/default/inc_addShowOptions.tmpl +++ b/gui/slick/interfaces/default/inc_addShowOptions.tmpl @@ -41,6 +41,14 @@

+
+ + +
+ #set $qualities = $Quality.splitQuality($sickbeard.QUALITY_DEFAULT) #set global $anyQualities = $qualities[0] #set global $bestQualities = $qualities[1] diff --git a/gui/slick/interfaces/default/inc_top.tmpl b/gui/slick/interfaces/default/inc_top.tmpl index b7bc1c18..25b423e3 100644 --- a/gui/slick/interfaces/default/inc_top.tmpl +++ b/gui/slick/interfaces/default/inc_top.tmpl @@ -278,7 +278,7 @@ a > i.icon-question-sign { background-image: url("$sbRoot/images/glyphicons-half
  • Anime
  • - +
    diff --git a/gui/slick/js/addShowOptions.js b/gui/slick/js/addShowOptions.js index ae5b5d88..a6286c5b 100644 --- a/gui/slick/js/addShowOptions.js +++ b/gui/slick/js/addShowOptions.js @@ -3,15 +3,23 @@ $(document).ready(function () { $('#saveDefaultsButton').click(function () { var anyQualArray = []; var bestQualArray = []; - $('#anyQualities option:selected').each(function (i, d) {anyQualArray.push($(d).val()); }); - $('#bestQualities option:selected').each(function (i, d) {bestQualArray.push($(d).val()); }); + $('#anyQualities option:selected').each(function (i, d) { + anyQualArray.push($(d).val()); + }); + $('#bestQualities option:selected').each(function (i, d) { + bestQualArray.push($(d).val()); + }); + + $.get(sbRoot + '/config/general/saveAddShowDefaults', { + defaultStatus: $('#statusSelect').val(), + anyQualities: anyQualArray.join(','), + bestQualities: bestQualArray.join(','), + defaultFlattenFolders: $('#flatten_folders').prop('checked'), + subtitles: $('#subtitles').prop('checked'), + anime: $('#anime').prop('checked'), + scene: $('#scene').prop('checked') + }); - $.get(sbRoot + '/config/general/saveAddShowDefaults', {defaultStatus: $('#statusSelect').val(), - anyQualities: anyQualArray.join(','), - bestQualities: bestQualArray.join(','), - defaultFlattenFolders: $('#flatten_folders').prop('checked'), - subtitles: $('#subtitles').prop('checked') }); - $(this).attr('disabled', true); $.pnotify({ pnotify_title: 'Saved Defaults', @@ -20,7 +28,7 @@ $(document).ready(function () { }); }); - $('#statusSelect, #qualityPreset, #flatten_folders, #anyQualities, #bestQualities, #subtitles').change(function () { + $('#statusSelect, #qualityPreset, #flatten_folders, #anyQualities, #bestQualities, #subtitles, #scene, #anime').change(function () { $('#saveDefaultsButton').attr('disabled', false); }); diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index d0e05570..ea5b7133 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -161,6 +161,7 @@ FLATTEN_FOLDERS_DEFAULT = None SUBTITLES_DEFAULT = None INDEXER_DEFAULT = None INDEXER_TIMEOUT = None +SCENE_DEFAULT = None ANIME_DEFAULT = None PROVIDER_ORDER = [] @@ -476,7 +477,7 @@ def initialize(consoleLogging=True): USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, LOCALHOST_IP, TMDB_API_KEY, DEBUG, PROXY_SETTING, \ AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \ ANIME_DEFAULT, NAMING_ANIME, ANIMESUPPORT, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \ - ANIME_SPLIT_HOME, maintenanceScheduler + ANIME_SPLIT_HOME, maintenanceScheduler, SCENE_DEFAULT if __INITIALIZED__: return False @@ -589,6 +590,7 @@ def initialize(consoleLogging=True): INDEXER_DEFAULT = check_setting_int(CFG, 'General', 'indexer_default', 0) INDEXER_TIMEOUT = check_setting_int(CFG, 'General', 'indexer_timeout', 10) ANIME_DEFAULT = bool(check_setting_int(CFG, 'General', 'anime_default', 0)) + SCENE_DEFAULT = bool(check_setting_int(CFG, 'General', 'scene_default', 0)) PROVIDER_ORDER = check_setting_str(CFG, 'General', 'provider_order', '').split() @@ -1410,6 +1412,7 @@ def save_config(): new_config['General']['indexer_default'] = int(INDEXER_DEFAULT) new_config['General']['indexer_timeout'] = int(INDEXER_TIMEOUT) new_config['General']['anime_default'] = int(ANIME_DEFAULT) + new_config['General']['scene_default'] = int(SCENE_DEFAULT) new_config['General']['provider_order'] = ' '.join(PROVIDER_ORDER) new_config['General']['version_notify'] = int(VERSION_NOTIFY) new_config['General']['auto_update'] = int(AUTO_UPDATE) diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py index 9d4f44f6..46d9d32f 100644 --- a/sickbeard/show_queue.py +++ b/sickbeard/show_queue.py @@ -132,9 +132,9 @@ class ShowQueue(generic_queue.GenericQueue): return queueItemObj def addShow(self, indexer, indexer_id, showDir, default_status=None, quality=None, flatten_folders=None, - subtitles=None, lang="en", anime=None): + subtitles=None, lang="en", anime=None, scene=None): queueItemObj = QueueItemAdd(indexer, indexer_id, showDir, default_status, quality, flatten_folders, lang, - subtitles, anime) + subtitles, anime, scene) self.add_item(queueItemObj) @@ -189,7 +189,7 @@ class ShowQueueItem(generic_queue.QueueItem): class QueueItemAdd(ShowQueueItem): - def __init__(self, indexer, indexer_id, showDir, default_status, quality, flatten_folders, lang, subtitles, anime): + def __init__(self, indexer, indexer_id, showDir, default_status, quality, flatten_folders, lang, subtitles, anime, scene): self.indexer = indexer self.indexer_id = indexer_id @@ -200,6 +200,7 @@ class QueueItemAdd(ShowQueueItem): self.lang = lang self.subtitles = subtitles self.anime = anime + self.scene = scene self.show = None @@ -285,6 +286,7 @@ class QueueItemAdd(ShowQueueItem): self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.flatten_folders = self.flatten_folders if self.flatten_folders != None else sickbeard.FLATTEN_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime != None else sickbeard.ANIME_DEFAULT + self.show.scene = self.scene if self.scene != None else sickbeard.SCENE_DEFAULT self.show.paused = False # be smartish about this @@ -294,8 +296,6 @@ class QueueItemAdd(ShowQueueItem): self.show.air_by_date = 0 if self.show.classification and "sports" in self.show.classification.lower(): self.show.sports = 1 - #if self.show.genre and "animation" in self.show.genre.lower(): - # self.show.anime = 1 except sickbeard.indexer_exception, e: logger.log( @@ -385,7 +385,7 @@ class QueueItemAdd(ShowQueueItem): sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer, force=True) # check if show has XEM mapping so we can determin if searches should go by scene numbering or indexer numbering. - if sickbeard.scene_numbering.get_xem_numbering_for_show(self.show.indexerid, self.show.indexer): + if not self.scene and sickbeard.scene_numbering.get_xem_numbering_for_show(self.show.indexerid, self.show.indexer): self.show.scene = 1 self.finish() diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 803dd427..66315646 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -990,7 +990,8 @@ class ConfigGeneral: sickbeard.ROOT_DIRS = rootDirString @cherrypy.expose - def saveAddShowDefaults(self, defaultStatus, anyQualities, bestQualities, defaultFlattenFolders, subtitles=False, anime=False): + def saveAddShowDefaults(self, defaultStatus, anyQualities, bestQualities, defaultFlattenFolders, subtitles=False, + anime=False, scene=False): if anyQualities: anyQualities = anyQualities.split(',') @@ -1010,7 +1011,8 @@ class ConfigGeneral: sickbeard.FLATTEN_FOLDERS_DEFAULT = config.checkbox_to_value(defaultFlattenFolders) sickbeard.SUBTITLES_DEFAULT = config.checkbox_to_value(subtitles) - sickbeard.ANIME_DEFAULT = int(anime) + sickbeard.ANIME_DEFAULT = config.checkbox_to_value(anime) + sickbeard.SCENE_DEFAULT = config.checkbox_to_value(scene) sickbeard.save_config() @@ -2336,7 +2338,8 @@ class NewHomeAddShows: @cherrypy.expose def addNewShow(self, whichSeries=None, indexerLang="en", rootDir=None, defaultStatus=None, anyQualities=None, bestQualities=None, flatten_folders=None, subtitles=None, - fullShowPath=None, other_shows=None, skipShow=None, providedIndexer=None, anime=None): + fullShowPath=None, other_shows=None, skipShow=None, providedIndexer=None, anime=None, + scene=None): """ Receive tvdb id, dir, and other options and create a show from them. If extra show dirs are provided then it forwards back to newShow, if not it goes to /home. @@ -2381,6 +2384,10 @@ class NewHomeAddShows: indexer_id = int(series_pieces[3]) show_name = series_pieces[4] else: + # if no indexer was provided use the default indexer set in General settings + if not providedIndexer: + providedIndexer = sickbeard.INDEXER_DEFAULT + indexer = int(providedIndexer) indexer_id = int(whichSeries) show_name = os.path.basename(os.path.normpath(fullShowPath)) @@ -2410,11 +2417,11 @@ class NewHomeAddShows: helpers.chmodAsParent(show_dir) # prepare the inputs for passing along + scene = config.checkbox_to_value(scene) anime = config.checkbox_to_value(anime) flatten_folders = config.checkbox_to_value(flatten_folders) subtitles = config.checkbox_to_value(subtitles) - if not anyQualities: anyQualities = [] if not bestQualities: @@ -2427,7 +2434,7 @@ class NewHomeAddShows: # add the show sickbeard.showQueueScheduler.action.addShow(indexer, indexer_id, show_dir, int(defaultStatus), newQuality, - flatten_folders, subtitles, indexerLang, anime) # @UndefinedVariable + flatten_folders, subtitles, indexerLang, anime, scene) # @UndefinedVariable ui.notifications.message('Show added', 'Adding the specified show into ' + show_dir) return finishAddShow() @@ -2498,7 +2505,9 @@ class NewHomeAddShows: sickbeard.STATUS_DEFAULT, sickbeard.QUALITY_DEFAULT, sickbeard.FLATTEN_FOLDERS_DEFAULT, - sickbeard.SUBTITLES_DEFAULT) + sickbeard.SUBTITLES_DEFAULT, + sickbeard.ANIME_DEFAULT, + sickbeard.SCENE_DEFAULT) num_added += 1 if num_added: From e62d5ad50c8592bf9e1daadfd4b03e754f23761e Mon Sep 17 00:00:00 2001 From: echel0n Date: Sun, 1 Jun 2014 22:21:09 -0700 Subject: [PATCH 69/82] Fix for nonetype being returned when trying to load data from TVDB Api for actors. --- lib/tvdb_api/tvdb_api.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py index d9f6f550..3ac42736 100644 --- a/lib/tvdb_api/tvdb_api.py +++ b/lib/tvdb_api/tvdb_api.py @@ -781,18 +781,19 @@ class Tvdb: actorsEt = self._getetsrc(self.config['url_actorsInfo'] % (sid)) cur_actors = Actors() - for curActorItem in actorsEt["actor"]: - curActor = Actor() - for k, v in curActorItem.items(): - k = k.lower() - if v is not None: - if k == "image": - v = self.config['url_artworkPrefix'] % (v) - else: - v = self._cleanData(v) - curActor[k] = v - cur_actors.append(curActor) - self._setShowData(sid, '_actors', cur_actors) + if actorsEt: + for curActorItem in actorsEt["actor"]: + curActor = Actor() + for k, v in curActorItem.items(): + k = k.lower() + if v is not None: + if k == "image": + v = self.config['url_artworkPrefix'] % (v) + else: + v = self._cleanData(v) + curActor[k] = v + cur_actors.append(curActor) + self._setShowData(sid, '_actors', cur_actors) def _getShowData(self, sid, language, seriesSearch=False): """Takes a series ID, gets the epInfo URL and parses the TVDB From 2e387b1ce8b79faebd3e8e9da421882b8b561db3 Mon Sep 17 00:00:00 2001 From: JackDandy Date: Tue, 3 Jun 2014 18:43:37 +0100 Subject: [PATCH 70/82] Expose "Date Style"... "Use System Default" only when FuzzyMoment is off. If the Date Style "Use System Default" is selected and FuzzyMoments is clicked on, then an appropriate Date Style is chosen from explicit defaults. This change prevents issues where moments() cannot interpret or guess locale date formats. --- .../interfaces/default/config_general.tmpl | 39 ++++++++++++------- gui/slick/js/config.js | 33 +++++++++++++++- gui/slick/js/fuzzyMoment.js | 4 +- sickbeard/webserve.py | 3 +- 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/gui/slick/interfaces/default/config_general.tmpl b/gui/slick/interfaces/default/config_general.tmpl index a96c2367..59c3359c 100644 --- a/gui/slick/interfaces/default/config_general.tmpl +++ b/gui/slick/interfaces/default/config_general.tmpl @@ -370,31 +370,42 @@
    - +
    - -
    - - +
    +
    + + +
    diff --git a/gui/slick/js/config.js b/gui/slick/js/config.js index 709d3ac7..e9fafc52 100644 --- a/gui/slick/js/config.js +++ b/gui/slick/js/config.js @@ -9,7 +9,38 @@ $(document).ready(function(){ $('#content_'+$(this).attr('id')).fadeIn("fast", "linear"); else $('#content_'+$(this).attr('id')).fadeOut("fast", "linear"); - }); + }); + + $(".viewIf").click(function() { + if ($(this).prop('checked')) { + $('.hide_if_'+$(this).attr('id')).css('display','none'); + $('.show_if_'+$(this).attr('id')).fadeIn("fast", "linear"); + } else { + $('.show_if_'+$(this).attr('id')).css('display','none'); + $('.hide_if_'+$(this).attr('id')).fadeIn("fast", "linear"); + } + }); + + $(".datePresets").click(function() { + var def = $('#date_presets').val() + if ($(this).prop('checked') && '%x' == def) { + def = '%a, %b %d, %Y' + $('#date_use_system_default').html('1') + } else if (!$(this).prop('checked') && '1' == $('#date_use_system_default').html()) + def = '%x' + + $('#date_presets').attr('name', 'date_preset_old') + $('#date_presets').attr('id', 'date_presets_old') + + $('#date_presets_na').attr('name', 'date_preset') + $('#date_presets_na').attr('id', 'date_presets') + + $('#date_presets_old').attr('name', 'date_preset_na') + $('#date_presets_old').attr('id', 'date_presets_na') + + if (def) + $('#date_presets').val(def) + }); // bind 'myForm' and provide a simple callback function $('#configForm').ajaxForm({ diff --git a/gui/slick/js/fuzzyMoment.js b/gui/slick/js/fuzzyMoment.js index f1812dc6..0b24597b 100644 --- a/gui/slick/js/fuzzyMoment.js +++ b/gui/slick/js/fuzzyMoment.js @@ -108,8 +108,8 @@ airdate = airdatetime.clone().hour(0).minute(0).second(0).millisecond(0), today = moment({}), day = Math.abs(airdate.diff(today, 'days')), - week = airdate.diff(today, 'week'), isPast = week < 0, week = Math.abs(week), - titleThis = false, qTipTime = false + week = Math.abs(weekdiff = airdate.diff(today, 'week')), isPast = weekdiff < 0, + titleThis = false, qTipTime = false, result = (0 == week ? airdatetime.calendar() : ''); if (/\bOn\b/i.test(result)) { diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 66315646..fe356eff 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -1047,7 +1047,7 @@ class ConfigGeneral: web_password=None, version_notify=None, enable_https=None, https_cert=None, https_key=None, handle_reverse_proxy=None, sort_article=None, auto_update=None, proxy_setting=None, anon_redirect=None, git_path=None, calendar_unprotected=None, - fuzzy_dating=None, trim_zero=None, date_preset=None, time_preset=None, + fuzzy_dating=None, trim_zero=None, date_preset=None, date_preset_na=None, time_preset=None, indexer_timeout=None): results = [] @@ -1081,6 +1081,7 @@ class ConfigGeneral: if date_preset: sickbeard.DATE_PRESET = date_preset + discarded_na_data = date_preset_na if indexer_default: sickbeard.INDEXER_DEFAULT = config.to_int(indexer_default) From 211334574fd8c0d3817d191ca6ac3a2ccde1ce90 Mon Sep 17 00:00:00 2001 From: JackDandy Date: Wed, 4 Jun 2014 00:40:05 +0100 Subject: [PATCH 71/82] Change align Search column, move Filename column data to hover over Episode to gain screen estate, span the Airdate so qTip is closer. --- gui/slick/css/default.css | 4 ++ gui/slick/interfaces/default/displayShow.tmpl | 41 +++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/gui/slick/css/default.css b/gui/slick/css/default.css index dd7990b7..6b9056a1 100644 --- a/gui/slick/css/default.css +++ b/gui/slick/css/default.css @@ -472,6 +472,10 @@ text-align: center; .sickbeardTable td.search img { padding-right: 2px; } +.sickbeardTable td.search { + text-align: center; + width:5% +} .sickbeardTable td small { font-size: 11px; diff --git a/gui/slick/interfaces/default/displayShow.tmpl b/gui/slick/interfaces/default/displayShow.tmpl index f2a0381c..103b07b9 100644 --- a/gui/slick/interfaces/default/displayShow.tmpl +++ b/gui/slick/interfaces/default/displayShow.tmpl @@ -29,7 +29,6 @@ @@ -302,7 +311,7 @@

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

    - 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 + NFOTBNEpisode#if $show.is_anime then "Absolute" else ""# #if $scene then "Scene #" else ""# #if $scene_anime then "Scene Absolute" else ""#NameAirdate#if $sickbeard.USE_SUBTITLES and $show.subtitles then "Subtitles" else ""#StatusSearch #set $curSeason = int($epResult["season"]) #end if @@ -316,7 +325,16 @@ \"Y" \"Y" - $epResult["episode"] + +#if $epLoc and $show._location and $epLoc.lower().startswith($show._location.lower()): + #set $epLoc = os.path.basename($epLoc[len($show._location)+1:]) +#elif $epLoc and (not $epLoc.lower().startswith($show._location.lower()) or not $show._location): + #set $epLoc = os.path.basename($epLoc) +#end if +#if $epLoc != "" and $epLoc != None: + $epResult["episode"] +#else + $epResult["episode"]#end if# #if $show.is_anime: $epResult["absolute_number"] #end if @@ -354,23 +372,10 @@ #if $epResult["description"] != "" and $epResult["description"] != None: " /> - #end if + #end if $epResult["name"] -
    #if int($epResult["airdate"]) == 1 then "never" else $sbdatetime.sbdatetime.sbfdate($network_timezones.parse_date_time($epResult["airdate"],$show.airs,$show.network))#
    - -#if $epLoc and $show._location and $epLoc.lower().startswith($show._location.lower()): - #set $epLoc = os.path.basename($epLoc[len($show._location)+1:]) -#elif $epLoc and (not $epLoc.lower().startswith($show._location.lower()) or not $show._location): - #set $epLoc = os.path.basename($epLoc) -#end if -#if $epLoc != "" and $epLoc != None: -[details] -#else -$epLoc -#end if - - + #if int($epResult["airdate"]) == 1 then "never" else $sbdatetime.sbdatetime.sbfdate($network_timezones.parse_date_time($epResult["airdate"],$show.airs,$show.network))# #if $sickbeard.USE_SUBTITLES and $show.subtitles: #if $epResult["subtitles"]: From 011cdb40a5c6597dc50a9189acb7b06ceb2ac160 Mon Sep 17 00:00:00 2001 From: echel0n Date: Tue, 3 Jun 2014 20:14:46 -0700 Subject: [PATCH 72/82] Switched from PayPal to Google Wallet for accepting site support membership upgrades. --- gui/slick/images/btn-google.jpg | Bin 0 -> 1526 bytes gui/slick/images/paypal/btn_donateCC_LG.gif | Bin 2332 -> 0 bytes gui/slick/images/paypal/btn_donate_LG.gif | Bin 1714 -> 0 bytes gui/slick/interfaces/default/inc_top.tmpl | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 gui/slick/images/btn-google.jpg delete mode 100644 gui/slick/images/paypal/btn_donateCC_LG.gif delete mode 100644 gui/slick/images/paypal/btn_donate_LG.gif diff --git a/gui/slick/images/btn-google.jpg b/gui/slick/images/btn-google.jpg new file mode 100644 index 0000000000000000000000000000000000000000..67b8c319a2b1c6b1b95380f0b9d49e16e04e6b2a GIT binary patch literal 1526 zcmb7=c{J2}7>B<fFKCiND7F1 z!A^ieAdyG}O43j$6dEIg#Ym8omd44za(Fx}2g3wKRV4yZMFED_sIO5`QzMhf1SJhk z4U(oRiA?$-fh4OKG)5MSl_e2jBI$o4ehgqNPzC`ANCQa05CVq8wLldBDFi@3;3pU) z8Vey%Qj*k29zY0$6cT~J;r<w}9ey=4s|34#tD(it z(-EbT&9xAKP?9J71SxT%G2n+*2L_N75(Qz9i2rhl79e4Ll)Aa2J0494koZc73hkem zPiDkDKt^((6pVlY9SrIMnfYmJGAE`*ZQ_lnuxo$rLCqrV1!_g~u@>&jfG$gh`%8uL zoL^0*4y>J4OrhB1t5|V_?seP*ySmW08r5?X3;Cy8veNg>myaC&__EXQfSjN->Dt@I z4ZGteM7TEgsf0{>!>uf4&ynK6dG6f5{ln{E&kmz|-+lsIL_`?hxwQs!`rO8FLd7-yGxog5IG6g7)TcEFY|-26gN8#;tkobVirzoc)WLC+}>R(%P>B%7ROm73@ho*X5yv8-sthx%|KKI?M~;1aATW*`__C)oZt;Vl z^|5J*+tb4#mY)y1IWEtO&{UZl{`&S&9^G!GFgAO$qea$Mk#kDaO~vWcG3rbDzR75E0zb6%d4LX$ zUu}n>tnB6ly*+d)+@tatYbpAMKbyjxKDjTD_hc`iCGgDF#zHPVT7qVS!L0agLZ6+N zLc9zy^K}uzg52Jdo#nut0JTSccAXEDGx>Y@zp$GZD-BC7>b}&*4L3O%! z#)|9)T7qe53q=h&PJI!5m`%;j)TH{Tx`o;J!bR*0*&$lh;1gZe{9DyQN_qx9 zR%i6RsFyLTeRD4|W{=a#zMu6+d@{4{O=*oc^&NXf7x;v3pN$F|zV+SGrE1@7d^0Ns z?~uDfI79foLNI}8aiBCl5hz~yRPRw->seHKRgIcAZS;X5FiV>8{EN8kfBt3^u{$fz zo~jBckKeTE;O`aLU06I_&|quwvOm>=@JyQ6&DW*t>~c*x-Zxpa<$6RKoS5M^SwRP0 sV$jfE`M$_2`#z7`#n{G8?${9M>d1_~G}1tN-O!N}?b2><-Y)L`2N~au_5c6? literal 0 HcmV?d00001 diff --git a/gui/slick/images/paypal/btn_donateCC_LG.gif b/gui/slick/images/paypal/btn_donateCC_LG.gif deleted file mode 100644 index 2d1ec159beb1196e6ef23dccbc550daa5287288f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2332 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 DPfQA9 diff --git a/gui/slick/interfaces/default/inc_top.tmpl b/gui/slick/interfaces/default/inc_top.tmpl index 25b423e3..90568266 100644 --- a/gui/slick/interfaces/default/inc_top.tmpl +++ b/gui/slick/interfaces/default/inc_top.tmpl @@ -278,7 +278,7 @@ a > i.icon-question-sign { background-image: url("$sbRoot/images/glyphicons-half
  • Anime
  • - +
    From 2204a106bc67024d93f07cb2a0628e76e5e77de3 Mon Sep 17 00:00:00 2001 From: echel0n Date: Tue, 3 Jun 2014 20:25:37 -0700 Subject: [PATCH 73/82] Updated MOTD to comply with AUP policies. --- readme-FailedDownloads.md | 34 ---------------------------------- readme.md | 27 ++++++++++----------------- 2 files changed, 10 insertions(+), 51 deletions(-) delete mode 100644 readme-FailedDownloads.md diff --git a/readme-FailedDownloads.md b/readme-FailedDownloads.md deleted file mode 100644 index eb12e462..00000000 --- a/readme-FailedDownloads.md +++ /dev/null @@ -1,34 +0,0 @@ -SickRage - Failed Downloads -===== - -*SickRage Failed Downloads is a fork from SickRage - ThePirateBay.* - -Features added: - -* Failed Download Handling (Tolstyak) -* User Interface Toggle for Failed Download Handling -* Treat directories where no video files were found as if they were failed downloads - -SickRage - Failed Downloads is almost a direct copy of the following project: - -* [SickRage - Tolstyak's branch][tolstyak] - -These features can be enabled in the Post Processing Configuration menu. It must be configured as specified below. - -## The original readme from Tolstyak is: - -The primary new feature of my branch is the handling of failed downloads. -If you're using SABnzbd, set the following options under Switches: - -* Disable Abort jobs that cannot be completed -* Disable Post-Process Only Verified Jobs - -And under Special: - -* Enable empty_postproc - -## Bugs - -Report bugs in github - -[tolstyak]: https://github.com/tolstyak/sick-beard diff --git a/readme.md b/readme.md index 3166d374..8248cea3 100644 --- a/readme.md +++ b/readme.md @@ -1,39 +1,32 @@ SickRage ===== +SickRage is a Video File Manager for TV Shows, It watches for new episodes of your favorite shows and when they are posted it does its magic. + *SickRage is currently in beta release stage. There may be severe bugs in it and at any given time it may not work at all.* There are currently a lot of changes that we're working on, which affect the very core of how SickRage works. We're doing this to lay the groundwork -for making SickRage seriously more awesome, scalable and resource-friendly than it already is. We know it will be a bumpy ride, but we also know -that SickRage deserves to grow from a USENET grabber into a media independant grabber of anything TV show related. And beyond. +for making SickRage seriously more awesome, scalable and resource-friendly than it already is. While we're doing this, please expect SickRage do strange things, or maybe even not work at all. In any case, we need your help. If you see SickRage behaving weird, check if someone has reported it, and if not, open a new issue. There is little to no use to report "software should be stable". We will focus on that later, not now. -SickRage is a PVR for torrent and newsgroup users. It watches for new episodes of your favorite shows and when they are posted it downloads them, sorts and renames them, and optionally generates metadata for them. It retrieves show information from theTVDB.com and TVRage.com. - !!! Please before using this with your existing database (sickbeard.db) please make a backup copy of it and delete any other database files such as cache.db and failed.db if present, we HIGHLY recommend starting out with no database files at all to make this a fresh start but the choice is at your own risk !!! FEATURES: -- automatically retrieves new episode torrent or nzb files -- can scan your existing library and then download any old seasons or episodes you're missing -- can watch for better versions and upgrade your existing episodes (to from TV DVD/BluRay for example) - XBMC library updates, poster/fanart downloads, and NFO/TBN generation - configurable episode renaming -- sends NZBs directly to SABnzbd, prioritizes and categorizes them properly - available for any platform, uses simple HTTP interface -- can notify XBMC, Growl, or Twitter when new episodes are downloaded +- can notify XBMC, Growl, or Twitter when new episodes are available - specials and double episode support - Automatic XEM Scene Numbering/Naming for seasons/episodes -- Failed handling now attempts to snatch a different release and excludes failed releases from future snatch attempts. -- Episode Status Manager now allows for mass failing seasons/episodes to force retrying to download new releases. +- Episode Status Manager now allows for mass failing seasons/episodes to force retrying. - DVD Order numbering for returning the results in DVD order instead of Air-By-Date order. -- Improved Failed handling code for both NZB and Torrent downloads. +- Improved Failed handling code for shows. - DupeKey/DupeScore for NZBGet 12+ - Searches both TheTVDB.com, TVRage.com and AniDB.net for shows, seasons, episodes -- Importing of existing video files now allows you to choose which indexer you wish to have SickBeard download its show info from. +- Importing of existing video files now allows you to choose which indexer you wish to have SickBeard search its show info from. - Your tvshow.nfo files are now tagged with a indexer key so that SickBeard can easily tell if the shows info comes from TheTVDB or TVRage. -- Failed download handling has been improved now for both NZB and Torrents. -- Sports shows are now able to be searched for and downloaded by both NZB and Torrent providers. +- Sports shows are now able to be searched for.. ## Dependencies @@ -41,8 +34,8 @@ To run SickRage from source you will need Python 2.6+ and Cheetah 2.1.0+. ## Forums -Any questions or setup info your looking for can be found at out forums http://www.sickrage.tv +Any questions or setup info your looking for can be found at out forums https://www.sickrage.tv
    -If you find a bug please report at our forums http://sickrage.tv/forums/forum/help-support/bug-issue-reports +If you find a bug please report at our forums https://sickrage.tv/forums/forum/help-support/bug-issue-reports
    Be sure to provide a sickrage log in debug mode where is the error evidence or it'll never get fixed. From 8ac0b799862ec323d96fd427434b8f01d4886f76 Mon Sep 17 00:00:00 2001 From: echel0n Date: Tue, 3 Jun 2014 21:14:38 -0700 Subject: [PATCH 74/82] Fixes originally aired dates and times issues. Please perform a mass update of all shows after updating to this new commit to have changes take affect. --- lib/tvdb_api/tvdb_api.py | 2 +- lib/tvrage_api/tvrage_api.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py index 3ac42736..5138c4d8 100644 --- a/lib/tvdb_api/tvdb_api.py +++ b/lib/tvdb_api/tvdb_api.py @@ -584,7 +584,7 @@ class Tvdb: if key == 'airs_time': value = parse(value).time() - value = value.strftime("%I:%M") + value = value.strftime("%I:%M %p") except: pass diff --git a/lib/tvrage_api/tvrage_api.py b/lib/tvrage_api/tvrage_api.py index 69031bd5..5b4f2b90 100644 --- a/lib/tvrage_api/tvrage_api.py +++ b/lib/tvrage_api/tvrage_api.py @@ -456,7 +456,7 @@ class TVRage: if key == 'airs_time': value = parse(value).time() - value = value.strftime("%I:%M") + value = value.strftime("%I:%M %p") except: pass From e7170328aacfcf710adedc1f04b8ad4c890d2d37 Mon Sep 17 00:00:00 2001 From: echel0n Date: Tue, 3 Jun 2014 22:20:54 -0700 Subject: [PATCH 75/82] Fix for Indexer API issues --- gui/slick/css/default.css | 2 +- gui/slick/interfaces/default/inc_top.tmpl | 2 +- lib/tvdb_api/tvdb_api.py | 6 +++--- lib/tvrage_api/tvrage_api.py | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gui/slick/css/default.css b/gui/slick/css/default.css index 6b9056a1..4b8a5b66 100644 --- a/gui/slick/css/default.css +++ b/gui/slick/css/default.css @@ -734,7 +734,7 @@ div#summary tr td { #donate a, #donate a:hover { border: 0 ; - padding: 4px 15px 4px; + padding: 8px 15px 8px; } #contentWrapper { diff --git a/gui/slick/interfaces/default/inc_top.tmpl b/gui/slick/interfaces/default/inc_top.tmpl index 90568266..083fd645 100644 --- a/gui/slick/interfaces/default/inc_top.tmpl +++ b/gui/slick/interfaces/default/inc_top.tmpl @@ -278,7 +278,7 @@ a > i.icon-question-sign { background-image: url("$sbRoot/images/glyphicons-half
  • Anime
  • - +

    *=e=K<2XCsd1yL%7Eh>RupUzq=y;) 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ʊ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), From 277d630a6fc0892f1e8ee4450cdb49dd69afef13 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sat, 31 May 2014 03:35:57 -0700 Subject: [PATCH 50/82] Fixed issues with scene converting --- gui/slick/interfaces/default/config_anime.tmpl | 5 ++--- sickbeard/failedProcessor.py | 4 ++-- sickbeard/postProcessor.py | 4 ++-- sickbeard/tvcache.py | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/gui/slick/interfaces/default/config_anime.tmpl b/gui/slick/interfaces/default/config_anime.tmpl index 166c1102..3b42550e 100644 --- a/gui/slick/interfaces/default/config_anime.tmpl +++ b/gui/slick/interfaces/default/config_anime.tmpl @@ -7,14 +7,13 @@ #set global $topmenu="config"# #include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_top.tmpl") + + #if $varExists('header')

    diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py index 5138c4d8..2895f030 100644 --- a/lib/tvdb_api/tvdb_api.py +++ b/lib/tvdb_api/tvdb_api.py @@ -582,9 +582,9 @@ class Tvdb: value = parse(value, fuzzy=True).date() value = value.strftime("%Y-%m-%d") - if key == 'airs_time': - value = parse(value).time() - value = value.strftime("%I:%M %p") + #if key == 'airs_time': + # value = parse(value).time() + # value = value.strftime("%I:%M %p") except: pass diff --git a/lib/tvrage_api/tvrage_api.py b/lib/tvrage_api/tvrage_api.py index 5b4f2b90..87f5f187 100644 --- a/lib/tvrage_api/tvrage_api.py +++ b/lib/tvrage_api/tvrage_api.py @@ -454,9 +454,9 @@ class TVRage: value = parse(value, fuzzy=True).date() value = value.strftime("%Y-%m-%d") - if key == 'airs_time': - value = parse(value).time() - value = value.strftime("%I:%M %p") + #if key == 'airs_time': + # value = parse(value).time() + # value = value.strftime("%I:%M %p") except: pass From 37fceb2704629c5c6355d0d50a53414bd57c2613 Mon Sep 17 00:00:00 2001 From: echel0n Date: Tue, 3 Jun 2014 22:30:54 -0700 Subject: [PATCH 76/82] Removed unrequired extra sql transaction append line. --- sickbeard/dailysearcher.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sickbeard/dailysearcher.py b/sickbeard/dailysearcher.py index d0ca71bd..f45cf291 100644 --- a/sickbeard/dailysearcher.py +++ b/sickbeard/dailysearcher.py @@ -71,8 +71,6 @@ class DailySearcher(): logger.log(u"New episode " + ep.prettyName() + " airs today, setting status to WANTED") ep.status = common.WANTED - sql_l.append(ep.get_sql()) - if ep.status == common.WANTED: if show not in todaysEps: todaysEps[show] = [ep] From 7e91d3a600515c261bbdd559e3462ecf1060761b Mon Sep 17 00:00:00 2001 From: echel0n Date: Tue, 3 Jun 2014 23:52:55 -0700 Subject: [PATCH 77/82] Fix for scene_names table does not exist errors. --- sickbeard/db.py | 9 ++++++--- sickbeard/name_cache.py | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/sickbeard/db.py b/sickbeard/db.py index a324a745..5dfca35c 100644 --- a/sickbeard/db.py +++ b/sickbeard/db.py @@ -115,7 +115,7 @@ class DBConnection: with db_lock: # remove None types - querylist = [i for i in querylist if i!=None] + querylist = [i for i in querylist if i != None] if querylist == None: return @@ -125,7 +125,7 @@ class DBConnection: # Transaction self.connection.isolation_level = None - self.connection.execute('begin') + self.connection.execute('BEGIN') while attempt < 5: try: @@ -140,7 +140,7 @@ class DBConnection: logger.log(qu[0] + " with args " + str(qu[1]), logger.DEBUG) sqlResult.append(self.connection.execute(qu[0], qu[1])) - self.connection.execute('commit') + self.connection.execute('COMMIT') logger.log(u"Transaction with " + str(len(querylist)) + u" queries executed", logger.DEBUG) return sqlResult @@ -240,6 +240,9 @@ class DBConnection: d[col[0]] = row[idx] return d + def hasTable(self, tableName): + return len(self.action("SELECT 1 FROM sqlite_master WHERE name = ?;", (tableName, )).fetchall()) > 0 + def sanityCheckDatabase(connection, sanity_check): sanity_check(connection).check() diff --git a/sickbeard/name_cache.py b/sickbeard/name_cache.py index a39e5192..c47046a9 100644 --- a/sickbeard/name_cache.py +++ b/sickbeard/name_cache.py @@ -45,11 +45,14 @@ def retrieveNameFromCache(name): Returns: the TVDB and TVRAGE id that resulted from the cache lookup or None if the show wasn't found in the cache """ + cache_results = None + # standardize the name we're using to account for small differences in providers name = sanitizeSceneName(name) cacheDB = db.DBConnection('cache.db') - cache_results = cacheDB.select("SELECT * FROM scene_names WHERE name = ?", [name]) + if cacheDB.hasTable('scene_names'): + cache_results = cacheDB.select("SELECT * FROM scene_names WHERE name = ?", [name]) if cache_results: return int(cache_results[0]["indexer_id"]) From 272ecd0ab8241a6f37e2936f5cdfc742c225cd90 Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 4 Jun 2014 00:11:56 -0700 Subject: [PATCH 78/82] Fix for mass updating not actually changing any show options when editing --- sickbeard/webserve.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index fe356eff..cb8568c5 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3211,7 +3211,7 @@ class Home: if directCall: do_update_exceptions = False else: - if directCall or set(exceptions_list) == set(showObj.exceptions): + if set(exceptions_list) == set(showObj.exceptions): do_update_exceptions = False else: do_update_exceptions = True @@ -3278,19 +3278,37 @@ class Home: except exceptions.CantRefreshException, e: errors.append("Unable to refresh this show: " + ex(e)) - showObj.paused = paused + if paused: + showObj.paused = paused - # if this routine was called via the mass edit, do not change the options that are not passed - if not directCall: + if air_by_date: showObj.air_by_date = air_by_date + + if scene: showObj.scene = scene + + if sports: showObj.sports = sports + + if anime: showObj.anime = anime + + if subtitles: showObj.subtitles = subtitles + + if indexer_lang: showObj.lang = indexer_lang + + if dvdorder: showObj.dvdorder = dvdorder + + if archive_firstmatch: showObj.archive_firstmatch = archive_firstmatch + + if rls_ignore_words: showObj.rls_ignore_words = rls_ignore_words.strip() + + if rls_require_words: showObj.rls_require_words = rls_require_words.strip() # if we change location clear the db of episodes, change it, write to db, and rescan From 5beb45d29dad7e28259b5deb91f48131424b86b4 Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 4 Jun 2014 00:16:43 -0700 Subject: [PATCH 79/82] Small correction for mass update fix. --- sickbeard/webserve.py | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index cb8568c5..66f0c695 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3278,32 +3278,15 @@ class Home: except exceptions.CantRefreshException, e: errors.append("Unable to refresh this show: " + ex(e)) - if paused: - showObj.paused = paused - - if air_by_date: - showObj.air_by_date = air_by_date - - if scene: - showObj.scene = scene - - if sports: - showObj.sports = sports - - if anime: - showObj.anime = anime - - if subtitles: - showObj.subtitles = subtitles - - if indexer_lang: - showObj.lang = indexer_lang - - if dvdorder: - showObj.dvdorder = dvdorder - - if archive_firstmatch: - showObj.archive_firstmatch = archive_firstmatch + showObj.paused = paused + showObj.air_by_date = air_by_date + showObj.scene = scene + showObj.sports = sports + showObj.anime = anime + showObj.subtitles = subtitles + showObj.lang = indexer_lang + showObj.dvdorder = dvdorder + showObj.archive_firstmatch = archive_firstmatch if rls_ignore_words: showObj.rls_ignore_words = rls_ignore_words.strip() From 0713cb4039c4f6f34cdf99917ac508ce98777d2e Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 4 Jun 2014 00:21:21 -0700 Subject: [PATCH 80/82] Another small tweak of code for edit show function. --- sickbeard/webserve.py | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 66f0c695..6289df6b 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3278,20 +3278,37 @@ class Home: except exceptions.CantRefreshException, e: errors.append("Unable to refresh this show: " + ex(e)) - showObj.paused = paused - showObj.air_by_date = air_by_date - showObj.scene = scene - showObj.sports = sports - showObj.anime = anime - showObj.subtitles = subtitles - showObj.lang = indexer_lang - showObj.dvdorder = dvdorder - showObj.archive_firstmatch = archive_firstmatch + if showObj.paused != paused: + showObj.paused = paused - if rls_ignore_words: + if showObj.air_by_date != air_by_date: + showObj.air_by_date = air_by_date + + if showObj.scene != scene: + showObj.scene = scene + + if showObj.sports != sports: + showObj.sports = sports + + if showObj.anime != anime: + showObj.anime = anime + + if showObj.subtitles != subtitles: + showObj.subtitles = subtitles + + if showObj.lang != indexer_lang: + showObj.lang = indexer_lang + + if showObj.dvdorder != dvdorder: + showObj.dvdorder = dvdorder + + if showObj.archive_firstmatch != archive_firstmatch: + showObj.archive_firstmatch = archive_firstmatch + + if rls_ignore_words and showObj.rls_ignore_words != rls_ignore_words.strip(): showObj.rls_ignore_words = rls_ignore_words.strip() - if rls_require_words: + if rls_require_words and showObj.rls_require_words != rls_require_words.strip(): showObj.rls_require_words = rls_require_words.strip() # if we change location clear the db of episodes, change it, write to db, and rescan From d09f2a22765ceb37be563d1c8dc6703baa7c805f Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 4 Jun 2014 00:34:35 -0700 Subject: [PATCH 81/82] Fix for scene numbering not being set properly during a mass edit --- sickbeard/webserve.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 6289df6b..b2e8e8c0 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -640,7 +640,7 @@ class Manage: return _munge(t) @cherrypy.expose - def massEditSubmit(self, paused=None, anime=None, flatten_folders=None, quality_preset=False, subtitles=None, + def massEditSubmit(self, paused=None, anime=None, scene=None, flatten_folders=None, quality_preset=False, subtitles=None, anyQualities=[], bestQualities=[], toEdit=None, *args, **kwargs): dir_map = {} @@ -680,6 +680,12 @@ class Manage: new_anime = True if anime == 'enable' else False new_anime = 'on' if new_anime else 'off' + if scene == 'keep': + new_scene = showObj.is_anime + else: + new_scene = True if scene == 'enable' else False + new_scene = 'on' if new_scene else 'off' + if flatten_folders == 'keep': new_flatten_folders = showObj.flatten_folders else: @@ -699,7 +705,8 @@ class Manage: exceptions_list = [] curErrors += Home().editShow(curShow, new_show_dir, anyQualities, bestQualities, exceptions_list, - new_flatten_folders, new_paused, subtitles=new_subtitles, anime=new_anime, directCall=True) + new_flatten_folders, new_paused, subtitles=new_subtitles, anime=new_anime, + scene=new_scene, directCall=True) if curErrors: logger.log(u"Errors: " + str(curErrors), logger.ERROR) From 8f3469cce7d610022453b88846cdea9c164be91b Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 4 Jun 2014 00:35:43 -0700 Subject: [PATCH 82/82] Fix typo in last commit --- sickbeard/webserve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index b2e8e8c0..3ba31cd2 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -681,7 +681,7 @@ class Manage: new_anime = 'on' if new_anime else 'off' if scene == 'keep': - new_scene = showObj.is_anime + new_scene = showObj.is_scene else: new_scene = True if scene == 'enable' else False new_scene = 'on' if new_scene else 'off'