From a39403fb8be586e9b9e4b326616156fbfed27c6c Mon Sep 17 00:00:00 2001 From: Vincent Reher Date: Thu, 22 Jun 2023 09:22:42 -0700 Subject: [PATCH] This new branch is a follow-up to the latest and final commit to branch issue/270/tdelibs-V3. It includes the following files that were mistakenly omitted in that commit: tdecore/CMakeLists.txt tdecore/README.tdestringmatcher tdecore/tdeglobal.cpp tdecore/tdeglobal.h tdecore/tdestringmatcher.cpp tdecore/tdestringmatcher.h tdeio/tdeio/tdefileitem.cpp tdeio/tdeio/tdefileitem.h It also includes updates to the following files, some of which are based on recent feedback from @MicheleC: tdecore/tequivchars-mapping.h tdecore/tequivchars.cpp tdecore/tequivchars.h Signed-off-by: Vincent Reher --- tdecore/CMakeLists.txt | 5 +- tdecore/README.tdestringmatcher | 121 ++ tdecore/tdeglobal.cpp | 31 + tdecore/tdeglobal.h | 17 + tdecore/tdestringmatcher.cpp | 649 +++++++ tdecore/tdestringmatcher.h | 134 ++ tdecore/tequivchars-mapping.h | 3085 +++++++++++++++++++++++++++++++ tdecore/tequivchars.cpp | 241 +++ tdecore/tequivchars.h | 34 + tdeio/tdeio/tdefileitem.cpp | 60 +- tdeio/tdeio/tdefileitem.h | 45 +- 11 files changed, 4406 insertions(+), 16 deletions(-) create mode 100644 tdecore/README.tdestringmatcher create mode 100755 tdecore/tdestringmatcher.cpp create mode 100644 tdecore/tdestringmatcher.h create mode 100644 tdecore/tequivchars-mapping.h create mode 100755 tdecore/tequivchars.cpp create mode 100644 tdecore/tequivchars.h diff --git a/tdecore/CMakeLists.txt b/tdecore/CMakeLists.txt index c794a8039..3df630ac3 100644 --- a/tdecore/CMakeLists.txt +++ b/tdecore/CMakeLists.txt @@ -72,7 +72,7 @@ install( FILES kcalendarsystem.h kcalendarsystemfactory.h kmacroexpander.h kmanagerselection.h kmountpoint.h kuser.h klockfile.h kidna.h ktempdir.h kshell.h fixx11h.h kxerrorhandler.h - tdelibs_export.h kde_file.h ktimezones.h + tdelibs_export.h kde_file.h ktimezones.h tdestringmatcher.h tequivchars.h ${CMAKE_CURRENT_BINARY_DIR}/kdemacros.h DESTINATION ${INCLUDE_INSTALL_DIR} ) @@ -135,13 +135,14 @@ set( ${target}_SRCS kprotocolinfo_tdecore.cpp kprotocolinfofactory.cpp kxerrorhandler.cpp kuser.cpp tdeconfigskeleton.cpp tdeconfigdialogmanager.cpp klockfile.cpp kqiodevicegzip_p.cpp ktimezones.cpp ksimpledirwatch.cpp + tdestringmatcher.cpp tequivchars.cpp ) tde_add_library( ${target} SHARED AUTOMOC SOURCES ${${target}_SRCS} VERSION 14.1.0 EMBED tdecorenetwork-static - LINK DCOP-shared tdefx-shared ICE SM ${ZLIB_LIBRARIES} ${RESOLV_LIBRARIES} + LINK DCOP-shared tdefx-shared ICE SM ${ZLIB_LIBRARIES} LINK_PRIVATE ltdlc-static ${KDESVGICONS} ${XCOMPOSITE_LIBRARIES} ${LIBIDN_LIBRARIES} ${LIBBFD_LIBRARIES} ${LIB_UTIL} ${GAMIN_LIBRARIES} ${Backtrace_LIBRARY} diff --git a/tdecore/README.tdestringmatcher b/tdecore/README.tdestringmatcher new file mode 100644 index 000000000..dc9e6bca5 --- /dev/null +++ b/tdecore/README.tdestringmatcher @@ -0,0 +1,121 @@ +The TDEStringMatcher class provides string matching against a list of one +or more match patterns along with associated options. A single pattern with +its associated options will be referred to herein as a "match specification". + +Current match specification options include: + + * Type of match pattern: + + REGEX: Pattern is a regular expression. + WILDCARD: Pattern is a wildcard expression like that used + in POSIX shell file globbing. + SUBSTRING: Pattern is a simple substring that matches any + string in which it occurs. Substring characters do not + have any other meaning that controls matching. + + * Alphanumeric character handling in a pattern: + + NONE: each unescaped alphanumeric character in a pattern + is distinct and will match only itself. + CASE INSENSITIVE: each unescaped letter in a pattern + will match its lower and upper case variants. + EQUIVALENCE: Each unescaped variant of an alphanumeric + character will match all stylistic and accented + variations of that character. + + * Desired outcome of matching + + TRUE: match succeeds if a string matches the match pattern. + FALSE: match succeeds if a string does NOT match the match pattern. + +Applications may set and get match specification lists either directly or +indirectly (using an encoded match specifications string). The matching +functions provided are: + + matchAny(): strings match if they match any pattern in list. + matchAll(): strings match only if the match all patterns in list. + +MATCH SPECIFICATIONS STRING + +The TDEStringMatcher class provides applications an encoded match +specifications string solely intended to be used for storing and retrieving +match specifications. These strings are formatted as follows: + + OptionString PatternString [ OptionString PatternString ...] + +Option strings may contain only the following characters: + + 'r' - Match pattern is a regular expression [default] + 'w' - Match pattern is a wildcard expression + 's' - Match pattern is a simple substring + 'c' - Letter case variants are distinct (e.g. case-sensitive) [default] + 'i' - Letter case variants are equivalent (e.g. case-insensitive) + 'e' - All letter & number character variants are equivalent + '=' - Match succeeds if pattern matches [default] + '!' - Match succeeds if pattern does NOT match (inverted match) + +Option strings should ideally contain exactly 3 characters indicating match +pattern type, alphanumeric character handling, and desired outcome of matching. +Specifying fewer option characters is possible but may result in unexpected +inferred values. Specifying additional and possibly contradictory option +characters is also possible, with later characters overriding earlier ones. + +Pattern strings may not be empty. Invalid pattern strings will cause the +entire match specifications string to be rejected. + +Match specifications strings that are stored in TDE configuration files will +be modified as follows: + + '\' characters in original pattern are encoded as '\\' + The separator is encoded as '\t' + +Using file name matching as an example, the match specifications string: + wc= .* rc= ~$ se! e ri= ^a.+\.[0-9]+$ +encoded in a TDE configuration file as: + wc=\t.*\trc=\t~$\tse!\te\tri=\t^a.+\\.[0-9]+$ +will match file names as follows: + + * All "dotfiles" would be matched with wildcard matching. + * All file names ending with '~' (e.g kwrite backup names) would be + matched with case-sensitive regex matching. + * All filenames that do NOT contain an equivalent variant of the letter + 'e' (e.g. 'e','ê','Ě','E') would be matched with substring matching. + * All file names starting with letter 'a' or 'A' and ending with '.' + followed by one or more numeric digits would be matched with case- + insensitive regex matching. + +IMPLEMENTATION NOTES: + + * Regular expressions are currently supported by TQRegExp and are + thereby subject to its limitations and bugs. This may be changed + in the future (e.g. direct access to PCRE2, porting of Qt 5.x + QRegularExpression). + + * Wildcard pattern matching on GLIBC systems is done using the fnmatch + function with GNU extended patterns supported. Consult the fnmatch(3) + and glob(7) manual pages for more information. On non-GLIBC systems, + basic (not extended) wildcard patterns are converted to basic regular + expressions and processed by the underlying regular expression engine. + + * Simple substrings are also supported as match patterns. These are + currently processed by the TQString.find() function. In the future, + these may be converted and processed by the underlying regex engine, + depending on the tradeoff between code simplification and efficiency. + + * Alphanumeric equivalence is conceptually similar to [=x=] POSIX + equivalence class bracket expressions (which are not supported) + but is intended to apply globally in patterns. The following + are caveats when this option is utilized: + + - There is potentially significant overhead due to the fact that + match patterns and match strings must be converted prior to + matching. Conversion requires character-by-character lookup + and replacement using a pre-built table. + + - The table contains equivalents for [0-9A-Z] which should work + well for Latin-derived languages. It also contains support for + other numeric and non-latin letter characters, the efficacy of + which is not as certain. + + - Due to the 16-bit size limitation of TQChar, the table does not + contain mappings for codepoints greater than U+FFFF. diff --git a/tdecore/tdeglobal.cpp b/tdecore/tdeglobal.cpp index 09f496034..03f39ac80 100644 --- a/tdecore/tdeglobal.cpp +++ b/tdecore/tdeglobal.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #ifdef __TDE_HAVE_TDEHWLIB #include @@ -131,6 +133,32 @@ KCharsets *TDEGlobal::charsets() return _charsets; } +TEquivChars *TDEGlobal::equivChars() +{ + if( _equivChars == 0 ) { + _equivChars = new TEquivChars(); + } + return _equivChars; +} + +TDEStringMatcher *TDEGlobal::hiddenFileMatcher() +{ + if( _hiddenFileMatcher == 0 ) { + //-Debug: TSMTRACE << "TDEGlobal::hiddenFileMatcher(): Global HFM initialization STARTED" << endl; + _hiddenFileMatcher = new TDEStringMatcher(); + TDEGlobal::config()->setGroup( "General" ); + const char* settingsDefault = "wc=\t.*"; // wildcard match of dotfiles + // CAUTION: for economy of expression, we are leveraging our insider knowledge + // that TSM::StringDivider is defined as '\t' instead of more properly doing this: + // char settingsDefault[5] = { 'w', TSM::StringDivider, '.', '*', 0 }; + TQString settings = TDEGlobal::config()->readEntry( "globalHiddenFileSpec", settingsDefault ); + //-Debug: TSMTRACE << "TDEGlobal::hiddenFileMatcher(): using retrieved patternString = '" << settings << "'" << endl; + _hiddenFileMatcher->setMatchSpecs( settings ); + } + + return _hiddenFileMatcher; +} + void TDEGlobal::setActiveInstance(TDEInstance *i) { _activeInstance = i; @@ -223,6 +251,9 @@ TDEInstance *TDEGlobal::_instance = 0; TDEInstance *TDEGlobal::_activeInstance = 0; TDELocale *TDEGlobal::_locale = 0; KCharsets *TDEGlobal::_charsets = 0; +TEquivChars *TDEGlobal::_equivChars = 0; +TDEStringMatcher *TDEGlobal::_hiddenFileMatcher = 0; + KStaticDeleterList *TDEGlobal::_staticDeleters = 0; #ifdef WIN32 diff --git a/tdecore/tdeglobal.h b/tdecore/tdeglobal.h index 1269c36a9..ebb465cf0 100644 --- a/tdecore/tdeglobal.h +++ b/tdecore/tdeglobal.h @@ -30,6 +30,8 @@ class TDEHardwareDevices; class TDEGlobalNetworkManager; #endif class TDELocale; +class TDEStringMatcher; +class TEquivChars; class TDEStandardDirs; class KStaticDeleterBase; class KStaticDeleterList; @@ -107,6 +109,18 @@ public: */ static KCharsets *charsets(); + /** + * The global alphanumeric character equivalence mapper. + * @return the global alphanumeric character equivalence mapper. + */ + static TEquivChars *equivChars(); + + /** + * The global hidden file matcher. + * @return the global hidden file matcher + */ + static TDEStringMatcher *hiddenFileMatcher(); + /** * Creates a static TQString. * @@ -174,6 +188,9 @@ public: static TDEInstance *_instance; static TDELocale *_locale; static KCharsets *_charsets; + static TDEStringMatcher *_hiddenFileMatcher; + static TEquivChars *_equivChars; + static KStaticDeleterList *_staticDeleters; /** diff --git a/tdecore/tdestringmatcher.cpp b/tdecore/tdestringmatcher.cpp new file mode 100755 index 000000000..7e9f1ee0d --- /dev/null +++ b/tdecore/tdestringmatcher.cpp @@ -0,0 +1,649 @@ +#include "tdestringmatcher.h" +#include "tequivchars.h" + +#include +#include +#include + +#include +#ifdef __GLIBC__ +#include +#pragma message "TSM using GLIBC fnmatch() for wildcard matching" +#endif + +//================================================================================================ + +namespace TSM { + +class AuxData +{ +public: + AuxData(); + TQString patternConverted; // Pattern converted from original (e.g ANCHandling::EQUIVALENCE) + TQRegExp* matchEngine; // Used when PatternType::REGEX +#ifdef __GLIBC__ + int fnmatchFlags; // Used by fnmatch() when PatternType::WILDCARD +#endif + bool isCaseSensitive; // PatternType::SUBSTRING +}; + +AuxData::AuxData() +{ + isCaseSensitive = true; +#ifdef __GLIBC__ + fnmatchFlags = FNM_EXTMATCH; // Bash shell option 'extglob' +#endif + matchEngine = nullptr; + patternConverted = ""; +} + +} // End of namespace TSM + +//================================================================================================ + +using namespace TSM; + +typedef TQValueVector AuxDataList; + +class TDEStringMatcher::TDEStringMatcherPrivate { +public: + + // Properties that may be set / accessed through the TSM interface + TQString m_matchSpecString; + MatchSpecList m_matchSpecList; + + // Properties that are internal implementation only + AuxDataList m_auxData; + void clearAll(); +}; + +void TDEStringMatcher::TDEStringMatcherPrivate::clearAll() +{ + m_matchSpecString = ""; + m_matchSpecList.clear(); + for ( size_t index = 0 ; index < m_auxData.count() ; index++ ) { + if ( m_auxData[index].matchEngine != nullptr ) { + TSMTRACE << "Freeing match engine " << m_auxData[index].matchEngine << endl; + delete m_auxData[index].matchEngine; + } + } + m_auxData.clear(); +} + +//================================================================================================ + +TDEStringMatcher::TDEStringMatcher() +{ + TSMTRACE << "TSM::TDEStringMatcher(): New instance created: " << this << endl; + d = new TDEStringMatcherPrivate; +} + +TDEStringMatcher::~TDEStringMatcher() +{ + d->clearAll(); + delete d; + TSMTRACE << "TSM::~TDEStringMatcher(): Instance destroyed: " << this << endl; +} + + +//================================================================================================ +// Match specification output functions +//================================================================================================ + +const TQString TDEStringMatcher::getMatchSpecString() const +{ + return d->m_matchSpecString; +} + +const MatchSpecList TDEStringMatcher::getMatchSpecs() const +{ + return d->m_matchSpecList; +} + + +//================================================================================================ +// Match specification input functions +//================================================================================================ + +bool TDEStringMatcher::setMatchSpecs( MatchSpecList newMatchSpecList ) +{ + TDEStringMatcherPrivate workArea; + + TQStringList newMatchSpecs; + + TSMTRACE << "TSM::setPatterns(): validating match specification list" << endl; + + for ( MatchSpec matchSpec : newMatchSpecList ) { + + if ( matchSpec.pattern.isEmpty() ) { + TSMTRACE << " Error: empty pattern!" << endl; + workArea.clearAll(); + return false; + } + if ( matchSpec.pattern.find( TQChar(PatterStringDivider) ) >= 0 ) { + TSMTRACE << " Error: pattern contains reserved separator character" << endl; + workArea.clearAll(); + return false; + } + + AuxData auxWork; + TQString inferredOptionString; + + // Validate / process PatternType + + auxWork.patternConverted = matchSpec.pattern; + switch ( matchSpec.patternType ) { + case PatternType::WILDCARD : + inferredOptionString += TQChar('w'); +#ifndef __GLIBC__ + auxWork.patternConverted = wildcardToRegex( auxWork.patternConverted ); + TSMTRACE << " Converted wildcard expression '" << matchSpec.pattern << "' to regex '" << auxWork.patternConverted << "'" << endl; +#endif + break; + case PatternType::REGEX : + inferredOptionString += TQChar('r'); + break; + case PatternType::SUBSTRING : + inferredOptionString += TQChar('s'); + break; + default: + TSMTRACE << " Error: pattern type out of range" << endl; + workArea.clearAll(); + return false; + } + + // Validate / process ANCHandling + + TQString before = auxWork.patternConverted; + switch ( matchSpec.ancHandling ) { + case ANCHandling::CASE_SENSITIVE : + inferredOptionString += TQChar('c'); + auxWork.isCaseSensitive = true; + break; + case ANCHandling::CASE_INSENSITIVE : + inferredOptionString += TQChar('i'); + auxWork.isCaseSensitive = false; +#ifdef __GLIBC__ + auxWork.fnmatchFlags |= FNM_CASEFOLD; +#endif + break; + case ANCHandling::EQUIVALENCE : + inferredOptionString += TQChar('e'); + auxWork.isCaseSensitive = true; + auxWork.patternConverted = TDEGlobal::equivChars()->replaceChars( auxWork.patternConverted, true ); + TSMTRACE << " Converted match pattern '" << before << "' to equivalent '" << auxWork.patternConverted << "'" << endl; + break; + default: + TSMTRACE << " Error: alphabetic character handling specification out of range" << endl; + workArea.clearAll(); + return false; + } + + if ( matchSpec.expectMatch ) + inferredOptionString += TQChar('='); + else + inferredOptionString += TQChar('!'); + + // Test validity of pattern + + TQRegExp rxWork; + int result; + + switch ( matchSpec.patternType ) { + case PatternType::WILDCARD : +#ifdef __GLIBC__ // Test wildcard expression using a subject matter expert + result = fnmatch( + auxWork.patternConverted.local8Bit().data(), + auxWork.patternConverted.local8Bit().data(), + auxWork.fnmatchFlags + ); // Comparison should fail + switch ( result ) { + case 0: // matched + case FNM_NOMATCH: // not matched + break; + default: + TSMTRACE << " Error: invalid wildcard syntax" << endl; + workArea.clearAll(); + return false; + } + break; +#endif // Otherwise we will test wildcard expression as one converted to a regex + case PatternType::REGEX : + // Prepare regex + rxWork.setPattern( auxWork.patternConverted ); + rxWork.setCaseSensitive( auxWork.isCaseSensitive ); + // Test regex + if ( rxWork.isValid() ) { + auxWork.matchEngine = new TQRegExp; + *auxWork.matchEngine = rxWork; + TSMTRACE << "AuxData: Allocated regex engine for matching '" << auxWork.matchEngine->pattern() << "'" << endl; + } + else { + TSMTRACE << " Error: invalid regex syntax'" << endl; + workArea.clearAll(); + return false; + } + break; + // if (! rxWork.isReallyWhatUserIntended() ) { HA HA + } + + // This particular match specification is good + + newMatchSpecs.append( inferredOptionString ); + newMatchSpecs.append( matchSpec.pattern ); + workArea.m_auxData.append( auxWork ); + } + + // All proposed match specifications are good, update everything accordingly + + workArea.m_matchSpecList = newMatchSpecList; + workArea.m_matchSpecString = newMatchSpecs.join( TQChar(PatterStringDivider) ); + d->clearAll(); + *d = workArea; + //-Debug: TSMTRACE << " Notifying slots of pattern change" << endl; + emit patternsChanged(); + //-Debug: TSMTRACE << " All slots have been notified" << endl; + TSMTRACE << "TSM::setPatterns(): Patterns were successfully regenerated from list" << endl << endl; + return true; +} + +//================================================================================================= + +bool TDEStringMatcher::setMatchSpecs( TQString newMatchSpecString ) +{ + if ( newMatchSpecString == d->m_matchSpecString ) + return true; + + TDEStringMatcherPrivate workArea; + + MatchSpec matchSpec = { + PatternType::DEFAULT, + ANCHandling::DEFAULT, + true, // seeking matches, not non-matches + "" + }; + + TSMTRACE << "TSM::setPatterns: Proposed match specification string: <" << newMatchSpecString << ">" << endl; + + if ( newMatchSpecString.isEmpty() ) { + TSMTRACE << " Empty pattern string => match specifications will be cleared" << endl; + d->m_matchSpecList.clear(); + d->m_matchSpecString = ""; + emit patternsChanged(); + return true; + } + + TQStringList newMatchSpecs = TQStringList::split( PatterStringDivider, newMatchSpecString, true ); + + if ( newMatchSpecs.count() % 2 != 0 ) { + TSMTRACE << " Error: match specification string must contain an even number of components" << endl; + return false; + } + + bool processingOptionString = true; // expected format: option string , pattern string, ... + + for ( TQString &specification : newMatchSpecs ) { + + if ( processingOptionString ) { + specification = specification.lower(); + TSMTRACE << " Processing match option string: '" << specification << "'" << endl; + for ( int i = 0 ; i < specification.length() ; i++ ) { + + TQChar optionChar = specification[i]; + //Debug: TSMTRACE << " Option character: '" << optionChar << "'" << endl; + + switch ( optionChar ) { + case 'r' : matchSpec.patternType = PatternType::REGEX ; break; + case 'w' : matchSpec.patternType = PatternType::WILDCARD ; break; + case 's' : matchSpec.patternType = PatternType::SUBSTRING ; break; + case 'c' : matchSpec.ancHandling = ANCHandling::CASE_SENSITIVE ; break; + case 'i' : matchSpec.ancHandling = ANCHandling::CASE_INSENSITIVE; break; + case 'e' : matchSpec.ancHandling = ANCHandling::EQUIVALENCE ; break; + case '=' : matchSpec.expectMatch = true ; break; + case '!' : matchSpec.expectMatch = false ; break; + default: + // We reserve ALL other possible option characters for future use! + TSMTRACE << " Error: invalid option character" << endl; + workArea.clearAll(); + return false; + } + } + + processingOptionString = false; // next spec should be a pattern string + } // processingOptionString + + else { // ! processingOptionString + + TSMTRACE << " Processing match pattern string: '" << specification << "'" << endl; + + if ( specification.isEmpty() ) { + TSMTRACE << " Error: empty pattern!" << endl; + workArea.clearAll(); + return false; + } + + AuxData auxWork; + + // Validate / process PatternType + + auxWork.patternConverted = specification; + switch ( matchSpec.patternType ) { + case PatternType::WILDCARD : +#ifndef __GLIBC__ + auxWork.patternConverted = wildcardToRegex( specification ); + TSMTRACE << " Converted wildcard expression '" << specification << "' to regex '" << auxWork.patternConverted << "'" << endl; + break; +#endif + case PatternType::REGEX : + case PatternType::SUBSTRING : + break; + default : + // This should never arise since the content of this field was set within this function + kdWarning() << "Error while processing '" << specification + << "' pattern type out of range: " << (uchar) matchSpec.patternType + << endl; + workArea.clearAll(); + return false; + } + + // Validate / process ANCHandling + + TQString before = auxWork.patternConverted; + switch ( matchSpec.ancHandling ) { + case ANCHandling::CASE_SENSITIVE : + auxWork.isCaseSensitive = true; + break; + case ANCHandling::CASE_INSENSITIVE : + auxWork.isCaseSensitive = false; +#ifdef __GLIBC__ + auxWork.fnmatchFlags |= FNM_CASEFOLD; +#endif + break; + case ANCHandling::EQUIVALENCE : + auxWork.isCaseSensitive = true; + auxWork.patternConverted = TDEGlobal::equivChars()->replaceChars( auxWork.patternConverted, true ); + TSMTRACE << " Converted match pattern '" << before << "' to equivalent '" << auxWork.patternConverted << "'" << endl; + break; + default: break; + kdWarning() << "Error while processing '" << specification + << "' alphabetic character handling specification out of range: " << (uchar) matchSpec.ancHandling + << endl; + workArea.clearAll(); + return false; + } + + // Test validity of pattern + + TQRegExp rxWork; // single working copy == each pattern inherits previous options + int result; + + switch ( matchSpec.patternType ) { + case PatternType::WILDCARD : +#ifdef __GLIBC__ // Test wildcard expression using a subject matter expert + result = fnmatch( + auxWork.patternConverted.local8Bit().data(), + auxWork.patternConverted.local8Bit().data(), + auxWork.fnmatchFlags + ); // Comparison should fail + switch ( result ) { + case 0: // matched + case FNM_NOMATCH: // not matched + break; + default: + TSMTRACE << " Error: invalid wildcard syntax" << endl; + workArea.clearAll(); + return false; + } + break; +#endif // Otherwise we will test wildcard expression as one converted to x regex + case PatternType::REGEX : + // Prepare regex + rxWork.setPattern( auxWork.patternConverted ); + rxWork.setCaseSensitive( auxWork.isCaseSensitive ); + // Test regex + if ( rxWork.isValid() ) { + auxWork.matchEngine = new TQRegExp; + *auxWork.matchEngine = rxWork; + TSMTRACE << " AuxData: Allocated regex engine " << auxWork.matchEngine << "for pattern: " << auxWork.matchEngine->pattern() << endl; + } + else { + TSMTRACE << " Error: invalid regex syntax" << endl; + workArea.clearAll(); + return false; + } + break; + // if (! rxWork.isReallyWhatUserIntended() ) { HA HA + } + + matchSpec.pattern = specification; + workArea.m_matchSpecList.push_back( matchSpec ); + workArea.m_auxData.append( auxWork ); + + processingOptionString = true; // next spec should be an option string + } // ! processingOptionString completed + } + + workArea.m_matchSpecString = newMatchSpecString; + d->clearAll(); + *d = workArea; + TSMTRACE << " Final patternString: '" << d->m_matchSpecString << "'" << endl; + TSMTRACE << " Number of match patterns in list: '" << d->m_matchSpecList.count() << "'" << endl; + //-Debug: TSMTRACE << " Notifying slots of pattern change" << endl; + emit patternsChanged(); + //-Debug: TSMTRACE << " All slots have been notified" << endl; + TSMTRACE << "TSM::setPatterns(): Patterns were successfully regenerated from string" << endl << endl; + return true; +} + +//================================================================================================ +// Match functions +//================================================================================================ + +bool TDEStringMatcher::matchAny( const TQString& stringToMatch ) const +{ +/* DEBUG + TSMTRACE << "TSM:matchAny(): Attempting to match string '" << stringToMatch << "' against stored patterns" << endl; + if ( d->m_matchSpecList.isEmpty() ) { + //-Debug: TSMTRACE << "Match failed on empty pattern list!" << endl; + return false; + } +*/ + TQString equivalentString; + + for ( size_t index = 0 ; index < d->m_matchSpecList.count() ; index++ ) + { + TQString matchWhat = stringToMatch; + TQString matchThis = d->m_auxData[index].patternConverted; + + if ( d->m_matchSpecList[index].ancHandling == ANCHandling::EQUIVALENCE ) { + if ( equivalentString.isEmpty() ) { + equivalentString = TDEGlobal::equivChars()->replaceChars( stringToMatch, false ) ; + } + matchWhat = equivalentString; + } + + bool matchFound = false; + switch ( d->m_matchSpecList[index].patternType ) { + case PatternType::WILDCARD : +#ifdef __GLIBC__ + matchFound = ( fnmatch( + matchThis.local8Bit().data(), + matchWhat.local8Bit().data(), + d->m_auxData[index].fnmatchFlags + ) == 0 ); + break; +#endif + case PatternType::REGEX : + matchFound = ( d->m_auxData[index].matchEngine->search( matchWhat ) >= 0 ); + break; + case PatternType::SUBSTRING : + matchFound = ( matchWhat.find( matchThis, 0, d->m_auxData[index].isCaseSensitive ) >= 0 ); + break; + } + + if ( matchFound == d->m_matchSpecList[index].expectMatch ) { + TSMTRACE << " Success! match of pattern '" << matchThis << "' against '" << matchWhat << "' turned out as expected" << endl; + return true; + } + } + + TSMTRACE << " Match failed, there were no pattern matches against '" << stringToMatch << "' that turned out as expected" << endl; + return false ; +} + +bool TDEStringMatcher::matchAll( const TQString& stringToMatch ) const +{ + TSMTRACE << "TSM:matchAll(): Attempting to match string '" << stringToMatch << "' against stored patterns" << endl; + if ( d->m_matchSpecList.isEmpty() ) { + //-Debug: TSMTRACE << "Match failed on empty pattern list!" << endl; + return false; + } + + TQString equivalentString; + + for ( size_t index = 0 ; index < d->m_matchSpecList.count() ; index++ ) + { + TQString matchWhat = stringToMatch; + TQString matchThis = d->m_auxData[index].patternConverted; + + if ( d->m_matchSpecList[index].ancHandling == ANCHandling::EQUIVALENCE ) { + if ( equivalentString.isEmpty() ) { + equivalentString = TDEGlobal::equivChars()->replaceChars( stringToMatch, false ) ; + } + matchWhat = equivalentString; + } + + bool matchFound = false; + switch ( d->m_matchSpecList[index].patternType ) { + case PatternType::WILDCARD : +#ifdef __GLIBC__ + matchFound = ( fnmatch( + matchThis.local8Bit().data(), + matchWhat.local8Bit().data(), + d->m_auxData[index].fnmatchFlags + ) == 0 ); + break; +#endif + case PatternType::REGEX : + matchFound = ( d->m_auxData[index].matchEngine->search( matchWhat ) >= 0 ); + break; + case PatternType::SUBSTRING : + matchFound = ( matchWhat.find( matchThis, 0, d->m_auxData[index].isCaseSensitive ) >= 0 ); + break; + } + + if ( matchFound != d->m_matchSpecList[index].expectMatch ) { + TSMTRACE << " Match of pattern '" << matchThis << "' against '" << matchWhat << "' did not turn out as expected" << endl; + return false; + } + } + + TSMTRACE << " Expected pattern matching succeeded" << endl; + return true; +} + +//================================================================================================ +// Utility functions +//================================================================================================ + +/* + The following code is a modified copy of that found in tqt3/src/tools/qregexp.cpp. + We export this as utility function for applications that wish to convert a basic + wildcard expression into a basic regular expression. TSM will not use this unless + GLIBC fnmatch() is not available. +*/ +TQString TDEStringMatcher::wildcardToRegex( const TQString& wildcardPattern ) +{ + int wclen = wildcardPattern.length(); + TQString rx = TQString::fromLatin1( "" ); + int i = 0; + const TQChar *wc = wildcardPattern.unicode(); + while ( i < wclen ) { + TQChar c = wc[i++]; + switch ( c.unicode() ) { + case '*': + rx += TQString::fromLatin1( ".*" ); + break; + case '?': + rx += TQChar( '.' ); + break; + case '$': + case '(': + case ')': + case '+': + case '.': + case '\\': + case '^': + case '{': + case '|': + case '}': + rx += TQChar( '\\' ); + rx += c; + break; + case '[': + rx += c; + /* This is not correct, POSIX states that negation character is '!' + if ( wc[i] == TQChar('^') ) + rx += wc[i++]; + */ + if ( wc[i] == TQChar('!') ) { + rx += TQChar('^'); + i++; + } else if ( wc[i] == TQChar('^') ) { + rx += TQChar( '\\' ); + rx += wc[i++]; + } + if ( i < wclen ) { + if ( rx[i] == ']' ) + rx += wc[i++]; + while ( i < wclen && wc[i] != TQChar(']') ) { + if ( wc[i] == '\\' ) + rx += TQChar( '\\' ); + rx += wc[i++]; + } + } + break; + default: + rx += c; + } + } + /* Wildcard patterns must match entire string */ + return TQChar('^') + rx + TQChar('$'); + /* TBD: Add support for extglob */ +} +static TQString escapeRegexChars( const TQString& basicString ) +{ + int wclen = basicString.length(); + TQString outputString = TQString::fromLatin1( "" ); + int i = 0; + const TQChar *wc = basicString.unicode(); + while ( i < wclen ) { + TQChar c = wc[i++]; + switch ( c.unicode() ) { + case '+': + case '.': + case '^': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '|': + case '$': + case '?': + case '*': + case '\\': + outputString += TQChar( '\\' ); + outputString += c; + break; + default: + outputString += c; + } + } + return outputString; +} + +//================================================================================================ + +#include "tdestringmatcher.moc" diff --git a/tdecore/tdestringmatcher.h b/tdecore/tdestringmatcher.h new file mode 100644 index 000000000..504ccfa8c --- /dev/null +++ b/tdecore/tdestringmatcher.h @@ -0,0 +1,134 @@ +#ifndef TDESTRINGMATCHER_H +#define TDESTRINGMATCHER_H + +#include "tdelibs_export.h" + +#include +#include + +#define TSMTRACE kdWarning() << " " + +namespace TSM +{ +/** + * Enumeration used by the TDEStringMatcher class + * defining types of patterns to be matched + */ +enum class PatternType: uchar +{ + REGEX, + WILDCARD, + SUBSTRING, + //OTHER, + DEFAULT = REGEX +}; + +/** + * Enumeration used by the TDEStringMatcher class + * defining special handling of alphanumeric characters + */ +enum class ANCHandling: uchar +{ + CASE_SENSITIVE = 0, // No handling, each character distinct + CASE_INSENSITIVE = 1, // Alphabetic case variants are same + EQUIVALENCE = 2, // Alphanumeric equivalents are same + DEFAULT = CASE_SENSITIVE +}; + +/** + * Structure used by the TDEStringMatcher class + * representing properties of a single match specification. + */ +struct MatchSpec +{ + PatternType patternType; + ANCHandling ancHandling; + bool expectMatch; // "matching" vs. "not matching" + TQString pattern; +}; + +/** + * Container used in a TDEStringMatcher object + * representing multiple match specifications. + */ +typedef TQValueVector MatchSpecList; + +// Use horizontal tab as m_patternString separator +inline constexpr char PatterStringDivider { '\t' }; + +} // End of namespace TSM + + +/** + * Generic string matcher class. + */ +class TDECORE_EXPORT TDEStringMatcher : public TQObject +{ +Q_OBJECT +public: + + TDEStringMatcher(); + ~TDEStringMatcher(); + + /** + @return list of currently defined match specifications. + */ + const TSM::MatchSpecList getMatchSpecs() const; + + /** + @return string encoding list of currently defined match specifications. + */ + const TQString getMatchSpecString() const; + + /** + Use @param newMatchSpecList to generate the internal list of match + specifications to be used for pattern matching. + */ + bool setMatchSpecs( TSM::MatchSpecList newMatchSpecList ); + + /** + Use specially encoded @param newPatternString to generate the internal + list of match specifications to be used for pattern matching. Refer + to file README.tdestringmatcher in tdelibs/tdecore source code for + more information on how the input string should be formatted. + */ + bool setMatchSpecs( TQString newMatchSpecString ); + + /** + @return whether or not @param stringToMatch matches any of + the current match specifications. + */ + bool matchAny( const TQString& stringToMatch ) const; + + /** + @return whether or not @param stringToMatch matches all of + the current match specifications. + */ + bool matchAll( const TQString& stringToMatch ) const; + + /** + @return a basic regular expression formed by converting the basic + wildcard expression in @param wildcardPattern. + */ + TQString wildcardToRegex( const TQString& wildcardPattern ); + + /** + @return a string that is @param basicString with all special regular + expression characters escaped. Useful for regular expression engines + that do not support /Q.../E. + */ + TQString escapeRegexChars( const TQString& basicString ); + + +signals: + + void patternsChanged(); + +private: + + class TDEStringMatcherPrivate; + TDEStringMatcherPrivate *d; + +}; + +#endif diff --git a/tdecore/tequivchars-mapping.h b/tdecore/tequivchars-mapping.h new file mode 100644 index 000000000..fd625189b --- /dev/null +++ b/tdecore/tequivchars-mapping.h @@ -0,0 +1,3085 @@ +#ifndef TEQUIVCHARS_MAPPING_H +#define TEQUIVCHARS_MAPPING_H + +#ifndef OPTIMIZE_ASCII_LOOKUP +[2993]={ // Make sure this dimension accurately reflects content of table below + { 0x00041 , 0x00061 }, // => + { 0x00042 , 0x00062 }, // => + { 0x00043 , 0x00063 }, // => + { 0x00044 , 0x00064 }, // => + { 0x00045 , 0x00065 }, // => + { 0x00046 , 0x00066 }, // => + { 0x00047 , 0x00067 }, // => + { 0x00048 , 0x00068 }, // => + { 0x00049 , 0x00069 }, // => + { 0x0004a , 0x0006a }, // => + { 0x0004b , 0x0006b }, // => + { 0x0004c , 0x0006c }, // => + { 0x0004d , 0x0006d }, // => + { 0x0004e , 0x0006e }, // => + { 0x0004f , 0x0006f }, // => + { 0x00050 , 0x00070 }, // => + { 0x00051 , 0x00071 }, // => + { 0x00052 , 0x00072 }, // => + { 0x00053 , 0x00073 }, // => + { 0x00054 , 0x00074 }, // => + { 0x00055 , 0x00075 }, // => + { 0x00056 , 0x00076 }, // => + { 0x00057 , 0x00077 }, // => + { 0x00058 , 0x00078 }, // => + { 0x00059 , 0x00079 }, // => + { 0x0005a , 0x0007a }, // => +#else +[2967]={ // Make sure this dimension accurately reflects content of table below + /* Excluded ASCII characters are handled as a special case in our code. */ +#endif + { 0x000aa , 0x00061 }, // => + { 0x000b2 , 0x00032 }, // => + { 0x000b3 , 0x00033 }, // => + { 0x000b5 , 0x003bc }, // => + { 0x000b9 , 0x00031 }, // => + { 0x000ba , 0x0006f }, // => + { 0x000c0 , 0x00061 }, // => + { 0x000c1 , 0x00061 }, // => + { 0x000c2 , 0x00061 }, // => + { 0x000c3 , 0x00061 }, // => + { 0x000c4 , 0x00061 }, // => + { 0x000c5 , 0x00061 }, // => + { 0x000c7 , 0x00063 }, // => + { 0x000c8 , 0x00065 }, // => + { 0x000c9 , 0x00065 }, // => + { 0x000ca , 0x00065 }, // => + { 0x000cb , 0x00065 }, // => + { 0x000cc , 0x00069 }, // => + { 0x000cd , 0x00069 }, // => + { 0x000ce , 0x00069 }, // => + { 0x000cf , 0x00069 }, // => + { 0x000d0 , 0x00064 }, // => + { 0x000d1 , 0x0006e }, // => + { 0x000d2 , 0x0006f }, // => + { 0x000d3 , 0x0006f }, // => + { 0x000d4 , 0x0006f }, // => + { 0x000d5 , 0x0006f }, // => + { 0x000d6 , 0x0006f }, // => + { 0x000d8 , 0x0006f }, // => + { 0x000d9 , 0x00075 }, // => + { 0x000da , 0x00075 }, // => + { 0x000db , 0x00075 }, // => + { 0x000dc , 0x00075 }, // => + { 0x000dd , 0x00079 }, // => + { 0x000de , 0x000fe }, // => + { 0x000e0 , 0x00061 }, // => + { 0x000e1 , 0x00061 }, // => + { 0x000e2 , 0x00061 }, // => + { 0x000e3 , 0x00061 }, // => + { 0x000e4 , 0x00061 }, // => + { 0x000e5 , 0x00061 }, // => + { 0x000e7 , 0x00063 }, // => + { 0x000e8 , 0x00065 }, // => + { 0x000e9 , 0x00065 }, // => + { 0x000ea , 0x00065 }, // => + { 0x000eb , 0x00065 }, // => + { 0x000ec , 0x00069 }, // => + { 0x000ed , 0x00069 }, // => + { 0x000ee , 0x00069 }, // => + { 0x000ef , 0x00069 }, // => + { 0x000f0 , 0x00064 }, // => + { 0x000f1 , 0x0006e }, // => + { 0x000f2 , 0x0006f }, // => + { 0x000f3 , 0x0006f }, // => + { 0x000f4 , 0x0006f }, // => + { 0x000f5 , 0x0006f }, // => + { 0x000f6 , 0x0006f }, // => + { 0x000f8 , 0x0006f }, // => + { 0x000f9 , 0x00075 }, // => + { 0x000fa , 0x00075 }, // => + { 0x000fb , 0x00075 }, // => + { 0x000fc , 0x00075 }, // => + { 0x000fd , 0x00079 }, // => + { 0x000ff , 0x00079 }, // => + { 0x00100 , 0x00061 }, // => + { 0x00101 , 0x00061 }, // => + { 0x00102 , 0x00061 }, // => + { 0x00103 , 0x00061 }, // => + { 0x00104 , 0x00061 }, // => + { 0x00105 , 0x00061 }, // => + { 0x00106 , 0x00063 }, // => + { 0x00107 , 0x00063 }, // => + { 0x00108 , 0x00063 }, // => + { 0x00109 , 0x00063 }, // => + { 0x0010a , 0x00063 }, // => + { 0x0010b , 0x00063 }, // => + { 0x0010c , 0x00063 }, // => + { 0x0010d , 0x00063 }, // => + { 0x0010e , 0x00064 }, // => + { 0x0010f , 0x00064 }, // => + { 0x00110 , 0x00064 }, // => + { 0x00111 , 0x00064 }, // => + { 0x00112 , 0x00065 }, // => + { 0x00113 , 0x00065 }, // => + { 0x00114 , 0x00065 }, // => + { 0x00115 , 0x00065 }, // => + { 0x00116 , 0x00065 }, // => + { 0x00117 , 0x00065 }, // => + { 0x00118 , 0x00065 }, // => + { 0x00119 , 0x00065 }, // => + { 0x0011a , 0x00065 }, // => + { 0x0011b , 0x00065 }, // => + { 0x0011c , 0x00067 }, // => + { 0x0011d , 0x00067 }, // => + { 0x0011e , 0x00067 }, // => + { 0x0011f , 0x00067 }, // => + { 0x00120 , 0x00067 }, // => + { 0x00121 , 0x00067 }, // => + { 0x00122 , 0x00067 }, // => + { 0x00123 , 0x00067 }, // => + { 0x00124 , 0x00068 }, // => + { 0x00125 , 0x00068 }, // => + { 0x00126 , 0x00068 }, // => + { 0x00127 , 0x00068 }, // => + { 0x00128 , 0x00069 }, // => + { 0x00129 , 0x00069 }, // => + { 0x0012a , 0x00069 }, // => + { 0x0012b , 0x00069 }, // => + { 0x0012c , 0x00069 }, // => + { 0x0012d , 0x00069 }, // => + { 0x0012e , 0x00069 }, // => + { 0x0012f , 0x00069 }, // => + { 0x00130 , 0x00069 }, // => + { 0x00134 , 0x0006a }, // => + { 0x00135 , 0x0006a }, // => + { 0x00136 , 0x0006b }, // => + { 0x00137 , 0x0006b }, // => + { 0x00139 , 0x0006c }, // => + { 0x0013a , 0x0006c }, // => + { 0x0013b , 0x0006c }, // => + { 0x0013c , 0x0006c }, // => + { 0x0013d , 0x0006c }, // => + { 0x0013e , 0x0006c }, // => + { 0x0013f , 0x0006c }, // => + { 0x00140 , 0x0006c }, // => + { 0x00141 , 0x0006c }, // => + { 0x00142 , 0x0006c }, // => + { 0x00143 , 0x0006e }, // => + { 0x00144 , 0x0006e }, // => + { 0x00145 , 0x0006e }, // => + { 0x00146 , 0x0006e }, // => + { 0x00147 , 0x0006e }, // => + { 0x00148 , 0x0006e }, // => + { 0x0014a , 0x0014b }, // => + { 0x0014c , 0x0006f }, // => + { 0x0014d , 0x0006f }, // => + { 0x0014e , 0x0006f }, // => + { 0x0014f , 0x0006f }, // => + { 0x00150 , 0x0006f }, // => + { 0x00151 , 0x0006f }, // => + { 0x00154 , 0x00072 }, // => + { 0x00155 , 0x00072 }, // => + { 0x00156 , 0x00072 }, // => + { 0x00157 , 0x00072 }, // => + { 0x00158 , 0x00072 }, // => + { 0x00159 , 0x00072 }, // => + { 0x0015a , 0x00073 }, // => + { 0x0015b , 0x00073 }, // => + { 0x0015c , 0x00073 }, // => + { 0x0015d , 0x00073 }, // => + { 0x0015e , 0x00073 }, // => + { 0x0015f , 0x00073 }, // => + { 0x00160 , 0x00073 }, // => + { 0x00161 , 0x00073 }, // => + { 0x00162 , 0x00074 }, // => + { 0x00163 , 0x00074 }, // => + { 0x00164 , 0x00074 }, // => + { 0x00165 , 0x00074 }, // => + { 0x00166 , 0x00167 }, // => + { 0x00168 , 0x00075 }, // => + { 0x00169 , 0x00075 }, // => + { 0x0016a , 0x00075 }, // => + { 0x0016b , 0x00075 }, // => + { 0x0016c , 0x00075 }, // => + { 0x0016d , 0x00075 }, // => + { 0x0016e , 0x00075 }, // => + { 0x0016f , 0x00075 }, // => + { 0x00170 , 0x00075 }, // => + { 0x00171 , 0x00075 }, // => + { 0x00172 , 0x00075 }, // => + { 0x00173 , 0x00075 }, // => + { 0x00174 , 0x00077 }, // => + { 0x00175 , 0x00077 }, // => + { 0x00176 , 0x00079 }, // => + { 0x00177 , 0x00079 }, // => + { 0x00178 , 0x00079 }, // => + { 0x00179 , 0x0007a }, // => + { 0x0017a , 0x0007a }, // => + { 0x0017b , 0x0007a }, // => + { 0x0017c , 0x0007a }, // => + { 0x0017d , 0x0007a }, // => + { 0x0017e , 0x0007a }, // => + { 0x0017f , 0x00073 }, // => + { 0x00181 , 0x00253 }, // => + { 0x00182 , 0x00183 }, // => + { 0x00184 , 0x00185 }, // => + { 0x00186 , 0x00254 }, // => + { 0x00187 , 0x00188 }, // => + { 0x00189 , 0x00256 }, // => + { 0x0018a , 0x00257 }, // => + { 0x0018b , 0x0018c }, // => + { 0x0018e , 0x001dd }, // => + { 0x0018f , 0x00259 }, // => + { 0x00190 , 0x0025b }, // => + { 0x00191 , 0x00192 }, // => + { 0x00193 , 0x00260 }, // => + { 0x00194 , 0x00263 }, // => + { 0x00196 , 0x00269 }, // => + { 0x00197 , 0x00268 }, // => + { 0x00198 , 0x00199 }, // => + { 0x0019c , 0x0026f }, // => + { 0x0019d , 0x00272 }, // => + { 0x0019f , 0x00275 }, // => + { 0x001a0 , 0x0006f }, // => + { 0x001a1 , 0x0006f }, // => + { 0x001a2 , 0x001a3 }, // => + { 0x001a4 , 0x001a5 }, // => + { 0x001a6 , 0x00280 }, // => + { 0x001a7 , 0x001a8 }, // => + { 0x001a9 , 0x00283 }, // => + { 0x001ac , 0x001ad }, // => + { 0x001ae , 0x00288 }, // => + { 0x001af , 0x00075 }, // => + { 0x001b0 , 0x00075 }, // => + { 0x001b1 , 0x0028a }, // => + { 0x001b2 , 0x0028b }, // => + { 0x001b3 , 0x001b4 }, // => + { 0x001b5 , 0x001b6 }, // => + { 0x001b7 , 0x00292 }, // => + { 0x001b8 , 0x001b9 }, // => + { 0x001bc , 0x001bd }, // => + { 0x001cd , 0x00061 }, // => + { 0x001ce , 0x00061 }, // => + { 0x001cf , 0x00069 }, // => + { 0x001d0 , 0x00069 }, // => + { 0x001d1 , 0x0006f }, // => + { 0x001d2 , 0x0006f }, // => + { 0x001d3 , 0x00075 }, // => + { 0x001d4 , 0x00075 }, // => + { 0x001d5 , 0x00075 }, // => + { 0x001d6 , 0x00075 }, // => + { 0x001d7 , 0x00075 }, // => + { 0x001d8 , 0x00075 }, // => + { 0x001d9 , 0x00075 }, // => + { 0x001da , 0x00075 }, // => + { 0x001db , 0x00075 }, // => + { 0x001dc , 0x00075 }, // => + { 0x001de , 0x00061 }, // => + { 0x001df , 0x00061 }, // => + { 0x001e0 , 0x00061 }, // => + { 0x001e1 , 0x00061 }, // => + { 0x001e4 , 0x001e5 }, // => + { 0x001e6 , 0x00067 }, // => + { 0x001e7 , 0x00067 }, // => + { 0x001e8 , 0x0006b }, // => + { 0x001e9 , 0x0006b }, // => + { 0x001ea , 0x0006f }, // => + { 0x001eb , 0x0006f }, // => + { 0x001ec , 0x0006f }, // => + { 0x001ed , 0x0006f }, // => + { 0x001ee , 0x00292 }, // => + { 0x001ef , 0x00292 }, // => + { 0x001f0 , 0x0006a }, // => + { 0x001f4 , 0x00067 }, // => + { 0x001f5 , 0x00067 }, // => + { 0x001f6 , 0x00195 }, // => + { 0x001f7 , 0x001bf }, // => + { 0x001f8 , 0x0006e }, // => + { 0x001f9 , 0x0006e }, // => + { 0x001fa , 0x00061 }, // => + { 0x001fb , 0x00061 }, // => + { 0x001fe , 0x0006f }, // => + { 0x001ff , 0x0006f }, // => + { 0x00200 , 0x00061 }, // => + { 0x00201 , 0x00061 }, // => + { 0x00202 , 0x00061 }, // => + { 0x00203 , 0x00061 }, // => + { 0x00204 , 0x00065 }, // => + { 0x00205 , 0x00065 }, // => + { 0x00206 , 0x00065 }, // => + { 0x00207 , 0x00065 }, // => + { 0x00208 , 0x00069 }, // => + { 0x00209 , 0x00069 }, // => + { 0x0020a , 0x00069 }, // => + { 0x0020b , 0x00069 }, // => + { 0x0020c , 0x0006f }, // => + { 0x0020d , 0x0006f }, // => + { 0x0020e , 0x0006f }, // => + { 0x0020f , 0x0006f }, // => + { 0x00210 , 0x00072 }, // => + { 0x00211 , 0x00072 }, // => + { 0x00212 , 0x00072 }, // => + { 0x00213 , 0x00072 }, // => + { 0x00214 , 0x00075 }, // => + { 0x00215 , 0x00075 }, // => + { 0x00216 , 0x00075 }, // => + { 0x00217 , 0x00075 }, // => + { 0x00218 , 0x00073 }, // => + { 0x00219 , 0x00073 }, // => + { 0x0021a , 0x00074 }, // => + { 0x0021b , 0x00074 }, // => + { 0x0021c , 0x0021d }, // => + { 0x0021e , 0x00068 }, // => + { 0x0021f , 0x00068 }, // => + { 0x00220 , 0x0019e }, // => + { 0x00222 , 0x00223 }, // => + { 0x00224 , 0x00225 }, // => + { 0x00226 , 0x00061 }, // => + { 0x00227 , 0x00061 }, // => + { 0x00228 , 0x00065 }, // => + { 0x00229 , 0x00065 }, // => + { 0x0022a , 0x0006f }, // => + { 0x0022b , 0x0006f }, // => + { 0x0022c , 0x0006f }, // => + { 0x0022d , 0x0006f }, // => + { 0x0022e , 0x0006f }, // => + { 0x0022f , 0x0006f }, // => + { 0x00230 , 0x0006f }, // => + { 0x00231 , 0x0006f }, // => + { 0x00232 , 0x00079 }, // => + { 0x00233 , 0x00079 }, // => + { 0x0023a , 0x02c65 }, // => + { 0x0023b , 0x0023c }, // => + { 0x0023d , 0x0019a }, // => + { 0x0023e , 0x02c66 }, // => + { 0x00241 , 0x00242 }, // => + { 0x00243 , 0x00180 }, // => + { 0x00244 , 0x00289 }, // => + { 0x00245 , 0x0028c }, // => + { 0x00246 , 0x00247 }, // => + { 0x00248 , 0x00249 }, // => + { 0x0024a , 0x0024b }, // => + { 0x0024c , 0x0024d }, // => + { 0x0024e , 0x0024f }, // => + { 0x002b0 , 0x00068 }, // => + { 0x002b1 , 0x00266 }, // => + { 0x002b2 , 0x0006a }, // => + { 0x002b3 , 0x00072 }, // => + { 0x002b4 , 0x00279 }, // => + { 0x002b5 , 0x0027b }, // => + { 0x002b6 , 0x00281 }, // => + { 0x002b7 , 0x00077 }, // => + { 0x002b8 , 0x00079 }, // => + { 0x002e0 , 0x00263 }, // => + { 0x002e1 , 0x0006c }, // => + { 0x002e2 , 0x00073 }, // => + { 0x002e3 , 0x00078 }, // => + { 0x002e4 , 0x00295 }, // => + { 0x00370 , 0x00371 }, // => + { 0x00372 , 0x00373 }, // => + { 0x00376 , 0x00377 }, // => + { 0x0037a , 0x003b9 }, // => + { 0x0037f , 0x003f3 }, // => + { 0x00386 , 0x003b1 }, // => + { 0x00388 , 0x003b5 }, // => + { 0x00389 , 0x003b7 }, // => + { 0x0038a , 0x003b9 }, // => + { 0x0038c , 0x003bf }, // => + { 0x0038e , 0x003c5 }, // => + { 0x0038f , 0x003c9 }, // => + { 0x00390 , 0x003b9 }, // => + { 0x00391 , 0x003b1 }, // => + { 0x00392 , 0x003b2 }, // => + { 0x00393 , 0x003b3 }, // => + { 0x00394 , 0x003b4 }, // => + { 0x00395 , 0x003b5 }, // => + { 0x00396 , 0x003b6 }, // => + { 0x00397 , 0x003b7 }, // => + { 0x00398 , 0x003b8 }, // => + { 0x00399 , 0x003b9 }, // => + { 0x0039a , 0x003ba }, // => + { 0x0039b , 0x003bb }, // => + { 0x0039c , 0x003bc }, // => + { 0x0039d , 0x003bd }, // => + { 0x0039e , 0x003be }, // => + { 0x0039f , 0x003bf }, // => + { 0x003a0 , 0x003c0 }, // => + { 0x003a1 , 0x003c1 }, // => + { 0x003a3 , 0x003c3 }, // => + { 0x003a4 , 0x003c4 }, // => + { 0x003a5 , 0x003c5 }, // => + { 0x003a6 , 0x003c6 }, // => + { 0x003a7 , 0x003c7 }, // => + { 0x003a8 , 0x003c8 }, // => + { 0x003a9 , 0x003c9 }, // => + { 0x003aa , 0x003b9 }, // => + { 0x003ab , 0x003c5 }, // => + { 0x003ac , 0x003b1 }, // => + { 0x003ad , 0x003b5 }, // => + { 0x003ae , 0x003b7 }, // => + { 0x003af , 0x003b9 }, // => + { 0x003b0 , 0x003c5 }, // => + { 0x003c2 , 0x003c3 }, // => + { 0x003ca , 0x003b9 }, // => + { 0x003cb , 0x003c5 }, // => + { 0x003cc , 0x003bf }, // => + { 0x003cd , 0x003c5 }, // => + { 0x003ce , 0x003c9 }, // => + { 0x003d0 , 0x003b2 }, // => + { 0x003d1 , 0x003b8 }, // => + { 0x003d2 , 0x003c5 }, // => + { 0x003d3 , 0x003c5 }, // => + { 0x003d4 , 0x003c5 }, // => + { 0x003d5 , 0x003c6 }, // => + { 0x003d6 , 0x003c0 }, // => + { 0x003d8 , 0x003d9 }, // => + { 0x003da , 0x003db }, // => + { 0x003dc , 0x003dd }, // => + { 0x003de , 0x003df }, // => + { 0x003e0 , 0x003e1 }, // => + { 0x003e2 , 0x003e3 }, // => + { 0x003e4 , 0x003e5 }, // => + { 0x003e6 , 0x003e7 }, // => + { 0x003e8 , 0x003e9 }, // => + { 0x003ea , 0x003eb }, // => + { 0x003ec , 0x003ed }, // => + { 0x003ee , 0x003ef }, // => + { 0x003f0 , 0x003ba }, // => + { 0x003f1 , 0x003c1 }, // => + { 0x003f2 , 0x003c3 }, // => + { 0x003f4 , 0x003b8 }, // => + { 0x003f5 , 0x003b5 }, // => + { 0x003f7 , 0x003f8 }, // => + { 0x003f9 , 0x003c3 }, // => + { 0x003fa , 0x003fb }, // => + { 0x003fd , 0x0037b }, // => + { 0x003fe , 0x0037c }, // => + { 0x003ff , 0x0037d }, // => + { 0x00400 , 0x00435 }, // => + { 0x00401 , 0x00435 }, // => + { 0x00402 , 0x00452 }, // => + { 0x00403 , 0x00433 }, // => + { 0x00404 , 0x00454 }, // => + { 0x00405 , 0x00455 }, // => + { 0x00406 , 0x00456 }, // => + { 0x00407 , 0x00456 }, // => + { 0x00408 , 0x00458 }, // => + { 0x00409 , 0x00459 }, // => + { 0x0040a , 0x0045a }, // => + { 0x0040b , 0x0045b }, // => + { 0x0040c , 0x0043a }, // => + { 0x0040d , 0x00438 }, // => + { 0x0040e , 0x00443 }, // => + { 0x0040f , 0x0045f }, // => + { 0x00410 , 0x00430 }, // => + { 0x00411 , 0x00431 }, // => + { 0x00412 , 0x00432 }, // => + { 0x00413 , 0x00433 }, // => + { 0x00414 , 0x00434 }, // => + { 0x00415 , 0x00435 }, // => + { 0x00416 , 0x00436 }, // => + { 0x00417 , 0x00437 }, // => + { 0x00418 , 0x00438 }, // => + { 0x00419 , 0x00439 }, // => + { 0x0041a , 0x0043a }, // => + { 0x0041b , 0x0043b }, // => + { 0x0041c , 0x0043c }, // => + { 0x0041d , 0x0043d }, // => + { 0x0041e , 0x0043e }, // => + { 0x0041f , 0x0043f }, // => + { 0x00420 , 0x00440 }, // => + { 0x00421 , 0x00441 }, // => + { 0x00422 , 0x00442 }, // => + { 0x00423 , 0x00443 }, // => + { 0x00424 , 0x00444 }, // => + { 0x00425 , 0x00445 }, // => + { 0x00426 , 0x00446 }, // => + { 0x00427 , 0x00447 }, // => + { 0x00428 , 0x00448 }, // => + { 0x00429 , 0x00449 }, // => + { 0x0042a , 0x0044a }, // => + { 0x0042b , 0x0044b }, // => + { 0x0042c , 0x0044c }, // => + { 0x0042d , 0x0044d }, // => + { 0x0042e , 0x0044e }, // => + { 0x0042f , 0x0044f }, // => + { 0x00450 , 0x00435 }, // => + { 0x00451 , 0x00435 }, // => + { 0x00453 , 0x00433 }, // => + { 0x00457 , 0x00456 }, // => + { 0x0045c , 0x0043a }, // => + { 0x0045d , 0x00438 }, // => + { 0x0045e , 0x00443 }, // => + { 0x00460 , 0x00461 }, // => + { 0x00462 , 0x00463 }, // => + { 0x00464 , 0x00465 }, // => + { 0x00466 , 0x00467 }, // => + { 0x00468 , 0x00469 }, // => + { 0x0046a , 0x0046b }, // => + { 0x0046c , 0x0046d }, // => + { 0x0046e , 0x0046f }, // => + { 0x00470 , 0x00471 }, // => + { 0x00472 , 0x00473 }, // => + { 0x00474 , 0x00475 }, // => + { 0x00476 , 0x00475 }, // => + { 0x00477 , 0x00475 }, // => + { 0x00478 , 0x00479 }, // => + { 0x0047a , 0x0047b }, // => + { 0x0047c , 0x0047d }, // => + { 0x0047e , 0x0047f }, // => + { 0x00480 , 0x00481 }, // => + { 0x0048a , 0x0048b }, // => + { 0x0048c , 0x0048d }, // => + { 0x0048e , 0x0048f }, // => + { 0x00490 , 0x00433 }, // => + { 0x00491 , 0x00433 }, // => + { 0x00492 , 0x00493 }, // => + { 0x00494 , 0x00495 }, // => + { 0x00496 , 0x00497 }, // => + { 0x00498 , 0x00499 }, // => + { 0x0049a , 0x0049b }, // => + { 0x0049c , 0x0049d }, // => + { 0x0049e , 0x0049f }, // => + { 0x004a0 , 0x004a1 }, // => + { 0x004a2 , 0x004a3 }, // => + { 0x004a4 , 0x004a5 }, // => + { 0x004a6 , 0x004a7 }, // => + { 0x004a8 , 0x004a9 }, // => + { 0x004aa , 0x004ab }, // => + { 0x004ac , 0x004ad }, // => + { 0x004ae , 0x004af }, // => + { 0x004b0 , 0x004b1 }, // => + { 0x004b2 , 0x004b3 }, // => + { 0x004b4 , 0x004b5 }, // => + { 0x004b6 , 0x004b7 }, // => + { 0x004b8 , 0x004b9 }, // => + { 0x004ba , 0x004bb }, // => + { 0x004bc , 0x004bd }, // => + { 0x004be , 0x004bf }, // => + { 0x004c0 , 0x004cf }, // => + { 0x004c1 , 0x00436 }, // => + { 0x004c2 , 0x00436 }, // => + { 0x004c3 , 0x004c4 }, // => + { 0x004c5 , 0x004c6 }, // => + { 0x004c7 , 0x004c8 }, // => + { 0x004c9 , 0x004ca }, // => + { 0x004cb , 0x004cc }, // => + { 0x004cd , 0x004ce }, // => + { 0x004d0 , 0x00430 }, // => + { 0x004d1 , 0x00430 }, // => + { 0x004d2 , 0x00430 }, // => + { 0x004d3 , 0x00430 }, // => + { 0x004d4 , 0x004d5 }, // => + { 0x004d6 , 0x00435 }, // => + { 0x004d7 , 0x00435 }, // => + { 0x004d8 , 0x004d9 }, // => + { 0x004da , 0x004d9 }, // => + { 0x004db , 0x004d9 }, // => + { 0x004dc , 0x00436 }, // => + { 0x004dd , 0x00436 }, // => + { 0x004de , 0x00437 }, // => + { 0x004df , 0x00437 }, // => + { 0x004e0 , 0x004e1 }, // => + { 0x004e2 , 0x00438 }, // => + { 0x004e3 , 0x00438 }, // => + { 0x004e4 , 0x00438 }, // => + { 0x004e5 , 0x00438 }, // => + { 0x004e6 , 0x0043e }, // => + { 0x004e7 , 0x0043e }, // => + { 0x004e8 , 0x004e9 }, // => + { 0x004ea , 0x004e9 }, // => + { 0x004eb , 0x004e9 }, // => + { 0x004ec , 0x0044d }, // => + { 0x004ed , 0x0044d }, // => + { 0x004ee , 0x00443 }, // => + { 0x004ef , 0x00443 }, // => + { 0x004f0 , 0x00443 }, // => + { 0x004f1 , 0x00443 }, // => + { 0x004f2 , 0x00443 }, // => + { 0x004f3 , 0x00443 }, // => + { 0x004f4 , 0x00447 }, // => + { 0x004f5 , 0x00447 }, // => + { 0x004f6 , 0x004f7 }, // => + { 0x004f8 , 0x0044b }, // => + { 0x004f9 , 0x0044b }, // => + { 0x004fa , 0x004fb }, // => + { 0x004fc , 0x004fd }, // => + { 0x004fe , 0x004ff }, // => + { 0x00500 , 0x00501 }, // => + { 0x00502 , 0x00503 }, // => + { 0x00504 , 0x00505 }, // => + { 0x00506 , 0x00507 }, // => + { 0x00508 , 0x00509 }, // => + { 0x0050a , 0x0050b }, // => + { 0x0050c , 0x0050d }, // => + { 0x0050e , 0x0050f }, // => + { 0x00510 , 0x00511 }, // => + { 0x00512 , 0x00513 }, // => + { 0x00514 , 0x00515 }, // => + { 0x00516 , 0x00517 }, // => + { 0x00518 , 0x00519 }, // => + { 0x0051a , 0x0051b }, // => + { 0x0051c , 0x0051d }, // => + { 0x0051e , 0x0051f }, // => + { 0x00520 , 0x00521 }, // => + { 0x00522 , 0x00523 }, // => + { 0x00524 , 0x00525 }, // => + { 0x00526 , 0x00527 }, // => + { 0x00528 , 0x00529 }, // => + { 0x0052a , 0x0052b }, // => + { 0x0052c , 0x0052d }, // => + { 0x0052e , 0x0052f }, // => + { 0x00531 , 0x00561 }, // => + { 0x00532 , 0x00562 }, // => + { 0x00533 , 0x00563 }, // => + { 0x00534 , 0x00564 }, // => + { 0x00535 , 0x00565 }, // => + { 0x00536 , 0x00566 }, // => + { 0x00537 , 0x00567 }, // => + { 0x00538 , 0x00568 }, // => + { 0x00539 , 0x00569 }, // => + { 0x0053a , 0x0056a }, // => + { 0x0053b , 0x0056b }, // => + { 0x0053c , 0x0056c }, // => + { 0x0053d , 0x0056d }, // => + { 0x0053e , 0x0056e }, // => + { 0x0053f , 0x0056f }, // => + { 0x00540 , 0x00570 }, // => + { 0x00541 , 0x00571 }, // => + { 0x00542 , 0x00572 }, // => + { 0x00543 , 0x00573 }, // => + { 0x00544 , 0x00574 }, // => + { 0x00545 , 0x00575 }, // => + { 0x00546 , 0x00576 }, // => + { 0x00547 , 0x00577 }, // => + { 0x00548 , 0x00578 }, // => + { 0x00549 , 0x00579 }, // => + { 0x0054a , 0x0057a }, // => + { 0x0054b , 0x0057b }, // => + { 0x0054c , 0x0057c }, // => + { 0x0054d , 0x0057d }, // => + { 0x0054e , 0x0057e }, // => + { 0x0054f , 0x0057f }, // => + { 0x00550 , 0x00580 }, // => + { 0x00551 , 0x00581 }, // => + { 0x00552 , 0x00582 }, // => + { 0x00553 , 0x00583 }, // => + { 0x00554 , 0x00584 }, // => + { 0x00555 , 0x00585 }, // => + { 0x00556 , 0x00586 }, // => + { 0x005da , 0x005db }, // => + { 0x005dd , 0x005de }, // => + { 0x005df , 0x005e0 }, // => + { 0x005e3 , 0x005e4 }, // => + { 0x005e5 , 0x005e6 }, // => + { 0x00660 , 0x00030 }, // => + { 0x00661 , 0x00031 }, // => + { 0x00662 , 0x00032 }, // => + { 0x00663 , 0x00033 }, // => + { 0x00664 , 0x00034 }, // => + { 0x00665 , 0x00035 }, // => + { 0x00666 , 0x00036 }, // => + { 0x00667 , 0x00037 }, // => + { 0x00668 , 0x00038 }, // => + { 0x00669 , 0x00039 }, // => + { 0x00674 , 0x00621 }, // => + { 0x006c0 , 0x006d5 }, // => + { 0x006c2 , 0x006c1 }, // => + { 0x006d3 , 0x006d2 }, // => + { 0x006e5 , 0x00648 }, // => + { 0x006e6 , 0x0064a }, // => + { 0x006f0 , 0x00030 }, // => + { 0x006f1 , 0x00031 }, // => + { 0x006f2 , 0x00032 }, // => + { 0x006f3 , 0x00033 }, // => + { 0x006f4 , 0x00034 }, // => + { 0x006f5 , 0x00035 }, // => + { 0x006f6 , 0x00036 }, // => + { 0x006f7 , 0x00037 }, // => + { 0x006f8 , 0x00038 }, // => + { 0x006f9 , 0x00039 }, // => + { 0x00714 , 0x00713 }, // => + { 0x0071c , 0x0071b }, // => + { 0x00724 , 0x00723 }, // => + { 0x00727 , 0x00726 }, // => + { 0x0072d , 0x00712 }, // => + { 0x0072e , 0x00713 }, // => + { 0x0072f , 0x00715 }, // => + { 0x007c0 , 0x00030 }, // => + { 0x007c1 , 0x00031 }, // => + { 0x007c2 , 0x00032 }, // => + { 0x007c3 , 0x00033 }, // => + { 0x007c4 , 0x00034 }, // => + { 0x007c5 , 0x00035 }, // => + { 0x007c6 , 0x00036 }, // => + { 0x007c7 , 0x00037 }, // => + { 0x007c8 , 0x00038 }, // => + { 0x007c9 , 0x00039 }, // => + { 0x007e8 , 0x007d6 }, // => + { 0x007e9 , 0x007d7 }, // => + { 0x007ea , 0x007d9 }, // => + { 0x008ad , 0x00627 }, // => + { 0x00929 , 0x00928 }, // => + { 0x00931 , 0x00930 }, // => + { 0x00934 , 0x00933 }, // => + { 0x00958 , 0x00915 }, // => + { 0x00959 , 0x00916 }, // => + { 0x0095a , 0x00917 }, // => + { 0x0095b , 0x0091c }, // => + { 0x0095c , 0x00921 }, // => + { 0x0095d , 0x00922 }, // => + { 0x0095e , 0x0092b }, // => + { 0x0095f , 0x0092f }, // => + { 0x00966 , 0x00030 }, // => + { 0x00967 , 0x00031 }, // => + { 0x00968 , 0x00032 }, // => + { 0x00969 , 0x00033 }, // => + { 0x0096a , 0x00034 }, // => + { 0x0096b , 0x00035 }, // => + { 0x0096c , 0x00036 }, // => + { 0x0096d , 0x00037 }, // => + { 0x0096e , 0x00038 }, // => + { 0x0096f , 0x00039 }, // => + { 0x009dc , 0x009a1 }, // => + { 0x009dd , 0x009a2 }, // => + { 0x009df , 0x009af }, // => + { 0x009e6 , 0x00030 }, // => + { 0x009e7 , 0x00031 }, // => + { 0x009e8 , 0x00032 }, // => + { 0x009e9 , 0x00033 }, // => + { 0x009ea , 0x00034 }, // => + { 0x009eb , 0x00035 }, // => + { 0x009ec , 0x00036 }, // => + { 0x009ed , 0x00037 }, // => + { 0x009ee , 0x00038 }, // => + { 0x009ef , 0x00039 }, // => + { 0x00a33 , 0x00a32 }, // => + { 0x00a36 , 0x00a38 }, // => + { 0x00a59 , 0x00a16 }, // => + { 0x00a5a , 0x00a17 }, // => + { 0x00a5b , 0x00a1c }, // => + { 0x00a5e , 0x00a2b }, // => + { 0x00a66 , 0x00030 }, // => + { 0x00a67 , 0x00031 }, // => + { 0x00a68 , 0x00032 }, // => + { 0x00a69 , 0x00033 }, // => + { 0x00a6a , 0x00034 }, // => + { 0x00a6b , 0x00035 }, // => + { 0x00a6c , 0x00036 }, // => + { 0x00a6d , 0x00037 }, // => + { 0x00a6e , 0x00038 }, // => + { 0x00a6f , 0x00039 }, // => + { 0x00ae6 , 0x00030 }, // => + { 0x00ae7 , 0x00031 }, // => + { 0x00ae8 , 0x00032 }, // => + { 0x00ae9 , 0x00033 }, // => + { 0x00aea , 0x00034 }, // => + { 0x00aeb , 0x00035 }, // => + { 0x00aec , 0x00036 }, // => + { 0x00aed , 0x00037 }, // => + { 0x00aee , 0x00038 }, // => + { 0x00aef , 0x00039 }, // => + { 0x00b5c , 0x00b21 }, // => + { 0x00b5d , 0x00b22 }, // => + { 0x00b66 , 0x00030 }, // => + { 0x00b67 , 0x00031 }, // => + { 0x00b68 , 0x00032 }, // => + { 0x00b69 , 0x00033 }, // => + { 0x00b6a , 0x00034 }, // => + { 0x00b6b , 0x00035 }, // => + { 0x00b6c , 0x00036 }, // => + { 0x00b6d , 0x00037 }, // => + { 0x00b6e , 0x00038 }, // => + { 0x00b6f , 0x00039 }, // => + { 0x00be6 , 0x00030 }, // => + { 0x00be7 , 0x00031 }, // => + { 0x00be8 , 0x00032 }, // => + { 0x00be9 , 0x00033 }, // => + { 0x00bea , 0x00034 }, // => + { 0x00beb , 0x00035 }, // => + { 0x00bec , 0x00036 }, // => + { 0x00bed , 0x00037 }, // => + { 0x00bee , 0x00038 }, // => + { 0x00bef , 0x00039 }, // => + { 0x00c66 , 0x00030 }, // => + { 0x00c67 , 0x00031 }, // => + { 0x00c68 , 0x00032 }, // => + { 0x00c69 , 0x00033 }, // => + { 0x00c6a , 0x00034 }, // => + { 0x00c6b , 0x00035 }, // => + { 0x00c6c , 0x00036 }, // => + { 0x00c6d , 0x00037 }, // => + { 0x00c6e , 0x00038 }, // => + { 0x00c6f , 0x00039 }, // => + { 0x00c78 , 0x00030 }, // => + { 0x00c79 , 0x00031 }, // => + { 0x00c7a , 0x00032 }, // => + { 0x00c7b , 0x00033 }, // => + { 0x00c7c , 0x00031 }, // => + { 0x00c7d , 0x00032 }, // => + { 0x00c7e , 0x00033 }, // => + { 0x00ce6 , 0x00030 }, // => + { 0x00ce7 , 0x00031 }, // => + { 0x00ce8 , 0x00032 }, // => + { 0x00ce9 , 0x00033 }, // => + { 0x00cea , 0x00034 }, // => + { 0x00ceb , 0x00035 }, // => + { 0x00cec , 0x00036 }, // => + { 0x00ced , 0x00037 }, // => + { 0x00cee , 0x00038 }, // => + { 0x00cef , 0x00039 }, // => + { 0x00d66 , 0x00030 }, // => + { 0x00d67 , 0x00031 }, // => + { 0x00d68 , 0x00032 }, // => + { 0x00d69 , 0x00033 }, // => + { 0x00d6a , 0x00034 }, // => + { 0x00d6b , 0x00035 }, // => + { 0x00d6c , 0x00036 }, // => + { 0x00d6d , 0x00037 }, // => + { 0x00d6e , 0x00038 }, // => + { 0x00d6f , 0x00039 }, // => + { 0x00de6 , 0x00030 }, // => + { 0x00de7 , 0x00031 }, // => + { 0x00de8 , 0x00032 }, // => + { 0x00de9 , 0x00033 }, // => + { 0x00dea , 0x00034 }, // => + { 0x00deb , 0x00035 }, // => + { 0x00dec , 0x00036 }, // => + { 0x00ded , 0x00037 }, // => + { 0x00dee , 0x00038 }, // => + { 0x00def , 0x00039 }, // => + { 0x00e50 , 0x00030 }, // => + { 0x00e51 , 0x00031 }, // => + { 0x00e52 , 0x00032 }, // => + { 0x00e53 , 0x00033 }, // => + { 0x00e54 , 0x00034 }, // => + { 0x00e55 , 0x00035 }, // => + { 0x00e56 , 0x00036 }, // => + { 0x00e57 , 0x00037 }, // => + { 0x00e58 , 0x00038 }, // => + { 0x00e59 , 0x00039 }, // => + { 0x00ed0 , 0x00030 }, // => + { 0x00ed1 , 0x00031 }, // => + { 0x00ed2 , 0x00032 }, // => + { 0x00ed3 , 0x00033 }, // => + { 0x00ed4 , 0x00034 }, // => + { 0x00ed5 , 0x00035 }, // => + { 0x00ed6 , 0x00036 }, // => + { 0x00ed7 , 0x00037 }, // => + { 0x00ed8 , 0x00038 }, // => + { 0x00ed9 , 0x00039 }, // => + { 0x00f20 , 0x00030 }, // => + { 0x00f21 , 0x00031 }, // => + { 0x00f22 , 0x00032 }, // => + { 0x00f23 , 0x00033 }, // => + { 0x00f24 , 0x00034 }, // => + { 0x00f25 , 0x00035 }, // => + { 0x00f26 , 0x00036 }, // => + { 0x00f27 , 0x00037 }, // => + { 0x00f28 , 0x00038 }, // => + { 0x00f29 , 0x00039 }, // => + { 0x00f2a , 0x00031 }, // => + { 0x00f2b , 0x00032 }, // => + { 0x00f2c , 0x00033 }, // => + { 0x00f2d , 0x00034 }, // => + { 0x00f2e , 0x00035 }, // => + { 0x00f2f , 0x00036 }, // => + { 0x00f30 , 0x00037 }, // => + { 0x00f31 , 0x00038 }, // => + { 0x00f32 , 0x00039 }, // => + { 0x00f33 , 0x00030 }, // => + { 0x00f6a , 0x00f62 }, // => + { 0x01040 , 0x00030 }, // => + { 0x01041 , 0x00031 }, // => + { 0x01042 , 0x00032 }, // => + { 0x01043 , 0x00033 }, // => + { 0x01044 , 0x00034 }, // => + { 0x01045 , 0x00035 }, // => + { 0x01046 , 0x00036 }, // => + { 0x01047 , 0x00037 }, // => + { 0x01048 , 0x00038 }, // => + { 0x01049 , 0x00039 }, // => + { 0x01090 , 0x00030 }, // => + { 0x01091 , 0x00031 }, // => + { 0x01092 , 0x00032 }, // => + { 0x01093 , 0x00033 }, // => + { 0x01094 , 0x00034 }, // => + { 0x01095 , 0x00035 }, // => + { 0x01096 , 0x00036 }, // => + { 0x01097 , 0x00037 }, // => + { 0x01098 , 0x00038 }, // => + { 0x01099 , 0x00039 }, // => + { 0x010a0 , 0x02d00 }, // => + { 0x010a1 , 0x02d01 }, // => + { 0x010a2 , 0x02d02 }, // => + { 0x010a3 , 0x02d03 }, // => + { 0x010a4 , 0x02d04 }, // => + { 0x010a5 , 0x02d05 }, // => + { 0x010a6 , 0x02d06 }, // => + { 0x010a7 , 0x02d07 }, // => + { 0x010a8 , 0x02d08 }, // => + { 0x010a9 , 0x02d09 }, // => + { 0x010aa , 0x02d0a }, // => + { 0x010ab , 0x02d0b }, // => + { 0x010ac , 0x02d0c }, // => + { 0x010ad , 0x02d0d }, // => + { 0x010ae , 0x02d0e }, // => + { 0x010af , 0x02d0f }, // => + { 0x010b0 , 0x02d10 }, // => + { 0x010b1 , 0x02d11 }, // => + { 0x010b2 , 0x02d12 }, // => + { 0x010b3 , 0x02d13 }, // => + { 0x010b4 , 0x02d14 }, // => + { 0x010b5 , 0x02d15 }, // => + { 0x010b6 , 0x02d16 }, // => + { 0x010b7 , 0x02d17 }, // => + { 0x010b8 , 0x02d18 }, // => + { 0x010b9 , 0x02d19 }, // => + { 0x010ba , 0x02d1a }, // => + { 0x010bb , 0x02d1b }, // => + { 0x010bc , 0x02d1c }, // => + { 0x010bd , 0x02d1d }, // => + { 0x010be , 0x02d1e }, // => + { 0x010bf , 0x02d1f }, // => + { 0x010c0 , 0x02d20 }, // => + { 0x010c1 , 0x02d21 }, // => + { 0x010c2 , 0x02d22 }, // => + { 0x010c3 , 0x02d23 }, // => + { 0x010c4 , 0x02d24 }, // => + { 0x010c5 , 0x02d25 }, // => + { 0x010c7 , 0x02d27 }, // => + { 0x010cd , 0x02d2d }, // => + { 0x010fc , 0x010dc }, // => + { 0x01369 , 0x00031 }, // => + { 0x0136a , 0x00032 }, // => + { 0x0136b , 0x00033 }, // => + { 0x0136c , 0x00034 }, // => + { 0x0136d , 0x00035 }, // => + { 0x0136e , 0x00036 }, // => + { 0x0136f , 0x00037 }, // => + { 0x01370 , 0x00038 }, // => + { 0x01371 , 0x00039 }, // => + { 0x013a0 , 0x0ab70 }, // => + { 0x013a1 , 0x0ab71 }, // => + { 0x013a2 , 0x0ab72 }, // => + { 0x013a3 , 0x0ab73 }, // => + { 0x013a4 , 0x0ab74 }, // => + { 0x013a5 , 0x0ab75 }, // => + { 0x013a6 , 0x0ab76 }, // => + { 0x013a7 , 0x0ab77 }, // => + { 0x013a8 , 0x0ab78 }, // => + { 0x013a9 , 0x0ab79 }, // => + { 0x013aa , 0x0ab7a }, // => + { 0x013ab , 0x0ab7b }, // => + { 0x013ac , 0x0ab7c }, // => + { 0x013ad , 0x0ab7d }, // => + { 0x013ae , 0x0ab7e }, // => + { 0x013af , 0x0ab7f }, // => + { 0x013b0 , 0x0ab80 }, // => + { 0x013b1 , 0x0ab81 }, // => + { 0x013b2 , 0x0ab82 }, // => + { 0x013b3 , 0x0ab83 }, // => + { 0x013b4 , 0x0ab84 }, // => + { 0x013b5 , 0x0ab85 }, // => + { 0x013b6 , 0x0ab86 }, // => + { 0x013b7 , 0x0ab87 }, // => + { 0x013b8 , 0x0ab88 }, // => + { 0x013b9 , 0x0ab89 }, // => + { 0x013ba , 0x0ab8a }, // => + { 0x013bb , 0x0ab8b }, // => + { 0x013bc , 0x0ab8c }, // => + { 0x013bd , 0x0ab8d }, // => + { 0x013be , 0x0ab8e }, // => + { 0x013bf , 0x0ab8f }, // => + { 0x013c0 , 0x0ab90 }, // => + { 0x013c1 , 0x0ab91 }, // => + { 0x013c2 , 0x0ab92 }, // => + { 0x013c3 , 0x0ab93 }, // => + { 0x013c4 , 0x0ab94 }, // => + { 0x013c5 , 0x0ab95 }, // => + { 0x013c6 , 0x0ab96 }, // => + { 0x013c7 , 0x0ab97 }, // => + { 0x013c8 , 0x0ab98 }, // => + { 0x013c9 , 0x0ab99 }, // => + { 0x013ca , 0x0ab9a }, // => + { 0x013cb , 0x0ab9b }, // => + { 0x013cc , 0x0ab9c }, // => + { 0x013cd , 0x0ab9d }, // => + { 0x013ce , 0x0ab9e }, // => + { 0x013cf , 0x0ab9f }, // => + { 0x013d0 , 0x0aba0 }, // => + { 0x013d1 , 0x0aba1 }, // => + { 0x013d2 , 0x0aba2 }, // => + { 0x013d3 , 0x0aba3 }, // => + { 0x013d4 , 0x0aba4 }, // => + { 0x013d5 , 0x0aba5 }, // => + { 0x013d6 , 0x0aba6 }, // => + { 0x013d7 , 0x0aba7 }, // => + { 0x013d8 , 0x0aba8 }, // => + { 0x013d9 , 0x0aba9 }, // => + { 0x013da , 0x0abaa }, // => + { 0x013db , 0x0abab }, // => + { 0x013dc , 0x0abac }, // => + { 0x013dd , 0x0abad }, // => + { 0x013de , 0x0abae }, // => + { 0x013df , 0x0abaf }, // => + { 0x013e0 , 0x0abb0 }, // => + { 0x013e1 , 0x0abb1 }, // => + { 0x013e2 , 0x0abb2 }, // => + { 0x013e3 , 0x0abb3 }, // => + { 0x013e4 , 0x0abb4 }, // => + { 0x013e5 , 0x0abb5 }, // => + { 0x013e6 , 0x0abb6 }, // => + { 0x013e7 , 0x0abb7 }, // => + { 0x013e8 , 0x0abb8 }, // => + { 0x013e9 , 0x0abb9 }, // => + { 0x013ea , 0x0abba }, // => + { 0x013eb , 0x0abbb }, // => + { 0x013ec , 0x0abbc }, // => + { 0x013ed , 0x0abbd }, // => + { 0x013ee , 0x0abbe }, // => + { 0x013ef , 0x0abbf }, // => + { 0x013f0 , 0x013f8 }, // => + { 0x013f1 , 0x013f9 }, // => + { 0x013f2 , 0x013fa }, // => + { 0x013f3 , 0x013fb }, // => + { 0x013f4 , 0x013fc }, // => + { 0x013f5 , 0x013fd }, // => + { 0x016a1 , 0x016a0 }, // => + { 0x016a4 , 0x016a2 }, // => + { 0x016a5 , 0x016a2 }, // => + { 0x016a7 , 0x016a6 }, // => + { 0x016a9 , 0x016a8 }, // => + { 0x016ac , 0x016a8 }, // => + { 0x016ad , 0x016a8 }, // => + { 0x016ae , 0x016a8 }, // => + { 0x016b3 , 0x016b2 }, // => + { 0x016b4 , 0x016b2 }, // => + { 0x016b5 , 0x016b2 }, // => + { 0x016b6 , 0x016b2 }, // => + { 0x016bb , 0x016ba }, // => + { 0x016bc , 0x016ba }, // => + { 0x016bd , 0x016ba }, // => + { 0x016bf , 0x016be }, // => + { 0x016c0 , 0x016be }, // => + { 0x016c2 , 0x016c1 }, // => + { 0x016c4 , 0x016c3 }, // => + { 0x016c6 , 0x016c5 }, // => + { 0x016cb , 0x016ca }, // => + { 0x016cc , 0x016ca }, // => + { 0x016cd , 0x016ca }, // => + { 0x016ce , 0x016ca }, // => + { 0x016d0 , 0x016cf }, // => + { 0x016d1 , 0x016cf }, // => + { 0x016d3 , 0x016d2 }, // => + { 0x016d4 , 0x016d2 }, // => + { 0x016d5 , 0x016c8 }, // => + { 0x016d8 , 0x016d7 }, // => + { 0x016d9 , 0x016d7 }, // => + { 0x016db , 0x016da }, // => + { 0x016dd , 0x016dc }, // => + { 0x016e7 , 0x016e6 }, // => + { 0x016e8 , 0x016e6 }, // => + { 0x016e9 , 0x016b9 }, // => + { 0x016ea , 0x016ca }, // => + { 0x017e0 , 0x00030 }, // => + { 0x017e1 , 0x00031 }, // => + { 0x017e2 , 0x00032 }, // => + { 0x017e3 , 0x00033 }, // => + { 0x017e4 , 0x00034 }, // => + { 0x017e5 , 0x00035 }, // => + { 0x017e6 , 0x00036 }, // => + { 0x017e7 , 0x00037 }, // => + { 0x017e8 , 0x00038 }, // => + { 0x017e9 , 0x00039 }, // => + { 0x017f0 , 0x00030 }, // => + { 0x017f1 , 0x00031 }, // => + { 0x017f2 , 0x00032 }, // => + { 0x017f3 , 0x00033 }, // => + { 0x017f4 , 0x00034 }, // => + { 0x017f5 , 0x00035 }, // => + { 0x017f6 , 0x00036 }, // => + { 0x017f7 , 0x00037 }, // => + { 0x017f8 , 0x00038 }, // => + { 0x017f9 , 0x00039 }, // => + { 0x01810 , 0x00030 }, // => + { 0x01811 , 0x00031 }, // => + { 0x01812 , 0x00032 }, // => + { 0x01813 , 0x00033 }, // => + { 0x01814 , 0x00034 }, // => + { 0x01815 , 0x00035 }, // => + { 0x01816 , 0x00036 }, // => + { 0x01817 , 0x00037 }, // => + { 0x01818 , 0x00038 }, // => + { 0x01819 , 0x00039 }, // => + { 0x01946 , 0x00030 }, // => + { 0x01947 , 0x00031 }, // => + { 0x01948 , 0x00032 }, // => + { 0x01949 , 0x00033 }, // => + { 0x0194a , 0x00034 }, // => + { 0x0194b , 0x00035 }, // => + { 0x0194c , 0x00036 }, // => + { 0x0194d , 0x00037 }, // => + { 0x0194e , 0x00038 }, // => + { 0x0194f , 0x00039 }, // => + { 0x019d0 , 0x00030 }, // => + { 0x019d1 , 0x00031 }, // => + { 0x019d2 , 0x00032 }, // => + { 0x019d3 , 0x00033 }, // => + { 0x019d4 , 0x00034 }, // => + { 0x019d5 , 0x00035 }, // => + { 0x019d6 , 0x00036 }, // => + { 0x019d7 , 0x00037 }, // => + { 0x019d8 , 0x00038 }, // => + { 0x019d9 , 0x00039 }, // => + { 0x019da , 0x00031 }, // => + { 0x01a80 , 0x00030 }, // => + { 0x01a81 , 0x00031 }, // => + { 0x01a82 , 0x00032 }, // => + { 0x01a83 , 0x00033 }, // => + { 0x01a84 , 0x00034 }, // => + { 0x01a85 , 0x00035 }, // => + { 0x01a86 , 0x00036 }, // => + { 0x01a87 , 0x00037 }, // => + { 0x01a88 , 0x00038 }, // => + { 0x01a89 , 0x00039 }, // => + { 0x01a90 , 0x00030 }, // => + { 0x01a91 , 0x00031 }, // => + { 0x01a92 , 0x00032 }, // => + { 0x01a93 , 0x00033 }, // => + { 0x01a94 , 0x00034 }, // => + { 0x01a95 , 0x00035 }, // => + { 0x01a96 , 0x00036 }, // => + { 0x01a97 , 0x00037 }, // => + { 0x01a98 , 0x00038 }, // => + { 0x01a99 , 0x00039 }, // => + { 0x01b50 , 0x00030 }, // => + { 0x01b51 , 0x00031 }, // => + { 0x01b52 , 0x00032 }, // => + { 0x01b53 , 0x00033 }, // => + { 0x01b54 , 0x00034 }, // => + { 0x01b55 , 0x00035 }, // => + { 0x01b56 , 0x00036 }, // => + { 0x01b57 , 0x00037 }, // => + { 0x01b58 , 0x00038 }, // => + { 0x01b59 , 0x00039 }, // => + { 0x01bb0 , 0x00030 }, // => + { 0x01bb1 , 0x00031 }, // => + { 0x01bb2 , 0x00032 }, // => + { 0x01bb3 , 0x00033 }, // => + { 0x01bb4 , 0x00034 }, // => + { 0x01bb5 , 0x00035 }, // => + { 0x01bb6 , 0x00036 }, // => + { 0x01bb7 , 0x00037 }, // => + { 0x01bb8 , 0x00038 }, // => + { 0x01bb9 , 0x00039 }, // => + { 0x01bba , 0x01b83 }, // => + { 0x01bbe , 0x01b8a }, // => + { 0x01bbf , 0x01b99 }, // => + { 0x01bc1 , 0x01bc0 }, // => + { 0x01bc3 , 0x01bc2 }, // => + { 0x01bc4 , 0x01bc2 }, // => + { 0x01bc6 , 0x01bc5 }, // => + { 0x01bc8 , 0x01bc7 }, // => + { 0x01bca , 0x01bc9 }, // => + { 0x01bcc , 0x01bcb }, // => + { 0x01bcd , 0x01bcb }, // => + { 0x01bcf , 0x01bce }, // => + { 0x01bd3 , 0x01bd2 }, // => + { 0x01bd5 , 0x01bd4 }, // => + { 0x01bd7 , 0x01bd6 }, // => + { 0x01bd9 , 0x01bd8 }, // => + { 0x01bda , 0x01bd8 }, // => + { 0x01bdc , 0x01bdb }, // => + { 0x01bdf , 0x01bde }, // => + { 0x01c40 , 0x00030 }, // => + { 0x01c41 , 0x00031 }, // => + { 0x01c42 , 0x00032 }, // => + { 0x01c43 , 0x00033 }, // => + { 0x01c44 , 0x00034 }, // => + { 0x01c45 , 0x00035 }, // => + { 0x01c46 , 0x00036 }, // => + { 0x01c47 , 0x00037 }, // => + { 0x01c48 , 0x00038 }, // => + { 0x01c49 , 0x00039 }, // => + { 0x01c50 , 0x00030 }, //
    => + { 0x01c51 , 0x00031 }, //
      => + { 0x01c52 , 0x00032 }, //
        => + { 0x01c53 , 0x00033 }, //
          => + { 0x01c54 , 0x00034 }, //
            => + { 0x01c55 , 0x00035 }, //
              => + { 0x01c56 , 0x00036 }, //
                => + { 0x01c57 , 0x00037 }, //
                  => + { 0x01c58 , 0x00038 }, //
                    => + { 0x01c59 , 0x00039 }, //
                      => + { 0x01c80 , 0x00432 }, // => + { 0x01c81 , 0x00434 }, // => + { 0x01c82 , 0x0043e }, // => + { 0x01c83 , 0x00441 }, // => + { 0x01c84 , 0x00442 }, // => + { 0x01c85 , 0x00442 }, // => + { 0x01c86 , 0x0044a }, // => + { 0x01c87 , 0x00463 }, // => + { 0x01c88 , 0x0a64b }, // => + { 0x01cea , 0x01ce9 }, // => + { 0x01ceb , 0x01ce9 }, // => + { 0x01cec , 0x01ce9 }, // => + { 0x01cee , 0x01ce9 }, // => + { 0x01cef , 0x01ce9 }, // => + { 0x01cf0 , 0x01ce9 }, // => + { 0x01cf1 , 0x01ce9 }, // => + { 0x01d2c , 0x00061 }, // => + { 0x01d2e , 0x00062 }, // => + { 0x01d30 , 0x00064 }, // => + { 0x01d31 , 0x00065 }, // => + { 0x01d32 , 0x001dd }, // => + { 0x01d33 , 0x00067 }, // => + { 0x01d34 , 0x00068 }, // => + { 0x01d35 , 0x00069 }, // => + { 0x01d36 , 0x0006a }, // => + { 0x01d37 , 0x0006b }, // => + { 0x01d38 , 0x0006c }, // => + { 0x01d39 , 0x0006d }, // => + { 0x01d3a , 0x0006e }, // => + { 0x01d3c , 0x0006f }, // => + { 0x01d3d , 0x00223 }, // => + { 0x01d3e , 0x00070 }, // => + { 0x01d3f , 0x00072 }, // => + { 0x01d40 , 0x00074 }, // => + { 0x01d41 , 0x00075 }, // => + { 0x01d42 , 0x00077 }, // => + { 0x01d43 , 0x00061 }, // => + { 0x01d44 , 0x00250 }, // => + { 0x01d45 , 0x00251 }, // => + { 0x01d46 , 0x01d02 }, // => + { 0x01d47 , 0x00062 }, // => + { 0x01d48 , 0x00064 }, // => + { 0x01d49 , 0x00065 }, // => + { 0x01d4a , 0x00259 }, // => + { 0x01d4b , 0x0025b }, // => + { 0x01d4c , 0x01d08 }, // => + { 0x01d4d , 0x00067 }, // => + { 0x01d4e , 0x01d09 }, // => + { 0x01d4f , 0x0006b }, // => + { 0x01d50 , 0x0006d }, // => + { 0x01d51 , 0x0014b }, // => + { 0x01d52 , 0x0006f }, // => + { 0x01d53 , 0x00254 }, // => + { 0x01d54 , 0x01d16 }, // => + { 0x01d55 , 0x01d17 }, // => + { 0x01d56 , 0x00070 }, // => + { 0x01d57 , 0x00074 }, // => + { 0x01d58 , 0x00075 }, // => + { 0x01d59 , 0x01d1d }, // => + { 0x01d5a , 0x0026f }, // => + { 0x01d5b , 0x00076 }, // => + { 0x01d5c , 0x01d25 }, // => + { 0x01d5d , 0x003b2 }, // => + { 0x01d5e , 0x003b3 }, // => + { 0x01d5f , 0x003b4 }, // => + { 0x01d60 , 0x003c6 }, // => + { 0x01d61 , 0x003c7 }, // => + { 0x01d62 , 0x00069 }, // => + { 0x01d63 , 0x00072 }, // => + { 0x01d64 , 0x00075 }, // => + { 0x01d65 , 0x00076 }, // => + { 0x01d66 , 0x003b2 }, // => + { 0x01d67 , 0x003b3 }, // => + { 0x01d68 , 0x003c1 }, // => + { 0x01d69 , 0x003c6 }, // => + { 0x01d6a , 0x003c7 }, // => + { 0x01d78 , 0x0043d }, // => + { 0x01d79 , 0x00067 }, // => + { 0x01d9b , 0x00252 }, // => + { 0x01d9c , 0x00063 }, // => + { 0x01d9d , 0x00255 }, // => + { 0x01d9e , 0x00064 }, // => + { 0x01d9f , 0x0025c }, // => + { 0x01da0 , 0x00066 }, // => + { 0x01da1 , 0x0025f }, // => + { 0x01da2 , 0x00261 }, // => + { 0x01da3 , 0x00265 }, // => + { 0x01da4 , 0x00268 }, // => + { 0x01da5 , 0x00269 }, // => + { 0x01da6 , 0x0026a }, // => + { 0x01da7 , 0x01d7b }, // => + { 0x01da8 , 0x0029d }, // => + { 0x01da9 , 0x0026d }, // => + { 0x01daa , 0x01d85 }, // => + { 0x01dab , 0x0029f }, // => + { 0x01dac , 0x00271 }, // => + { 0x01dad , 0x00270 }, // => + { 0x01dae , 0x00272 }, // => + { 0x01daf , 0x00273 }, // => + { 0x01db0 , 0x00274 }, // => + { 0x01db1 , 0x00275 }, // => + { 0x01db2 , 0x00278 }, // => + { 0x01db3 , 0x00282 }, // => + { 0x01db4 , 0x00283 }, // => + { 0x01db5 , 0x001ab }, // => + { 0x01db6 , 0x00289 }, // => + { 0x01db7 , 0x0028a }, // => + { 0x01db8 , 0x01d1c }, // => + { 0x01db9 , 0x0028b }, // => + { 0x01dba , 0x0028c }, // => + { 0x01dbb , 0x0007a }, // => + { 0x01dbc , 0x00290 }, // => + { 0x01dbd , 0x00291 }, // => + { 0x01dbe , 0x00292 }, // => + { 0x01dbf , 0x003b8 }, // => + { 0x01e00 , 0x00061 }, // => + { 0x01e01 , 0x00061 }, // => + { 0x01e02 , 0x00062 }, // => + { 0x01e03 , 0x00062 }, // => + { 0x01e04 , 0x00062 }, // => + { 0x01e05 , 0x00062 }, // => + { 0x01e06 , 0x00062 }, // => + { 0x01e07 , 0x00062 }, // => + { 0x01e08 , 0x00063 }, // => + { 0x01e09 , 0x00063 }, // => + { 0x01e0a , 0x00064 }, // => + { 0x01e0b , 0x00064 }, // => + { 0x01e0c , 0x00064 }, // => + { 0x01e0d , 0x00064 }, // => + { 0x01e0e , 0x00064 }, // => + { 0x01e0f , 0x00064 }, // => + { 0x01e10 , 0x00064 }, // => + { 0x01e11 , 0x00064 }, // => + { 0x01e12 , 0x00064 }, // => + { 0x01e13 , 0x00064 }, // => + { 0x01e14 , 0x00065 }, // => + { 0x01e15 , 0x00065 }, // => + { 0x01e16 , 0x00065 }, // => + { 0x01e17 , 0x00065 }, // => + { 0x01e18 , 0x00065 }, // => + { 0x01e19 , 0x00065 }, // => + { 0x01e1a , 0x00065 }, // => + { 0x01e1b , 0x00065 }, // => + { 0x01e1c , 0x00065 }, // => + { 0x01e1d , 0x00065 }, // => + { 0x01e1e , 0x00066 }, // => + { 0x01e1f , 0x00066 }, // => + { 0x01e20 , 0x00067 }, // => + { 0x01e21 , 0x00067 }, // => + { 0x01e22 , 0x00068 }, // => + { 0x01e23 , 0x00068 }, // => + { 0x01e24 , 0x00068 }, // => + { 0x01e25 , 0x00068 }, // => + { 0x01e26 , 0x00068 }, // => + { 0x01e27 , 0x00068 }, // => + { 0x01e28 , 0x00068 }, // => + { 0x01e29 , 0x00068 }, // => + { 0x01e2a , 0x00068 }, // => + { 0x01e2b , 0x00068 }, // => + { 0x01e2c , 0x00069 }, // => + { 0x01e2d , 0x00069 }, // => + { 0x01e2e , 0x00069 }, // => + { 0x01e2f , 0x00069 }, // => + { 0x01e30 , 0x0006b }, // => + { 0x01e31 , 0x0006b }, // => + { 0x01e32 , 0x0006b }, // => + { 0x01e33 , 0x0006b }, // => + { 0x01e34 , 0x0006b }, // => + { 0x01e35 , 0x0006b }, // => + { 0x01e36 , 0x0006c }, // => + { 0x01e37 , 0x0006c }, // => + { 0x01e38 , 0x0006c }, // => + { 0x01e39 , 0x0006c }, // => + { 0x01e3a , 0x0006c }, // => + { 0x01e3b , 0x0006c }, // => + { 0x01e3c , 0x0006c }, // => + { 0x01e3d , 0x0006c }, // => + { 0x01e3e , 0x0006d }, // => + { 0x01e3f , 0x0006d }, // => + { 0x01e40 , 0x0006d }, // => + { 0x01e41 , 0x0006d }, // => + { 0x01e42 , 0x0006d }, // => + { 0x01e43 , 0x0006d }, // => + { 0x01e44 , 0x0006e }, // => + { 0x01e45 , 0x0006e }, // => + { 0x01e46 , 0x0006e }, // => + { 0x01e47 , 0x0006e }, // => + { 0x01e48 , 0x0006e }, // => + { 0x01e49 , 0x0006e }, // => + { 0x01e4a , 0x0006e }, // => + { 0x01e4b , 0x0006e }, // => + { 0x01e4c , 0x0006f }, // => + { 0x01e4d , 0x0006f }, // => + { 0x01e4e , 0x0006f }, // => + { 0x01e4f , 0x0006f }, // => + { 0x01e50 , 0x0006f }, // => + { 0x01e51 , 0x0006f }, // => + { 0x01e52 , 0x0006f }, // => + { 0x01e53 , 0x0006f }, // => + { 0x01e54 , 0x00070 }, // => + { 0x01e55 , 0x00070 }, // => + { 0x01e56 , 0x00070 }, // => + { 0x01e57 , 0x00070 }, // => + { 0x01e58 , 0x00072 }, // => + { 0x01e59 , 0x00072 }, // => + { 0x01e5a , 0x00072 }, // => + { 0x01e5b , 0x00072 }, // => + { 0x01e5c , 0x00072 }, // => + { 0x01e5d , 0x00072 }, // => + { 0x01e5e , 0x00072 }, // => + { 0x01e5f , 0x00072 }, // => + { 0x01e60 , 0x00073 }, // => + { 0x01e61 , 0x00073 }, // => + { 0x01e62 , 0x00073 }, // => + { 0x01e63 , 0x00073 }, // => + { 0x01e64 , 0x00073 }, // => + { 0x01e65 , 0x00073 }, // => + { 0x01e66 , 0x00073 }, // => + { 0x01e67 , 0x00073 }, // => + { 0x01e68 , 0x00073 }, // => + { 0x01e69 , 0x00073 }, // => + { 0x01e6a , 0x00074 }, // => + { 0x01e6b , 0x00074 }, // => + { 0x01e6c , 0x00074 }, // => + { 0x01e6d , 0x00074 }, // => + { 0x01e6e , 0x00074 }, // => + { 0x01e6f , 0x00074 }, // => + { 0x01e70 , 0x00074 }, // => + { 0x01e71 , 0x00074 }, // => + { 0x01e72 , 0x00075 }, // => + { 0x01e73 , 0x00075 }, // => + { 0x01e74 , 0x00075 }, // => + { 0x01e75 , 0x00075 }, // => + { 0x01e76 , 0x00075 }, // => + { 0x01e77 , 0x00075 }, // => + { 0x01e78 , 0x00075 }, // => + { 0x01e79 , 0x00075 }, // => + { 0x01e7a , 0x00075 }, // => + { 0x01e7b , 0x00075 }, // => + { 0x01e7c , 0x00076 }, // => + { 0x01e7d , 0x00076 }, // => + { 0x01e7e , 0x00076 }, // => + { 0x01e7f , 0x00076 }, // => + { 0x01e80 , 0x00077 }, // => + { 0x01e81 , 0x00077 }, // => + { 0x01e82 , 0x00077 }, // => + { 0x01e83 , 0x00077 }, // => + { 0x01e84 , 0x00077 }, // => + { 0x01e85 , 0x00077 }, // => + { 0x01e86 , 0x00077 }, // => + { 0x01e87 , 0x00077 }, // => + { 0x01e88 , 0x00077 }, // => + { 0x01e89 , 0x00077 }, // => + { 0x01e8a , 0x00078 }, // => + { 0x01e8b , 0x00078 }, // => + { 0x01e8c , 0x00078 }, // => + { 0x01e8d , 0x00078 }, // => + { 0x01e8e , 0x00079 }, // => + { 0x01e8f , 0x00079 }, // => + { 0x01e90 , 0x0007a }, // => + { 0x01e91 , 0x0007a }, // => + { 0x01e92 , 0x0007a }, // => + { 0x01e93 , 0x0007a }, // => + { 0x01e94 , 0x0007a }, // => + { 0x01e95 , 0x0007a }, // => + { 0x01e96 , 0x00068 }, // => + { 0x01e97 , 0x00074 }, // => + { 0x01e98 , 0x00077 }, // => + { 0x01e99 , 0x00079 }, // => + { 0x01e9b , 0x00073 }, // => + { 0x01ea0 , 0x00061 }, // => + { 0x01ea1 , 0x00061 }, // => + { 0x01ea2 , 0x00061 }, // => + { 0x01ea3 , 0x00061 }, // => + { 0x01ea4 , 0x00061 }, // => + { 0x01ea5 , 0x00061 }, // => + { 0x01ea6 , 0x00061 }, // => + { 0x01ea7 , 0x00061 }, // => + { 0x01ea8 , 0x00061 }, // => + { 0x01ea9 , 0x00061 }, // => + { 0x01eaa , 0x00061 }, // => + { 0x01eab , 0x00061 }, // => + { 0x01eac , 0x00061 }, // => + { 0x01ead , 0x00061 }, // => + { 0x01eae , 0x00061 }, // => + { 0x01eaf , 0x00061 }, // => + { 0x01eb0 , 0x00061 }, // => + { 0x01eb1 , 0x00061 }, // => + { 0x01eb2 , 0x00061 }, // => + { 0x01eb3 , 0x00061 }, // => + { 0x01eb4 , 0x00061 }, // => + { 0x01eb5 , 0x00061 }, // => + { 0x01eb6 , 0x00061 }, // => + { 0x01eb7 , 0x00061 }, // => + { 0x01eb8 , 0x00065 }, // => + { 0x01eb9 , 0x00065 }, // => + { 0x01eba , 0x00065 }, // => + { 0x01ebb , 0x00065 }, // => + { 0x01ebc , 0x00065 }, // => + { 0x01ebd , 0x00065 }, // => + { 0x01ebe , 0x00065 }, // => + { 0x01ebf , 0x00065 }, // => + { 0x01ec0 , 0x00065 }, // => + { 0x01ec1 , 0x00065 }, // => + { 0x01ec2 , 0x00065 }, // => + { 0x01ec3 , 0x00065 }, // => + { 0x01ec4 , 0x00065 }, // => + { 0x01ec5 , 0x00065 }, // => + { 0x01ec6 , 0x00065 }, // => + { 0x01ec7 , 0x00065 }, // => + { 0x01ec8 , 0x00069 }, // => + { 0x01ec9 , 0x00069 }, // => + { 0x01eca , 0x00069 }, // => + { 0x01ecb , 0x00069 }, // => + { 0x01ecc , 0x0006f }, // => + { 0x01ecd , 0x0006f }, // => + { 0x01ece , 0x0006f }, // => + { 0x01ecf , 0x0006f }, // => + { 0x01ed0 , 0x0006f }, // => + { 0x01ed1 , 0x0006f }, // => + { 0x01ed2 , 0x0006f }, // => + { 0x01ed3 , 0x0006f }, // => + { 0x01ed4 , 0x0006f }, // => + { 0x01ed5 , 0x0006f }, // => + { 0x01ed6 , 0x0006f }, // => + { 0x01ed7 , 0x0006f }, // => + { 0x01ed8 , 0x0006f }, // => + { 0x01ed9 , 0x0006f }, // => + { 0x01eda , 0x0006f }, // => + { 0x01edb , 0x0006f }, // => + { 0x01edc , 0x0006f }, // => + { 0x01edd , 0x0006f }, // => + { 0x01ede , 0x0006f }, // => + { 0x01edf , 0x0006f }, // => + { 0x01ee0 , 0x0006f }, // => + { 0x01ee1 , 0x0006f }, // => + { 0x01ee2 , 0x0006f }, // => + { 0x01ee3 , 0x0006f }, // => + { 0x01ee4 , 0x00075 }, // => + { 0x01ee5 , 0x00075 }, // => + { 0x01ee6 , 0x00075 }, // => + { 0x01ee7 , 0x00075 }, // => + { 0x01ee8 , 0x00075 }, // => + { 0x01ee9 , 0x00075 }, // => + { 0x01eea , 0x00075 }, // => + { 0x01eeb , 0x00075 }, // => + { 0x01eec , 0x00075 }, // => + { 0x01eed , 0x00075 }, // => + { 0x01eee , 0x00075 }, // => + { 0x01eef , 0x00075 }, // => + { 0x01ef0 , 0x00075 }, // => + { 0x01ef1 , 0x00075 }, // => + { 0x01ef2 , 0x00079 }, // => + { 0x01ef3 , 0x00079 }, // => + { 0x01ef4 , 0x00079 }, // => + { 0x01ef5 , 0x00079 }, // => + { 0x01ef6 , 0x00079 }, // => + { 0x01ef7 , 0x00079 }, // => + { 0x01ef8 , 0x00079 }, // => + { 0x01ef9 , 0x00079 }, // => + { 0x01efc , 0x01efd }, // => + { 0x01efe , 0x01eff }, // => + { 0x01f00 , 0x003b1 }, // => + { 0x01f01 , 0x003b1 }, // => + { 0x01f02 , 0x003b1 }, // => + { 0x01f03 , 0x003b1 }, // => + { 0x01f04 , 0x003b1 }, // => + { 0x01f05 , 0x003b1 }, // => + { 0x01f06 , 0x003b1 }, // => + { 0x01f07 , 0x003b1 }, // => + { 0x01f08 , 0x003b1 }, // => + { 0x01f09 , 0x003b1 }, // => + { 0x01f0a , 0x003b1 }, // => + { 0x01f0b , 0x003b1 }, // => + { 0x01f0c , 0x003b1 }, // => + { 0x01f0d , 0x003b1 }, // => + { 0x01f0e , 0x003b1 }, // => + { 0x01f0f , 0x003b1 }, // => + { 0x01f10 , 0x003b5 }, // => + { 0x01f11 , 0x003b5 }, // => + { 0x01f12 , 0x003b5 }, // => + { 0x01f13 , 0x003b5 }, // => + { 0x01f14 , 0x003b5 }, // => + { 0x01f15 , 0x003b5 }, // => + { 0x01f18 , 0x003b5 }, // => + { 0x01f19 , 0x003b5 }, // => + { 0x01f1a , 0x003b5 }, // => + { 0x01f1b , 0x003b5 }, // => + { 0x01f1c , 0x003b5 }, // => + { 0x01f1d , 0x003b5 }, // => + { 0x01f20 , 0x003b7 }, // => + { 0x01f21 , 0x003b7 }, // => + { 0x01f22 , 0x003b7 }, // => + { 0x01f23 , 0x003b7 }, // => + { 0x01f24 , 0x003b7 }, // => + { 0x01f25 , 0x003b7 }, // => + { 0x01f26 , 0x003b7 }, // => + { 0x01f27 , 0x003b7 }, // => + { 0x01f28 , 0x003b7 }, // => + { 0x01f29 , 0x003b7 }, // => + { 0x01f2a , 0x003b7 }, // => + { 0x01f2b , 0x003b7 }, // => + { 0x01f2c , 0x003b7 }, // => + { 0x01f2d , 0x003b7 }, // => + { 0x01f2e , 0x003b7 }, // => + { 0x01f2f , 0x003b7 }, // => + { 0x01f30 , 0x003b9 }, // => + { 0x01f31 , 0x003b9 }, // => + { 0x01f32 , 0x003b9 }, // => + { 0x01f33 , 0x003b9 }, // => + { 0x01f34 , 0x003b9 }, // => + { 0x01f35 , 0x003b9 }, // => + { 0x01f36 , 0x003b9 }, // => + { 0x01f37 , 0x003b9 }, // => + { 0x01f38 , 0x003b9 }, // => + { 0x01f39 , 0x003b9 }, // => + { 0x01f3a , 0x003b9 }, // => + { 0x01f3b , 0x003b9 }, // => + { 0x01f3c , 0x003b9 }, // => + { 0x01f3d , 0x003b9 }, // => + { 0x01f3e , 0x003b9 }, // => + { 0x01f3f , 0x003b9 }, // => + { 0x01f40 , 0x003bf }, // => + { 0x01f41 , 0x003bf }, // => + { 0x01f42 , 0x003bf }, // => + { 0x01f43 , 0x003bf }, // => + { 0x01f44 , 0x003bf }, // => + { 0x01f45 , 0x003bf }, // => + { 0x01f48 , 0x003bf }, // => + { 0x01f49 , 0x003bf }, // => + { 0x01f4a , 0x003bf }, // => + { 0x01f4b , 0x003bf }, // => + { 0x01f4c , 0x003bf }, // => + { 0x01f4d , 0x003bf }, // => + { 0x01f50 , 0x003c5 }, // => + { 0x01f51 , 0x003c5 }, // => + { 0x01f52 , 0x003c5 }, // => + { 0x01f53 , 0x003c5 }, // => + { 0x01f54 , 0x003c5 }, // => + { 0x01f55 , 0x003c5 }, // => + { 0x01f56 , 0x003c5 }, // => + { 0x01f57 , 0x003c5 }, // => + { 0x01f59 , 0x003c5 }, // => + { 0x01f5b , 0x003c5 }, // => + { 0x01f5d , 0x003c5 }, // => + { 0x01f5f , 0x003c5 }, // => + { 0x01f60 , 0x003c9 }, // => + { 0x01f61 , 0x003c9 }, // => + { 0x01f62 , 0x003c9 }, // => + { 0x01f63 , 0x003c9 }, // => + { 0x01f64 , 0x003c9 }, // => + { 0x01f65 , 0x003c9 }, // => + { 0x01f66 , 0x003c9 }, // => + { 0x01f67 , 0x003c9 }, // => + { 0x01f68 , 0x003c9 }, // => + { 0x01f69 , 0x003c9 }, // => + { 0x01f6a , 0x003c9 }, // => + { 0x01f6b , 0x003c9 }, // => + { 0x01f6c , 0x003c9 }, // => + { 0x01f6d , 0x003c9 }, // => + { 0x01f6e , 0x003c9 }, // => + { 0x01f6f , 0x003c9 }, // => + { 0x01f70 , 0x003b1 }, // => + { 0x01f71 , 0x003b1 }, // => + { 0x01f72 , 0x003b5 }, // => + { 0x01f73 , 0x003b5 }, // => + { 0x01f74 , 0x003b7 }, // => + { 0x01f75 , 0x003b7 }, // => + { 0x01f76 , 0x003b9 }, // => + { 0x01f77 , 0x003b9 }, // => + { 0x01f78 , 0x003bf }, // => + { 0x01f79 , 0x003bf }, // => + { 0x01f7a , 0x003c5 }, // => + { 0x01f7b , 0x003c5 }, // => + { 0x01f7c , 0x003c9 }, // => + { 0x01f7d , 0x003c9 }, // => + { 0x01f80 , 0x003b1 }, // => + { 0x01f81 , 0x003b1 }, // => + { 0x01f82 , 0x003b1 }, // => + { 0x01f83 , 0x003b1 }, // => + { 0x01f84 , 0x003b1 }, // => + { 0x01f85 , 0x003b1 }, // => + { 0x01f86 , 0x003b1 }, // => + { 0x01f87 , 0x003b1 }, // => + { 0x01f88 , 0x003b1 }, // => + { 0x01f89 , 0x003b1 }, // => + { 0x01f8a , 0x003b1 }, // => + { 0x01f8b , 0x003b1 }, // => + { 0x01f8c , 0x003b1 }, // => + { 0x01f8d , 0x003b1 }, // => + { 0x01f8e , 0x003b1 }, // => + { 0x01f8f , 0x003b1 }, // => + { 0x01f90 , 0x003b7 }, // => + { 0x01f91 , 0x003b7 }, // => + { 0x01f92 , 0x003b7 }, // => + { 0x01f93 , 0x003b7 }, // => + { 0x01f94 , 0x003b7 }, // => + { 0x01f95 , 0x003b7 }, // => + { 0x01f96 , 0x003b7 }, // => + { 0x01f97 , 0x003b7 }, // => + { 0x01f98 , 0x003b7 }, // => + { 0x01f99 , 0x003b7 }, // => + { 0x01f9a , 0x003b7 }, // => + { 0x01f9b , 0x003b7 }, // => + { 0x01f9c , 0x003b7 }, // => + { 0x01f9d , 0x003b7 }, // => + { 0x01f9e , 0x003b7 }, // => + { 0x01f9f , 0x003b7 }, // => + { 0x01fa0 , 0x003c9 }, // => + { 0x01fa1 , 0x003c9 }, // => + { 0x01fa2 , 0x003c9 }, // => + { 0x01fa3 , 0x003c9 }, // => + { 0x01fa4 , 0x003c9 }, // => + { 0x01fa5 , 0x003c9 }, // => + { 0x01fa6 , 0x003c9 }, // => + { 0x01fa7 , 0x003c9 }, // => + { 0x01fa8 , 0x003c9 }, // => + { 0x01fa9 , 0x003c9 }, // => + { 0x01faa , 0x003c9 }, // => + { 0x01fab , 0x003c9 }, // => + { 0x01fac , 0x003c9 }, // => + { 0x01fad , 0x003c9 }, // => + { 0x01fae , 0x003c9 }, // => + { 0x01faf , 0x003c9 }, // => + { 0x01fb0 , 0x003b1 }, // => + { 0x01fb1 , 0x003b1 }, // => + { 0x01fb2 , 0x003b1 }, // => + { 0x01fb3 , 0x003b1 }, // => + { 0x01fb4 , 0x003b1 }, // => + { 0x01fb6 , 0x003b1 }, // => + { 0x01fb7 , 0x003b1 }, // => + { 0x01fb8 , 0x003b1 }, // => + { 0x01fb9 , 0x003b1 }, // => + { 0x01fba , 0x003b1 }, // => + { 0x01fbb , 0x003b1 }, // => + { 0x01fbc , 0x003b1 }, // => + { 0x01fbe , 0x003b9 }, // => + { 0x01fc2 , 0x003b7 }, // => + { 0x01fc3 , 0x003b7 }, // => + { 0x01fc4 , 0x003b7 }, // => + { 0x01fc6 , 0x003b7 }, // => + { 0x01fc7 , 0x003b7 }, // => + { 0x01fc8 , 0x003b5 }, // => + { 0x01fc9 , 0x003b5 }, // => + { 0x01fca , 0x003b7 }, // => + { 0x01fcb , 0x003b7 }, // => + { 0x01fcc , 0x003b7 }, // => + { 0x01fd0 , 0x003b9 }, // => + { 0x01fd1 , 0x003b9 }, // => + { 0x01fd2 , 0x003b9 }, // => + { 0x01fd3 , 0x003b9 }, // => + { 0x01fd6 , 0x003b9 }, // => + { 0x01fd7 , 0x003b9 }, // => + { 0x01fd8 , 0x003b9 }, // => + { 0x01fd9 , 0x003b9 }, // => + { 0x01fda , 0x003b9 }, // => + { 0x01fdb , 0x003b9 }, // => + { 0x01fe0 , 0x003c5 }, // => + { 0x01fe1 , 0x003c5 }, // => + { 0x01fe2 , 0x003c5 }, // => + { 0x01fe3 , 0x003c5 }, // => + { 0x01fe4 , 0x003c1 }, // => + { 0x01fe5 , 0x003c1 }, // => + { 0x01fe6 , 0x003c5 }, // => + { 0x01fe7 , 0x003c5 }, // => + { 0x01fe8 , 0x003c5 }, // => + { 0x01fe9 , 0x003c5 }, // => + { 0x01fea , 0x003c5 }, // => + { 0x01feb , 0x003c5 }, // => + { 0x01fec , 0x003c1 }, // => + { 0x01ff2 , 0x003c9 }, // => + { 0x01ff3 , 0x003c9 }, // => + { 0x01ff4 , 0x003c9 }, // => + { 0x01ff6 , 0x003c9 }, // => + { 0x01ff7 , 0x003c9 }, // => + { 0x01ff8 , 0x003bf }, // => + { 0x01ff9 , 0x003bf }, // => + { 0x01ffa , 0x003c9 }, // => + { 0x01ffb , 0x003c9 }, // => + { 0x01ffc , 0x003c9 }, // => + { 0x02070 , 0x00030 }, // => + { 0x02071 , 0x00069 }, // => + { 0x02074 , 0x00034 }, // => + { 0x02075 , 0x00035 }, // => + { 0x02076 , 0x00036 }, // => + { 0x02077 , 0x00037 }, // => + { 0x02078 , 0x00038 }, // => + { 0x02079 , 0x00039 }, // => + { 0x0207f , 0x0006e }, // => + { 0x02080 , 0x00030 }, // => + { 0x02081 , 0x00031 }, // => + { 0x02082 , 0x00032 }, // => + { 0x02083 , 0x00033 }, // => + { 0x02084 , 0x00034 }, // => + { 0x02085 , 0x00035 }, // => + { 0x02086 , 0x00036 }, // => + { 0x02087 , 0x00037 }, // => + { 0x02088 , 0x00038 }, // => + { 0x02089 , 0x00039 }, // => + { 0x02090 , 0x00061 }, // => + { 0x02091 , 0x00065 }, // => + { 0x02092 , 0x0006f }, // => + { 0x02093 , 0x00078 }, // => + { 0x02094 , 0x00259 }, // => + { 0x02095 , 0x00068 }, // => + { 0x02096 , 0x0006b }, // => + { 0x02097 , 0x0006c }, // => + { 0x02098 , 0x0006d }, // => + { 0x02099 , 0x0006e }, // => + { 0x0209a , 0x00070 }, // => + { 0x0209b , 0x00073 }, // => + { 0x0209c , 0x00074 }, // => + { 0x02102 , 0x00063 }, // => + { 0x02107 , 0x0025b }, // => + { 0x0210a , 0x00067 }, //