pax_global_header00006660000000000000000000000064151113271710014511gustar00rootroot0000000000000052 comment=6d84c501354751af3960fd89fa6bff6c27c8266e nuspell-5.1.7/000077500000000000000000000000001511132717100132055ustar00rootroot00000000000000nuspell-5.1.7/.clang-format000066400000000000000000000002241511132717100155560ustar00rootroot00000000000000BasedOnStyle: LLVM IndentWidth: 8 UseTab: ForIndentation BreakBeforeBraces: Stroustrup PointerAlignment: Left AlwaysBreakTemplateDeclarations: true nuspell-5.1.7/.github/000077500000000000000000000000001511132717100145455ustar00rootroot00000000000000nuspell-5.1.7/.github/workflows/000077500000000000000000000000001511132717100166025ustar00rootroot00000000000000nuspell-5.1.7/.github/workflows/cmake.yml000066400000000000000000000053231511132717100204100ustar00rootroot00000000000000name: CMake on: [ push, pull_request ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Debug CMAKE_BUILD_PARALLEL_LEVEL: 4 CTEST_PARALLEL_LEVEL: 5 jobs: build-linux: # The CMake configure and build commands are platform agnostic and should work equally # well on Windows or Mac. You can convert this to a matrix build if you need # cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest strategy: matrix: cxxflags: [ "", "-fsanitize=address", "-fsanitize=undefined", "-Wall -Wextra -Werror" ] env: CXXFLAGS: ${{ matrix.cxxflags }} steps: - uses: actions/checkout@v4 - name: Install dependencies run: sudo apt-get update && sudo apt-get install catch2 pandoc doxygen - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Test working-directory: ${{github.workspace}}/build # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} build-windows: runs-on: windows-latest steps: - uses: actions/checkout@v4 - name: Bring runner env vars to workflows shell: bash run: | echo "local_app_data=$LOCALAPPDATA" >> $GITHUB_ENV echo "vcpkg_root=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - uses: actions/cache@v4 with: # use backslashes in path here for Windows. path: ${{ env.local_app_data }}\vcpkg\archives key: windows-vcpkg-cache-${{ hashFiles('vcpkg.json') }} restore-keys: windows-vcpkg-cache- - name: Install documentation generators run: choco install pandoc doxygen.install - name: Configure CMake run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} env: CMAKE_TOOLCHAIN_FILE: ${{ env.vcpkg_root }}/scripts/buildsystems/vcpkg.cmake - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Test working-directory: ${{github.workspace}}/build run: ctest -C ${{env.BUILD_TYPE}} nuspell-5.1.7/.gitignore000066400000000000000000000001421511132717100151720ustar00rootroot00000000000000/build/ # QtCreator /.qtcreator/ # Visual Studio /.vs/ /out/ /CMakeSettings.json # Vim .?*.swp nuspell-5.1.7/AUTHORS000066400000000000000000000001131511132717100142500ustar00rootroot00000000000000Authors of Nuspell: * Dimitrij Mijoski Contributors: * Sander van Geloven nuspell-5.1.7/CHANGELOG.md000066400000000000000000000306351511132717100150250ustar00rootroot00000000000000# Changelog Changelog of project Nuspell. All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [5.1.7] - 2025-11-25 ### Added - Add API documentation that is generated when building by Doxygen. Doxygen is a new build-only dependency. ### Changed - Raise the minimum required version of CMake to 3.18. ## [5.1.6] - 2024-07-04 ### Changed - Be more explicit about Pandoc dependency, do not quietly continue building if it is not found. Otherwise, packagers will forget to add it as dependency. Alternatively, one can disable building the docs and the dependency with the CMake option BUILD_DOCS=OFF. ### Fix - Fix compatibility with older versions of Pandoc. ## [5.1.5] - 2024-07-03 ### Added - Added man-page for the CLI tool. Pandoc is again dependency for building. ### Fixed - Fix edge case when parsing LONG flags in the .aff file. ## [5.1.4] - 2023-11-08 ### Changed - Raise the minimum required version of dependency Catch2 to v3.1.1. See #133. ## [5.1.3] - 2023-08-27 ### Added - Added Vcpkg manifest file called `vcpkg.json` for easier development and testing, mainly on Windows. ### Changed - The build-only and test-only dependency Catch2 is now pulled with `FetchContent` if first it is not found with `find_package`. The Git submodule is no longer used. ### Fixed - The documentation generated by Doxygen no longer shows the inline namespace used for versioning of the ABI. It was not of interest to users of the library. ## [5.1.2] - 2022-09-29 ### Changed - Rewrite internal testing tool verify and improve it to support testing suggestions. ### Fixed - Greatly improve the speed of suggestions in certain edge cases. See #45. - Fix minor encoding issue in the CLI tool on Windows when reading from file(s) instead of the standard input. UTF-8 is now the default encoding in that case and not the one of the console. ## [5.1.1] - 2022-09-09 ### Added - Add configuration option `BUILD_TOOLS` that can be used to disable building the CLI tool. It is ON by default. See #122. ### Changed - Made error reporting more detailed and robust. The message in the thrown exception is much richer when there are parsing errors. The library does not write directly to `cerr`, it does not pollute it. See #123. ### Fixed - Fix compiler warnings regarding usage of deprecated functions. - Fix CLI tool on Windows + MSVC to properly accept arguments. Windows + MSVC now requires library `getopt` from Vcpkg. Fixes #122. ## [5.1.0] - 2022-02-15 ### Added - Add new API for finding dictionaries on the filesystem that uses facilities from C++17 `std::filesystem`. ### Changed - Simplify CLI tool and removed some unused features from it. ### Deprecated - Deprecate old API for finding dictionaries on the filesystem that used strings for paths. ### Removed - Remove man-page for CLI tool and dependency on pandoc. Just use --help to get manual for the CLI tool. ## [5.0.1] - 2021-11-12 ### Fixed - Fix parsing of .dic files for some problematic dictionaries. Fixes #99. ### Changed - Simplify internal calls to `icu::UnicodeString::toTitle()` which results with a minor speedup. This enables Nuspell to be linked to unconventional ICU builds without break iterator, like the one in Firefox. - Require GCC 8 as minimal version of GCC because internally `std::from_chars()` is used now. ## [5.0.0] - 2021-06-12 ### Fixed - Greatly reduce memory usage. See issues #80 and #97. - Increase speed of spellchecking. - Fix long lagging when generating suggestions in edge cases. See #45. - Fix building on OS Haiku. Fixes #44. ### Changed - Split file `dictionary.hxx/cxx` into multiple files. The other files are implementation details and the public header `dictionary.hxx` is now clean of private details. ### Removed - Remove functions and classes that were deprecated in v4.x. See issue #103. ## [4.2.0] - 2020-12-12 ### Deprecated - Deprecate functions that allowed non-Unicode encoding. In particular, `Dictionary::imbue()` and `Dictionary::imbue_utf8()`. ### Removed - Completely remove dependency on Boost. The CLI tools were refactored to use ICU directly. ## [4.1.0] - 2020-11-19 ### Added - Add new API for finding dictionaries on the file-system. It is a set of free functions located in the file finder.hxx. ### Fixed - Improve searching for dictionaries on the file-system. Fix finding them on Fedora. Fixes #94. ### Deprecated - Deprecate the old API for finding dictionaries, i.e. the class `Finder` in the file finder.hxx. ## [4.0.1] - 2020-11-02 ### Fixed - Fix handling CRLF line endings in .dic. Fixes #89. - Fix CMake scripts for unusual install prefixes. - Improve hash-table insertion, avoid temporaries. This improves loading times. ### Changed - Switch man-page generator from Ronn to Pandoc. This changes the dependencies for building. See the README. ## [4.0.0] - 2020-10-19 ### Fixed - Fix lifetime issue (segmentation fault) in ngram-based suggestions. Fixes #84. - Fix internal usage of `std::codecvt` in edge case in function `to_wide()` and `to_narrow()` - Fix not propagating recursion depth in spell_break(), which caused hangup. Fixes #85. - Fix overwriting of PDB files when compiling with Visual Studio. This prevented debugging nuspell.dll. Fixes #86. - Fix output of CLI tool to be more compatible to ispell and hunspell. ### Changed - Boost is no longer a dependency of the library at all. It is still a dependency of the CLI tool. Closes #79. Fixes #71. - Use `std::string_view` in the public API instead of `const std::string&`. Also use it internally at various places. - Build as shared library by default. Building as static is still possible via the CMake's variable `BUILD_SHARED_LIBS`. - The public API is annotated with dll-export/visibility attributes, and also some private functions are annotated needed for testing. This reduces the file size. Closes #65. - Use Unicode text segmentation by default in the CLI tool. Simple segmentation on white-space is still available via CLI option. ### Removed - Delete deprecated functions in the class Finder. - Drop under-designed and undocumented feature in the CLI tool about personal dictionaries. ## [3.1.2] - 2020-07-01 ### Fixed - Internal refactorings that reduce function templates in `utils` and `finder`. ### Changed - File `utils.hxx` is not installed any more. It is a private header. ### Deprecated - Some functions for searching dictionaries in class `Finder` are deprecated as they were searching in directories that no longer contain dictionaries. ## [3.1.1] - 2020-05-04 ### Changed - Updated description in README. Packagers are encouraged to update it in their packages. - Moved Hunspell files from the directory "src" into the directory named "external" to clarify that it is third-party dependency. Previously, some packagers confused Hunspell's license notices as part of Nuspell. Hunspell is used only for testing and it is not part of the main program. ### Fixed - Fixed bugs on FreeBSD and other BSDs related to encoding conversions. Now all tests pass on FreeBSD and the support for it is not experimental anymore. - Fixed compiling on NetBSD. ## [3.1.0] - 2020-04-07 ### Added - Add so called hidden homonym feature. This feature enables words in mixed case in the dictionary to be accepted when met in uppercase in the input text. Also enables uppercase word to get lowercase suffix, and the whole derived word be accepted in all uppercase in some input text. - Improve suggestions to handle words in various casing. - Add new complex method for giving suggestions based on ngram similarity of the wrong word with the words in the dictionary. ## [3.0.0] - 2019-11-23 ### Added - Added compounding features: CHECKCOMPOUNDREP, FORCEUCASE, COMPOUNDWORDMAX. - Added compounding features specific only to Hungarian language: COMPOUNDROOT, COMPOUNDSYLLABLE, SYLLABLENUM. These three basically are extension to COMPOUNDWORDMAX. - Added six new simple suggestion methods. ### Changed - Building and using the library requires a compiler with C++17 support. - The functions of the public API now accept strings encoded in UTF-8 by default. You should not call the function `imbue()` and you should not use `locale` and `codecvt` objects at all if you need UTF-8 strings. Use `imbue()` only if you need API that accepts strings in other encoding. ### Fixed - Major improvement in speed. The best case is almost 3x faster than Hunspell, and the worst case is now matching and exceeding Hunspell's speed by a few percent. Previously, the worst case was usually triggered with incorrect words and was major bottleneck, it was slower than Hunspell. - Fixed loading Dutch dictionary, a regression introduced in 2.3.0. ## [2.3.0] - 2019-08-08 ### Added - Support for macOS - Support for building with MSVC on Windows - Support for building with pre-installed Catch 2 - Continuous integration/testing for all three major operating systems - In the CLI tool, Unicode text segmentation now can be combined with all modes. ### Changed - In Cmake the exported target has namespace, e.g. Nuspell::nuspell ### Fixed - Building from a tarball. Previously only a git clone worked. - Small internal fixes in Unicode transformations on Windows (because wchar_t is 16 bits there). - Major improvements in aff parser brings better error handling. ## [2.2.0] - 2019-03-19 ### Added - Added build System CMake. Supports building as shared library. ### Changed - Public API changed again, last for v2: - `Dictionary::suggest()` return data inside simple `vector`. `List_Strings` is not used anymore. - Constructors of class `Dictionary` like `Dictionary::load_from_path()` throw `Dictionary_Loading_Error` on error. Previously they were throwing `ios_base::failure`. - Boost::Locale is not dependency of library Nuspell anymore. It is still a dependency of the CLI tool. The library depends directly on ICU. Internally, all string now are in Unicode (UTF-8 or UTF-32, it depends of the need). ### Removed - Removed old Autotools build system. - Removed `NOSUGGEST_MODE` in CLI tool. It was very similar to `MISSPELLED_WORDS_MODE`. - Class `Finder` does not search for Myspell dictionaries on the file-system anymore. ### Fixed - Support compiling with GCC 5. Previously GCC 7 was needed. - Faster dictionary loading and better internal error handling when parsing a dictionary file. - Faster spellchecking as a consequence of faster case classification, which in turn, is a consequence of all string being Unicode and directly using ICU. ## [2.1.0] - 2019-01-03 ### Changed - Public API classes are inside inline namespace v2 - `List_Strings` is renamed to just `List_Strings`. Affects client code. ### Fixed - Improve public API docs ## [2.0.0] - 2018-11-22 ### Added - First public release - Spelling error detection (checking) is closely matching Hunspell - Support for spelling error correction (suggestions) [5.1.7]: https://github.com/nuspell/nuspell/compare/v5.1.6...v5.1.7 [5.1.6]: https://github.com/nuspell/nuspell/compare/v5.1.5...v5.1.6 [5.1.5]: https://github.com/nuspell/nuspell/compare/v5.1.4...v5.1.5 [5.1.4]: https://github.com/nuspell/nuspell/compare/v5.1.3...v5.1.4 [5.1.3]: https://github.com/nuspell/nuspell/compare/v5.1.2...v5.1.3 [5.1.2]: https://github.com/nuspell/nuspell/compare/v5.1.1...v5.1.2 [5.1.1]: https://github.com/nuspell/nuspell/compare/v5.1.0...v5.1.1 [5.1.0]: https://github.com/nuspell/nuspell/compare/v5.0.1...v5.1.0 [5.0.1]: https://github.com/nuspell/nuspell/compare/v5.0.0...v5.0.1 [5.0.0]: https://github.com/nuspell/nuspell/compare/v4.2.0...v5.0.0 [4.2.0]: https://github.com/nuspell/nuspell/compare/v4.1.0...v4.2.0 [4.1.0]: https://github.com/nuspell/nuspell/compare/v4.0.1...v4.1.0 [4.0.1]: https://github.com/nuspell/nuspell/compare/v4.0.0...v4.0.1 [4.0.0]: https://github.com/nuspell/nuspell/compare/v3.1.2...v4.0.0 [3.1.2]: https://github.com/nuspell/nuspell/compare/v3.1.1...v3.1.2 [3.1.1]: https://github.com/nuspell/nuspell/compare/v3.1.0...v3.1.1 [3.1.0]: https://github.com/nuspell/nuspell/compare/v3.0.0...v3.1.0 [3.0.0]: https://github.com/nuspell/nuspell/compare/v2.3.0...v3.0.0 [2.3.0]: https://github.com/nuspell/nuspell/compare/v2.2.0...v2.3.0 [2.2.0]: https://github.com/nuspell/nuspell/compare/v2.1.0...v2.2.0 [2.1.0]: https://github.com/nuspell/nuspell/compare/v2.0.0...v2.1.0 [2.0.0]: https://github.com/nuspell/nuspell/compare/v1.6.2...v2.0.0 nuspell-5.1.7/CMakeLists.txt000066400000000000000000000043221511132717100157460ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.18) project(nuspell VERSION 5.1.7 DESCRIPTION "Nuspell spellchecking library" HOMEPAGE_URL https://nuspell.github.io/ LANGUAGES CXX) include(GNUInstallDirs) include(CMakePackageConfigHelpers) include(CMakeDependentOption) option(BUILD_SHARED_LIBS "Build as shared library" ON) option(BUILD_TESTING "Build the testing tree." ON) option(BUILD_TOOLS "Build the CLI tool." ON) option(BUILD_DOCS "Build the docs." ON) cmake_dependent_option(BUILD_MAN "Build man-pages." ON BUILD_DOCS OFF) cmake_dependent_option(BUILD_API_DOCS "Build API docs." ON BUILD_DOCS OFF) find_package(ICU 60 REQUIRED COMPONENTS uc data) get_directory_property(subproject PARENT_DIRECTORY) add_subdirectory(src/nuspell) if (MSVC AND (BUILD_TOOLS OR BUILD_TESTING)) find_path(GETOPT_INCLUDE_DIR getopt.h REQUIRED) find_library(GETOPT_LIBRARY getopt REQUIRED) endif() if (BUILD_TOOLS) add_subdirectory(src/tools) endif() if (subproject) # if added as subproject just build Nuspell # no need to test, build docs or install return() endif() if (BUILD_DOCS) add_subdirectory(docs) endif() macro(fetch_catch2) include(FetchContent) FetchContent_Declare(Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG 3f0283de7a9c43200033da996ff9093be3ac84dc #v3.3.2 ) set(old_build_shared_libs ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS OFF) FetchContent_MakeAvailable(Catch2) target_compile_features(Catch2 PRIVATE cxx_std_17) set(BUILD_SHARED_LIBS ${old_build_shared_libs}) endmacro() if (BUILD_TESTING) enable_testing() find_package(Catch2 3.1.1 QUIET) if (NOT Catch2_FOUND) fetch_catch2() endif() add_subdirectory(external/hunspell/hunspell) add_subdirectory(tests) endif() configure_file(nuspell.pc.in nuspell.pc @ONLY) #configure_file(NuspellConfig.cmake NuspellConfig.cmake COPYONLY) write_basic_package_version_file(NuspellConfigVersion.cmake COMPATIBILITY AnyNewerVersion) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/nuspell.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/NuspellConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/NuspellConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nuspell) install(FILES README.md DESTINATION ${CMAKE_INSTALL_DOCDIR}) nuspell-5.1.7/COPYING000066400000000000000000001045131511132717100142440ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . nuspell-5.1.7/COPYING.LESSER000066400000000000000000000167431511132717100152470ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. nuspell-5.1.7/NuspellConfig.cmake000066400000000000000000000002041511132717100167530ustar00rootroot00000000000000include(CMakeFindDependencyMacro) find_dependency(ICU COMPONENTS uc data) include("${CMAKE_CURRENT_LIST_DIR}/NuspellTargets.cmake") nuspell-5.1.7/README.md000066400000000000000000000201571511132717100144710ustar00rootroot00000000000000# About Nuspell Nuspell is a fast and safe spelling checker software program. It is designed for languages with rich morphology and complex word compounding. Nuspell is written in modern C++ and it supports Hunspell dictionaries. Main features of Nuspell spelling checker: - Provides software library and command-line tool. - Suggests high-quality spelling corrections. - Backward compatibility with Hunspell dictionary file format. - Up to 3.5 times faster than Hunspell. - Full Unicode support backed by ICU. - Twofold affix stripping (for agglutinative languages, like Azeri, Basque, Estonian, Finnish, Hungarian, Turkish, etc.). - Supports complex compounds (for example, Hungarian, German and Dutch). - Supports advanced features, for example: special casing rules (Turkish dotted i or German sharp s), conditional affixes, circumfixes, fogemorphemes, forbidden words, pseudoroots and homonyms. - Free and open source software. Licensed under GNU LGPL v3 or later. # Building Nuspell ## Dependencies Build-only dependencies: - C++ 17 compiler with support for `std::filesystem`, e.g. GCC >= v9 - CMake >= v3.18 - Catch2 >= v3.1.1 (optional, needed only when building the tests is enabled) - Getopt (Needed only on Windows + MSVC and only when the CLI tool or the tests are built. It is available in Vcpkg. Other platforms provide it out of the box.) - Pandoc (optional, needed only when building the man-pages is enabled) - Doxygen (optional, needed only when building the API docs is enabled) Run-time (and build-time) dependencies: - ICU4C Recommended tools for developers: qtcreator, ninja, clang-format, gdb, vim. ## Building on GNU/Linux and Unixes We first need to download the dependencies. Some may already be preinstalled. For Ubuntu and Debian: ```bash sudo apt install g++ cmake libicu-dev catch2 pandoc doxygen ``` Then run the following commands inside the Nuspell directory: ```bash mkdir build cd build cmake .. make sudo make install sudo ldconfig # needed only sometimes and only on Linux ``` For faster build process run `make -j`, or use Ninja instead of Make. If you are making a Linux distribution package (dep, rpm) you need some additional configurations on the CMake invocation. For example: ```bash cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr ``` ## Building on OSX and macOS 1. Install Apple's Command-line tools. 2. Install Homebrew package manager. 3. Install dependencies with the next commands. ```bash brew install cmake icu4c catch2 pandoc doxygen export ICU_ROOT=$(brew --prefix icu4c) ``` Then run the standard cmake and make. See above. The ICU\_ROOT variable is needed because icu4c is keg-only package in Homebrew and CMake can not find it by default. Alternatively, you can use `-DICU_ROOT=...` on the cmake command line. If you want to build with GCC instead of Clang, you need to pull GCC with Homebrew and rebuild all the dependencies with it. See Homewbrew manuals. ## Building on Windows ### Compiling with Visual C++ 1. Install Visual Studio 2017 or newer. Alternatively, you can use Visual Studio Build Tools. 2. Install Git for Windows and Cmake. 3. Install Vcpkg in some folder, e.g. in `c:\vcpkg`. 4. Install Pandoc. You can manually install or use `choco install pandoc`. 4. Install Doxygen. You can manually install or use `choco install doxygen.install`. 5. Run the commands below. Vcpkg will work in manifest mode and it will automatically install the dependencies. ```bat mkdir build cd build cmake .. -DCMAKE_TOOLCHAIN_FILE=c:\vcpkg\scripts\buildsystems\vcpkg.cmake -A x64 cmake --build . ``` ### Compiling with Mingw64 and MSYS2 Download MSYS2, update everything and install the following packages: ```bash pacman -S base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-icu \ mingw-w64-x86_64-cmake mingw-w64-x86_64-catch mingw-w64-x86_64-doxygen ``` Then from inside the Nuspell folder run: ```bash mkdir build cd build cmake .. -G "Unix Makefiles" -DBUILD_MAN=OFF make make install ``` ### Building in Cygwin environment Download the above mentioned dependencies with Cygwin package manager. Then compile the same way as on Linux. Cygwin builds depend on Cygwin1.dll. ## Building on FreeBSD Install the following required packages ```bash pkg cmake icu catch2 pandoc doxygen ``` Then run the standard cmake and make as on Linux. See above. # Using the software ## Using the command-line tool The main executable is located in `src/nuspell`. After compiling and installing you can run the Nuspell spell checker with a Nuspell, Hunspell or Myspell dictionary: nuspell -d en_US text.txt For more details run see the [man-page](docs/nuspell.1.md). ## Using the Library Sample program: ```cpp #include #include #include using namespace std; int main() { auto dirs = vector(); nuspell::append_default_dir_paths(dirs); auto dict_path = nuspell::search_dirs_for_one_dict(dirs, "en_US"); if (empty(dict_path)) return 1; // Return error because we can not find the requested // dictionary. auto dict = nuspell::Dictionary(); try { dict.load_aff_dic(dict_path); } catch (const nuspell::Dictionary_Loading_Error& e) { cerr << e.what() << '\n'; return 1; } auto word = string(); auto sugs = vector(); while (cin >> word) { if (dict.spell(word)) { cout << "Word \"" << word << "\" is ok.\n"; continue; } cout << "Word \"" << word << "\" is incorrect.\n"; dict.suggest(word, sugs); if (sugs.empty()) continue; cout << " Suggestions are: "; for (auto& sug : sugs) cout << sug << ' '; cout << '\n'; } } ``` On the command line you can link like this: ```bash g++ example.cxx -std=c++17 -lnuspell -licuuc -licudata # or better, use pkg-config g++ example.cxx -std=c++17 $(pkg-config --cflags --libs nuspell) ``` Within Cmake you can use `find_package()` to link. For example: ```cmake find_package(Nuspell) add_executable(myprogram main.cpp) target_link_libraries(myprogram Nuspell::nuspell) ``` # Dictionaries Myspell, Hunspell and Nuspell dictionaries: # Advanced topics ## Debugging Nuspell First, always install the debugger: ```bash sudo apt install gdb ``` For debugging we need to create a debug build and then we need to start `gdb`. ```bash mkdir debug cd debug cmake .. -DCMAKE_BUILD_TYPE=Debug make -j gdb src/nuspell/nuspell ``` We recommend debugging to be done [with an IDE](https://github.com/nuspell/nuspell/wiki/IDE-Setup). ## Testing To run the tests, run the following command after building: ctest # See also Full documentation in the [wiki](https://github.com/nuspell/nuspell/wiki). API Documentation for developers will be generated from the source files by configuring CMake with `-DBUILD_API_DOCS=ON` (ON by default) and building. The result can be viewed by opening `BUILD_DIR/docs/html/index.html` during development, or by opening `INSTALL_PREFIX/share/doc/nuspell/html/index.html` after installing. nuspell-5.1.7/clang-format.sh000077500000000000000000000001231511132717100161120ustar00rootroot00000000000000cd $(dirname "$0") clang-format -style=file -i src/nuspell/*.[ch]xx tests/*.[ch]xx nuspell-5.1.7/docs/000077500000000000000000000000001511132717100141355ustar00rootroot00000000000000nuspell-5.1.7/docs/CMakeLists.txt000066400000000000000000000030121511132717100166710ustar00rootroot00000000000000if (BUILD_MAN) find_program(PANDOC_EXECUTABLE pandoc REQUIRED) if (BUILD_TOOLS) add_custom_command(OUTPUT nuspell.1 COMMAND ${PANDOC_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/nuspell.1.md --standalone --output=nuspell.1 "--metadata=footer:Nuspell ${PROJECT_VERSION}" MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/nuspell.1.md COMMENT "Building manpage nuspell.1") add_custom_target(man_pages ALL DEPENDS nuspell.1) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/nuspell.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() endif() if (BUILD_API_DOCS) find_package(Doxygen REQUIRED) # Project related configuration options set(DOXYGEN_BUILTIN_STL_SUPPORT YES) # Build related configuration options set(DOXYGEN_HIDE_UNDOC_MEMBERS YES) set(DOXYGEN_HIDE_UNDOC_CLASSES YES) # Configuration options related to the preprocessor set(DOXYGEN_MACRO_EXPANSION YES) set(DOXYGEN_EXPAND_ONLY_PREDEF YES) set(DOXYGEN_INCLUDE_PATH ${PROJECT_BINARY_DIR}/src/nuspell) set(DOXYGEN_PREDEFINED NUSPELL_BEGIN_INLINE_NAMESPACE= NUSPELL_END_INLINE_NAMESPACE= NUSPELL_EXPORT= NUSPELL_DEPRECATED_EXPORT=) # Define to empty # Configuration options related to diagram generator tools set(DOXYGEN_DOT_IMAGE_FORMAT svg) get_target_property(sources Nuspell::nuspell SOURCES) list(TRANSFORM sources PREPEND nuspell/) doxygen_add_docs(api_docs ${sources} ALL USE_STAMP_FILE WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR}) endif() nuspell-5.1.7/docs/ISSUE_TEMPLATE.md000066400000000000000000000020541511132717100166430ustar00rootroot00000000000000The issues can be of three types (delete two rows and leave only one): - Bug reports - Change request or feature request - Others, questions # Reporting bugs When reporting a bug you must tell us the state of your system and the steps to reproduce the bug. For the state please specify the following: | key | value | |-------------------------------------------|-------| | Operating system, distribution, version = | | | Nuspell version = | | | Dictionary, package name, version = | | | Command-line tool or GUI application = | | ## Steps to reproduce ## Bugged behavior (output) ## Expected behavior (output) # Change/feature request If you want current behavior to get changed, please explain how do you want it changed. If it's completely new, please explain it how do you want it, as verbose as possible. # Other issues If you have just questions or some other type of issue, you have the freedom to ask it in any way. Try to be as verbose as possible. nuspell-5.1.7/docs/Third-party_licenses000066400000000000000000000152251511132717100201610ustar00rootroot00000000000000This file contains the copying permission notices for project that Nuspell uses. These notices all require that a copy of the notice be included in the accompanying documentation and be distributed with binary distributions of the code, so be sure to include this file along with any binary distributions derived from Nuspell. Hunspell license: Version: MPL 1.1/GPL 2.0/LGPL 2.1 Copyright (C) 2002-2017 Németh László The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. Contributor(s): David Einstein Davide Prina Giuseppe Modugno Gianluca Turconi Simon Brouwer Noll János Bíró Árpád Goldman Eleonóra Sarlós Tamás Bencsáth Boldizsár Halácsy Péter Dvornik László Gefferth András Nagy Viktor Varga Dániel Chris Halls Rene Engelhard Bram Moolenaar Dafydd Jones Harri Pitkänen Andras Timar Tor Lillqvist Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. MySpell license: Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada And Contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All modifications to the source code must be clearly marked as such. Binary redistributions based on modified source code must be clearly marked as modified versions in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Catch2 license: Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ICU License: Copyright © 1991-2019 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in https://www.unicode.org/copyright.html. Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either (a) this copyright and permission notice appear with all copies of the Data Files or Software, or (b) this copyright and permission notice appear in associated Documentation. THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. nuspell-5.1.7/docs/nuspell.1.md000066400000000000000000000054251511132717100163060ustar00rootroot00000000000000--- title: NUSPELL section: 1 header: User Commands footer: Nuspell vX.Y # override this on the command line in CMake author: Dimitrij Mijoski date: 2024-07-03 # This date should be changed when significant changes in this # document are made. It is not release date or build date. --- # NAME nuspell - Command-line tool for spellchecking. # SYNOPSIS **nuspell** \[**-d** _dict_NAME_\] \[_OPTION_\]... \[_FILE_\]... **nuspell** **-D|\--help|\--version** # DESCRIPTION Check spelling of each _FILE_. If no _FILE_ is specified, check standard input. The text in the input is first segmented into words with an algorithm that recognizes punctuation and then each word is checked. # OPTIONS __-d, \--dictionary=__*di_CT* : Use _di_CT_ dictionary. Only one is supported. A dictionary consists of two files with extensions .dic and .aff. The **-d** option accepts either dictionary name without filename extension, usually a language tag, or a path (with slash) to the .aff file including the filename extension. When just a name is given, it will be searched among the list of dictionaries in the default directories (see option **-D**). When a path to .aff is given, only the dictionary under the path is considered. When **-d** is not present, the CLI tools tries to load a dictionary using the language tag from the active locale. **-D, \--list-dictionaries** : Print search paths and available dictionaries and exit. __\--encoding=__*ENC* : Set both input and output encoding. __\--input-encoding=__*ENC* : Set input encoding, default is active locale. __\--output-encoding=__*ENC* : Set output encoding, default is active locale. **\--help** : Print short help. **\--version** : Print version number. # EXIT STATUS Returns error if the argument syntax is invalid, if the dictionary can not be loaded or if some input file can not be opened. Otherwise, spell checking has occurred and returns success. # ENVIRONMENT **DICTIONARY** : Specify dictionary, same as option **-d**. **DICPATH** : Path to additional directory to search for dictionaries. # CAVEATS The CLI tool is primarily intended to be used interactively by human. The input is plain text and the output is mostly plain text with some symbols and words that are meant to be read by human and not by machine. The format of the output is not strictly defined and may change, thus it is not machine-readable. Other programs should use the C++ library directly which has stable API. # EXAMPLES nuspell -d en_US file.txt nuspell -d ../../subdir/di_CT.aff # REPORTING BUGS Bug reports: # COPYRIGHT Copyright 2016-2024 Nuspell authors. # SEE ALSO Full documentation: Home page: nuspell-5.1.7/external/000077500000000000000000000000001511132717100150275ustar00rootroot00000000000000nuspell-5.1.7/external/hunspell/000077500000000000000000000000001511132717100166615ustar00rootroot00000000000000nuspell-5.1.7/external/hunspell/hunspell/000077500000000000000000000000001511132717100205135ustar00rootroot00000000000000nuspell-5.1.7/external/hunspell/hunspell/CMakeLists.txt000066400000000000000000000015341511132717100232560ustar00rootroot00000000000000add_library(hunspell affentry.cxx affentry.hxx affixmgr.cxx affixmgr.hxx atypes.hxx baseaffix.hxx csutil.cxx csutil.hxx filemgr.cxx filemgr.hxx hashmgr.cxx hashmgr.hxx htypes.hxx hunspell.cxx hunspell.h hunspell.hxx hunzip.cxx hunzip.hxx langnum.hxx hunvisapi.h phonet.cxx phonet.hxx replist.cxx replist.hxx suggestmgr.cxx suggestmgr.hxx utf_info.hxx w_char.hxx) set_target_properties(hunspell PROPERTIES DEFINE_SYMBOL BUILDING_LIBHUNSPELL CXX_VISIBILITY_PRESET hidden) if (NOT BUILD_SHARED_LIBS) target_compile_definitions(hunspell PUBLIC HUNSPELL_STATIC) endif() target_include_directories(hunspell INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/..) if (MSVC) # Suppress some useless warnings target_compile_definitions(hunspell PRIVATE _CRT_SECURE_NO_WARNINGS) target_compile_options(hunspell PRIVATE /wd4251) endif() nuspell-5.1.7/external/hunspell/hunspell/affentry.cxx000066400000000000000000001025261511132717100230630ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "affentry.hxx" #include "csutil.hxx" AffEntry::~AffEntry() { if (opts & aeLONGCOND) free(c.l.conds2); if (morphcode && !(opts & aeALIASM)) free(morphcode); if (contclass && !(opts & aeALIASF)) free(contclass); } PfxEntry::PfxEntry(AffixMgr* pmgr) // register affix manager : pmyMgr(pmgr), next(NULL), nexteq(NULL), nextne(NULL), flgnxt(NULL) { } // add prefix to this word assuming conditions hold std::string PfxEntry::add(const char* word, size_t len) { std::string result; if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) && (len >= numconds) && test_condition(word) && (!strip.size() || (strncmp(word, strip.c_str(), strip.size()) == 0))) { /* we have a match so add prefix */ result.assign(appnd); result.append(word + strip.size()); } return result; } inline char* PfxEntry::nextchar(char* p) { if (p) { p++; if (opts & aeLONGCOND) { // jump to the 2nd part of the condition if (p == c.conds + MAXCONDLEN_1) return c.l.conds2; // end of the MAXCONDLEN length condition } else if (p == c.conds + MAXCONDLEN) return NULL; return *p ? p : NULL; } return NULL; } inline int PfxEntry::test_condition(const char* st) { const char* pos = NULL; // group with pos input position bool neg = false; // complementer bool ingroup = false; // character in the group if (numconds == 0) return 1; char* p = c.conds; while (1) { switch (*p) { case '\0': return 1; case '[': { neg = false; ingroup = false; p = nextchar(p); pos = st; break; } case '^': { p = nextchar(p); neg = true; break; } case ']': { if ((neg && ingroup) || (!neg && !ingroup)) return 0; pos = NULL; p = nextchar(p); // skip the next character if (!ingroup && *st) for (st++; (opts & aeUTF8) && (*st & 0xc0) == 0x80; st++) ; if (*st == '\0' && p) return 0; // word <= condition break; } case '.': if (!pos) { // dots are not metacharacters in groups: [.] p = nextchar(p); // skip the next character for (st++; (opts & aeUTF8) && (*st & 0xc0) == 0x80; st++) ; if (*st == '\0' && p) return 0; // word <= condition break; } /* FALLTHROUGH */ default: { if (*st == *p) { st++; p = nextchar(p); if ((opts & aeUTF8) && (*(st - 1) & 0x80)) { // multibyte while (p && (*p & 0xc0) == 0x80) { // character if (*p != *st) { if (!pos) return 0; st = pos; break; } p = nextchar(p); st++; } if (pos && st != pos) { ingroup = true; while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { } } } else if (pos) { ingroup = true; while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { } } } else if (pos) { // group p = nextchar(p); } else return 0; } } if (!p) return 1; } } // check if this prefix entry matches struct hentry* PfxEntry::checkword(const char* word, int len, char in_compound, const FLAG needflag) { struct hentry* he; // hash entry of root word or NULL // on entry prefix is 0 length or already matches the beginning of the word. // So if the remaining root word has positive length // and if there are enough chars in root word and added back strip chars // to meet the number of characters conditions, then test it int tmpl = len - appnd.size(); // length of tmpword if (tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) { // generate new root word by removing prefix and adding // back any characters that would have been stripped std::string tmpword(strip); tmpword.append(word + appnd.size()); // now make sure all of the conditions on characters // are met. Please see the appendix at the end of // this file for more info on exactly what is being // tested // if all conditions are met then check if resulting // root word in the dictionary if (test_condition(tmpword.c_str())) { tmpl += strip.size(); if ((he = pmyMgr->lookup(tmpword.c_str())) != NULL) { do { if (TESTAFF(he->astr, aflag, he->alen) && // forbid single prefixes with needaffix flag !TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) && // needflag ((!needflag) || TESTAFF(he->astr, needflag, he->alen) || (contclass && TESTAFF(contclass, needflag, contclasslen)))) return he; he = he->next_homonym; // check homonyms } while (he); } // prefix matched but no root word was found // if aeXPRODUCT is allowed, try again but now // ross checked combined with a suffix // if ((opts & aeXPRODUCT) && in_compound) { if ((opts & aeXPRODUCT)) { he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, aeXPRODUCT, this, FLAG_NULL, needflag, in_compound); if (he) return he; } } } return NULL; } // check if this prefix entry matches struct hentry* PfxEntry::check_twosfx(const char* word, int len, char in_compound, const FLAG needflag) { // on entry prefix is 0 length or already matches the beginning of the word. // So if the remaining root word has positive length // and if there are enough chars in root word and added back strip chars // to meet the number of characters conditions, then test it int tmpl = len - appnd.size(); // length of tmpword if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && (tmpl + strip.size() >= numconds)) { // generate new root word by removing prefix and adding // back any characters that would have been stripped std::string tmpword(strip); tmpword.append(word + appnd.size()); // now make sure all of the conditions on characters // are met. Please see the appendix at the end of // this file for more info on exactly what is being // tested // if all conditions are met then check if resulting // root word in the dictionary if (test_condition(tmpword.c_str())) { tmpl += strip.size(); // prefix matched but no root word was found // if aeXPRODUCT is allowed, try again but now // cross checked combined with a suffix if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { // hash entry of root word or NULL struct hentry* he = pmyMgr->suffix_check_twosfx(tmpword.c_str(), tmpl, aeXPRODUCT, this, needflag); if (he) return he; } } } return NULL; } // check if this prefix entry matches std::string PfxEntry::check_twosfx_morph(const char* word, int len, char in_compound, const FLAG needflag) { std::string result; // on entry prefix is 0 length or already matches the beginning of the word. // So if the remaining root word has positive length // and if there are enough chars in root word and added back strip chars // to meet the number of characters conditions, then test it int tmpl = len - appnd.size(); // length of tmpword if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && (tmpl + strip.size() >= numconds)) { // generate new root word by removing prefix and adding // back any characters that would have been stripped std::string tmpword(strip); tmpword.append(word + appnd.size()); // now make sure all of the conditions on characters // are met. Please see the appendix at the end of // this file for more info on exactly what is being // tested // if all conditions are met then check if resulting // root word in the dictionary if (test_condition(tmpword.c_str())) { tmpl += strip.size(); // prefix matched but no root word was found // if aeXPRODUCT is allowed, try again but now // ross checked combined with a suffix if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { result = pmyMgr->suffix_check_twosfx_morph(tmpword.c_str(), tmpl, aeXPRODUCT, this, needflag); } } } return result; } // check if this prefix entry matches std::string PfxEntry::check_morph(const char* word, int len, char in_compound, const FLAG needflag) { std::string result; // on entry prefix is 0 length or already matches the beginning of the word. // So if the remaining root word has positive length // and if there are enough chars in root word and added back strip chars // to meet the number of characters conditions, then test it int tmpl = len - appnd.size(); // length of tmpword if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && (tmpl + strip.size() >= numconds)) { // generate new root word by removing prefix and adding // back any characters that would have been stripped std::string tmpword(strip); tmpword.append(word + appnd.size()); // now make sure all of the conditions on characters // are met. Please see the appendix at the end of // this file for more info on exactly what is being // tested // if all conditions are met then check if resulting // root word in the dictionary if (test_condition(tmpword.c_str())) { tmpl += strip.size(); struct hentry* he; // hash entry of root word or NULL if ((he = pmyMgr->lookup(tmpword.c_str())) != NULL) { do { if (TESTAFF(he->astr, aflag, he->alen) && // forbid single prefixes with needaffix flag !TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) && // needflag ((!needflag) || TESTAFF(he->astr, needflag, he->alen) || (contclass && TESTAFF(contclass, needflag, contclasslen)))) { if (morphcode) { result.append(" "); result.append(morphcode); } else result.append(getKey()); if (!HENTRY_FIND(he, MORPH_STEM)) { result.append(" "); result.append(MORPH_STEM); result.append(HENTRY_WORD(he)); } // store the pointer of the hash entry if (HENTRY_DATA(he)) { result.append(" "); result.append(HENTRY_DATA2(he)); } else { // return with debug information char* flag = pmyMgr->encode_flag(getFlag()); result.append(" "); result.append(MORPH_FLAG); result.append(flag); free(flag); } result.append("\n"); } he = he->next_homonym; } while (he); } // prefix matched but no root word was found // if aeXPRODUCT is allowed, try again but now // ross checked combined with a suffix if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, aeXPRODUCT, this, FLAG_NULL, needflag); if (!st.empty()) { result.append(st); } } } } return result; } SfxEntry::SfxEntry(AffixMgr* pmgr) : pmyMgr(pmgr) // register affix manager , next(NULL), nexteq(NULL), nextne(NULL), flgnxt(NULL), l_morph(NULL), r_morph(NULL), eq_morph(NULL) { } // add suffix to this word assuming conditions hold std::string SfxEntry::add(const char* word, size_t len) { std::string result; /* make sure all conditions match */ if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) && (len >= numconds) && test_condition(word + len, word) && (!strip.size() || (strcmp(word + len - strip.size(), strip.c_str()) == 0))) { result.assign(word); /* we have a match so add suffix */ result.replace(len - strip.size(), std::string::npos, appnd); } return result; } inline char* SfxEntry::nextchar(char* p) { if (p) { p++; if (opts & aeLONGCOND) { // jump to the 2nd part of the condition if (p == c.l.conds1 + MAXCONDLEN_1) return c.l.conds2; // end of the MAXCONDLEN length condition } else if (p == c.conds + MAXCONDLEN) return NULL; return *p ? p : NULL; } return NULL; } inline int SfxEntry::test_condition(const char* st, const char* beg) { const char* pos = NULL; // group with pos input position bool neg = false; // complementer bool ingroup = false; // character in the group if (numconds == 0) return 1; char* p = c.conds; st--; int i = 1; while (1) { switch (*p) { case '\0': return 1; case '[': p = nextchar(p); pos = st; break; case '^': p = nextchar(p); neg = true; break; case ']': if (!neg && !ingroup) return 0; i++; // skip the next character if (!ingroup) { for (; (opts & aeUTF8) && (st >= beg) && (*st & 0xc0) == 0x80; st--) ; st--; } pos = NULL; neg = false; ingroup = false; p = nextchar(p); if (st < beg && p) return 0; // word <= condition break; case '.': if (!pos) { // dots are not metacharacters in groups: [.] p = nextchar(p); // skip the next character for (st--; (opts & aeUTF8) && (st >= beg) && (*st & 0xc0) == 0x80; st--) ; if (st < beg) { // word <= condition if (p) return 0; else return 1; } if ((opts & aeUTF8) && (*st & 0x80)) { // head of the UTF-8 character st--; if (st < beg) { // word <= condition if (p) return 0; else return 1; } } break; } /* FALLTHROUGH */ default: { if (*st == *p) { p = nextchar(p); if ((opts & aeUTF8) && (*st & 0x80)) { st--; while (p && (st >= beg)) { if (*p != *st) { if (!pos) return 0; st = pos; break; } // first byte of the UTF-8 multibyte character if ((*p & 0xc0) != 0x80) break; p = nextchar(p); st--; } if (pos && st != pos) { if (neg) return 0; else if (i == numconds) return 1; ingroup = true; while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { } st--; } if (p && *p != ']') p = nextchar(p); } else if (pos) { if (neg) return 0; else if (i == numconds) return 1; ingroup = true; while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { } // if (p && *p != ']') p = nextchar(p); st--; } if (!pos) { i++; st--; } if (st < beg && p && *p != ']') return 0; // word <= condition } else if (pos) { // group p = nextchar(p); } else return 0; } } if (!p) return 1; } } // see if this suffix is present in the word struct hentry* SfxEntry::checkword(const char* word, int len, int optflags, PfxEntry* ppfx, const FLAG cclass, const FLAG needflag, const FLAG badflag) { struct hentry* he; // hash entry pointer PfxEntry* ep = ppfx; // if this suffix is being cross checked with a prefix // but it does not support cross products skip it if (((optflags & aeXPRODUCT) != 0) && ((opts & aeXPRODUCT) == 0)) return NULL; // upon entry suffix is 0 length or already matches the end of the word. // So if the remaining root word has positive length // and if there are enough chars in root word and added back strip chars // to meet the number of characters conditions, then test it int tmpl = len - appnd.size(); // length of tmpword // the second condition is not enough for UTF-8 strings // it checked in test_condition() if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && (tmpl + strip.size() >= numconds)) { // generate new root word by removing suffix and adding // back any characters that would have been stripped or // or null terminating the shorter string std::string tmpstring(word, tmpl); if (strip.size()) { tmpstring.append(strip); } const char* tmpword = tmpstring.c_str(); const char* endword = tmpword + tmpstring.size(); // now make sure all of the conditions on characters // are met. Please see the appendix at the end of // this file for more info on exactly what is being // tested // if all conditions are met then check if resulting // root word in the dictionary if (test_condition(endword, tmpword)) { #ifdef SZOSZABLYA_POSSIBLE_ROOTS fprintf(stdout, "%s %s %c\n", word, tmpword, aflag); #endif if ((he = pmyMgr->lookup(tmpword)) != NULL) { do { // check conditional suffix (enabled by prefix) if ((TESTAFF(he->astr, aflag, he->alen) || (ep && ep->getCont() && TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && (((optflags & aeXPRODUCT) == 0) || (ep && TESTAFF(he->astr, ep->getFlag(), he->alen)) || // enabled by prefix ((contclass) && (ep && TESTAFF(contclass, ep->getFlag(), contclasslen)))) && // handle cont. class ((!cclass) || ((contclass) && TESTAFF(contclass, cclass, contclasslen))) && // check only in compound homonyms (bad flags) (!badflag || !TESTAFF(he->astr, badflag, he->alen)) && // handle required flag ((!needflag) || (TESTAFF(he->astr, needflag, he->alen) || ((contclass) && TESTAFF(contclass, needflag, contclasslen))))) return he; he = he->next_homonym; // check homonyms } while (he); } } } return NULL; } // see if two-level suffix is present in the word struct hentry* SfxEntry::check_twosfx(const char* word, int len, int optflags, PfxEntry* ppfx, const FLAG needflag) { PfxEntry* ep = ppfx; // if this suffix is being cross checked with a prefix // but it does not support cross products skip it if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0) return NULL; // upon entry suffix is 0 length or already matches the end of the word. // So if the remaining root word has positive length // and if there are enough chars in root word and added back strip chars // to meet the number of characters conditions, then test it int tmpl = len - appnd.size(); // length of tmpword if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && (tmpl + strip.size() >= numconds)) { // generate new root word by removing suffix and adding // back any characters that would have been stripped or // or null terminating the shorter string std::string tmpword(word); tmpword.resize(tmpl); tmpword.append(strip); tmpl += strip.size(); const char* beg = tmpword.c_str(); const char* end = beg + tmpl; // now make sure all of the conditions on characters // are met. Please see the appendix at the end of // this file for more info on exactly what is being // tested // if all conditions are met then recall suffix_check if (test_condition(end, beg)) { struct hentry* he; // hash entry pointer if (ppfx) { // handle conditional suffix if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, (FLAG)aflag, needflag, IN_CPD_NOT); else he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, optflags, ppfx, (FLAG)aflag, needflag, IN_CPD_NOT); } else { he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, (FLAG)aflag, needflag, IN_CPD_NOT); } if (he) return he; } } return NULL; } // see if two-level suffix is present in the word std::string SfxEntry::check_twosfx_morph(const char* word, int len, int optflags, PfxEntry* ppfx, const FLAG needflag) { PfxEntry* ep = ppfx; std::string result; // if this suffix is being cross checked with a prefix // but it does not support cross products skip it if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0) return result; // upon entry suffix is 0 length or already matches the end of the word. // So if the remaining root word has positive length // and if there are enough chars in root word and added back strip chars // to meet the number of characters conditions, then test it int tmpl = len - appnd.size(); // length of tmpword if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && (tmpl + strip.size() >= numconds)) { // generate new root word by removing suffix and adding // back any characters that would have been stripped or // or null terminating the shorter string std::string tmpword(word); tmpword.resize(tmpl); tmpword.append(strip); tmpl += strip.size(); const char* beg = tmpword.c_str(); const char* end = beg + tmpl; // now make sure all of the conditions on characters // are met. Please see the appendix at the end of // this file for more info on exactly what is being // tested // if all conditions are met then recall suffix_check if (test_condition(end, beg)) { if (ppfx) { // handle conditional suffix if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) { std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, needflag); if (!st.empty()) { if (ppfx->getMorph()) { result.append(ppfx->getMorph()); result.append(" "); } result.append(st); mychomp(result); } } else { std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, optflags, ppfx, aflag, needflag); if (!st.empty()) { result.append(st); mychomp(result); } } } else { std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, needflag); if (!st.empty()) { result.append(st); mychomp(result); } } } } return result; } // get next homonym with same affix struct hentry* SfxEntry::get_next_homonym(struct hentry* he, int optflags, PfxEntry* ppfx, const FLAG cclass, const FLAG needflag) { PfxEntry* ep = ppfx; FLAG eFlag = ep ? ep->getFlag() : FLAG_NULL; while (he->next_homonym) { he = he->next_homonym; if ((TESTAFF(he->astr, aflag, he->alen) || (ep && ep->getCont() && TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && ((optflags & aeXPRODUCT) == 0 || TESTAFF(he->astr, eFlag, he->alen) || // handle conditional suffix ((contclass) && TESTAFF(contclass, eFlag, contclasslen))) && // handle cont. class ((!cclass) || ((contclass) && TESTAFF(contclass, cclass, contclasslen))) && // handle required flag ((!needflag) || (TESTAFF(he->astr, needflag, he->alen) || ((contclass) && TESTAFF(contclass, needflag, contclasslen))))) return he; } return NULL; } void SfxEntry::initReverseWord() { rappnd = appnd; reverseword(rappnd); } #if 0 Appendix: Understanding Affix Code An affix is either a prefix or a suffix attached to root words to make other words. Basically a Prefix or a Suffix is set of AffEntry objects which store information about the prefix or suffix along with supporting routines to check if a word has a particular prefix or suffix or a combination. The structure affentry is defined as follows: struct affentry { unsigned short aflag; // ID used to represent the affix std::string strip; // string to strip before adding affix std::string appnd; // the affix string to add char numconds; // the number of conditions that must be met char opts; // flag: aeXPRODUCT- combine both prefix and suffix char conds[SETSIZE]; // array which encodes the conditions to be met }; Here is a suffix borrowed from the en_US.aff file. This file is whitespace delimited. SFX D Y 4 SFX D 0 e d SFX D y ied [^aeiou]y SFX D 0 ed [^ey] SFX D 0 ed [aeiou]y This information can be interpreted as follows: In the first line has 4 fields Field ----- 1 SFX - indicates this is a suffix 2 D - is the name of the character flag which represents this suffix 3 Y - indicates it can be combined with prefixes (cross product) 4 4 - indicates that sequence of 4 affentry structures are needed to properly store the affix information The remaining lines describe the unique information for the 4 SfxEntry objects that make up this affix. Each line can be interpreted as follows: (note fields 1 and 2 are as a check against line 1 info) Field ----- 1 SFX - indicates this is a suffix 2 D - is the name of the character flag for this affix 3 y - the string of chars to strip off before adding affix (a 0 here indicates the NULL string) 4 ied - the string of affix characters to add 5 [^aeiou]y - the conditions which must be met before the affix can be applied Field 5 is interesting. Since this is a suffix, field 5 tells us that there are 2 conditions that must be met. The first condition is that the next to the last character in the word must *NOT* be any of the following "a", "e", "i", "o" or "u". The second condition is that the last character of the word must end in "y". So how can we encode this information concisely and be able to test for both conditions in a fast manner? The answer is found but studying the wonderful ispell code of Geoff Kuenning, et.al. (now available under a normal BSD license). If we set up a conds array of 256 bytes indexed (0 to 255) and access it using a character (cast to an unsigned char) of a string, we have 8 bits of information we can store about that character. Specifically we could use each bit to say if that character is allowed in any of the last (or first for prefixes) 8 characters of the word. Basically, each character at one end of the word (up to the number of conditions) is used to index into the conds array and the resulting value found there says whether the that character is valid for a specific character position in the word. For prefixes, it does this by setting bit 0 if that char is valid in the first position, bit 1 if valid in the second position, and so on. If a bit is not set, then that char is not valid for that postion in the word. If working with suffixes bit 0 is used for the character closest to the front, bit 1 for the next character towards the end, ..., with bit numconds-1 representing the last char at the end of the string. Note: since entries in the conds[] are 8 bits, only 8 conditions (read that only 8 character positions) can be examined at one end of a word (the beginning for prefixes and the end for suffixes. So to make this clearer, lets encode the conds array values for the first two affentries for the suffix D described earlier. For the first affentry: numconds = 1 (only examine the last character) conds['e'] = (1 << 0) (the word must end in an E) all others are all 0 For the second affentry: numconds = 2 (only examine the last two characters) conds[X] = conds[X] | (1 << 0) (aeiou are not allowed) where X is all characters *but* a, e, i, o, or u conds['y'] = (1 << 1) (the last char must be a y) all other bits for all other entries in the conds array are zero #endif nuspell-5.1.7/external/hunspell/hunspell/affentry.hxx000066400000000000000000000203361511132717100230660ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef AFFIX_HXX_ #define AFFIX_HXX_ #include "atypes.hxx" #include "baseaffix.hxx" #include "affixmgr.hxx" /* A Prefix Entry */ class PfxEntry : public AffEntry { private: PfxEntry(const PfxEntry&); PfxEntry& operator=(const PfxEntry&); private: AffixMgr* pmyMgr; PfxEntry* next; PfxEntry* nexteq; PfxEntry* nextne; PfxEntry* flgnxt; public: explicit PfxEntry(AffixMgr* pmgr); bool allowCross() const { return ((opts & aeXPRODUCT) != 0); } struct hentry* checkword(const char* word, int len, char in_compound, const FLAG needflag = FLAG_NULL); struct hentry* check_twosfx(const char* word, int len, char in_compound, const FLAG needflag = FLAG_NULL); std::string check_morph(const char* word, int len, char in_compound, const FLAG needflag = FLAG_NULL); std::string check_twosfx_morph(const char* word, int len, char in_compound, const FLAG needflag = FLAG_NULL); FLAG getFlag() { return aflag; } const char* getKey() { return appnd.c_str(); } std::string add(const char* word, size_t len); inline short getKeyLen() { return appnd.size(); } inline const char* getMorph() { return morphcode; } inline const unsigned short* getCont() { return contclass; } inline short getContLen() { return contclasslen; } inline PfxEntry* getNext() { return next; } inline PfxEntry* getNextNE() { return nextne; } inline PfxEntry* getNextEQ() { return nexteq; } inline PfxEntry* getFlgNxt() { return flgnxt; } inline void setNext(PfxEntry* ptr) { next = ptr; } inline void setNextNE(PfxEntry* ptr) { nextne = ptr; } inline void setNextEQ(PfxEntry* ptr) { nexteq = ptr; } inline void setFlgNxt(PfxEntry* ptr) { flgnxt = ptr; } inline char* nextchar(char* p); inline int test_condition(const char* st); }; /* A Suffix Entry */ class SfxEntry : public AffEntry { private: SfxEntry(const SfxEntry&); SfxEntry& operator=(const SfxEntry&); private: AffixMgr* pmyMgr; std::string rappnd; SfxEntry* next; SfxEntry* nexteq; SfxEntry* nextne; SfxEntry* flgnxt; SfxEntry* l_morph; SfxEntry* r_morph; SfxEntry* eq_morph; public: explicit SfxEntry(AffixMgr* pmgr); bool allowCross() const { return ((opts & aeXPRODUCT) != 0); } struct hentry* checkword(const char* word, int len, int optflags, PfxEntry* ppfx, const FLAG cclass, const FLAG needflag, const FLAG badflag); struct hentry* check_twosfx(const char* word, int len, int optflags, PfxEntry* ppfx, const FLAG needflag = FLAG_NULL); std::string check_twosfx_morph(const char* word, int len, int optflags, PfxEntry* ppfx, const FLAG needflag = FLAG_NULL); struct hentry* get_next_homonym(struct hentry* he); struct hentry* get_next_homonym(struct hentry* word, int optflags, PfxEntry* ppfx, const FLAG cclass, const FLAG needflag); FLAG getFlag() { return aflag; } const char* getKey() { return rappnd.c_str(); } std::string add(const char* word, size_t len); inline const char* getMorph() { return morphcode; } inline const unsigned short* getCont() { return contclass; } inline short getContLen() { return contclasslen; } inline const char* getAffix() { return appnd.c_str(); } inline short getKeyLen() { return appnd.size(); } inline SfxEntry* getNext() { return next; } inline SfxEntry* getNextNE() { return nextne; } inline SfxEntry* getNextEQ() { return nexteq; } inline SfxEntry* getLM() { return l_morph; } inline SfxEntry* getRM() { return r_morph; } inline SfxEntry* getEQM() { return eq_morph; } inline SfxEntry* getFlgNxt() { return flgnxt; } inline void setNext(SfxEntry* ptr) { next = ptr; } inline void setNextNE(SfxEntry* ptr) { nextne = ptr; } inline void setNextEQ(SfxEntry* ptr) { nexteq = ptr; } inline void setFlgNxt(SfxEntry* ptr) { flgnxt = ptr; } void initReverseWord(); inline char* nextchar(char* p); inline int test_condition(const char* st, const char* begin); }; #endif nuspell-5.1.7/external/hunspell/hunspell/affixmgr.cxx000066400000000000000000004520051511132717100230500ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "affixmgr.hxx" #include "affentry.hxx" #include "langnum.hxx" #include "csutil.hxx" AffixMgr::AffixMgr(const char* affpath, const std::vector& ptr, const char* key) : alldic(ptr) , pHMgr(ptr[0]) { // register hash manager and load affix data from aff file csconv = NULL; utf8 = 0; complexprefixes = 0; parsedmaptable = false; parsedbreaktable = false; parsedrep = false; iconvtable = NULL; oconvtable = NULL; // allow simplified compound forms (see 3rd field of CHECKCOMPOUNDPATTERN) simplifiedcpd = 0; parsedcheckcpd = false; parseddefcpd = false; phone = NULL; compoundflag = FLAG_NULL; // permits word in compound forms compoundbegin = FLAG_NULL; // may be first word in compound forms compoundmiddle = FLAG_NULL; // may be middle word in compound forms compoundend = FLAG_NULL; // may be last word in compound forms compoundroot = FLAG_NULL; // compound word signing flag compoundpermitflag = FLAG_NULL; // compound permitting flag for suffixed word compoundforbidflag = FLAG_NULL; // compound fordidden flag for suffixed word compoundmoresuffixes = 0; // allow more suffixes within compound words checkcompounddup = 0; // forbid double words in compounds checkcompoundrep = 0; // forbid bad compounds (may be non-compound word with // a REP substitution) checkcompoundcase = 0; // forbid upper and lowercase combinations at word bounds checkcompoundtriple = 0; // forbid compounds with triple letters simplifiedtriple = 0; // allow simplified triple letters in compounds // (Schiff+fahrt -> Schiffahrt) forbiddenword = FORBIDDENWORD; // forbidden word signing flag nosuggest = FLAG_NULL; // don't suggest words signed with NOSUGGEST flag nongramsuggest = FLAG_NULL; langnum = 0; // language code (see http://l10n.openoffice.org/languages.html) needaffix = FLAG_NULL; // forbidden root, allowed only with suffixes cpdwordmax = -1; // default: unlimited wordcount in compound words cpdmin = -1; // undefined cpdmaxsyllable = 0; // default: unlimited syllablecount in compound words pfxappnd = NULL; // previous prefix for counting syllables of the prefix BUG sfxappnd = NULL; // previous suffix for counting syllables of the suffix BUG sfxextra = 0; // modifier for syllable count of sfxappnd BUG checknum = 0; // checking numbers, and word with numbers havecontclass = 0; // flags of possible continuing classes (double affix) // LEMMA_PRESENT: not put root into the morphological output. Lemma presents // in morhological description in dictionary file. It's often combined with // PSEUDOROOT. lemma_present = FLAG_NULL; circumfix = FLAG_NULL; onlyincompound = FLAG_NULL; maxngramsugs = -1; // undefined maxdiff = -1; // undefined onlymaxdiff = 0; maxcpdsugs = -1; // undefined nosplitsugs = 0; sugswithdots = 0; keepcase = 0; forceucase = 0; warn = 0; forbidwarn = 0; checksharps = 0; substandard = FLAG_NULL; fullstrip = 0; sfx = NULL; pfx = NULL; for (int i = 0; i < SETSIZE; i++) { pStart[i] = NULL; sStart[i] = NULL; pFlag[i] = NULL; sFlag[i] = NULL; } for (int j = 0; j < CONTSIZE; j++) { contclasses[j] = 0; } if (parse_file(affpath, key)) { HUNSPELL_WARNING(stderr, "Failure loading aff file %s\n", affpath); } if (cpdmin == -1) cpdmin = MINCPDLEN; } AffixMgr::~AffixMgr() { // pass through linked prefix entries and clean up for (int i = 0; i < SETSIZE; i++) { pFlag[i] = NULL; PfxEntry* ptr = pStart[i]; PfxEntry* nptr = NULL; while (ptr) { nptr = ptr->getNext(); delete (ptr); ptr = nptr; nptr = NULL; } } // pass through linked suffix entries and clean up for (int j = 0; j < SETSIZE; j++) { sFlag[j] = NULL; SfxEntry* ptr = sStart[j]; SfxEntry* nptr = NULL; while (ptr) { nptr = ptr->getNext(); delete (ptr); ptr = nptr; nptr = NULL; } sStart[j] = NULL; } delete iconvtable; delete oconvtable; delete phone; FREE_FLAG(compoundflag); FREE_FLAG(compoundbegin); FREE_FLAG(compoundmiddle); FREE_FLAG(compoundend); FREE_FLAG(compoundpermitflag); FREE_FLAG(compoundforbidflag); FREE_FLAG(compoundroot); FREE_FLAG(forbiddenword); FREE_FLAG(nosuggest); FREE_FLAG(nongramsuggest); FREE_FLAG(needaffix); FREE_FLAG(lemma_present); FREE_FLAG(circumfix); FREE_FLAG(onlyincompound); cpdwordmax = 0; pHMgr = NULL; cpdmin = 0; cpdmaxsyllable = 0; free_utf_tbl(); checknum = 0; #ifdef MOZILLA_CLIENT delete[] csconv; #endif } void AffixMgr::finishFileMgr(FileMgr* afflst) { delete afflst; // convert affix trees to sorted list process_pfx_tree_to_list(); process_sfx_tree_to_list(); } // read in aff file and build up prefix and suffix entry objects int AffixMgr::parse_file(const char* affpath, const char* key) { // checking flag duplication char dupflags[CONTSIZE]; char dupflags_ini = 1; // first line indicator for removing byte order mark int firstline = 1; // open the affix file FileMgr* afflst = new FileMgr(affpath, key); if (!afflst) { HUNSPELL_WARNING( stderr, "error: could not open affix description file %s\n", affpath); return 1; } // step one is to parse the affix file building up the internal // affix data structures // read in each line ignoring any that do not // start with a known line type indicator std::string line; while (afflst->getline(line)) { mychomp(line); /* remove byte order mark */ if (firstline) { firstline = 0; // Affix file begins with byte order mark: possible incompatibility with // old Hunspell versions if (line.compare(0, 3, "\xEF\xBB\xBF", 3) == 0) { line.erase(0, 3); } } /* parse in the keyboard string */ if (line.compare(0, 3, "KEY", 3) == 0) { if (!parse_string(line, keystring, afflst->getlinenum())) { finishFileMgr(afflst); return 1; } } /* parse in the try string */ if (line.compare(0, 3, "TRY", 3) == 0) { if (!parse_string(line, trystring, afflst->getlinenum())) { finishFileMgr(afflst); return 1; } } /* parse in the name of the character set used by the .dict and .aff */ if (line.compare(0, 3, "SET", 3) == 0) { if (!parse_string(line, encoding, afflst->getlinenum())) { finishFileMgr(afflst); return 1; } if (encoding == "UTF-8") { utf8 = 1; #ifndef OPENOFFICEORG #ifndef MOZILLA_CLIENT initialize_utf_tbl(); #endif #endif } } /* parse COMPLEXPREFIXES for agglutinative languages with right-to-left * writing system */ if (line.compare(0, 15, "COMPLEXPREFIXES", 15) == 0) complexprefixes = 1; /* parse in the flag used by the controlled compound words */ if (line.compare(0, 12, "COMPOUNDFLAG", 12) == 0) { if (!parse_flag(line, &compoundflag, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by compound words */ if (line.compare(0, 13, "COMPOUNDBEGIN", 13) == 0) { if (complexprefixes) { if (!parse_flag(line, &compoundend, afflst)) { finishFileMgr(afflst); return 1; } } else { if (!parse_flag(line, &compoundbegin, afflst)) { finishFileMgr(afflst); return 1; } } } /* parse in the flag used by compound words */ if (line.compare(0, 14, "COMPOUNDMIDDLE", 14) == 0) { if (!parse_flag(line, &compoundmiddle, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by compound words */ if (line.compare(0, 11, "COMPOUNDEND", 11) == 0) { if (complexprefixes) { if (!parse_flag(line, &compoundbegin, afflst)) { finishFileMgr(afflst); return 1; } } else { if (!parse_flag(line, &compoundend, afflst)) { finishFileMgr(afflst); return 1; } } } /* parse in the data used by compound_check() method */ if (line.compare(0, 15, "COMPOUNDWORDMAX", 15) == 0) { if (!parse_num(line, &cpdwordmax, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag sign compounds in dictionary */ if (line.compare(0, 12, "COMPOUNDROOT", 12) == 0) { if (!parse_flag(line, &compoundroot, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by compound_check() method */ if (line.compare(0, 18, "COMPOUNDPERMITFLAG", 18) == 0) { if (!parse_flag(line, &compoundpermitflag, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by compound_check() method */ if (line.compare(0, 18, "COMPOUNDFORBIDFLAG", 18) == 0) { if (!parse_flag(line, &compoundforbidflag, afflst)) { finishFileMgr(afflst); return 1; } } if (line.compare(0, 20, "COMPOUNDMORESUFFIXES", 20) == 0) { compoundmoresuffixes = 1; } if (line.compare(0, 16, "CHECKCOMPOUNDDUP", 16) == 0) { checkcompounddup = 1; } if (line.compare(0, 16, "CHECKCOMPOUNDREP", 16) == 0) { checkcompoundrep = 1; } if (line.compare(0, 19, "CHECKCOMPOUNDTRIPLE", 19) == 0) { checkcompoundtriple = 1; } if (line.compare(0, 16, "SIMPLIFIEDTRIPLE", 16) == 0) { simplifiedtriple = 1; } if (line.compare(0, 17, "CHECKCOMPOUNDCASE", 17) == 0) { checkcompoundcase = 1; } if (line.compare(0, 9, "NOSUGGEST", 9) == 0) { if (!parse_flag(line, &nosuggest, afflst)) { finishFileMgr(afflst); return 1; } } if (line.compare(0, 14, "NONGRAMSUGGEST", 14) == 0) { if (!parse_flag(line, &nongramsuggest, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by forbidden words */ if (line.compare(0, 13, "FORBIDDENWORD", 13) == 0) { if (!parse_flag(line, &forbiddenword, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by forbidden words (is deprecated) */ if (line.compare(0, 13, "LEMMA_PRESENT", 13) == 0) { if (!parse_flag(line, &lemma_present, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by circumfixes */ if (line.compare(0, 9, "CIRCUMFIX", 9) == 0) { if (!parse_flag(line, &circumfix, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by fogemorphemes */ if (line.compare(0, 14, "ONLYINCOMPOUND", 14) == 0) { if (!parse_flag(line, &onlyincompound, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by `needaffixs' (is deprecated) */ if (line.compare(0, 10, "PSEUDOROOT", 10) == 0) { if (!parse_flag(line, &needaffix, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by `needaffixs' */ if (line.compare(0, 9, "NEEDAFFIX", 9) == 0) { if (!parse_flag(line, &needaffix, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the minimal length for words in compounds */ if (line.compare(0, 11, "COMPOUNDMIN", 11) == 0) { if (!parse_num(line, &cpdmin, afflst)) { finishFileMgr(afflst); return 1; } if (cpdmin < 1) cpdmin = 1; } /* parse in the max. words and syllables in compounds */ if (line.compare(0, 16, "COMPOUNDSYLLABLE", 16) == 0) { if (!parse_cpdsyllable(line, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by compound_check() method */ if (line.compare(0, 11, "SYLLABLENUM", 11) == 0) { if (!parse_string(line, cpdsyllablenum, afflst->getlinenum())) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by the controlled compound words */ if (line.compare(0, 8, "CHECKNUM", 8) == 0) { checknum = 1; } /* parse in the extra word characters */ if (line.compare(0, 9, "WORDCHARS", 9) == 0) { if (!parse_array(line, wordchars, wordchars_utf16, utf8, afflst->getlinenum())) { finishFileMgr(afflst); return 1; } } /* parse in the ignored characters (for example, Arabic optional diacretics * charachters */ if (line.compare(0, 6, "IGNORE", 6) == 0) { if (!parse_array(line, ignorechars, ignorechars_utf16, utf8, afflst->getlinenum())) { finishFileMgr(afflst); return 1; } } /* parse in the typical fault correcting table */ if (line.compare(0, 3, "REP", 3) == 0) { if (!parse_reptable(line, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the input conversion table */ if (line.compare(0, 5, "ICONV", 5) == 0) { if (!parse_convtable(line, afflst, &iconvtable, "ICONV")) { finishFileMgr(afflst); return 1; } } /* parse in the output conversion table */ if (line.compare(0, 5, "OCONV", 5) == 0) { if (!parse_convtable(line, afflst, &oconvtable, "OCONV")) { finishFileMgr(afflst); return 1; } } /* parse in the phonetic translation table */ if (line.compare(0, 5, "PHONE", 5) == 0) { if (!parse_phonetable(line, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the checkcompoundpattern table */ if (line.compare(0, 20, "CHECKCOMPOUNDPATTERN", 20) == 0) { if (!parse_checkcpdtable(line, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the defcompound table */ if (line.compare(0, 12, "COMPOUNDRULE", 12) == 0) { if (!parse_defcpdtable(line, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the related character map table */ if (line.compare(0, 3, "MAP", 3) == 0) { if (!parse_maptable(line, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the word breakpoints table */ if (line.compare(0, 5, "BREAK", 5) == 0) { if (!parse_breaktable(line, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the language for language specific codes */ if (line.compare(0, 4, "LANG", 4) == 0) { if (!parse_string(line, lang, afflst->getlinenum())) { finishFileMgr(afflst); return 1; } langnum = get_lang_num(lang); } if (line.compare(0, 7, "VERSION", 7) == 0) { size_t startpos = line.find_first_not_of(" \t", 7); if (startpos != std::string::npos) { version = line.substr(startpos); } } if (line.compare(0, 12, "MAXNGRAMSUGS", 12) == 0) { if (!parse_num(line, &maxngramsugs, afflst)) { finishFileMgr(afflst); return 1; } } if (line.compare(0, 11, "ONLYMAXDIFF", 11) == 0) onlymaxdiff = 1; if (line.compare(0, 7, "MAXDIFF", 7) == 0) { if (!parse_num(line, &maxdiff, afflst)) { finishFileMgr(afflst); return 1; } } if (line.compare(0, 10, "MAXCPDSUGS", 10) == 0) { if (!parse_num(line, &maxcpdsugs, afflst)) { finishFileMgr(afflst); return 1; } } if (line.compare(0, 11, "NOSPLITSUGS", 11) == 0) { nosplitsugs = 1; } if (line.compare(0, 9, "FULLSTRIP", 9) == 0) { fullstrip = 1; } if (line.compare(0, 12, "SUGSWITHDOTS", 12) == 0) { sugswithdots = 1; } /* parse in the flag used by forbidden words */ if (line.compare(0, 8, "KEEPCASE", 8) == 0) { if (!parse_flag(line, &keepcase, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by `forceucase' */ if (line.compare(0, 10, "FORCEUCASE", 10) == 0) { if (!parse_flag(line, &forceucase, afflst)) { finishFileMgr(afflst); return 1; } } /* parse in the flag used by `warn' */ if (line.compare(0, 4, "WARN", 4) == 0) { if (!parse_flag(line, &warn, afflst)) { finishFileMgr(afflst); return 1; } } if (line.compare(0, 10, "FORBIDWARN", 10) == 0) { forbidwarn = 1; } /* parse in the flag used by the affix generator */ if (line.compare(0, 11, "SUBSTANDARD", 11) == 0) { if (!parse_flag(line, &substandard, afflst)) { finishFileMgr(afflst); return 1; } } if (line.compare(0, 11, "CHECKSHARPS", 11) == 0) { checksharps = 1; } /* parse this affix: P - prefix, S - suffix */ // affix type char ft = ' '; if (line.compare(0, 3, "PFX", 3) == 0) ft = complexprefixes ? 'S' : 'P'; if (line.compare(0, 3, "SFX", 3) == 0) ft = complexprefixes ? 'P' : 'S'; if (ft != ' ') { if (dupflags_ini) { memset(dupflags, 0, sizeof(dupflags)); dupflags_ini = 0; } if (!parse_affix(line, ft, afflst, dupflags)) { finishFileMgr(afflst); return 1; } } } finishFileMgr(afflst); // affix trees are sorted now // now we can speed up performance greatly taking advantage of the // relationship between the affixes and the idea of "subsets". // View each prefix as a potential leading subset of another and view // each suffix (reversed) as a potential trailing subset of another. // To illustrate this relationship if we know the prefix "ab" is found in the // word to examine, only prefixes that "ab" is a leading subset of need be // examined. // Furthermore is "ab" is not present then none of the prefixes that "ab" is // is a subset need be examined. // The same argument goes for suffix string that are reversed. // Then to top this off why not examine the first char of the word to quickly // limit the set of prefixes to examine (i.e. the prefixes to examine must // be leading supersets of the first character of the word (if they exist) // To take advantage of this "subset" relationship, we need to add two links // from entry. One to take next if the current prefix is found (call it // nexteq) // and one to take next if the current prefix is not found (call it nextne). // Since we have built ordered lists, all that remains is to properly // initialize // the nextne and nexteq pointers that relate them process_pfx_order(); process_sfx_order(); /* get encoding for CHECKCOMPOUNDCASE */ if (!utf8) { csconv = get_current_cs(get_encoding()); for (int i = 0; i <= 255; i++) { if ((csconv[i].cupper != csconv[i].clower) && (wordchars.find((char)i) == std::string::npos)) { wordchars.push_back((char)i); } } } // default BREAK definition if (!parsedbreaktable) { breaktable.push_back("-"); breaktable.push_back("^-"); breaktable.push_back("-$"); parsedbreaktable = true; } return 0; } // we want to be able to quickly access prefix information // both by prefix flag, and sorted by prefix string itself // so we need to set up two indexes int AffixMgr::build_pfxtree(PfxEntry* pfxptr) { PfxEntry* ptr; PfxEntry* pptr; PfxEntry* ep = pfxptr; // get the right starting points const char* key = ep->getKey(); const unsigned char flg = (unsigned char)(ep->getFlag() & 0x00FF); // first index by flag which must exist ptr = pFlag[flg]; ep->setFlgNxt(ptr); pFlag[flg] = ep; // handle the special case of null affix string if (strlen(key) == 0) { // always inset them at head of list at element 0 ptr = pStart[0]; ep->setNext(ptr); pStart[0] = ep; return 0; } // now handle the normal case ep->setNextEQ(NULL); ep->setNextNE(NULL); unsigned char sp = *((const unsigned char*)key); ptr = pStart[sp]; // handle the first insert if (!ptr) { pStart[sp] = ep; return 0; } // otherwise use binary tree insertion so that a sorted // list can easily be generated later pptr = NULL; for (;;) { pptr = ptr; if (strcmp(ep->getKey(), ptr->getKey()) <= 0) { ptr = ptr->getNextEQ(); if (!ptr) { pptr->setNextEQ(ep); break; } } else { ptr = ptr->getNextNE(); if (!ptr) { pptr->setNextNE(ep); break; } } } return 0; } // we want to be able to quickly access suffix information // both by suffix flag, and sorted by the reverse of the // suffix string itself; so we need to set up two indexes int AffixMgr::build_sfxtree(SfxEntry* sfxptr) { sfxptr->initReverseWord(); SfxEntry* ptr; SfxEntry* pptr; SfxEntry* ep = sfxptr; /* get the right starting point */ const char* key = ep->getKey(); const unsigned char flg = (unsigned char)(ep->getFlag() & 0x00FF); // first index by flag which must exist ptr = sFlag[flg]; ep->setFlgNxt(ptr); sFlag[flg] = ep; // next index by affix string // handle the special case of null affix string if (strlen(key) == 0) { // always inset them at head of list at element 0 ptr = sStart[0]; ep->setNext(ptr); sStart[0] = ep; return 0; } // now handle the normal case ep->setNextEQ(NULL); ep->setNextNE(NULL); unsigned char sp = *((const unsigned char*)key); ptr = sStart[sp]; // handle the first insert if (!ptr) { sStart[sp] = ep; return 0; } // otherwise use binary tree insertion so that a sorted // list can easily be generated later pptr = NULL; for (;;) { pptr = ptr; if (strcmp(ep->getKey(), ptr->getKey()) <= 0) { ptr = ptr->getNextEQ(); if (!ptr) { pptr->setNextEQ(ep); break; } } else { ptr = ptr->getNextNE(); if (!ptr) { pptr->setNextNE(ep); break; } } } return 0; } // convert from binary tree to sorted list int AffixMgr::process_pfx_tree_to_list() { for (int i = 1; i < SETSIZE; i++) { pStart[i] = process_pfx_in_order(pStart[i], NULL); } return 0; } PfxEntry* AffixMgr::process_pfx_in_order(PfxEntry* ptr, PfxEntry* nptr) { if (ptr) { nptr = process_pfx_in_order(ptr->getNextNE(), nptr); ptr->setNext(nptr); nptr = process_pfx_in_order(ptr->getNextEQ(), ptr); } return nptr; } // convert from binary tree to sorted list int AffixMgr::process_sfx_tree_to_list() { for (int i = 1; i < SETSIZE; i++) { sStart[i] = process_sfx_in_order(sStart[i], NULL); } return 0; } SfxEntry* AffixMgr::process_sfx_in_order(SfxEntry* ptr, SfxEntry* nptr) { if (ptr) { nptr = process_sfx_in_order(ptr->getNextNE(), nptr); ptr->setNext(nptr); nptr = process_sfx_in_order(ptr->getNextEQ(), ptr); } return nptr; } // reinitialize the PfxEntry links NextEQ and NextNE to speed searching // using the idea of leading subsets this time int AffixMgr::process_pfx_order() { PfxEntry* ptr; // loop through each prefix list starting point for (int i = 1; i < SETSIZE; i++) { ptr = pStart[i]; // look through the remainder of the list // and find next entry with affix that // the current one is not a subset of // mark that as destination for NextNE // use next in list that you are a subset // of as NextEQ for (; ptr != NULL; ptr = ptr->getNext()) { PfxEntry* nptr = ptr->getNext(); for (; nptr != NULL; nptr = nptr->getNext()) { if (!isSubset(ptr->getKey(), nptr->getKey())) break; } ptr->setNextNE(nptr); ptr->setNextEQ(NULL); if ((ptr->getNext()) && isSubset(ptr->getKey(), (ptr->getNext())->getKey())) ptr->setNextEQ(ptr->getNext()); } // now clean up by adding smart search termination strings: // if you are already a superset of the previous prefix // but not a subset of the next, search can end here // so set NextNE properly ptr = pStart[i]; for (; ptr != NULL; ptr = ptr->getNext()) { PfxEntry* nptr = ptr->getNext(); PfxEntry* mptr = NULL; for (; nptr != NULL; nptr = nptr->getNext()) { if (!isSubset(ptr->getKey(), nptr->getKey())) break; mptr = nptr; } if (mptr) mptr->setNextNE(NULL); } } return 0; } // initialize the SfxEntry links NextEQ and NextNE to speed searching // using the idea of leading subsets this time int AffixMgr::process_sfx_order() { SfxEntry* ptr; // loop through each prefix list starting point for (int i = 1; i < SETSIZE; i++) { ptr = sStart[i]; // look through the remainder of the list // and find next entry with affix that // the current one is not a subset of // mark that as destination for NextNE // use next in list that you are a subset // of as NextEQ for (; ptr != NULL; ptr = ptr->getNext()) { SfxEntry* nptr = ptr->getNext(); for (; nptr != NULL; nptr = nptr->getNext()) { if (!isSubset(ptr->getKey(), nptr->getKey())) break; } ptr->setNextNE(nptr); ptr->setNextEQ(NULL); if ((ptr->getNext()) && isSubset(ptr->getKey(), (ptr->getNext())->getKey())) ptr->setNextEQ(ptr->getNext()); } // now clean up by adding smart search termination strings: // if you are already a superset of the previous suffix // but not a subset of the next, search can end here // so set NextNE properly ptr = sStart[i]; for (; ptr != NULL; ptr = ptr->getNext()) { SfxEntry* nptr = ptr->getNext(); SfxEntry* mptr = NULL; for (; nptr != NULL; nptr = nptr->getNext()) { if (!isSubset(ptr->getKey(), nptr->getKey())) break; mptr = nptr; } if (mptr) mptr->setNextNE(NULL); } } return 0; } // add flags to the result for dictionary debugging std::string& AffixMgr::debugflag(std::string& result, unsigned short flag) { char* st = encode_flag(flag); result.append(" "); result.append(MORPH_FLAG); if (st) { result.append(st); free(st); } return result; } // calculate the character length of the condition int AffixMgr::condlen(const char* st) { int l = 0; bool group = false; for (; *st; st++) { if (*st == '[') { group = true; l++; } else if (*st == ']') group = false; else if (!group && (!utf8 || (!(*st & 0x80) || ((*st & 0xc0) == 0x80)))) l++; } return l; } int AffixMgr::encodeit(AffEntry& entry, const char* cs) { if (strcmp(cs, ".") != 0) { entry.numconds = (char)condlen(cs); const size_t cslen = strlen(cs); const size_t short_part = std::min(MAXCONDLEN, cslen); memcpy(entry.c.conds, cs, short_part); if (short_part < MAXCONDLEN) { //blank out the remaining space memset(entry.c.conds + short_part, 0, MAXCONDLEN - short_part); } else if (cs[MAXCONDLEN]) { //there is more conditions than fit in fixed space, so its //a long condition entry.opts += aeLONGCOND; entry.c.l.conds2 = mystrdup(cs + MAXCONDLEN_1); if (!entry.c.l.conds2) return 1; } } else { entry.numconds = 0; entry.c.conds[0] = '\0'; } return 0; } // return 1 if s1 is a leading subset of s2 (dots are for infixes) inline int AffixMgr::isSubset(const char* s1, const char* s2) { while (((*s1 == *s2) || (*s1 == '.')) && (*s1 != '\0')) { s1++; s2++; } return (*s1 == '\0'); } // check word for prefixes struct hentry* AffixMgr::prefix_check(const char* word, int len, char in_compound, const FLAG needflag) { struct hentry* rv = NULL; pfx = NULL; pfxappnd = NULL; sfxappnd = NULL; sfxextra = 0; // first handle the special case of 0 length prefixes PfxEntry* pe = pStart[0]; while (pe) { if ( // fogemorpheme ((in_compound != IN_CPD_NOT) || !(pe->getCont() && (TESTAFF(pe->getCont(), onlyincompound, pe->getContLen())))) && // permit prefixes in compounds ((in_compound != IN_CPD_END) || (pe->getCont() && (TESTAFF(pe->getCont(), compoundpermitflag, pe->getContLen()))))) { // check prefix rv = pe->checkword(word, len, in_compound, needflag); if (rv) { pfx = pe; // BUG: pfx not stateless return rv; } } pe = pe->getNext(); } // now handle the general case unsigned char sp = *((const unsigned char*)word); PfxEntry* pptr = pStart[sp]; while (pptr) { if (isSubset(pptr->getKey(), word)) { if ( // fogemorpheme ((in_compound != IN_CPD_NOT) || !(pptr->getCont() && (TESTAFF(pptr->getCont(), onlyincompound, pptr->getContLen())))) && // permit prefixes in compounds ((in_compound != IN_CPD_END) || (pptr->getCont() && (TESTAFF(pptr->getCont(), compoundpermitflag, pptr->getContLen()))))) { // check prefix rv = pptr->checkword(word, len, in_compound, needflag); if (rv) { pfx = pptr; // BUG: pfx not stateless return rv; } } pptr = pptr->getNextEQ(); } else { pptr = pptr->getNextNE(); } } return NULL; } // check word for prefixes and two-level suffixes struct hentry* AffixMgr::prefix_check_twosfx(const char* word, int len, char in_compound, const FLAG needflag) { struct hentry* rv = NULL; pfx = NULL; sfxappnd = NULL; sfxextra = 0; // first handle the special case of 0 length prefixes PfxEntry* pe = pStart[0]; while (pe) { rv = pe->check_twosfx(word, len, in_compound, needflag); if (rv) return rv; pe = pe->getNext(); } // now handle the general case unsigned char sp = *((const unsigned char*)word); PfxEntry* pptr = pStart[sp]; while (pptr) { if (isSubset(pptr->getKey(), word)) { rv = pptr->check_twosfx(word, len, in_compound, needflag); if (rv) { pfx = pptr; return rv; } pptr = pptr->getNextEQ(); } else { pptr = pptr->getNextNE(); } } return NULL; } // check word for prefixes and morph std::string AffixMgr::prefix_check_morph(const char* word, int len, char in_compound, const FLAG needflag) { std::string result; pfx = NULL; sfxappnd = NULL; sfxextra = 0; // first handle the special case of 0 length prefixes PfxEntry* pe = pStart[0]; while (pe) { std::string st = pe->check_morph(word, len, in_compound, needflag); if (!st.empty()) { result.append(st); } pe = pe->getNext(); } // now handle the general case unsigned char sp = *((const unsigned char*)word); PfxEntry* pptr = pStart[sp]; while (pptr) { if (isSubset(pptr->getKey(), word)) { std::string st = pptr->check_morph(word, len, in_compound, needflag); if (!st.empty()) { // fogemorpheme if ((in_compound != IN_CPD_NOT) || !((pptr->getCont() && (TESTAFF(pptr->getCont(), onlyincompound, pptr->getContLen()))))) { result.append(st); pfx = pptr; } } pptr = pptr->getNextEQ(); } else { pptr = pptr->getNextNE(); } } return result; } // check word for prefixes and morph and two-level suffixes std::string AffixMgr::prefix_check_twosfx_morph(const char* word, int len, char in_compound, const FLAG needflag) { std::string result; pfx = NULL; sfxappnd = NULL; sfxextra = 0; // first handle the special case of 0 length prefixes PfxEntry* pe = pStart[0]; while (pe) { std::string st = pe->check_twosfx_morph(word, len, in_compound, needflag); if (!st.empty()) { result.append(st); } pe = pe->getNext(); } // now handle the general case unsigned char sp = *((const unsigned char*)word); PfxEntry* pptr = pStart[sp]; while (pptr) { if (isSubset(pptr->getKey(), word)) { std::string st = pptr->check_twosfx_morph(word, len, in_compound, needflag); if (!st.empty()) { result.append(st); pfx = pptr; } pptr = pptr->getNextEQ(); } else { pptr = pptr->getNextNE(); } } return result; } // Is word a non-compound with a REP substitution (see checkcompoundrep)? int AffixMgr::cpdrep_check(const char* word, int wl) { if ((wl < 2) || reptable.empty()) return 0; for (size_t i = 0; i < reptable.size(); ++i) { const char* r = word; const size_t lenp = reptable[i].pattern.size(); // search every occurence of the pattern in the word while ((r = strstr(r, reptable[i].pattern.c_str())) != NULL) { std::string candidate(word); size_t type = r == word && langnum != LANG_hu ? 1 : 0; if (r - word + reptable[i].pattern.size() == lenp && langnum != LANG_hu) type += 2; candidate.replace(r - word, lenp, reptable[i].outstrings[type]); if (candidate_check(candidate.c_str(), candidate.size())) return 1; ++r; // search for the next letter } } return 0; } // forbid compoundings when there are special patterns at word bound int AffixMgr::cpdpat_check(const char* word, int pos, hentry* r1, hentry* r2, const char /*affixed*/) { for (size_t i = 0; i < checkcpdtable.size(); ++i) { size_t len; if (isSubset(checkcpdtable[i].pattern2.c_str(), word + pos) && (!r1 || !checkcpdtable[i].cond || (r1->astr && TESTAFF(r1->astr, checkcpdtable[i].cond, r1->alen))) && (!r2 || !checkcpdtable[i].cond2 || (r2->astr && TESTAFF(r2->astr, checkcpdtable[i].cond2, r2->alen))) && // zero length pattern => only TESTAFF // zero pattern (0/flag) => unmodified stem (zero affixes allowed) (checkcpdtable[i].pattern.empty() || ((checkcpdtable[i].pattern[0] == '0' && r1->blen <= pos && strncmp(word + pos - r1->blen, r1->word, r1->blen) == 0) || (checkcpdtable[i].pattern[0] != '0' && ((len = checkcpdtable[i].pattern.size()) != 0) && strncmp(word + pos - len, checkcpdtable[i].pattern.c_str(), len) == 0)))) { return 1; } } return 0; } // forbid compounding with neighbouring upper and lower case characters at word // bounds int AffixMgr::cpdcase_check(const char* word, int pos) { if (utf8) { const char* p; for (p = word + pos - 1; (*p & 0xc0) == 0x80; p--) ; std::string pair(p); std::vector pair_u; u8_u16(pair_u, pair); unsigned short a = pair_u.size() > 1 ? ((pair_u[1].h << 8) + pair_u[1].l) : 0; unsigned short b = !pair_u.empty() ? ((pair_u[0].h << 8) + pair_u[0].l) : 0; if (((unicodetoupper(a, langnum) == a) || (unicodetoupper(b, langnum) == b)) && (a != '-') && (b != '-')) return 1; } else { unsigned char a = *(word + pos - 1); unsigned char b = *(word + pos); if ((csconv[a].ccase || csconv[b].ccase) && (a != '-') && (b != '-')) return 1; } return 0; } struct metachar_data { signed short btpp; // metacharacter (*, ?) position for backtracking signed short btwp; // word position for metacharacters int btnum; // number of matched characters in metacharacter }; // check compound patterns int AffixMgr::defcpd_check(hentry*** words, short wnum, hentry* rv, hentry** def, char all) { int w = 0; if (!*words) { w = 1; *words = def; } if (!*words) { return 0; } std::vector btinfo(1); short bt = 0; (*words)[wnum] = rv; // has the last word COMPOUNDRULE flag? if (rv->alen == 0) { (*words)[wnum] = NULL; if (w) *words = NULL; return 0; } int ok = 0; for (size_t i = 0; i < defcpdtable.size(); ++i) { for (size_t j = 0; j < defcpdtable[i].size(); ++j) { if (defcpdtable[i][j] != '*' && defcpdtable[i][j] != '?' && TESTAFF(rv->astr, defcpdtable[i][j], rv->alen)) { ok = 1; break; } } } if (ok == 0) { (*words)[wnum] = NULL; if (w) *words = NULL; return 0; } for (size_t i = 0; i < defcpdtable.size(); ++i) { size_t pp = 0; // pattern position signed short wp = 0; // "words" position int ok2; ok = 1; ok2 = 1; do { while ((pp < defcpdtable[i].size()) && (wp <= wnum)) { if (((pp + 1) < defcpdtable[i].size()) && ((defcpdtable[i][pp + 1] == '*') || (defcpdtable[i][pp + 1] == '?'))) { int wend = (defcpdtable[i][pp + 1] == '?') ? wp : wnum; ok2 = 1; pp += 2; btinfo[bt].btpp = pp; btinfo[bt].btwp = wp; while (wp <= wend) { if (!(*words)[wp]->alen || !TESTAFF((*words)[wp]->astr, defcpdtable[i][pp - 2], (*words)[wp]->alen)) { ok2 = 0; break; } wp++; } if (wp <= wnum) ok2 = 0; btinfo[bt].btnum = wp - btinfo[bt].btwp; if (btinfo[bt].btnum > 0) { ++bt; btinfo.resize(bt+1); } if (ok2) break; } else { ok2 = 1; if (!(*words)[wp] || !(*words)[wp]->alen || !TESTAFF((*words)[wp]->astr, defcpdtable[i][pp], (*words)[wp]->alen)) { ok = 0; break; } pp++; wp++; if ((defcpdtable[i].size() == pp) && !(wp > wnum)) ok = 0; } } if (ok && ok2) { size_t r = pp; while ((defcpdtable[i].size() > r) && ((r + 1) < defcpdtable[i].size()) && ((defcpdtable[i][r + 1] == '*') || (defcpdtable[i][r + 1] == '?'))) r += 2; if (defcpdtable[i].size() <= r) return 1; } // backtrack if (bt) do { ok = 1; btinfo[bt - 1].btnum--; pp = btinfo[bt - 1].btpp; wp = btinfo[bt - 1].btwp + (signed short)btinfo[bt - 1].btnum; } while ((btinfo[bt - 1].btnum < 0) && --bt); } while (bt); if (ok && ok2 && (!all || (defcpdtable[i].size() <= pp))) return 1; // check zero ending while (ok && ok2 && (defcpdtable[i].size() > pp) && ((pp + 1) < defcpdtable[i].size()) && ((defcpdtable[i][pp + 1] == '*') || (defcpdtable[i][pp + 1] == '?'))) pp += 2; if (ok && ok2 && (defcpdtable[i].size() <= pp)) return 1; } (*words)[wnum] = NULL; if (w) *words = NULL; return 0; } inline int AffixMgr::candidate_check(const char* word, int len) { struct hentry* rv = lookup(word); if (rv) return 1; // rv = prefix_check(word,len,1); // if (rv) return 1; rv = affix_check(word, len); if (rv) return 1; return 0; } // calculate number of syllable for compound-checking short AffixMgr::get_syllable(const std::string& word) { if (cpdmaxsyllable == 0) return 0; short num = 0; if (!utf8) { for (size_t i = 0; i < word.size(); ++i) { if (std::binary_search(cpdvowels.begin(), cpdvowels.end(), word[i])) { ++num; } } } else if (!cpdvowels_utf16.empty()) { std::vector w; u8_u16(w, word); for (size_t i = 0; i < w.size(); ++i) { if (std::binary_search(cpdvowels_utf16.begin(), cpdvowels_utf16.end(), w[i])) { ++num; } } } return num; } void AffixMgr::setcminmax(int* cmin, int* cmax, const char* word, int len) { if (utf8) { int i; for (*cmin = 0, i = 0; (i < cpdmin) && *cmin < len; i++) { for ((*cmin)++; *cmin < len && (word[*cmin] & 0xc0) == 0x80; (*cmin)++) ; } for (*cmax = len, i = 0; (i < (cpdmin - 1)) && *cmax >= 0; i++) { for ((*cmax)--; *cmax >= 0 && (word[*cmax] & 0xc0) == 0x80; (*cmax)--) ; } } else { *cmin = cpdmin; *cmax = len - cpdmin + 1; } } // check if compound word is correctly spelled // hu_mov_rule = spec. Hungarian rule (XXX) struct hentry* AffixMgr::compound_check(const std::string& word, short wordnum, short numsyllable, short maxwordnum, short wnum, hentry** words = NULL, hentry** rwords = NULL, char hu_mov_rule = 0, char is_sug = 0, int* info = NULL) { int i; short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2; struct hentry* rv = NULL; struct hentry* rv_first; std::string st; char ch = '\0'; int cmin; int cmax; int striple = 0; size_t scpd = 0; int soldi = 0; int oldcmin = 0; int oldcmax = 0; int oldlen = 0; int checkedstriple = 0; char affixed = 0; hentry** oldwords = words; size_t len = word.size(); int checked_prefix; setcminmax(&cmin, &cmax, word.c_str(), len); st.assign(word); for (i = cmin; i < cmax; i++) { // go to end of the UTF-8 character if (utf8) { for (; (st[i] & 0xc0) == 0x80; i++) ; if (i >= cmax) return NULL; } words = oldwords; int onlycpdrule = (words) ? 1 : 0; do { // onlycpdrule loop oldnumsyllable = numsyllable; oldwordnum = wordnum; checked_prefix = 0; do { // simplified checkcompoundpattern loop if (scpd > 0) { for (; scpd <= checkcpdtable.size() && (checkcpdtable[scpd - 1].pattern3.empty() || strncmp(word.c_str() + i, checkcpdtable[scpd - 1].pattern3.c_str(), checkcpdtable[scpd - 1].pattern3.size()) != 0); scpd++) ; if (scpd > checkcpdtable.size()) break; // break simplified checkcompoundpattern loop st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern); soldi = i; i += checkcpdtable[scpd - 1].pattern.size(); st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern2); st.replace(i + checkcpdtable[scpd - 1].pattern2.size(), std::string::npos, word.substr(soldi + checkcpdtable[scpd - 1].pattern3.size())); oldlen = len; len += checkcpdtable[scpd - 1].pattern.size() + checkcpdtable[scpd - 1].pattern2.size() - checkcpdtable[scpd - 1].pattern3.size(); oldcmin = cmin; oldcmax = cmax; setcminmax(&cmin, &cmax, st.c_str(), len); cmax = len - cpdmin + 1; } ch = st[i]; st[i] = '\0'; sfx = NULL; pfx = NULL; // FIRST WORD affixed = 1; rv = lookup(st.c_str()); // perhaps without prefix // search homonym with compound flag while ((rv) && !hu_mov_rule && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || !((compoundflag && !words && !onlycpdrule && TESTAFF(rv->astr, compoundflag, rv->alen)) || (compoundbegin && !wordnum && !onlycpdrule && TESTAFF(rv->astr, compoundbegin, rv->alen)) || (compoundmiddle && wordnum && !words && !onlycpdrule && TESTAFF(rv->astr, compoundmiddle, rv->alen)) || (!defcpdtable.empty() && onlycpdrule && ((!words && !wordnum && defcpd_check(&words, wnum, rv, rwords, 0)) || (words && defcpd_check(&words, wnum, rv, rwords, 0))))) || (scpd != 0 && checkcpdtable[scpd - 1].cond != FLAG_NULL && !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)))) { rv = rv->next_homonym; } if (rv) affixed = 0; if (!rv) { if (onlycpdrule) break; if (compoundflag && !(rv = prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundflag))) { if (((rv = suffix_check( st.c_str(), i, 0, NULL, FLAG_NULL, compoundflag, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || (compoundmoresuffixes && (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) && !hu_mov_rule && sfx->getCont() && ((compoundforbidflag && TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())) || (compoundend && TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { rv = NULL; } } if (rv || (((wordnum == 0) && compoundbegin && ((rv = suffix_check( st.c_str(), i, 0, NULL, FLAG_NULL, compoundbegin, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || (compoundmoresuffixes && (rv = suffix_check_twosfx( st.c_str(), i, 0, NULL, compoundbegin))) || // twofold suffixes + compound (rv = prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundbegin)))) || ((wordnum > 0) && compoundmiddle && ((rv = suffix_check( st.c_str(), i, 0, NULL, FLAG_NULL, compoundmiddle, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || (compoundmoresuffixes && (rv = suffix_check_twosfx( st.c_str(), i, 0, NULL, compoundmiddle))) || // twofold suffixes + compound (rv = prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundmiddle)))))) checked_prefix = 1; // else check forbiddenwords and needaffix } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) || TESTAFF(rv->astr, needaffix, rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) { st[i] = ch; // continue; break; } // check non_compound flag in suffix and prefix if ((rv) && !hu_mov_rule && ((pfx && pfx->getCont() && TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || (sfx && sfx->getCont() && TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())))) { rv = NULL; } // check compoundend flag in suffix and prefix if ((rv) && !checked_prefix && compoundend && !hu_mov_rule && ((pfx && pfx->getCont() && TESTAFF(pfx->getCont(), compoundend, pfx->getContLen())) || (sfx && sfx->getCont() && TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { rv = NULL; } // check compoundmiddle flag in suffix and prefix if ((rv) && !checked_prefix && (wordnum == 0) && compoundmiddle && !hu_mov_rule && ((pfx && pfx->getCont() && TESTAFF(pfx->getCont(), compoundmiddle, pfx->getContLen())) || (sfx && sfx->getCont() && TESTAFF(sfx->getCont(), compoundmiddle, sfx->getContLen())))) { rv = NULL; } // check forbiddenwords if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) { return NULL; } // increment word number, if the second root has a compoundroot flag if ((rv) && compoundroot && (TESTAFF(rv->astr, compoundroot, rv->alen))) { wordnum++; } // first word is acceptable in compound words? if (((rv) && (checked_prefix || (words && words[wnum]) || (compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || ((oldwordnum == 0) && compoundbegin && TESTAFF(rv->astr, compoundbegin, rv->alen)) || ((oldwordnum > 0) && compoundmiddle && TESTAFF(rv->astr, compoundmiddle, rv->alen)) // LANG_hu section: spec. Hungarian rule || ((langnum == LANG_hu) && hu_mov_rule && (TESTAFF( rv->astr, 'F', rv->alen) || // XXX hardwired Hungarian dictionary codes TESTAFF(rv->astr, 'G', rv->alen) || TESTAFF(rv->astr, 'H', rv->alen))) // END of LANG_hu section ) && ( // test CHECKCOMPOUNDPATTERN conditions scpd == 0 || checkcpdtable[scpd - 1].cond == FLAG_NULL || TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)) && !((checkcompoundtriple && scpd == 0 && !words && // test triple letters (word[i - 1] == word[i]) && (((i > 1) && (word[i - 1] == word[i - 2])) || ((word[i - 1] == word[i + 1])) // may be word[i+1] == '\0' )) || (checkcompoundcase && scpd == 0 && !words && cpdcase_check(word.c_str(), i)))) // LANG_hu section: spec. Hungarian rule || ((!rv) && (langnum == LANG_hu) && hu_mov_rule && (rv = affix_check(st.c_str(), i)) && (sfx && sfx->getCont() && ( // XXX hardwired Hungarian dic. codes TESTAFF(sfx->getCont(), (unsigned short)'x', sfx->getContLen()) || TESTAFF( sfx->getCont(), (unsigned short)'%', sfx->getContLen()))))) { // first word is ok condition // LANG_hu section: spec. Hungarian rule if (langnum == LANG_hu) { // calculate syllable number of the word numsyllable += get_syllable(st.substr(0, i)); // + 1 word, if syllable number of the prefix > 1 (hungarian // convention) if (pfx && (get_syllable(pfx->getKey()) > 1)) wordnum++; } // END of LANG_hu section // NEXT WORD(S) rv_first = rv; st[i] = ch; do { // striple loop // check simplifiedtriple if (simplifiedtriple) { if (striple) { checkedstriple = 1; i--; // check "fahrt" instead of "ahrt" in "Schiffahrt" } else if (i > 2 && word[i - 1] == word[i - 2]) striple = 1; } rv = lookup(st.c_str() + i); // perhaps without prefix // search homonym with compound flag while ((rv) && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || !((compoundflag && !words && TESTAFF(rv->astr, compoundflag, rv->alen)) || (compoundend && !words && TESTAFF(rv->astr, compoundend, rv->alen)) || (!defcpdtable.empty() && words && defcpd_check(&words, wnum + 1, rv, NULL, 1))) || (scpd != 0 && checkcpdtable[scpd - 1].cond2 != FLAG_NULL && !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen)))) { rv = rv->next_homonym; } // check FORCEUCASE if (rv && forceucase && (rv) && (TESTAFF(rv->astr, forceucase, rv->alen)) && !(info && *info & SPELL_ORIGCAP)) rv = NULL; if (rv && words && words[wnum + 1]) return rv_first; oldnumsyllable2 = numsyllable; oldwordnum2 = wordnum; // LANG_hu section: spec. Hungarian rule, XXX hardwired dictionary // code if ((rv) && (langnum == LANG_hu) && (TESTAFF(rv->astr, 'I', rv->alen)) && !(TESTAFF(rv->astr, 'J', rv->alen))) { numsyllable--; } // END of LANG_hu section // increment word number, if the second root has a compoundroot flag if ((rv) && (compoundroot) && (TESTAFF(rv->astr, compoundroot, rv->alen))) { wordnum++; } // check forbiddenwords if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) return NULL; // second word is acceptable, as a root? // hungarian conventions: compounding is acceptable, // when compound forms consist of 2 words, or if more, // then the syllable number of root words must be 6, or lesser. if ((rv) && ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) && (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || ((cpdmaxsyllable != 0) && (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->blen)) <= cpdmaxsyllable))) && ( // test CHECKCOMPOUNDPATTERN checkcpdtable.empty() || scpd != 0 || !cpdpat_check(word.c_str(), i, rv_first, rv, 0)) && ((!checkcompounddup || (rv != rv_first))) // test CHECKCOMPOUNDPATTERN conditions && (scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL || TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen))) { // forbid compound word, if it is a non-compound word with typical // fault if (checkcompoundrep && cpdrep_check(word.c_str(), len)) return NULL; return rv_first; } numsyllable = oldnumsyllable2; wordnum = oldwordnum2; // perhaps second word has prefix or/and suffix sfx = NULL; sfxflag = FLAG_NULL; rv = (compoundflag && !onlycpdrule) ? affix_check((word.c_str() + i), strlen(word.c_str() + i), compoundflag, IN_CPD_END) : NULL; if (!rv && compoundend && !onlycpdrule) { sfx = NULL; pfx = NULL; rv = affix_check((word.c_str() + i), strlen(word.c_str() + i), compoundend, IN_CPD_END); } if (!rv && !defcpdtable.empty() && words) { rv = affix_check((word.c_str() + i), strlen(word.c_str() + i), 0, IN_CPD_END); if (rv && defcpd_check(&words, wnum + 1, rv, NULL, 1)) return rv_first; rv = NULL; } // test CHECKCOMPOUNDPATTERN conditions (allowed forms) if (rv && !(scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL || TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen))) rv = NULL; // test CHECKCOMPOUNDPATTERN conditions (forbidden compounds) if (rv && !checkcpdtable.empty() && scpd == 0 && cpdpat_check(word.c_str(), i, rv_first, rv, affixed)) rv = NULL; // check non_compound flag in suffix and prefix if ((rv) && ((pfx && pfx->getCont() && TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || (sfx && sfx->getCont() && TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())))) { rv = NULL; } // check FORCEUCASE if (rv && forceucase && (rv) && (TESTAFF(rv->astr, forceucase, rv->alen)) && !(info && *info & SPELL_ORIGCAP)) rv = NULL; // check forbiddenwords if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) return NULL; // pfxappnd = prefix of word+i, or NULL // calculate syllable number of prefix. // hungarian convention: when syllable number of prefix is more, // than 1, the prefix+word counts as two words. if (langnum == LANG_hu) { // calculate syllable number of the word numsyllable += get_syllable(word.c_str() + i); // - affix syllable num. // XXX only second suffix (inflections, not derivations) if (sfxappnd) { std::string tmp(sfxappnd); reverseword(tmp); numsyllable -= get_syllable(tmp) + sfxextra; } else { numsyllable -= sfxextra; } // + 1 word, if syllable number of the prefix > 1 (hungarian // convention) if (pfx && (get_syllable(pfx->getKey()) > 1)) wordnum++; // increment syllable num, if last word has a SYLLABLENUM flag // and the suffix is beginning `s' if (!cpdsyllablenum.empty()) { switch (sfxflag) { case 'c': { numsyllable += 2; break; } case 'J': { numsyllable += 1; break; } case 'I': { if (rv && TESTAFF(rv->astr, 'J', rv->alen)) numsyllable += 1; break; } } } } // increment word number, if the second word has a compoundroot flag if ((rv) && (compoundroot) && (TESTAFF(rv->astr, compoundroot, rv->alen))) { wordnum++; } // second word is acceptable, as a word with prefix or/and suffix? // hungarian conventions: compounding is acceptable, // when compound forms consist 2 word, otherwise // the syllable number of root words is 6, or lesser. if ((rv) && (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) && ((!checkcompounddup || (rv != rv_first)))) { // forbid compound word, if it is a non-compound word with typical // fault if (checkcompoundrep && cpdrep_check(word.c_str(), len)) return NULL; return rv_first; } numsyllable = oldnumsyllable2; wordnum = oldwordnum2; // perhaps second word is a compound word (recursive call) if (wordnum + 2 < maxwordnum) { rv = compound_check(st.substr(i), wordnum + 1, numsyllable, maxwordnum, wnum + 1, words, rwords, 0, is_sug, info); if (rv && !checkcpdtable.empty() && ((scpd == 0 && cpdpat_check(word.c_str(), i, rv_first, rv, affixed)) || (scpd != 0 && !cpdpat_check(word.c_str(), i, rv_first, rv, affixed)))) rv = NULL; } else { rv = NULL; } if (rv) { // forbid compound word, if it is a non-compound word with typical // fault if (checkcompoundrep || forbiddenword) { if (checkcompoundrep && cpdrep_check(word.c_str(), len)) return NULL; // check first part if (strncmp(rv->word, word.c_str() + i, rv->blen) == 0) { char r = st[i + rv->blen]; st[i + rv->blen] = '\0'; if (checkcompoundrep && cpdrep_check(st.c_str(), i + rv->blen)) { st[ + i + rv->blen] = r; continue; } if (forbiddenword) { struct hentry* rv2 = lookup(word.c_str()); if (!rv2) rv2 = affix_check(word.c_str(), len); if (rv2 && rv2->astr && TESTAFF(rv2->astr, forbiddenword, rv2->alen) && (strncmp(rv2->word, st.c_str(), i + rv->blen) == 0)) { return NULL; } } st[i + rv->blen] = r; } } return rv_first; } } while (striple && !checkedstriple); // end of striple loop if (checkedstriple) { i++; checkedstriple = 0; striple = 0; } } // first word is ok condition if (soldi != 0) { i = soldi; soldi = 0; len = oldlen; cmin = oldcmin; cmax = oldcmax; } scpd++; } while (!onlycpdrule && simplifiedcpd && scpd <= checkcpdtable.size()); // end of simplifiedcpd loop scpd = 0; wordnum = oldwordnum; numsyllable = oldnumsyllable; if (soldi != 0) { i = soldi; st.assign(word); // XXX add more optim. soldi = 0; } else st[i] = ch; } while (!defcpdtable.empty() && oldwordnum == 0 && onlycpdrule++ < 1); // end of onlycpd loop } return NULL; } // check if compound word is correctly spelled // hu_mov_rule = spec. Hungarian rule (XXX) int AffixMgr::compound_check_morph(const char* word, int len, short wordnum, short numsyllable, short maxwordnum, short wnum, hentry** words, hentry** rwords, char hu_mov_rule, std::string& result, const std::string* partresult) { int i; short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2; int ok = 0; struct hentry* rv = NULL; struct hentry* rv_first; std::string st; char ch; int checked_prefix; std::string presult; int cmin; int cmax; char affixed = 0; hentry** oldwords = words; setcminmax(&cmin, &cmax, word, len); st.assign(word); for (i = cmin; i < cmax; i++) { // go to end of the UTF-8 character if (utf8) { for (; (st[i] & 0xc0) == 0x80; i++) ; if (i >= cmax) return 0; } words = oldwords; int onlycpdrule = (words) ? 1 : 0; do { // onlycpdrule loop oldnumsyllable = numsyllable; oldwordnum = wordnum; checked_prefix = 0; ch = st[i]; st[i] = '\0'; sfx = NULL; // FIRST WORD affixed = 1; presult.clear(); if (partresult) presult.append(*partresult); rv = lookup(st.c_str()); // perhaps without prefix // search homonym with compound flag while ((rv) && !hu_mov_rule && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || !((compoundflag && !words && !onlycpdrule && TESTAFF(rv->astr, compoundflag, rv->alen)) || (compoundbegin && !wordnum && !onlycpdrule && TESTAFF(rv->astr, compoundbegin, rv->alen)) || (compoundmiddle && wordnum && !words && !onlycpdrule && TESTAFF(rv->astr, compoundmiddle, rv->alen)) || (!defcpdtable.empty() && onlycpdrule && ((!words && !wordnum && defcpd_check(&words, wnum, rv, rwords, 0)) || (words && defcpd_check(&words, wnum, rv, rwords, 0))))))) { rv = rv->next_homonym; } if (rv) affixed = 0; if (rv) { presult.push_back(MSEP_FLD); presult.append(MORPH_PART); presult.append(st.c_str()); if (!HENTRY_FIND(rv, MORPH_STEM)) { presult.push_back(MSEP_FLD); presult.append(MORPH_STEM); presult.append(st.c_str()); } if (HENTRY_DATA(rv)) { presult.push_back(MSEP_FLD); presult.append(HENTRY_DATA2(rv)); } } if (!rv) { if (compoundflag && !(rv = prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundflag))) { if (((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL, compoundflag, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || (compoundmoresuffixes && (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) && !hu_mov_rule && sfx->getCont() && ((compoundforbidflag && TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())) || (compoundend && TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { rv = NULL; } } if (rv || (((wordnum == 0) && compoundbegin && ((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL, compoundbegin, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || (compoundmoresuffixes && (rv = suffix_check_twosfx( st.c_str(), i, 0, NULL, compoundbegin))) || // twofold suffix+compound (rv = prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundbegin)))) || ((wordnum > 0) && compoundmiddle && ((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL, compoundmiddle, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || (compoundmoresuffixes && (rv = suffix_check_twosfx( st.c_str(), i, 0, NULL, compoundmiddle))) || // twofold suffix+compound (rv = prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundmiddle)))))) { std::string p; if (compoundflag) p = affix_check_morph(st.c_str(), i, compoundflag); if (p.empty()) { if ((wordnum == 0) && compoundbegin) { p = affix_check_morph(st.c_str(), i, compoundbegin); } else if ((wordnum > 0) && compoundmiddle) { p = affix_check_morph(st.c_str(), i, compoundmiddle); } } if (!p.empty()) { presult.push_back(MSEP_FLD); presult.append(MORPH_PART); presult.append(st.c_str()); line_uniq_app(p, MSEP_REC); presult.append(p); } checked_prefix = 1; } // else check forbiddenwords } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || TESTAFF(rv->astr, needaffix, rv->alen))) { st[i] = ch; continue; } // check non_compound flag in suffix and prefix if ((rv) && !hu_mov_rule && ((pfx && pfx->getCont() && TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || (sfx && sfx->getCont() && TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())))) { continue; } // check compoundend flag in suffix and prefix if ((rv) && !checked_prefix && compoundend && !hu_mov_rule && ((pfx && pfx->getCont() && TESTAFF(pfx->getCont(), compoundend, pfx->getContLen())) || (sfx && sfx->getCont() && TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { continue; } // check compoundmiddle flag in suffix and prefix if ((rv) && !checked_prefix && (wordnum == 0) && compoundmiddle && !hu_mov_rule && ((pfx && pfx->getCont() && TESTAFF(pfx->getCont(), compoundmiddle, pfx->getContLen())) || (sfx && sfx->getCont() && TESTAFF(sfx->getCont(), compoundmiddle, sfx->getContLen())))) { rv = NULL; } // check forbiddenwords if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) continue; // increment word number, if the second root has a compoundroot flag if ((rv) && (compoundroot) && (TESTAFF(rv->astr, compoundroot, rv->alen))) { wordnum++; } // first word is acceptable in compound words? if (((rv) && (checked_prefix || (words && words[wnum]) || (compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || ((oldwordnum == 0) && compoundbegin && TESTAFF(rv->astr, compoundbegin, rv->alen)) || ((oldwordnum > 0) && compoundmiddle && TESTAFF(rv->astr, compoundmiddle, rv->alen)) // LANG_hu section: spec. Hungarian rule || ((langnum == LANG_hu) && // hu_mov_rule hu_mov_rule && (TESTAFF(rv->astr, 'F', rv->alen) || TESTAFF(rv->astr, 'G', rv->alen) || TESTAFF(rv->astr, 'H', rv->alen))) // END of LANG_hu section ) && !((checkcompoundtriple && !words && // test triple letters (word[i - 1] == word[i]) && (((i > 1) && (word[i - 1] == word[i - 2])) || ((word[i - 1] == word[i + 1])) // may be word[i+1] == '\0' )) || ( // test CHECKCOMPOUNDPATTERN !checkcpdtable.empty() && !words && cpdpat_check(word, i, rv, NULL, affixed)) || (checkcompoundcase && !words && cpdcase_check(word, i)))) // LANG_hu section: spec. Hungarian rule || ((!rv) && (langnum == LANG_hu) && hu_mov_rule && (rv = affix_check(st.c_str(), i)) && (sfx && sfx->getCont() && (TESTAFF(sfx->getCont(), (unsigned short)'x', sfx->getContLen()) || TESTAFF(sfx->getCont(), (unsigned short)'%', sfx->getContLen())))) // END of LANG_hu section ) { // LANG_hu section: spec. Hungarian rule if (langnum == LANG_hu) { // calculate syllable number of the word numsyllable += get_syllable(st.substr(0, i)); // + 1 word, if syllable number of the prefix > 1 (hungarian // convention) if (pfx && (get_syllable(pfx->getKey()) > 1)) wordnum++; } // END of LANG_hu section // NEXT WORD(S) rv_first = rv; rv = lookup((word + i)); // perhaps without prefix // search homonym with compound flag while ((rv) && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || !((compoundflag && !words && TESTAFF(rv->astr, compoundflag, rv->alen)) || (compoundend && !words && TESTAFF(rv->astr, compoundend, rv->alen)) || (!defcpdtable.empty() && words && defcpd_check(&words, wnum + 1, rv, NULL, 1))))) { rv = rv->next_homonym; } if (rv && words && words[wnum + 1]) { result.append(presult); result.append(" "); result.append(MORPH_PART); result.append(word + i); if (complexprefixes && HENTRY_DATA(rv)) result.append(HENTRY_DATA2(rv)); if (!HENTRY_FIND(rv, MORPH_STEM)) { result.append(" "); result.append(MORPH_STEM); result.append(HENTRY_WORD(rv)); } // store the pointer of the hash entry if (!complexprefixes && HENTRY_DATA(rv)) { result.append(" "); result.append(HENTRY_DATA2(rv)); } result.append("\n"); return 0; } oldnumsyllable2 = numsyllable; oldwordnum2 = wordnum; // LANG_hu section: spec. Hungarian rule if ((rv) && (langnum == LANG_hu) && (TESTAFF(rv->astr, 'I', rv->alen)) && !(TESTAFF(rv->astr, 'J', rv->alen))) { numsyllable--; } // END of LANG_hu section // increment word number, if the second root has a compoundroot flag if ((rv) && (compoundroot) && (TESTAFF(rv->astr, compoundroot, rv->alen))) { wordnum++; } // check forbiddenwords if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) { st[i] = ch; continue; } // second word is acceptable, as a root? // hungarian conventions: compounding is acceptable, // when compound forms consist of 2 words, or if more, // then the syllable number of root words must be 6, or lesser. if ((rv) && ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) && (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || ((cpdmaxsyllable != 0) && (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->blen)) <= cpdmaxsyllable))) && ((!checkcompounddup || (rv != rv_first)))) { // bad compound word result.append(presult); result.append(" "); result.append(MORPH_PART); result.append(word + i); if (HENTRY_DATA(rv)) { if (complexprefixes) result.append(HENTRY_DATA2(rv)); if (!HENTRY_FIND(rv, MORPH_STEM)) { result.append(" "); result.append(MORPH_STEM); result.append(HENTRY_WORD(rv)); } // store the pointer of the hash entry if (!complexprefixes) { result.append(" "); result.append(HENTRY_DATA2(rv)); } } result.append("\n"); ok = 1; } numsyllable = oldnumsyllable2; wordnum = oldwordnum2; // perhaps second word has prefix or/and suffix sfx = NULL; sfxflag = FLAG_NULL; if (compoundflag && !onlycpdrule) rv = affix_check((word + i), strlen(word + i), compoundflag); else rv = NULL; if (!rv && compoundend && !onlycpdrule) { sfx = NULL; pfx = NULL; rv = affix_check((word + i), strlen(word + i), compoundend); } if (!rv && !defcpdtable.empty() && words) { rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END); if (rv && words && defcpd_check(&words, wnum + 1, rv, NULL, 1)) { std::string m; if (compoundflag) m = affix_check_morph((word + i), strlen(word + i), compoundflag); if (m.empty() && compoundend) { m = affix_check_morph((word + i), strlen(word + i), compoundend); } result.append(presult); if (!m.empty()) { result.push_back(MSEP_FLD); result.append(MORPH_PART); result.append(word + i); line_uniq_app(m, MSEP_REC); result.append(m); } result.append("\n"); ok = 1; } } // check non_compound flag in suffix and prefix if ((rv) && ((pfx && pfx->getCont() && TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || (sfx && sfx->getCont() && TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())))) { rv = NULL; } // check forbiddenwords if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen)) && (!TESTAFF(rv->astr, needaffix, rv->alen))) { st[i] = ch; continue; } if (langnum == LANG_hu) { // calculate syllable number of the word numsyllable += get_syllable(word + i); // - affix syllable num. // XXX only second suffix (inflections, not derivations) if (sfxappnd) { std::string tmp(sfxappnd); reverseword(tmp); numsyllable -= get_syllable(tmp) + sfxextra; } else { numsyllable -= sfxextra; } // + 1 word, if syllable number of the prefix > 1 (hungarian // convention) if (pfx && (get_syllable(pfx->getKey()) > 1)) wordnum++; // increment syllable num, if last word has a SYLLABLENUM flag // and the suffix is beginning `s' if (!cpdsyllablenum.empty()) { switch (sfxflag) { case 'c': { numsyllable += 2; break; } case 'J': { numsyllable += 1; break; } case 'I': { if (rv && TESTAFF(rv->astr, 'J', rv->alen)) numsyllable += 1; break; } } } } // increment word number, if the second word has a compoundroot flag if ((rv) && (compoundroot) && (TESTAFF(rv->astr, compoundroot, rv->alen))) { wordnum++; } // second word is acceptable, as a word with prefix or/and suffix? // hungarian conventions: compounding is acceptable, // when compound forms consist 2 word, otherwise // the syllable number of root words is 6, or lesser. if ((rv) && (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) && ((!checkcompounddup || (rv != rv_first)))) { std::string m; if (compoundflag) m = affix_check_morph((word + i), strlen(word + i), compoundflag); if (m.empty() && compoundend) { m = affix_check_morph((word + i), strlen(word + i), compoundend); } result.append(presult); if (!m.empty()) { result.push_back(MSEP_FLD); result.append(MORPH_PART); result.append(word + i); line_uniq_app(m, MSEP_REC); result.append(m); } result.push_back(MSEP_REC); ok = 1; } numsyllable = oldnumsyllable2; wordnum = oldwordnum2; // perhaps second word is a compound word (recursive call) if ((wordnum + 2 < maxwordnum) && (ok == 0)) { compound_check_morph((word + i), strlen(word + i), wordnum + 1, numsyllable, maxwordnum, wnum + 1, words, rwords, 0, result, &presult); } else { rv = NULL; } } st[i] = ch; wordnum = oldwordnum; numsyllable = oldnumsyllable; } while (!defcpdtable.empty() && oldwordnum == 0 && onlycpdrule++ < 1); // end of onlycpd loop } return 0; } inline int AffixMgr::isRevSubset(const char* s1, const char* end_of_s2, int len) { while ((len > 0) && (*s1 != '\0') && ((*s1 == *end_of_s2) || (*s1 == '.'))) { s1++; end_of_s2--; len--; } return (*s1 == '\0'); } // check word for suffixes struct hentry* AffixMgr::suffix_check(const char* word, int len, int sfxopts, PfxEntry* ppfx, const FLAG cclass, const FLAG needflag, char in_compound) { struct hentry* rv = NULL; PfxEntry* ep = ppfx; // first handle the special case of 0 length suffixes SfxEntry* se = sStart[0]; while (se) { if (!cclass || se->getCont()) { // suffixes are not allowed in beginning of compounds if ((((in_compound != IN_CPD_BEGIN)) || // && !cclass // except when signed with compoundpermitflag flag (se->getCont() && compoundpermitflag && TESTAFF(se->getCont(), compoundpermitflag, se->getContLen()))) && (!circumfix || // no circumfix flag in prefix and suffix ((!ppfx || !(ep->getCont()) || !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && (!se->getCont() || !(TESTAFF(se->getCont(), circumfix, se->getContLen())))) || // circumfix flag in prefix AND suffix ((ppfx && (ep->getCont()) && TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && (se->getCont() && (TESTAFF(se->getCont(), circumfix, se->getContLen()))))) && // fogemorpheme (in_compound || !(se->getCont() && (TESTAFF(se->getCont(), onlyincompound, se->getContLen())))) && // needaffix on prefix or first suffix (cclass || !(se->getCont() && TESTAFF(se->getCont(), needaffix, se->getContLen())) || (ppfx && !((ep->getCont()) && TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))) { rv = se->checkword(word, len, sfxopts, ppfx, (FLAG)cclass, needflag, (in_compound ? 0 : onlyincompound)); if (rv) { sfx = se; // BUG: sfx not stateless return rv; } } } se = se->getNext(); } // now handle the general case if (len == 0) return NULL; // FULLSTRIP unsigned char sp = *((const unsigned char*)(word + len - 1)); SfxEntry* sptr = sStart[sp]; while (sptr) { if (isRevSubset(sptr->getKey(), word + len - 1, len)) { // suffixes are not allowed in beginning of compounds if ((((in_compound != IN_CPD_BEGIN)) || // && !cclass // except when signed with compoundpermitflag flag (sptr->getCont() && compoundpermitflag && TESTAFF(sptr->getCont(), compoundpermitflag, sptr->getContLen()))) && (!circumfix || // no circumfix flag in prefix and suffix ((!ppfx || !(ep->getCont()) || !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && (!sptr->getCont() || !(TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())))) || // circumfix flag in prefix AND suffix ((ppfx && (ep->getCont()) && TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && (sptr->getCont() && (TESTAFF(sptr->getCont(), circumfix, sptr->getContLen()))))) && // fogemorpheme (in_compound || !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) && // needaffix on prefix or first suffix (cclass || !(sptr->getCont() && TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) || (ppfx && !((ep->getCont()) && TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))) if (in_compound != IN_CPD_END || ppfx || !(sptr->getCont() && TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))) { rv = sptr->checkword(word, len, sfxopts, ppfx, cclass, needflag, (in_compound ? 0 : onlyincompound)); if (rv) { sfx = sptr; // BUG: sfx not stateless sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless if (!sptr->getCont()) sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless // LANG_hu section: spec. Hungarian rule else if (langnum == LANG_hu && sptr->getKeyLen() && sptr->getKey()[0] == 'i' && sptr->getKey()[1] != 'y' && sptr->getKey()[1] != 't') { sfxextra = 1; } // END of LANG_hu section return rv; } } sptr = sptr->getNextEQ(); } else { sptr = sptr->getNextNE(); } } return NULL; } // check word for two-level suffixes struct hentry* AffixMgr::suffix_check_twosfx(const char* word, int len, int sfxopts, PfxEntry* ppfx, const FLAG needflag) { struct hentry* rv = NULL; // first handle the special case of 0 length suffixes SfxEntry* se = sStart[0]; while (se) { if (contclasses[se->getFlag()]) { rv = se->check_twosfx(word, len, sfxopts, ppfx, needflag); if (rv) return rv; } se = se->getNext(); } // now handle the general case if (len == 0) return NULL; // FULLSTRIP unsigned char sp = *((const unsigned char*)(word + len - 1)); SfxEntry* sptr = sStart[sp]; while (sptr) { if (isRevSubset(sptr->getKey(), word + len - 1, len)) { if (contclasses[sptr->getFlag()]) { rv = sptr->check_twosfx(word, len, sfxopts, ppfx, needflag); if (rv) { sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless if (!sptr->getCont()) sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless return rv; } } sptr = sptr->getNextEQ(); } else { sptr = sptr->getNextNE(); } } return NULL; } // check word for two-level suffixes and morph std::string AffixMgr::suffix_check_twosfx_morph(const char* word, int len, int sfxopts, PfxEntry* ppfx, const FLAG needflag) { std::string result; std::string result2; std::string result3; // first handle the special case of 0 length suffixes SfxEntry* se = sStart[0]; while (se) { if (contclasses[se->getFlag()]) { std::string st = se->check_twosfx_morph(word, len, sfxopts, ppfx, needflag); if (!st.empty()) { if (ppfx) { if (ppfx->getMorph()) { result.append(ppfx->getMorph()); result.append(" "); } else debugflag(result, ppfx->getFlag()); } result.append(st); if (se->getMorph()) { result.append(" "); result.append(se->getMorph()); } else debugflag(result, se->getFlag()); result.append("\n"); } } se = se->getNext(); } // now handle the general case if (len == 0) return std::string(); // FULLSTRIP unsigned char sp = *((const unsigned char*)(word + len - 1)); SfxEntry* sptr = sStart[sp]; while (sptr) { if (isRevSubset(sptr->getKey(), word + len - 1, len)) { if (contclasses[sptr->getFlag()]) { std::string st = sptr->check_twosfx_morph(word, len, sfxopts, ppfx, needflag); if (!st.empty()) { sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless if (!sptr->getCont()) sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless result2.assign(st); result3.clear(); if (sptr->getMorph()) { result3.append(" "); result3.append(sptr->getMorph()); } else debugflag(result3, sptr->getFlag()); strlinecat(result2, result3); result2.append("\n"); result.append(result2); } } sptr = sptr->getNextEQ(); } else { sptr = sptr->getNextNE(); } } return result; } std::string AffixMgr::suffix_check_morph(const char* word, int len, int sfxopts, PfxEntry* ppfx, const FLAG cclass, const FLAG needflag, char in_compound) { std::string result; struct hentry* rv = NULL; PfxEntry* ep = ppfx; // first handle the special case of 0 length suffixes SfxEntry* se = sStart[0]; while (se) { if (!cclass || se->getCont()) { // suffixes are not allowed in beginning of compounds if (((((in_compound != IN_CPD_BEGIN)) || // && !cclass // except when signed with compoundpermitflag flag (se->getCont() && compoundpermitflag && TESTAFF(se->getCont(), compoundpermitflag, se->getContLen()))) && (!circumfix || // no circumfix flag in prefix and suffix ((!ppfx || !(ep->getCont()) || !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && (!se->getCont() || !(TESTAFF(se->getCont(), circumfix, se->getContLen())))) || // circumfix flag in prefix AND suffix ((ppfx && (ep->getCont()) && TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && (se->getCont() && (TESTAFF(se->getCont(), circumfix, se->getContLen()))))) && // fogemorpheme (in_compound || !((se->getCont() && (TESTAFF(se->getCont(), onlyincompound, se->getContLen()))))) && // needaffix on prefix or first suffix (cclass || !(se->getCont() && TESTAFF(se->getCont(), needaffix, se->getContLen())) || (ppfx && !((ep->getCont()) && TESTAFF(ep->getCont(), needaffix, ep->getContLen())))))) rv = se->checkword(word, len, sfxopts, ppfx, cclass, needflag, FLAG_NULL); while (rv) { if (ppfx) { if (ppfx->getMorph()) { result.append(ppfx->getMorph()); result.append(" "); } else debugflag(result, ppfx->getFlag()); } if (complexprefixes && HENTRY_DATA(rv)) result.append(HENTRY_DATA2(rv)); if (!HENTRY_FIND(rv, MORPH_STEM)) { result.append(" "); result.append(MORPH_STEM); result.append(HENTRY_WORD(rv)); } if (!complexprefixes && HENTRY_DATA(rv)) { result.append(" "); result.append(HENTRY_DATA2(rv)); } if (se->getMorph()) { result.append(" "); result.append(se->getMorph()); } else debugflag(result, se->getFlag()); result.append("\n"); rv = se->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag); } } se = se->getNext(); } // now handle the general case if (len == 0) return std::string(); // FULLSTRIP unsigned char sp = *((const unsigned char*)(word + len - 1)); SfxEntry* sptr = sStart[sp]; while (sptr) { if (isRevSubset(sptr->getKey(), word + len - 1, len)) { // suffixes are not allowed in beginning of compounds if (((((in_compound != IN_CPD_BEGIN)) || // && !cclass // except when signed with compoundpermitflag flag (sptr->getCont() && compoundpermitflag && TESTAFF(sptr->getCont(), compoundpermitflag, sptr->getContLen()))) && (!circumfix || // no circumfix flag in prefix and suffix ((!ppfx || !(ep->getCont()) || !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && (!sptr->getCont() || !(TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())))) || // circumfix flag in prefix AND suffix ((ppfx && (ep->getCont()) && TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && (sptr->getCont() && (TESTAFF(sptr->getCont(), circumfix, sptr->getContLen()))))) && // fogemorpheme (in_compound || !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) && // needaffix on first suffix (cclass || !(sptr->getCont() && TESTAFF(sptr->getCont(), needaffix, sptr->getContLen()))))) rv = sptr->checkword(word, len, sfxopts, ppfx, cclass, needflag, FLAG_NULL); while (rv) { if (ppfx) { if (ppfx->getMorph()) { result.append(ppfx->getMorph()); result.append(" "); } else debugflag(result, ppfx->getFlag()); } if (complexprefixes && HENTRY_DATA(rv)) result.append(HENTRY_DATA2(rv)); if (!HENTRY_FIND(rv, MORPH_STEM)) { result.append(" "); result.append(MORPH_STEM); result.append(HENTRY_WORD(rv)); } if (!complexprefixes && HENTRY_DATA(rv)) { result.append(" "); result.append(HENTRY_DATA2(rv)); } if (sptr->getMorph()) { result.append(" "); result.append(sptr->getMorph()); } else debugflag(result, sptr->getFlag()); result.append("\n"); rv = sptr->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag); } sptr = sptr->getNextEQ(); } else { sptr = sptr->getNextNE(); } } return result; } // check if word with affixes is correctly spelled struct hentry* AffixMgr::affix_check(const char* word, int len, const FLAG needflag, char in_compound) { // check all prefixes (also crossed with suffixes if allowed) struct hentry* rv = prefix_check(word, len, in_compound, needflag); if (rv) return rv; // if still not found check all suffixes rv = suffix_check(word, len, 0, NULL, FLAG_NULL, needflag, in_compound); if (havecontclass) { sfx = NULL; pfx = NULL; if (rv) return rv; // if still not found check all two-level suffixes rv = suffix_check_twosfx(word, len, 0, NULL, needflag); if (rv) return rv; // if still not found check all two-level suffixes rv = prefix_check_twosfx(word, len, IN_CPD_NOT, needflag); } return rv; } // check if word with affixes is correctly spelled std::string AffixMgr::affix_check_morph(const char* word, int len, const FLAG needflag, char in_compound) { std::string result; // check all prefixes (also crossed with suffixes if allowed) std::string st = prefix_check_morph(word, len, in_compound); if (!st.empty()) { result.append(st); } // if still not found check all suffixes st = suffix_check_morph(word, len, 0, NULL, '\0', needflag, in_compound); if (!st.empty()) { result.append(st); } if (havecontclass) { sfx = NULL; pfx = NULL; // if still not found check all two-level suffixes st = suffix_check_twosfx_morph(word, len, 0, NULL, needflag); if (!st.empty()) { result.append(st); } // if still not found check all two-level suffixes st = prefix_check_twosfx_morph(word, len, IN_CPD_NOT, needflag); if (!st.empty()) { result.append(st); } } return result; } // morphcmp(): compare MORPH_DERI_SFX, MORPH_INFL_SFX and MORPH_TERM_SFX fields // in the first line of the inputs // return 0, if inputs equal // return 1, if inputs may equal with a secondary suffix // otherwise return -1 static int morphcmp(const char* s, const char* t) { int se = 0; int te = 0; const char* sl; const char* tl; const char* olds; const char* oldt; if (!s || !t) return 1; olds = s; sl = strchr(s, '\n'); s = strstr(s, MORPH_DERI_SFX); if (!s || (sl && sl < s)) s = strstr(olds, MORPH_INFL_SFX); if (!s || (sl && sl < s)) { s = strstr(olds, MORPH_TERM_SFX); olds = NULL; } oldt = t; tl = strchr(t, '\n'); t = strstr(t, MORPH_DERI_SFX); if (!t || (tl && tl < t)) t = strstr(oldt, MORPH_INFL_SFX); if (!t || (tl && tl < t)) { t = strstr(oldt, MORPH_TERM_SFX); oldt = NULL; } while (s && t && (!sl || sl > s) && (!tl || tl > t)) { s += MORPH_TAG_LEN; t += MORPH_TAG_LEN; se = 0; te = 0; while ((*s == *t) && !se && !te) { s++; t++; switch (*s) { case ' ': case '\n': case '\t': case '\0': se = 1; } switch (*t) { case ' ': case '\n': case '\t': case '\0': te = 1; } } if (!se || !te) { // not terminal suffix difference if (olds) return -1; return 1; } olds = s; s = strstr(s, MORPH_DERI_SFX); if (!s || (sl && sl < s)) s = strstr(olds, MORPH_INFL_SFX); if (!s || (sl && sl < s)) { s = strstr(olds, MORPH_TERM_SFX); olds = NULL; } oldt = t; t = strstr(t, MORPH_DERI_SFX); if (!t || (tl && tl < t)) t = strstr(oldt, MORPH_INFL_SFX); if (!t || (tl && tl < t)) { t = strstr(oldt, MORPH_TERM_SFX); oldt = NULL; } } if (!s && !t && se && te) return 0; return 1; } std::string AffixMgr::morphgen(const char* ts, int wl, const unsigned short* ap, unsigned short al, const char* morph, const char* targetmorph, int level) { // handle suffixes if (!morph) return std::string(); // check substandard flag if (TESTAFF(ap, substandard, al)) return std::string(); if (morphcmp(morph, targetmorph) == 0) return ts; size_t stemmorphcatpos; std::string mymorph; // use input suffix fields, if exist if (strstr(morph, MORPH_INFL_SFX) || strstr(morph, MORPH_DERI_SFX)) { mymorph.assign(morph); mymorph.append(" "); stemmorphcatpos = mymorph.size(); } else { stemmorphcatpos = std::string::npos; } for (int i = 0; i < al; i++) { const unsigned char c = (unsigned char)(ap[i] & 0x00FF); SfxEntry* sptr = sFlag[c]; while (sptr) { if (sptr->getFlag() == ap[i] && sptr->getMorph() && ((sptr->getContLen() == 0) || // don't generate forms with substandard affixes !TESTAFF(sptr->getCont(), substandard, sptr->getContLen()))) { const char* stemmorph; if (stemmorphcatpos != std::string::npos) { mymorph.replace(stemmorphcatpos, std::string::npos, sptr->getMorph()); stemmorph = mymorph.c_str(); } else { stemmorph = sptr->getMorph(); } int cmp = morphcmp(stemmorph, targetmorph); if (cmp == 0) { std::string newword = sptr->add(ts, wl); if (!newword.empty()) { hentry* check = pHMgr->lookup(newword.c_str()); // XXX extra dic if (!check || !check->astr || !(TESTAFF(check->astr, forbiddenword, check->alen) || TESTAFF(check->astr, ONLYUPCASEFLAG, check->alen))) { return newword; } } } // recursive call for secondary suffixes if ((level == 0) && (cmp == 1) && (sptr->getContLen() > 0) && !TESTAFF(sptr->getCont(), substandard, sptr->getContLen())) { std::string newword = sptr->add(ts, wl); if (!newword.empty()) { std::string newword2 = morphgen(newword.c_str(), newword.size(), sptr->getCont(), sptr->getContLen(), stemmorph, targetmorph, 1); if (!newword2.empty()) { return newword2; } } } } sptr = sptr->getFlgNxt(); } } return std::string(); } int AffixMgr::expand_rootword(struct guessword* wlst, int maxn, const char* ts, int wl, const unsigned short* ap, unsigned short al, const char* bad, int badl, const char* phon) { int nh = 0; // first add root word to list if ((nh < maxn) && !(al && ((needaffix && TESTAFF(ap, needaffix, al)) || (onlyincompound && TESTAFF(ap, onlyincompound, al))))) { wlst[nh].word = mystrdup(ts); if (!wlst[nh].word) return 0; wlst[nh].allow = false; wlst[nh].orig = NULL; nh++; // add special phonetic version if (phon && (nh < maxn)) { wlst[nh].word = mystrdup(phon); if (!wlst[nh].word) return nh - 1; wlst[nh].allow = false; wlst[nh].orig = mystrdup(ts); if (!wlst[nh].orig) return nh - 1; nh++; } } // handle suffixes for (int i = 0; i < al; i++) { const unsigned char c = (unsigned char)(ap[i] & 0x00FF); SfxEntry* sptr = sFlag[c]; while (sptr) { if ((sptr->getFlag() == ap[i]) && (!sptr->getKeyLen() || ((badl > sptr->getKeyLen()) && (strcmp(sptr->getAffix(), bad + badl - sptr->getKeyLen()) == 0))) && // check needaffix flag !(sptr->getCont() && ((needaffix && TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) || (circumfix && TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())) || (onlyincompound && TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) { std::string newword = sptr->add(ts, wl); if (!newword.empty()) { if (nh < maxn) { wlst[nh].word = mystrdup(newword.c_str()); wlst[nh].allow = sptr->allowCross(); wlst[nh].orig = NULL; nh++; // add special phonetic version if (phon && (nh < maxn)) { std::string prefix(phon); std::string key(sptr->getKey()); reverseword(key); prefix.append(key); wlst[nh].word = mystrdup(prefix.c_str()); if (!wlst[nh].word) return nh - 1; wlst[nh].allow = false; wlst[nh].orig = mystrdup(newword.c_str()); if (!wlst[nh].orig) return nh - 1; nh++; } } } } sptr = sptr->getFlgNxt(); } } int n = nh; // handle cross products of prefixes and suffixes for (int j = 1; j < n; j++) if (wlst[j].allow) { for (int k = 0; k < al; k++) { const unsigned char c = (unsigned char)(ap[k] & 0x00FF); PfxEntry* cptr = pFlag[c]; while (cptr) { if ((cptr->getFlag() == ap[k]) && cptr->allowCross() && (!cptr->getKeyLen() || ((badl > cptr->getKeyLen()) && (strncmp(cptr->getKey(), bad, cptr->getKeyLen()) == 0)))) { int l1 = strlen(wlst[j].word); std::string newword = cptr->add(wlst[j].word, l1); if (!newword.empty()) { if (nh < maxn) { wlst[nh].word = mystrdup(newword.c_str()); wlst[nh].allow = cptr->allowCross(); wlst[nh].orig = NULL; nh++; } } } cptr = cptr->getFlgNxt(); } } } // now handle pure prefixes for (int m = 0; m < al; m++) { const unsigned char c = (unsigned char)(ap[m] & 0x00FF); PfxEntry* ptr = pFlag[c]; while (ptr) { if ((ptr->getFlag() == ap[m]) && (!ptr->getKeyLen() || ((badl > ptr->getKeyLen()) && (strncmp(ptr->getKey(), bad, ptr->getKeyLen()) == 0))) && // check needaffix flag !(ptr->getCont() && ((needaffix && TESTAFF(ptr->getCont(), needaffix, ptr->getContLen())) || (circumfix && TESTAFF(ptr->getCont(), circumfix, ptr->getContLen())) || (onlyincompound && TESTAFF(ptr->getCont(), onlyincompound, ptr->getContLen()))))) { std::string newword = ptr->add(ts, wl); if (!newword.empty()) { if (nh < maxn) { wlst[nh].word = mystrdup(newword.c_str()); wlst[nh].allow = ptr->allowCross(); wlst[nh].orig = NULL; nh++; } } } ptr = ptr->getFlgNxt(); } } return nh; } // return replacing table const std::vector& AffixMgr::get_reptable() const { return reptable; } // return iconv table RepList* AffixMgr::get_iconvtable() const { if (!iconvtable) return NULL; return iconvtable; } // return oconv table RepList* AffixMgr::get_oconvtable() const { if (!oconvtable) return NULL; return oconvtable; } // return replacing table struct phonetable* AffixMgr::get_phonetable() const { if (!phone) return NULL; return phone; } // return character map table const std::vector& AffixMgr::get_maptable() const { return maptable; } // return character map table const std::vector& AffixMgr::get_breaktable() const { return breaktable; } // return text encoding of dictionary const std::string& AffixMgr::get_encoding() { if (encoding.empty()) encoding = SPELL_ENCODING; return encoding; } // return text encoding of dictionary int AffixMgr::get_langnum() const { return langnum; } // return double prefix option int AffixMgr::get_complexprefixes() const { return complexprefixes; } // return FULLSTRIP option int AffixMgr::get_fullstrip() const { return fullstrip; } FLAG AffixMgr::get_keepcase() const { return keepcase; } FLAG AffixMgr::get_forceucase() const { return forceucase; } FLAG AffixMgr::get_warn() const { return warn; } int AffixMgr::get_forbidwarn() const { return forbidwarn; } int AffixMgr::get_checksharps() const { return checksharps; } char* AffixMgr::encode_flag(unsigned short aflag) const { return pHMgr->encode_flag(aflag); } // return the preferred ignore string for suggestions const char* AffixMgr::get_ignore() const { if (ignorechars.empty()) return NULL; return ignorechars.c_str(); } // return the preferred ignore string for suggestions const std::vector& AffixMgr::get_ignore_utf16() const { return ignorechars_utf16; } // return the keyboard string for suggestions char* AffixMgr::get_key_string() { if (keystring.empty()) keystring = SPELL_KEYSTRING; return mystrdup(keystring.c_str()); } // return the preferred try string for suggestions char* AffixMgr::get_try_string() const { if (trystring.empty()) return NULL; return mystrdup(trystring.c_str()); } // return the preferred try string for suggestions const std::string& AffixMgr::get_wordchars() const { return wordchars; } const std::vector& AffixMgr::get_wordchars_utf16() const { return wordchars_utf16; } // is there compounding? int AffixMgr::get_compound() const { return compoundflag || compoundbegin || !defcpdtable.empty(); } // return the compound words control flag FLAG AffixMgr::get_compoundflag() const { return compoundflag; } // return the forbidden words control flag FLAG AffixMgr::get_forbiddenword() const { return forbiddenword; } // return the forbidden words control flag FLAG AffixMgr::get_nosuggest() const { return nosuggest; } // return the forbidden words control flag FLAG AffixMgr::get_nongramsuggest() const { return nongramsuggest; } // return the forbidden words flag modify flag FLAG AffixMgr::get_needaffix() const { return needaffix; } // return the onlyincompound flag FLAG AffixMgr::get_onlyincompound() const { return onlyincompound; } // return the value of suffix const std::string& AffixMgr::get_version() const { return version; } // utility method to look up root words in hash table struct hentry* AffixMgr::lookup(const char* word) { struct hentry* he = NULL; for (size_t i = 0; i < alldic.size() && !he; ++i) { he = alldic[i]->lookup(word); } return he; } // return the value of suffix int AffixMgr::have_contclass() const { return havecontclass; } // return utf8 int AffixMgr::get_utf8() const { return utf8; } int AffixMgr::get_maxngramsugs(void) const { return maxngramsugs; } int AffixMgr::get_maxcpdsugs(void) const { return maxcpdsugs; } int AffixMgr::get_maxdiff(void) const { return maxdiff; } int AffixMgr::get_onlymaxdiff(void) const { return onlymaxdiff; } // return nosplitsugs int AffixMgr::get_nosplitsugs(void) const { return nosplitsugs; } // return sugswithdots int AffixMgr::get_sugswithdots(void) const { return sugswithdots; } /* parse flag */ bool AffixMgr::parse_flag(const std::string& line, unsigned short* out, FileMgr* af) { if (*out != FLAG_NULL && !(*out >= DEFAULTFLAGS)) { HUNSPELL_WARNING( stderr, "error: line %d: multiple definitions of an affix file parameter\n", af->getlinenum()); return false; } std::string s; if (!parse_string(line, s, af->getlinenum())) return false; *out = pHMgr->decode_flag(s.c_str()); return true; } /* parse num */ bool AffixMgr::parse_num(const std::string& line, int* out, FileMgr* af) { if (*out != -1) { HUNSPELL_WARNING( stderr, "error: line %d: multiple definitions of an affix file parameter\n", af->getlinenum()); return false; } std::string s; if (!parse_string(line, s, af->getlinenum())) return false; *out = atoi(s.c_str()); return true; } /* parse in the max syllablecount of compound words and */ bool AffixMgr::parse_cpdsyllable(const std::string& line, FileMgr* af) { int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { cpdmaxsyllable = atoi(std::string(start_piece, iter).c_str()); np++; break; } case 2: { if (!utf8) { cpdvowels.assign(start_piece, iter); std::sort(cpdvowels.begin(), cpdvowels.end()); } else { std::string piece(start_piece, iter); u8_u16(cpdvowels_utf16, piece); std::sort(cpdvowels_utf16.begin(), cpdvowels_utf16.end()); } np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np < 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing compoundsyllable information\n", af->getlinenum()); return false; } if (np == 2) cpdvowels = "AEIOUaeiou"; return true; } /* parse in the typical fault correcting table */ bool AffixMgr::parse_reptable(const std::string& line, FileMgr* af) { if (parsedrep) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } parsedrep = true; int numrep = -1; int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { numrep = atoi(std::string(start_piece, iter).c_str()); if (numrep < 1) { HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n", af->getlinenum()); return false; } reptable.reserve(numrep); np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the numrep lines to read in the remainder of the table */ for (int j = 0; j < numrep; ++j) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); reptable.push_back(replentry()); iter = nl.begin(); i = 0; int type = 0; start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), 3, "REP", 3) != 0) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); reptable.clear(); return false; } break; } case 1: { if (*start_piece == '^') type = 1; reptable.back().pattern.assign(start_piece + type, iter); mystrrep(reptable.back().pattern, "_", " "); if (!reptable.back().pattern.empty() && reptable.back().pattern[reptable.back().pattern.size() - 1] == '$') { type += 2; reptable.back().pattern.resize(reptable.back().pattern.size() - 1); } break; } case 2: { reptable.back().outstrings[type].assign(start_piece, iter); mystrrep(reptable.back().outstrings[type], "_", " "); break; } default: break; } ++i; start_piece = mystrsep(nl, iter); } if (reptable.back().pattern.empty() || reptable.back().outstrings[type].empty()) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); reptable.clear(); return false; } } return true; } /* parse in the typical fault correcting table */ bool AffixMgr::parse_convtable(const std::string& line, FileMgr* af, RepList** rl, const std::string& keyword) { if (*rl) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } int i = 0; int np = 0; int numrl = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { numrl = atoi(std::string(start_piece, iter).c_str()); if (numrl < 1) { HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n", af->getlinenum()); return false; } *rl = new RepList(numrl); if (!*rl) return false; np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the num lines to read in the remainder of the table */ for (int j = 0; j < numrl; j++) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); i = 0; std::string pattern; std::string pattern2; iter = nl.begin(); start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), keyword.size(), keyword, 0, keyword.size()) != 0) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); delete *rl; *rl = NULL; return false; } break; } case 1: { pattern.assign(start_piece, iter); break; } case 2: { pattern2.assign(start_piece, iter); break; } default: break; } ++i; } start_piece = mystrsep(nl, iter); } if (pattern.empty() || pattern2.empty()) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } (*rl)->add(pattern, pattern2); } return true; } /* parse in the typical fault correcting table */ bool AffixMgr::parse_phonetable(const std::string& line, FileMgr* af) { if (phone) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } int num = -1; int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { num = atoi(std::string(start_piece, iter).c_str()); if (num < 1) { HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); return false; } phone = new phonetable; phone->utf8 = (char)utf8; np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the phone->num lines to read in the remainder of the table */ for (int j = 0; j < num; ++j) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); i = 0; const size_t old_size = phone->rules.size(); iter = nl.begin(); start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), 5, "PHONE", 5) != 0) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } break; } case 1: { phone->rules.push_back(std::string(start_piece, iter)); break; } case 2: { phone->rules.push_back(std::string(start_piece, iter)); mystrrep(phone->rules.back(), "_", ""); break; } default: break; } ++i; } start_piece = mystrsep(nl, iter); } if (phone->rules.size() != old_size + 2) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); phone->rules.clear(); return false; } } phone->rules.push_back(""); phone->rules.push_back(""); init_phonet_hash(*phone); return true; } /* parse in the checkcompoundpattern table */ bool AffixMgr::parse_checkcpdtable(const std::string& line, FileMgr* af) { if (parsedcheckcpd) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } parsedcheckcpd = true; int numcheckcpd = -1; int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { numcheckcpd = atoi(std::string(start_piece, iter).c_str()); if (numcheckcpd < 1) { HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); return false; } checkcpdtable.reserve(numcheckcpd); np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the numcheckcpd lines to read in the remainder of the table */ for (int j = 0; j < numcheckcpd; ++j) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); i = 0; checkcpdtable.push_back(patentry()); iter = nl.begin(); start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), 20, "CHECKCOMPOUNDPATTERN", 20) != 0) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } break; } case 1: { checkcpdtable.back().pattern.assign(start_piece, iter); size_t slash_pos = checkcpdtable.back().pattern.find('/'); if (slash_pos != std::string::npos) { std::string chunk(checkcpdtable.back().pattern, slash_pos + 1); checkcpdtable.back().pattern.resize(slash_pos); checkcpdtable.back().cond = pHMgr->decode_flag(chunk.c_str()); } break; } case 2: { checkcpdtable.back().pattern2.assign(start_piece, iter); size_t slash_pos = checkcpdtable.back().pattern2.find('/'); if (slash_pos != std::string::npos) { std::string chunk(checkcpdtable.back().pattern2, slash_pos + 1); checkcpdtable.back().pattern2.resize(slash_pos); checkcpdtable.back().cond2 = pHMgr->decode_flag(chunk.c_str()); } break; } case 3: { checkcpdtable.back().pattern3.assign(start_piece, iter); simplifiedcpd = 1; break; } default: break; } i++; start_piece = mystrsep(nl, iter); } } return true; } /* parse in the compound rule table */ bool AffixMgr::parse_defcpdtable(const std::string& line, FileMgr* af) { if (parseddefcpd) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } parseddefcpd = true; int numdefcpd = -1; int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { numdefcpd = atoi(std::string(start_piece, iter).c_str()); if (numdefcpd < 1) { HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); return false; } defcpdtable.reserve(numdefcpd); np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the numdefcpd lines to read in the remainder of the table */ for (int j = 0; j < numdefcpd; ++j) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); i = 0; defcpdtable.push_back(flagentry()); iter = nl.begin(); start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), 12, "COMPOUNDRULE", 12) != 0) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); numdefcpd = 0; return false; } break; } case 1: { // handle parenthesized flags if (std::find(start_piece, iter, '(') != iter) { for (std::string::const_iterator k = start_piece; k != iter; ++k) { std::string::const_iterator chb = k; std::string::const_iterator che = k + 1; if (*k == '(') { std::string::const_iterator parpos = std::find(k, iter, ')'); if (parpos != iter) { chb = k + 1; che = parpos; k = parpos; } } if (*chb == '*' || *chb == '?') { defcpdtable.back().push_back((FLAG)*chb); } else { pHMgr->decode_flags(defcpdtable.back(), std::string(chb, che), af); } } } else { pHMgr->decode_flags(defcpdtable.back(), std::string(start_piece, iter), af); } break; } default: break; } ++i; start_piece = mystrsep(nl, iter); } if (defcpdtable.back().empty()) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } } return true; } /* parse in the character map table */ bool AffixMgr::parse_maptable(const std::string& line, FileMgr* af) { if (parsedmaptable) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } parsedmaptable = true; int nummap = -1; int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { nummap = atoi(std::string(start_piece, iter).c_str()); if (nummap < 1) { HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); return false; } maptable.reserve(nummap); np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the nummap lines to read in the remainder of the table */ for (int j = 0; j < nummap; ++j) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); i = 0; maptable.push_back(mapentry()); iter = nl.begin(); start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), 3, "MAP", 3) != 0) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); nummap = 0; return false; } break; } case 1: { for (std::string::const_iterator k = start_piece; k != iter; ++k) { std::string::const_iterator chb = k; std::string::const_iterator che = k + 1; if (*k == '(') { std::string::const_iterator parpos = std::find(k, iter, ')'); if (parpos != iter) { chb = k + 1; che = parpos; k = parpos; } } else { if (utf8 && (*k & 0xc0) == 0xc0) { ++k; while (k != iter && (*k & 0xc0) == 0x80) ++k; che = k; --k; } } maptable.back().push_back(std::string(chb, che)); } break; } default: break; } ++i; start_piece = mystrsep(nl, iter); } if (maptable.back().empty()) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } } return true; } /* parse in the word breakpoint table */ bool AffixMgr::parse_breaktable(const std::string& line, FileMgr* af) { if (parsedbreaktable) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } parsedbreaktable = true; int numbreak = -1; int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { numbreak = atoi(std::string(start_piece, iter).c_str()); if (numbreak < 0) { HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); return false; } if (numbreak == 0) return true; breaktable.reserve(numbreak); np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the numbreak lines to read in the remainder of the table */ for (int j = 0; j < numbreak; ++j) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); i = 0; iter = nl.begin(); start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), 5, "BREAK", 5) != 0) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); numbreak = 0; return false; } break; } case 1: { breaktable.push_back(std::string(start_piece, iter)); break; } default: break; } ++i; start_piece = mystrsep(nl, iter); } } if (breaktable.size() != static_cast(numbreak)) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } return true; } void AffixMgr::reverse_condition(std::string& piece) { if (piece.empty()) return; int neg = 0; for (std::string::reverse_iterator k = piece.rbegin(); k != piece.rend(); ++k) { switch (*k) { case '[': { if (neg) *(k - 1) = '['; else *k = ']'; break; } case ']': { *k = '['; if (neg) *(k - 1) = '^'; neg = 0; break; } case '^': { if (*(k - 1) == ']') neg = 1; else *(k - 1) = *k; break; } default: { if (neg) *(k - 1) = *k; } } } } class entries_container { std::vector entries; AffixMgr* m_mgr; char m_at; public: entries_container(char at, AffixMgr* mgr) : m_mgr(mgr) , m_at(at) { } void release() { entries.clear(); } void initialize(int numents, char opts, unsigned short aflag) { entries.reserve(numents); if (m_at == 'P') { entries.push_back(new PfxEntry(m_mgr)); } else { entries.push_back(new SfxEntry(m_mgr)); } entries.back()->opts = opts; entries.back()->aflag = aflag; } AffEntry* add_entry(char opts) { if (m_at == 'P') { entries.push_back(new PfxEntry(m_mgr)); } else { entries.push_back(new SfxEntry(m_mgr)); } AffEntry* ret = entries.back(); ret->opts = entries[0]->opts & opts; return ret; } AffEntry* first_entry() { return entries.empty() ? NULL : entries[0]; } ~entries_container() { for (size_t i = 0; i < entries.size(); ++i) { delete entries[i]; } } std::vector::iterator begin() { return entries.begin(); } std::vector::iterator end() { return entries.end(); } }; bool AffixMgr::parse_affix(const std::string& line, const char at, FileMgr* af, char* dupflags) { int numents = 0; // number of AffEntry structures to parse unsigned short aflag = 0; // affix char identifier char ff = 0; entries_container affentries(at, this); int i = 0; // checking lines with bad syntax #ifdef DEBUG int basefieldnum = 0; #endif // split affix header line into pieces int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { // piece 1 - is type of affix case 0: { np++; break; } // piece 2 - is affix char case 1: { np++; aflag = pHMgr->decode_flag(std::string(start_piece, iter).c_str()); if (((at == 'S') && (dupflags[aflag] & dupSFX)) || ((at == 'P') && (dupflags[aflag] & dupPFX))) { HUNSPELL_WARNING( stderr, "error: line %d: multiple definitions of an affix flag\n", af->getlinenum()); } dupflags[aflag] += (char)((at == 'S') ? dupSFX : dupPFX); break; } // piece 3 - is cross product indicator case 2: { np++; if (*start_piece == 'Y') ff = aeXPRODUCT; break; } // piece 4 - is number of affentries case 3: { np++; numents = atoi(std::string(start_piece, iter).c_str()); if ((numents <= 0) || ((std::numeric_limits::max() / sizeof(AffEntry)) < static_cast(numents))) { char* err = pHMgr->encode_flag(aflag); if (err) { HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); free(err); } return false; } char opts = ff; if (utf8) opts += aeUTF8; if (pHMgr->is_aliasf()) opts += aeALIASF; if (pHMgr->is_aliasm()) opts += aeALIASM; affentries.initialize(numents, opts, aflag); } default: break; } ++i; start_piece = mystrsep(line, iter); } // check to make sure we parsed enough pieces if (np != 4) { char* err = pHMgr->encode_flag(aflag); if (err) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); free(err); } return false; } // now parse numents affentries for this affix AffEntry* entry = affentries.first_entry(); for (int ent = 0; ent < numents; ++ent) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); iter = nl.begin(); i = 0; np = 0; // split line into pieces start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { switch (i) { // piece 1 - is type case 0: { np++; if (ent != 0) entry = affentries.add_entry((char)(aeXPRODUCT + aeUTF8 + aeALIASF + aeALIASM)); break; } // piece 2 - is affix char case 1: { np++; std::string chunk(start_piece, iter); if (pHMgr->decode_flag(chunk.c_str()) != aflag) { char* err = pHMgr->encode_flag(aflag); if (err) { HUNSPELL_WARNING(stderr, "error: line %d: affix %s is corrupt\n", af->getlinenum(), err); free(err); } return false; } if (ent != 0) { AffEntry* start_entry = affentries.first_entry(); entry->aflag = start_entry->aflag; } break; } // piece 3 - is string to strip or 0 for null case 2: { np++; entry->strip = std::string(start_piece, iter); if (complexprefixes) { if (utf8) reverseword_utf(entry->strip); else reverseword(entry->strip); } if (entry->strip.compare("0") == 0) { entry->strip.clear(); } break; } // piece 4 - is affix string or 0 for null case 3: { entry->morphcode = NULL; entry->contclass = NULL; entry->contclasslen = 0; np++; std::string::const_iterator dash = std::find(start_piece, iter, '/'); if (dash != iter) { entry->appnd = std::string(start_piece, dash); std::string dash_str(dash + 1, iter); if (!ignorechars.empty()) { if (utf8) { remove_ignored_chars_utf(entry->appnd, ignorechars_utf16); } else { remove_ignored_chars(entry->appnd, ignorechars); } } if (complexprefixes) { if (utf8) reverseword_utf(entry->appnd); else reverseword(entry->appnd); } if (pHMgr->is_aliasf()) { int index = atoi(dash_str.c_str()); entry->contclasslen = (unsigned short)pHMgr->get_aliasf( index, &(entry->contclass), af); if (!entry->contclasslen) HUNSPELL_WARNING(stderr, "error: bad affix flag alias: \"%s\"\n", dash_str.c_str()); } else { entry->contclasslen = (unsigned short)pHMgr->decode_flags( &(entry->contclass), dash_str.c_str(), af); std::sort(entry->contclass, entry->contclass + entry->contclasslen); } havecontclass = 1; for (unsigned short _i = 0; _i < entry->contclasslen; _i++) { contclasses[(entry->contclass)[_i]] = 1; } } else { entry->appnd = std::string(start_piece, iter); if (!ignorechars.empty()) { if (utf8) { remove_ignored_chars_utf(entry->appnd, ignorechars_utf16); } else { remove_ignored_chars(entry->appnd, ignorechars); } } if (complexprefixes) { if (utf8) reverseword_utf(entry->appnd); else reverseword(entry->appnd); } } if (entry->appnd.compare("0") == 0) { entry->appnd.clear(); } break; } // piece 5 - is the conditions descriptions case 4: { std::string chunk(start_piece, iter); np++; if (complexprefixes) { if (utf8) reverseword_utf(chunk); else reverseword(chunk); reverse_condition(chunk); } if (!entry->strip.empty() && chunk != "." && redundant_condition(at, entry->strip.c_str(), entry->strip.size(), chunk.c_str(), af->getlinenum())) chunk = "."; if (at == 'S') { reverseword(chunk); reverse_condition(chunk); } if (encodeit(*entry, chunk.c_str())) return false; break; } case 5: { std::string chunk(start_piece, iter); np++; if (pHMgr->is_aliasm()) { int index = atoi(chunk.c_str()); entry->morphcode = pHMgr->get_aliasm(index); } else { if (complexprefixes) { // XXX - fix me for morph. gen. if (utf8) reverseword_utf(chunk); else reverseword(chunk); } // add the remaining of the line std::string::const_iterator end = nl.end(); if (iter != end) { chunk.append(iter, end); } entry->morphcode = mystrdup(chunk.c_str()); if (!entry->morphcode) return false; } break; } default: break; } i++; start_piece = mystrsep(nl, iter); } // check to make sure we parsed enough pieces if (np < 4) { char* err = pHMgr->encode_flag(aflag); if (err) { HUNSPELL_WARNING(stderr, "error: line %d: affix %s is corrupt\n", af->getlinenum(), err); free(err); } return false; } #ifdef DEBUG // detect unnecessary fields, excepting comments if (basefieldnum) { int fieldnum = !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6); if (fieldnum != basefieldnum) HUNSPELL_WARNING(stderr, "warning: line %d: bad field number\n", af->getlinenum()); } else { basefieldnum = !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6); } #endif } // now create SfxEntry or PfxEntry objects and use links to // build an ordered (sorted by affix string) list std::vector::iterator start = affentries.begin(); std::vector::iterator end = affentries.end(); for (std::vector::iterator affentry = start; affentry != end; ++affentry) { if (at == 'P') { build_pfxtree(static_cast(*affentry)); } else { build_sfxtree(static_cast(*affentry)); } } //contents belong to AffixMgr now affentries.release(); return true; } int AffixMgr::redundant_condition(char ft, const char* strip, int stripl, const char* cond, int linenum) { int condl = strlen(cond); int i; int j; int neg; int in; if (ft == 'P') { // prefix if (strncmp(strip, cond, condl) == 0) return 1; if (utf8) { } else { for (i = 0, j = 0; (i < stripl) && (j < condl); i++, j++) { if (cond[j] != '[') { if (cond[j] != strip[i]) { HUNSPELL_WARNING(stderr, "warning: line %d: incompatible stripping " "characters and condition\n", linenum); return 0; } } else { neg = (cond[j + 1] == '^') ? 1 : 0; in = 0; do { j++; if (strip[i] == cond[j]) in = 1; } while ((j < (condl - 1)) && (cond[j] != ']')); if (j == (condl - 1) && (cond[j] != ']')) { HUNSPELL_WARNING(stderr, "error: line %d: missing ] in condition:\n%s\n", linenum, cond); return 0; } if ((!neg && !in) || (neg && in)) { HUNSPELL_WARNING(stderr, "warning: line %d: incompatible stripping " "characters and condition\n", linenum); return 0; } } } if (j >= condl) return 1; } } else { // suffix if ((stripl >= condl) && strcmp(strip + stripl - condl, cond) == 0) return 1; if (utf8) { } else { for (i = stripl - 1, j = condl - 1; (i >= 0) && (j >= 0); i--, j--) { if (cond[j] != ']') { if (cond[j] != strip[i]) { HUNSPELL_WARNING(stderr, "warning: line %d: incompatible stripping " "characters and condition\n", linenum); return 0; } } else { in = 0; do { j--; if (strip[i] == cond[j]) in = 1; } while ((j > 0) && (cond[j] != '[')); if ((j == 0) && (cond[j] != '[')) { HUNSPELL_WARNING(stderr, "error: line: %d: missing ] in condition:\n%s\n", linenum, cond); return 0; } neg = (cond[j + 1] == '^') ? 1 : 0; if ((!neg && !in) || (neg && in)) { HUNSPELL_WARNING(stderr, "warning: line %d: incompatible stripping " "characters and condition\n", linenum); return 0; } } } if (j < 0) return 1; } } return 0; } std::vector AffixMgr::get_suffix_words(short unsigned* suff, int len, const char* root_word) { std::vector slst; short unsigned* start_ptr = suff; for (int j = 0; j < SETSIZE; j++) { SfxEntry* ptr = sStart[j]; while (ptr) { suff = start_ptr; for (int i = 0; i < len; i++) { if ((*suff) == ptr->getFlag()) { std::string nw(root_word); nw.append(ptr->getAffix()); hentry* ht = ptr->checkword(nw.c_str(), nw.size(), 0, NULL, 0, 0, 0); if (ht) { slst.push_back(nw); } } suff++; } ptr = ptr->getNext(); } } return slst; } nuspell-5.1.7/external/hunspell/hunspell/affixmgr.hxx000066400000000000000000000346111511132717100230540ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef AFFIXMGR_HXX_ #define AFFIXMGR_HXX_ #include #include #include #include "atypes.hxx" #include "baseaffix.hxx" #include "hashmgr.hxx" #include "phonet.hxx" #include "replist.hxx" // check flag duplication #define dupSFX (1 << 0) #define dupPFX (1 << 1) class PfxEntry; class SfxEntry; class AffixMgr { PfxEntry* pStart[SETSIZE]; SfxEntry* sStart[SETSIZE]; PfxEntry* pFlag[SETSIZE]; SfxEntry* sFlag[SETSIZE]; const std::vector& alldic; const HashMgr* pHMgr; std::string keystring; std::string trystring; std::string encoding; struct cs_info* csconv; int utf8; int complexprefixes; FLAG compoundflag; FLAG compoundbegin; FLAG compoundmiddle; FLAG compoundend; FLAG compoundroot; FLAG compoundforbidflag; FLAG compoundpermitflag; int compoundmoresuffixes; int checkcompounddup; int checkcompoundrep; int checkcompoundcase; int checkcompoundtriple; int simplifiedtriple; FLAG forbiddenword; FLAG nosuggest; FLAG nongramsuggest; FLAG needaffix; int cpdmin; bool parsedrep; std::vector reptable; RepList* iconvtable; RepList* oconvtable; bool parsedmaptable; std::vector maptable; bool parsedbreaktable; std::vector breaktable; bool parsedcheckcpd; std::vector checkcpdtable; int simplifiedcpd; bool parseddefcpd; std::vector defcpdtable; phonetable* phone; int maxngramsugs; int maxcpdsugs; int maxdiff; int onlymaxdiff; int nosplitsugs; int sugswithdots; int cpdwordmax; int cpdmaxsyllable; std::string cpdvowels; // vowels (for calculating of Hungarian compounding limit, std::vector cpdvowels_utf16; //vowels for UTF-8 encoding std::string cpdsyllablenum; // syllable count incrementing flag const char* pfxappnd; // BUG: not stateless const char* sfxappnd; // BUG: not stateless int sfxextra; // BUG: not stateless FLAG sfxflag; // BUG: not stateless char* derived; // BUG: not stateless SfxEntry* sfx; // BUG: not stateless PfxEntry* pfx; // BUG: not stateless int checknum; std::string wordchars; // letters + spec. word characters std::vector wordchars_utf16; std::string ignorechars; // letters + spec. word characters std::vector ignorechars_utf16; std::string version; // affix and dictionary file version string std::string lang; // language int langnum; FLAG lemma_present; FLAG circumfix; FLAG onlyincompound; FLAG keepcase; FLAG forceucase; FLAG warn; int forbidwarn; FLAG substandard; int checksharps; int fullstrip; int havecontclass; // boolean variable char contclasses[CONTSIZE]; // flags of possible continuing classes (twofold // affix) public: AffixMgr(const char* affpath, const std::vector& ptr, const char* key = NULL); ~AffixMgr(); struct hentry* affix_check(const char* word, int len, const unsigned short needflag = (unsigned short)0, char in_compound = IN_CPD_NOT); struct hentry* prefix_check(const char* word, int len, char in_compound, const FLAG needflag = FLAG_NULL); inline int isSubset(const char* s1, const char* s2); struct hentry* prefix_check_twosfx(const char* word, int len, char in_compound, const FLAG needflag = FLAG_NULL); inline int isRevSubset(const char* s1, const char* end_of_s2, int len); struct hentry* suffix_check(const char* word, int len, int sfxopts, PfxEntry* ppfx, const FLAG cclass = FLAG_NULL, const FLAG needflag = FLAG_NULL, char in_compound = IN_CPD_NOT); struct hentry* suffix_check_twosfx(const char* word, int len, int sfxopts, PfxEntry* ppfx, const FLAG needflag = FLAG_NULL); std::string affix_check_morph(const char* word, int len, const FLAG needflag = FLAG_NULL, char in_compound = IN_CPD_NOT); std::string prefix_check_morph(const char* word, int len, char in_compound, const FLAG needflag = FLAG_NULL); std::string suffix_check_morph(const char* word, int len, int sfxopts, PfxEntry* ppfx, const FLAG cclass = FLAG_NULL, const FLAG needflag = FLAG_NULL, char in_compound = IN_CPD_NOT); std::string prefix_check_twosfx_morph(const char* word, int len, char in_compound, const FLAG needflag = FLAG_NULL); std::string suffix_check_twosfx_morph(const char* word, int len, int sfxopts, PfxEntry* ppfx, const FLAG needflag = FLAG_NULL); std::string morphgen(const char* ts, int wl, const unsigned short* ap, unsigned short al, const char* morph, const char* targetmorph, int level); int expand_rootword(struct guessword* wlst, int maxn, const char* ts, int wl, const unsigned short* ap, unsigned short al, const char* bad, int, const char*); short get_syllable(const std::string& word); int cpdrep_check(const char* word, int len); int cpdpat_check(const char* word, int len, hentry* r1, hentry* r2, const char affixed); int defcpd_check(hentry*** words, short wnum, hentry* rv, hentry** rwords, char all); int cpdcase_check(const char* word, int len); inline int candidate_check(const char* word, int len); void setcminmax(int* cmin, int* cmax, const char* word, int len); struct hentry* compound_check(const std::string& word, short wordnum, short numsyllable, short maxwordnum, short wnum, hentry** words, hentry** rwords, char hu_mov_rule, char is_sug, int* info); int compound_check_morph(const char* word, int len, short wordnum, short numsyllable, short maxwordnum, short wnum, hentry** words, hentry** rwords, char hu_mov_rule, std::string& result, const std::string* partresult); std::vector get_suffix_words(short unsigned* suff, int len, const char* root_word); struct hentry* lookup(const char* word); const std::vector& get_reptable() const; RepList* get_iconvtable() const; RepList* get_oconvtable() const; struct phonetable* get_phonetable() const; const std::vector& get_maptable() const; const std::vector& get_breaktable() const; const std::string& get_encoding(); int get_langnum() const; char* get_key_string(); char* get_try_string() const; const std::string& get_wordchars() const; const std::vector& get_wordchars_utf16() const; const char* get_ignore() const; const std::vector& get_ignore_utf16() const; int get_compound() const; FLAG get_compoundflag() const; FLAG get_forbiddenword() const; FLAG get_nosuggest() const; FLAG get_nongramsuggest() const; FLAG get_needaffix() const; FLAG get_onlyincompound() const; const char* get_derived() const; const std::string& get_version() const; int have_contclass() const; int get_utf8() const; int get_complexprefixes() const; char* get_suffixed(char) const; int get_maxngramsugs() const; int get_maxcpdsugs() const; int get_maxdiff() const; int get_onlymaxdiff() const; int get_nosplitsugs() const; int get_sugswithdots(void) const; FLAG get_keepcase(void) const; FLAG get_forceucase(void) const; FLAG get_warn(void) const; int get_forbidwarn(void) const; int get_checksharps(void) const; char* encode_flag(unsigned short aflag) const; int get_fullstrip() const; private: int parse_file(const char* affpath, const char* key); bool parse_flag(const std::string& line, unsigned short* out, FileMgr* af); bool parse_num(const std::string& line, int* out, FileMgr* af); bool parse_cpdsyllable(const std::string& line, FileMgr* af); bool parse_reptable(const std::string& line, FileMgr* af); bool parse_convtable(const std::string& line, FileMgr* af, RepList** rl, const std::string& keyword); bool parse_phonetable(const std::string& line, FileMgr* af); bool parse_maptable(const std::string& line, FileMgr* af); bool parse_breaktable(const std::string& line, FileMgr* af); bool parse_checkcpdtable(const std::string& line, FileMgr* af); bool parse_defcpdtable(const std::string& line, FileMgr* af); bool parse_affix(const std::string& line, const char at, FileMgr* af, char* dupflags); void reverse_condition(std::string&); std::string& debugflag(std::string& result, unsigned short flag); int condlen(const char*); int encodeit(AffEntry& entry, const char* cs); int build_pfxtree(PfxEntry* pfxptr); int build_sfxtree(SfxEntry* sfxptr); int process_pfx_order(); int process_sfx_order(); PfxEntry* process_pfx_in_order(PfxEntry* ptr, PfxEntry* nptr); SfxEntry* process_sfx_in_order(SfxEntry* ptr, SfxEntry* nptr); int process_pfx_tree_to_list(); int process_sfx_tree_to_list(); int redundant_condition(char, const char* strip, int stripl, const char* cond, int); void finishFileMgr(FileMgr* afflst); }; #endif nuspell-5.1.7/external/hunspell/hunspell/atypes.hxx000066400000000000000000000066541511132717100225640ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef ATYPES_HXX_ #define ATYPES_HXX_ #ifndef HUNSPELL_WARNING #include #ifdef HUNSPELL_WARNING_ON #define HUNSPELL_WARNING fprintf #else // empty inline function to switch off warnings (instead of the C99 standard // variadic macros) static inline void HUNSPELL_WARNING(FILE*, const char*, ...) {} #endif #endif // HUNSTEM def. #define HUNSTEM #include "w_char.hxx" #include #include #include #define SETSIZE 256 #define CONTSIZE 65536 // AffEntry options #define aeXPRODUCT (1 << 0) #define aeUTF8 (1 << 1) #define aeALIASF (1 << 2) #define aeALIASM (1 << 3) #define aeLONGCOND (1 << 4) // compound options #define IN_CPD_NOT 0 #define IN_CPD_BEGIN 1 #define IN_CPD_END 2 #define IN_CPD_OTHER 3 // info options #define SPELL_COMPOUND (1 << 0) #define SPELL_FORBIDDEN (1 << 1) #define SPELL_ALLCAP (1 << 2) #define SPELL_NOCAP (1 << 3) #define SPELL_INITCAP (1 << 4) #define SPELL_ORIGCAP (1 << 5) #define SPELL_WARN (1 << 6) #define MINCPDLEN 3 #define MAXCOMPOUND 10 #define MAXCONDLEN 20 #define MAXCONDLEN_1 (MAXCONDLEN - sizeof(char*)) #define MAXACC 1000 #define FLAG unsigned short #define FLAG_NULL 0x00 #define FREE_FLAG(a) a = 0 #define TESTAFF(a, b, c) (std::binary_search(a, a + c, b)) struct guessword { char* word; bool allow; char* orig; }; typedef std::vector mapentry; typedef std::vector flagentry; struct patentry { std::string pattern; std::string pattern2; std::string pattern3; FLAG cond; FLAG cond2; patentry() : cond(FLAG_NULL) , cond2(FLAG_NULL) { } }; #endif nuspell-5.1.7/external/hunspell/hunspell/baseaffix.hxx000066400000000000000000000047661511132717100232110ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef BASEAFF_HXX_ #define BASEAFF_HXX_ #include class AffEntry { private: AffEntry(const AffEntry&); AffEntry& operator=(const AffEntry&); public: AffEntry() : numconds(0), opts(0), aflag(0), morphcode(0), contclass(NULL), contclasslen(0) {} virtual ~AffEntry(); std::string appnd; std::string strip; unsigned char numconds; char opts; unsigned short aflag; union { char conds[MAXCONDLEN]; struct { char conds1[MAXCONDLEN_1]; char* conds2; } l; } c; char* morphcode; unsigned short* contclass; short contclasslen; }; #endif nuspell-5.1.7/external/hunspell/hunspell/csutil.cxx000066400000000000000000003745471511132717100225660ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "csutil.hxx" #include "atypes.hxx" #include "langnum.hxx" #ifdef _WIN32 #include #include #endif #ifdef OPENOFFICEORG #include #else #ifndef MOZILLA_CLIENT #include "utf_info.hxx" #define UTF_LST_LEN (sizeof(utf_lst) / (sizeof(unicode_info))) #endif #endif #ifdef MOZILLA_CLIENT #include "nsCOMPtr.h" #include "nsIUnicodeEncoder.h" #include "nsIUnicodeDecoder.h" #include "nsUnicharUtils.h" #include "mozilla/dom/EncodingUtils.h" using mozilla::dom::EncodingUtils; #endif struct unicode_info2 { char cletter; unsigned short cupper; unsigned short clower; }; static struct unicode_info2* utf_tbl = NULL; static int utf_tbl_count = 0; // utf_tbl can be used by multiple Hunspell instances void myopen(std::ifstream& stream, const char* path, std::ios_base::openmode mode) { #if defined(_WIN32) && defined(_MSC_VER) #define WIN32_LONG_PATH_PREFIX "\\\\?\\" if (strncmp(path, WIN32_LONG_PATH_PREFIX, 4) == 0) { int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); wchar_t* buff = new wchar_t[len]; wchar_t* buff2 = new wchar_t[len]; MultiByteToWideChar(CP_UTF8, 0, path, -1, buff, len); if (_wfullpath(buff2, buff, len) != NULL) { stream.open(buff2, mode); } delete [] buff; delete [] buff2; } else #endif stream.open(path, mode); } std::string& u16_u8(std::string& dest, const std::vector& src) { dest.clear(); std::vector::const_iterator u2 = src.begin(); std::vector::const_iterator u2_max = src.end(); while (u2 < u2_max) { signed char u8; if (u2->h) { // > 0xFF // XXX 4-byte haven't implemented yet. if (u2->h >= 0x08) { // >= 0x800 (3-byte UTF-8 character) u8 = 0xe0 + (u2->h >> 4); dest.push_back(u8); u8 = 0x80 + ((u2->h & 0xf) << 2) + (u2->l >> 6); dest.push_back(u8); u8 = 0x80 + (u2->l & 0x3f); dest.push_back(u8); } else { // < 0x800 (2-byte UTF-8 character) u8 = 0xc0 + (u2->h << 2) + (u2->l >> 6); dest.push_back(u8); u8 = 0x80 + (u2->l & 0x3f); dest.push_back(u8); } } else { // <= 0xFF if (u2->l & 0x80) { // >0x80 (2-byte UTF-8 character) u8 = 0xc0 + (u2->l >> 6); dest.push_back(u8); u8 = 0x80 + (u2->l & 0x3f); dest.push_back(u8); } else { // < 0x80 (1-byte UTF-8 character) u8 = u2->l; dest.push_back(u8); } } ++u2; } return dest; } int u8_u16(std::vector& dest, const std::string& src) { dest.clear(); std::string::const_iterator u8 = src.begin(); std::string::const_iterator u8_max = src.end(); while (u8 < u8_max) { w_char u2; switch ((*u8) & 0xf0) { case 0x00: case 0x10: case 0x20: case 0x30: case 0x40: case 0x50: case 0x60: case 0x70: { u2.h = 0; u2.l = *u8; break; } case 0x80: case 0x90: case 0xa0: case 0xb0: { HUNSPELL_WARNING(stderr, "UTF-8 encoding error. Unexpected continuation bytes " "in %ld. character position\n%s\n", static_cast(std::distance(src.begin(), u8)), src.c_str()); u2.h = 0xff; u2.l = 0xfd; break; } case 0xc0: case 0xd0: { // 2-byte UTF-8 codes if ((*(u8 + 1) & 0xc0) == 0x80) { u2.h = (*u8 & 0x1f) >> 2; u2.l = (static_cast(*u8) << 6) + (*(u8 + 1) & 0x3f); ++u8; } else { HUNSPELL_WARNING(stderr, "UTF-8 encoding error. Missing continuation byte in " "%ld. character position:\n%s\n", static_cast(std::distance(src.begin(), u8)), src.c_str()); u2.h = 0xff; u2.l = 0xfd; } break; } case 0xe0: { // 3-byte UTF-8 codes if ((*(u8 + 1) & 0xc0) == 0x80) { u2.h = ((*u8 & 0x0f) << 4) + ((*(u8 + 1) & 0x3f) >> 2); ++u8; if ((*(u8 + 1) & 0xc0) == 0x80) { u2.l = (static_cast(*u8) << 6) + (*(u8 + 1) & 0x3f); ++u8; } else { HUNSPELL_WARNING(stderr, "UTF-8 encoding error. Missing continuation byte " "in %ld. character position:\n%s\n", static_cast(std::distance(src.begin(), u8)), src.c_str()); u2.h = 0xff; u2.l = 0xfd; } } else { HUNSPELL_WARNING(stderr, "UTF-8 encoding error. Missing continuation byte in " "%ld. character position:\n%s\n", static_cast(std::distance(src.begin(), u8)), src.c_str()); u2.h = 0xff; u2.l = 0xfd; } break; } case 0xf0: { // 4 or more byte UTF-8 codes HUNSPELL_WARNING(stderr, "This UTF-8 encoding can't convert to UTF-16:\n%s\n", src.c_str()); u2.h = 0xff; u2.l = 0xfd; dest.push_back(u2); return -1; } } dest.push_back(u2); ++u8; } return dest.size(); } namespace { class is_any_of { public: explicit is_any_of(const std::string& in) : chars(in) {} bool operator()(char c) { return chars.find(c) != std::string::npos; } private: std::string chars; }; } std::string::const_iterator mystrsep(const std::string &str, std::string::const_iterator& start) { std::string::const_iterator end = str.end(); is_any_of op(" \t"); // don't use isspace() here, the string can be in some random charset // that's way different than the locale's std::string::const_iterator sp = start; while (sp != end && op(*sp)) ++sp; std::string::const_iterator dp = sp; while (dp != end && !op(*dp)) ++dp; start = dp; return sp; } // replaces strdup with ansi version char* mystrdup(const char* s) { char* d = NULL; if (s) { size_t sl = strlen(s) + 1; d = (char*)malloc(sl); if (d) { memcpy(d, s, sl); } else { HUNSPELL_WARNING(stderr, "Can't allocate memory.\n"); } } return d; } // remove cross-platform text line end characters void mychomp(std::string& s) { size_t k = s.size(); size_t newsize = k; if ((k > 0) && ((s[k - 1] == '\r') || (s[k - 1] == '\n'))) --newsize; if ((k > 1) && (s[k - 2] == '\r')) --newsize; s.resize(newsize); } // break text to lines std::vector line_tok(const std::string& text, char breakchar) { std::vector ret; if (text.empty()) { return ret; } std::stringstream ss(text); std::string tok; while(std::getline(ss, tok, breakchar)) { if (!tok.empty()) { ret.push_back(tok); } } return ret; } // uniq line in place void line_uniq(std::string& text, char breakchar) { std::vector lines = line_tok(text, breakchar); text.clear(); if (lines.empty()) { return; } text = lines[0]; for (size_t i = 1; i < lines.size(); ++i) { bool dup = false; for (size_t j = 0; j < i; ++j) { if (lines[i] == lines[j]) { dup = true; break; } } if (!dup) { if (!text.empty()) text.push_back(breakchar); text.append(lines[i]); } } } // uniq and boundary for compound analysis: "1\n\2\n\1" -> " ( \1 | \2 ) " void line_uniq_app(std::string& text, char breakchar) { if (text.find(breakchar) == std::string::npos) { return; } std::vector lines = line_tok(text, breakchar); text.clear(); if (lines.empty()) { return; } text = lines[0]; for (size_t i = 1; i < lines.size(); ++i) { bool dup = false; for (size_t j = 0; j < i; ++j) { if (lines[i] == lines[j]) { dup = true; break; } } if (!dup) { if (!text.empty()) text.push_back(breakchar); text.append(lines[i]); } } if (lines.size() == 1) { text = lines[0]; return; } text.assign(" ( "); for (size_t i = 0; i < lines.size(); ++i) { text.append(lines[i]); text.append(" | "); } text[text.size() - 2] = ')'; // " ) " } // append s to ends of every lines in text std::string& strlinecat(std::string& str, const std::string& apd) { size_t pos = 0; while ((pos = str.find('\n', pos)) != std::string::npos) { str.insert(pos, apd); pos += apd.length() + 1; } str.append(apd); return str; } int fieldlen(const char* r) { int n = 0; while (r && *r != ' ' && *r != '\t' && *r != '\0' && *r != '\n') { r++; n++; } return n; } bool copy_field(std::string& dest, const std::string& morph, const std::string& var) { if (morph.empty()) return false; size_t pos = morph.find(var); if (pos == std::string::npos) return false; dest.clear(); std::string beg(morph.substr(pos + MORPH_TAG_LEN, std::string::npos)); for (size_t i = 0; i < beg.size(); ++i) { const char c(beg[i]); if (c == ' ' || c == '\t' || c == '\n') break; dest.push_back(c); } return true; } std::string& mystrrep(std::string& str, const std::string& search, const std::string& replace) { size_t pos = 0; while ((pos = str.find(search, pos)) != std::string::npos) { str.replace(pos, search.length(), replace); pos += replace.length(); } return str; } // reverse word size_t reverseword(std::string& word) { std::reverse(word.begin(), word.end()); return word.size(); } // reverse word size_t reverseword_utf(std::string& word) { std::vector w; u8_u16(w, word); std::reverse(w.begin(), w.end()); u16_u8(word, w); return w.size(); } void uniqlist(std::vector& list) { if (list.size() < 2) return; std::vector ret; ret.push_back(list[0]); for (size_t i = 1; i < list.size(); ++i) { if (std::find(ret.begin(), ret.end(), list[i]) == ret.end()) ret.push_back(list[i]); } list.swap(ret); } namespace { unsigned char cupper(const struct cs_info* csconv, int nIndex) { if (nIndex < 0 || nIndex > 255) return nIndex; return csconv[nIndex].cupper; } unsigned char clower(const struct cs_info* csconv, int nIndex) { if (nIndex < 0 || nIndex > 255) return nIndex; return csconv[nIndex].clower; } unsigned char ccase(const struct cs_info* csconv, int nIndex) { if (nIndex < 0 || nIndex > 255) return nIndex; return csconv[nIndex].ccase; } } w_char upper_utf(w_char u, int langnum) { unsigned short idx = (u.h << 8) + u.l; unsigned short upridx = unicodetoupper(idx, langnum); if (idx != upridx) { u.h = (unsigned char)(upridx >> 8); u.l = (unsigned char)(upridx & 0x00FF); } return u; } w_char lower_utf(w_char u, int langnum) { unsigned short idx = (u.h << 8) + u.l; unsigned short lwridx = unicodetolower(idx, langnum); if (idx != lwridx) { u.h = (unsigned char)(lwridx >> 8); u.l = (unsigned char)(lwridx & 0x00FF); } return u; } // convert std::string to all caps std::string& mkallcap(std::string& s, const struct cs_info* csconv) { for (std::string::iterator aI = s.begin(), aEnd = s.end(); aI != aEnd; ++aI) { *aI = cupper(csconv, static_cast(*aI)); } return s; } // convert std::string to all little std::string& mkallsmall(std::string& s, const struct cs_info* csconv) { for (std::string::iterator aI = s.begin(), aEnd = s.end(); aI != aEnd; ++aI) { *aI = clower(csconv, static_cast(*aI)); } return s; } std::vector& mkallsmall_utf(std::vector& u, int langnum) { for (size_t i = 0; i < u.size(); ++i) { unsigned short idx = (u[i].h << 8) + u[i].l; unsigned short lwridx = unicodetolower(idx, langnum); if (idx != lwridx) { u[i].h = (unsigned char)(lwridx >> 8); u[i].l = (unsigned char)(lwridx & 0x00FF); } } return u; } std::vector& mkallcap_utf(std::vector& u, int langnum) { for (size_t i = 0; i < u.size(); i++) { unsigned short idx = (u[i].h << 8) + u[i].l; unsigned short upridx = unicodetoupper(idx, langnum); if (idx != upridx) { u[i].h = (unsigned char)(upridx >> 8); u[i].l = (unsigned char)(upridx & 0x00FF); } } return u; } std::string& mkinitcap(std::string& s, const struct cs_info* csconv) { if (!s.empty()) { s[0] = cupper(csconv, static_cast(s[0])); } return s; } std::vector& mkinitcap_utf(std::vector& u, int langnum) { if (!u.empty()) { unsigned short idx = (u[0].h << 8) + u[0].l; unsigned short upridx = unicodetoupper(idx, langnum); if (idx != upridx) { u[0].h = (unsigned char)(upridx >> 8); u[0].l = (unsigned char)(upridx & 0x00FF); } } return u; } std::string& mkinitsmall(std::string& s, const struct cs_info* csconv) { if (!s.empty()) { s[0] = clower(csconv, static_cast(s[0])); } return s; } std::vector& mkinitsmall_utf(std::vector& u, int langnum) { if (!u.empty()) { unsigned short idx = (u[0].h << 8) + u[0].l; unsigned short lwridx = unicodetolower(idx, langnum); if (idx != lwridx) { u[0].h = (unsigned char)(lwridx >> 8); u[0].l = (unsigned char)(lwridx & 0x00FF); } } return u; } // conversion function for protected memory void store_pointer(char* dest, char* source) { memcpy(dest, &source, sizeof(char*)); } // conversion function for protected memory char* get_stored_pointer(const char* s) { char* p; memcpy(&p, s, sizeof(char*)); return p; } #ifndef MOZILLA_CLIENT // these are simple character mappings for the // encodings supported // supplying isupper, tolower, and toupper static struct cs_info iso1_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, {0x00, 0xff, 0xff}}; static struct cs_info iso2_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x01, 0xb3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x01, 0xb5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x01, 0xb9, 0xa9}, {0x01, 0xba, 0xaa}, {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, {0x01, 0xbe, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xa3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xa5}, {0x00, 0xb6, 0xa6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xa9}, {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xae}, {0x00, 0xbf, 0xaf}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, {0x00, 0xff, 0xff}}; static struct cs_info iso3_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x01, 0x69, 0xa9}, {0x01, 0xba, 0xaa}, {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xa6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0x49}, {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xaf}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x00, 0xc3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x00, 0xd0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xe3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, {0x00, 0xff, 0xff}}; static struct cs_info iso4_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x01, 0xb3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x01, 0xb5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x01, 0xb9, 0xa9}, {0x01, 0xba, 0xaa}, {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, {0x01, 0xbe, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xa3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xa5}, {0x00, 0xb6, 0xa6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xa9}, {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xae}, {0x00, 0xbf, 0xbf}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, {0x00, 0xff, 0xff}}; static struct cs_info iso5_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xf1, 0xa1}, {0x01, 0xf2, 0xa2}, {0x01, 0xf3, 0xa3}, {0x01, 0xf4, 0xa4}, {0x01, 0xf5, 0xa5}, {0x01, 0xf6, 0xa6}, {0x01, 0xf7, 0xa7}, {0x01, 0xf8, 0xa8}, {0x01, 0xf9, 0xa9}, {0x01, 0xfa, 0xaa}, {0x01, 0xfb, 0xab}, {0x01, 0xfc, 0xac}, {0x00, 0xad, 0xad}, {0x01, 0xfe, 0xae}, {0x01, 0xff, 0xaf}, {0x01, 0xd0, 0xb0}, {0x01, 0xd1, 0xb1}, {0x01, 0xd2, 0xb2}, {0x01, 0xd3, 0xb3}, {0x01, 0xd4, 0xb4}, {0x01, 0xd5, 0xb5}, {0x01, 0xd6, 0xb6}, {0x01, 0xd7, 0xb7}, {0x01, 0xd8, 0xb8}, {0x01, 0xd9, 0xb9}, {0x01, 0xda, 0xba}, {0x01, 0xdb, 0xbb}, {0x01, 0xdc, 0xbc}, {0x01, 0xdd, 0xbd}, {0x01, 0xde, 0xbe}, {0x01, 0xdf, 0xbf}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x00, 0xd0, 0xb0}, {0x00, 0xd1, 0xb1}, {0x00, 0xd2, 0xb2}, {0x00, 0xd3, 0xb3}, {0x00, 0xd4, 0xb4}, {0x00, 0xd5, 0xb5}, {0x00, 0xd6, 0xb6}, {0x00, 0xd7, 0xb7}, {0x00, 0xd8, 0xb8}, {0x00, 0xd9, 0xb9}, {0x00, 0xda, 0xba}, {0x00, 0xdb, 0xbb}, {0x00, 0xdc, 0xbc}, {0x00, 0xdd, 0xbd}, {0x00, 0xde, 0xbe}, {0x00, 0xdf, 0xbf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xa1}, {0x00, 0xf2, 0xa2}, {0x00, 0xf3, 0xa3}, {0x00, 0xf4, 0xa4}, {0x00, 0xf5, 0xa5}, {0x00, 0xf6, 0xa6}, {0x00, 0xf7, 0xa7}, {0x00, 0xf8, 0xa8}, {0x00, 0xf9, 0xa9}, {0x00, 0xfa, 0xaa}, {0x00, 0xfb, 0xab}, {0x00, 0xfc, 0xac}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xae}, {0x00, 0xff, 0xaf}}; static struct cs_info iso6_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, {0x00, 0xff, 0xff}}; static struct cs_info iso7_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x01, 0xdc, 0xb6}, {0x00, 0xb7, 0xb7}, {0x01, 0xdd, 0xb8}, {0x01, 0xde, 0xb9}, {0x01, 0xdf, 0xba}, {0x00, 0xbb, 0xbb}, {0x01, 0xfc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x01, 0xfd, 0xbe}, {0x01, 0xfe, 0xbf}, {0x00, 0xc0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x00, 0xd2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x00, 0xdc, 0xb6}, {0x00, 0xdd, 0xb8}, {0x00, 0xde, 0xb9}, {0x00, 0xdf, 0xba}, {0x00, 0xe0, 0xe0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd3}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xbc}, {0x00, 0xfd, 0xbe}, {0x00, 0xfe, 0xbf}, {0x00, 0xff, 0xff}}; static struct cs_info iso8_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, {0x00, 0xff, 0xff}}; static struct cs_info iso9_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0xfd, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0xdd}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0x69, 0xdd}, {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0x49}, {0x00, 0xfe, 0xde}, {0x00, 0xff, 0xff}}; static struct cs_info iso10_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, {0x00, 0xff, 0xff}}; static struct cs_info koi8r_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xb3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x01, 0xa3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xe0}, {0x00, 0xc1, 0xe1}, {0x00, 0xc2, 0xe2}, {0x00, 0xc3, 0xe3}, {0x00, 0xc4, 0xe4}, {0x00, 0xc5, 0xe5}, {0x00, 0xc6, 0xe6}, {0x00, 0xc7, 0xe7}, {0x00, 0xc8, 0xe8}, {0x00, 0xc9, 0xe9}, {0x00, 0xca, 0xea}, {0x00, 0xcb, 0xeb}, {0x00, 0xcc, 0xec}, {0x00, 0xcd, 0xed}, {0x00, 0xce, 0xee}, {0x00, 0xcf, 0xef}, {0x00, 0xd0, 0xf0}, {0x00, 0xd1, 0xf1}, {0x00, 0xd2, 0xf2}, {0x00, 0xd3, 0xf3}, {0x00, 0xd4, 0xf4}, {0x00, 0xd5, 0xf5}, {0x00, 0xd6, 0xf6}, {0x00, 0xd7, 0xf7}, {0x00, 0xd8, 0xf8}, {0x00, 0xd9, 0xf9}, {0x00, 0xda, 0xfa}, {0x00, 0xdb, 0xfb}, {0x00, 0xdc, 0xfc}, {0x00, 0xdd, 0xfd}, {0x00, 0xde, 0xfe}, {0x00, 0xdf, 0xff}, {0x01, 0xc0, 0xe0}, {0x01, 0xc1, 0xe1}, {0x01, 0xc2, 0xe2}, {0x01, 0xc3, 0xe3}, {0x01, 0xc4, 0xe4}, {0x01, 0xc5, 0xe5}, {0x01, 0xc6, 0xe6}, {0x01, 0xc7, 0xe7}, {0x01, 0xc8, 0xe8}, {0x01, 0xc9, 0xe9}, {0x01, 0xca, 0xea}, {0x01, 0xcb, 0xeb}, {0x01, 0xcc, 0xec}, {0x01, 0xcd, 0xed}, {0x01, 0xce, 0xee}, {0x01, 0xcf, 0xef}, {0x01, 0xd0, 0xf0}, {0x01, 0xd1, 0xf1}, {0x01, 0xd2, 0xf2}, {0x01, 0xd3, 0xf3}, {0x01, 0xd4, 0xf4}, {0x01, 0xd5, 0xf5}, {0x01, 0xd6, 0xf6}, {0x01, 0xd7, 0xf7}, {0x01, 0xd8, 0xf8}, {0x01, 0xd9, 0xf9}, {0x01, 0xda, 0xfa}, {0x01, 0xdb, 0xfb}, {0x01, 0xdc, 0xfc}, {0x01, 0xdd, 0xfd}, {0x01, 0xde, 0xfe}, {0x01, 0xdf, 0xff}}; static struct cs_info koi8u_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xb3}, {0x00, 0xa4, 0xb4}, /* ie */ {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xb6}, /* i */ {0x00, 0xa7, 0xb7}, /* ii */ {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xbd}, /* g'' */ {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x01, 0xa3, 0xb3}, {0x00, 0xb4, 0xb4}, /* IE */ {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, /* I */ {0x00, 0xb7, 0xb7}, /* II */ {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xe0}, {0x00, 0xc1, 0xe1}, {0x00, 0xc2, 0xe2}, {0x00, 0xc3, 0xe3}, {0x00, 0xc4, 0xe4}, {0x00, 0xc5, 0xe5}, {0x00, 0xc6, 0xe6}, {0x00, 0xc7, 0xe7}, {0x00, 0xc8, 0xe8}, {0x00, 0xc9, 0xe9}, {0x00, 0xca, 0xea}, {0x00, 0xcb, 0xeb}, {0x00, 0xcc, 0xec}, {0x00, 0xcd, 0xed}, {0x00, 0xce, 0xee}, {0x00, 0xcf, 0xef}, {0x00, 0xd0, 0xf0}, {0x00, 0xd1, 0xf1}, {0x00, 0xd2, 0xf2}, {0x00, 0xd3, 0xf3}, {0x00, 0xd4, 0xf4}, {0x00, 0xd5, 0xf5}, {0x00, 0xd6, 0xf6}, {0x00, 0xd7, 0xf7}, {0x00, 0xd8, 0xf8}, {0x00, 0xd9, 0xf9}, {0x00, 0xda, 0xfa}, {0x00, 0xdb, 0xfb}, {0x00, 0xdc, 0xfc}, {0x00, 0xdd, 0xfd}, {0x00, 0xde, 0xfe}, {0x00, 0xdf, 0xff}, {0x01, 0xc0, 0xe0}, {0x01, 0xc1, 0xe1}, {0x01, 0xc2, 0xe2}, {0x01, 0xc3, 0xe3}, {0x01, 0xc4, 0xe4}, {0x01, 0xc5, 0xe5}, {0x01, 0xc6, 0xe6}, {0x01, 0xc7, 0xe7}, {0x01, 0xc8, 0xe8}, {0x01, 0xc9, 0xe9}, {0x01, 0xca, 0xea}, {0x01, 0xcb, 0xeb}, {0x01, 0xcc, 0xec}, {0x01, 0xcd, 0xed}, {0x01, 0xce, 0xee}, {0x01, 0xcf, 0xef}, {0x01, 0xd0, 0xf0}, {0x01, 0xd1, 0xf1}, {0x01, 0xd2, 0xf2}, {0x01, 0xd3, 0xf3}, {0x01, 0xd4, 0xf4}, {0x01, 0xd5, 0xf5}, {0x01, 0xd6, 0xf6}, {0x01, 0xd7, 0xf7}, {0x01, 0xd8, 0xf8}, {0x01, 0xd9, 0xf9}, {0x01, 0xda, 0xfa}, {0x01, 0xdb, 0xfb}, {0x01, 0xdc, 0xfc}, {0x01, 0xdd, 0xfd}, {0x01, 0xde, 0xfe}, {0x01, 0xdf, 0xff}}; static struct cs_info cp1251_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x01, 0x90, 0x80}, {0x01, 0x83, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x81}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x01, 0x9a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x01, 0x9c, 0x8c}, {0x01, 0x9d, 0x8d}, {0x01, 0x9e, 0x8e}, {0x01, 0x9f, 0x8f}, {0x00, 0x90, 0x80}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x8a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x8c}, {0x00, 0x9d, 0x8d}, {0x00, 0x9e, 0x8e}, {0x00, 0x9f, 0x8f}, {0x00, 0xa0, 0xa0}, {0x01, 0xa2, 0xa1}, {0x00, 0xa2, 0xa1}, {0x01, 0xbc, 0xa3}, {0x00, 0xa4, 0xa4}, {0x01, 0xb4, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x01, 0xb8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x01, 0xba, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x01, 0xb3, 0xb2}, {0x00, 0xb3, 0xb2}, {0x00, 0xb4, 0xa5}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xa8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xa3}, {0x01, 0xbe, 0xbd}, {0x00, 0xbe, 0xbd}, {0x00, 0xbf, 0xaf}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, {0x01, 0xfe, 0xde}, {0x01, 0xff, 0xdf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, {0x00, 0xff, 0xdf}}; static struct cs_info iso13_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0A, 0x0A}, {0x00, 0x0B, 0x0B}, {0x00, 0x0C, 0x0C}, {0x00, 0x0D, 0x0D}, {0x00, 0x0E, 0x0E}, {0x00, 0x0F, 0x0F}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1A, 0x1A}, {0x00, 0x1B, 0x1B}, {0x00, 0x1C, 0x1C}, {0x00, 0x1D, 0x1D}, {0x00, 0x1E, 0x1E}, {0x00, 0x1F, 0x1F}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2A, 0x2A}, {0x00, 0x2B, 0x2B}, {0x00, 0x2C, 0x2C}, {0x00, 0x2D, 0x2D}, {0x00, 0x2E, 0x2E}, {0x00, 0x2F, 0x2F}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3A, 0x3A}, {0x00, 0x3B, 0x3B}, {0x00, 0x3C, 0x3C}, {0x00, 0x3D, 0x3D}, {0x00, 0x3E, 0x3E}, {0x00, 0x3F, 0x3F}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6A, 0x4A}, {0x01, 0x6B, 0x4B}, {0x01, 0x6C, 0x4C}, {0x01, 0x6D, 0x4D}, {0x01, 0x6E, 0x4E}, {0x01, 0x6F, 0x4F}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7A, 0x5A}, {0x00, 0x5B, 0x5B}, {0x00, 0x5C, 0x5C}, {0x00, 0x5D, 0x5D}, {0x00, 0x5E, 0x5E}, {0x00, 0x5F, 0x5F}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6A, 0x4A}, {0x00, 0x6B, 0x4B}, {0x00, 0x6C, 0x4C}, {0x00, 0x6D, 0x4D}, {0x00, 0x6E, 0x4E}, {0x00, 0x6F, 0x4F}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7A, 0x5A}, {0x00, 0x7B, 0x7B}, {0x00, 0x7C, 0x7C}, {0x00, 0x7D, 0x7D}, {0x00, 0x7E, 0x7E}, {0x00, 0x7F, 0x7F}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8A, 0x8A}, {0x00, 0x8B, 0x8B}, {0x00, 0x8C, 0x8C}, {0x00, 0x8D, 0x8D}, {0x00, 0x8E, 0x8E}, {0x00, 0x8F, 0x8F}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9A, 0x9A}, {0x00, 0x9B, 0x9B}, {0x00, 0x9C, 0x9C}, {0x00, 0x9D, 0x9D}, {0x00, 0x9E, 0x9E}, {0x00, 0x9F, 0x9F}, {0x00, 0xA0, 0xA0}, {0x00, 0xA1, 0xA1}, {0x00, 0xA2, 0xA2}, {0x00, 0xA3, 0xA3}, {0x00, 0xA4, 0xA4}, {0x00, 0xA5, 0xA5}, {0x00, 0xA6, 0xA6}, {0x00, 0xA7, 0xA7}, {0x01, 0xB8, 0xA8}, {0x00, 0xA9, 0xA9}, {0x01, 0xBA, 0xAA}, {0x00, 0xAB, 0xAB}, {0x00, 0xAC, 0xAC}, {0x00, 0xAD, 0xAD}, {0x00, 0xAE, 0xAE}, {0x01, 0xBF, 0xAF}, {0x00, 0xB0, 0xB0}, {0x00, 0xB1, 0xB1}, {0x00, 0xB2, 0xB2}, {0x00, 0xB3, 0xB3}, {0x00, 0xB4, 0xB4}, {0x00, 0xB5, 0xB5}, {0x00, 0xB6, 0xB6}, {0x00, 0xB7, 0xB7}, {0x00, 0xB8, 0xA8}, {0x00, 0xB9, 0xB9}, {0x00, 0xBA, 0xAA}, {0x00, 0xBB, 0xBB}, {0x00, 0xBC, 0xBC}, {0x00, 0xBD, 0xBD}, {0x00, 0xBE, 0xBE}, {0x00, 0xBF, 0xAF}, {0x01, 0xE0, 0xC0}, {0x01, 0xE1, 0xC1}, {0x01, 0xE2, 0xC2}, {0x01, 0xE3, 0xC3}, {0x01, 0xE4, 0xC4}, {0x01, 0xE5, 0xC5}, {0x01, 0xE6, 0xC6}, {0x01, 0xE7, 0xC7}, {0x01, 0xE8, 0xC8}, {0x01, 0xE9, 0xC9}, {0x01, 0xEA, 0xCA}, {0x01, 0xEB, 0xCB}, {0x01, 0xEC, 0xCC}, {0x01, 0xED, 0xCD}, {0x01, 0xEE, 0xCE}, {0x01, 0xEF, 0xCF}, {0x01, 0xF0, 0xD0}, {0x01, 0xF1, 0xD1}, {0x01, 0xF2, 0xD2}, {0x01, 0xF3, 0xD3}, {0x01, 0xF4, 0xD4}, {0x01, 0xF5, 0xD5}, {0x01, 0xF6, 0xD6}, {0x00, 0xD7, 0xD7}, {0x01, 0xF8, 0xD8}, {0x01, 0xF9, 0xD9}, {0x01, 0xFA, 0xDA}, {0x01, 0xFB, 0xDB}, {0x01, 0xFC, 0xDC}, {0x01, 0xFD, 0xDD}, {0x01, 0xFE, 0xDE}, {0x00, 0xDF, 0xDF}, {0x00, 0xE0, 0xC0}, {0x00, 0xE1, 0xC1}, {0x00, 0xE2, 0xC2}, {0x00, 0xE3, 0xC3}, {0x00, 0xE4, 0xC4}, {0x00, 0xE5, 0xC5}, {0x00, 0xE6, 0xC6}, {0x00, 0xE7, 0xC7}, {0x00, 0xE8, 0xC8}, {0x00, 0xE9, 0xC9}, {0x00, 0xEA, 0xCA}, {0x00, 0xEB, 0xCB}, {0x00, 0xEC, 0xCC}, {0x00, 0xED, 0xCD}, {0x00, 0xEE, 0xCE}, {0x00, 0xEF, 0xCF}, {0x00, 0xF0, 0xD0}, {0x00, 0xF1, 0xD1}, {0x00, 0xF2, 0xD2}, {0x00, 0xF3, 0xD3}, {0x00, 0xF4, 0xD4}, {0x00, 0xF5, 0xD5}, {0x00, 0xF6, 0xD6}, {0x00, 0xF7, 0xF7}, {0x00, 0xF8, 0xD8}, {0x00, 0xF9, 0xD9}, {0x00, 0xFA, 0xDA}, {0x00, 0xFB, 0xDB}, {0x00, 0xFC, 0xDC}, {0x00, 0xFD, 0xDD}, {0x00, 0xFE, 0xDE}, {0x00, 0xFF, 0xFF}}; static struct cs_info iso14_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xa2, 0xa1}, {0x00, 0xa2, 0xa1}, {0x00, 0xa3, 0xa3}, {0x01, 0xa5, 0xa4}, {0x00, 0xa5, 0xa4}, {0x01, 0xa6, 0xab}, {0x00, 0xa7, 0xa7}, {0x01, 0xb8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x01, 0xba, 0xaa}, {0x00, 0xab, 0xa6}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x01, 0xff, 0xaf}, {0x01, 0xb1, 0xb0}, {0x00, 0xb1, 0xb0}, {0x01, 0xb3, 0xb2}, {0x00, 0xb3, 0xb2}, {0x01, 0xb5, 0xb4}, {0x00, 0xb5, 0xb4}, {0x00, 0xb6, 0xb6}, {0x01, 0xb9, 0xb7}, {0x00, 0xb8, 0xa8}, {0x00, 0xb9, 0xb6}, {0x00, 0xba, 0xaa}, {0x01, 0xbf, 0xbb}, {0x00, 0xbc, 0xac}, {0x01, 0xbe, 0xbd}, {0x00, 0xbe, 0xbd}, {0x00, 0xbf, 0xbb}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, {0x00, 0xff, 0xff}}; static struct cs_info iso15_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x01, 0xa8, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa6}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x01, 0xb8, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb4}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x01, 0xbd, 0xbc}, {0x00, 0xbd, 0xbc}, {0x01, 0xff, 0xbe}, {0x00, 0xbf, 0xbf}, {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, {0x00, 0xff, 0xbe}}; static struct cs_info iscii_devanagari_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, {0x00, 0xff, 0xff}}; static struct cs_info tis620_tbl[] = { {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, {0x00, 0xff, 0xff}}; struct enc_entry { const char* enc_name; struct cs_info* cs_table; }; static struct enc_entry encds[] = { {"iso88591", iso1_tbl}, // ISO-8859-1 {"iso88592", iso2_tbl}, // ISO-8859-2 {"iso88593", iso3_tbl}, // ISO-8859-3 {"iso88594", iso4_tbl}, // ISO-8859-4 {"iso88595", iso5_tbl}, // ISO-8859-5 {"iso88596", iso6_tbl}, // ISO-8859-6 {"iso88597", iso7_tbl}, // ISO-8859-7 {"iso88598", iso8_tbl}, // ISO-8859-8 {"iso88599", iso9_tbl}, // ISO-8859-9 {"iso885910", iso10_tbl}, // ISO-8859-10 {"tis620", tis620_tbl}, // TIS-620/ISO-8859-11 {"tis6202533", tis620_tbl}, // TIS-620/ISO-8859-11 {"iso885911", tis620_tbl}, // TIS-620/ISO-8859-11 {"iso885913", iso13_tbl}, // ISO-8859-13 {"iso885914", iso14_tbl}, // ISO-8859-14 {"iso885915", iso15_tbl}, // ISO-8859-15 {"koi8r", koi8r_tbl}, // KOI8-R {"koi8u", koi8u_tbl}, // KOI8-U {"cp1251", cp1251_tbl}, // CP-1251 {"microsoftcp1251", cp1251_tbl}, // microsoft-cp1251 {"xisciias", iscii_devanagari_tbl}, // x-iscii-as {"isciidevanagari", iscii_devanagari_tbl} // ISCII-DEVANAGARI }; /* map to lower case and remove non alphanumeric chars */ static void toAsciiLowerAndRemoveNonAlphanumeric(const char* pName, char* pBuf) { while (*pName) { /* A-Z */ if ((*pName >= 0x41) && (*pName <= 0x5A)) { *pBuf = (*pName) + 0x20; /* toAsciiLower */ pBuf++; } /* a-z, 0-9 */ else if (((*pName >= 0x61) && (*pName <= 0x7A)) || ((*pName >= 0x30) && (*pName <= 0x39))) { *pBuf = *pName; pBuf++; } pName++; } *pBuf = '\0'; } struct cs_info* get_current_cs(const std::string& es) { char* normalized_encoding = new char[es.size() + 1]; toAsciiLowerAndRemoveNonAlphanumeric(es.c_str(), normalized_encoding); struct cs_info* ccs = NULL; int n = sizeof(encds) / sizeof(encds[0]); for (int i = 0; i < n; i++) { if (strcmp(normalized_encoding, encds[i].enc_name) == 0) { ccs = encds[i].cs_table; break; } } delete[] normalized_encoding; if (!ccs) { HUNSPELL_WARNING(stderr, "error: unknown encoding %s: using %s as fallback\n", es.c_str(), encds[0].enc_name); ccs = encds[0].cs_table; } return ccs; } #else // XXX This function was rewritten for mozilla. Instead of storing the // conversion tables static in this file, create them when needed // with help the mozilla backend. struct cs_info* get_current_cs(const std::string& es) { struct cs_info* ccs = new cs_info[256]; // Initialze the array with dummy data so that we wouldn't need // to return null in case of failures. for (int i = 0; i <= 0xff; ++i) { ccs[i].ccase = false; ccs[i].clower = i; ccs[i].cupper = i; } nsCOMPtr encoder; nsCOMPtr decoder; nsresult rv; nsAutoCString label(es.c_str()); nsAutoCString encoding; if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) { return ccs; } encoder = EncodingUtils::EncoderForEncoding(encoding); decoder = EncodingUtils::DecoderForEncoding(encoding); encoder->SetOutputErrorBehavior(encoder->kOnError_Signal, nullptr, '?'); decoder->SetInputErrorBehavior(decoder->kOnError_Signal); for (unsigned int i = 0; i <= 0xff; ++i) { bool success = false; // We want to find the upper/lowercase equivalents of each byte // in this 1-byte character encoding. Call our encoding/decoding // APIs separately for each byte since they may reject some of the // bytes, and we want to handle errors separately for each byte. char lower, upper; do { if (i == 0) break; const char source = char(i); char16_t uni, uniCased; int32_t charLength = 1, uniLength = 1; rv = decoder->Convert(&source, &charLength, &uni, &uniLength); // Explicitly check NS_OK because we don't want to allow // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. if (rv != NS_OK || charLength != 1 || uniLength != 1) break; uniCased = ToLowerCase(uni); rv = encoder->Convert(&uniCased, &uniLength, &lower, &charLength); // Explicitly check NS_OK because we don't want to allow // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. if (rv != NS_OK || charLength != 1 || uniLength != 1) break; uniCased = ToUpperCase(uni); rv = encoder->Convert(&uniCased, &uniLength, &upper, &charLength); // Explicitly check NS_OK because we don't want to allow // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. if (rv != NS_OK || charLength != 1 || uniLength != 1) break; success = true; } while (0); if (success) { ccs[i].cupper = upper; ccs[i].clower = lower; } else { ccs[i].cupper = i; ccs[i].clower = i; } if (ccs[i].clower != (unsigned char)i) ccs[i].ccase = true; else ccs[i].ccase = false; } return ccs; } #endif // primitive isalpha() replacement for tokenization std::string get_casechars(const char* enc) { struct cs_info* csconv = get_current_cs(enc); std::string expw; for (int i = 0; i <= 255; ++i) { if (cupper(csconv, i) != clower(csconv, i)) { expw.push_back(static_cast(i)); } } #ifdef MOZILLA_CLIENT delete[] csconv; #endif return expw; } // language to encoding default map struct lang_map { const char* lang; int num; }; static struct lang_map lang2enc[] = {{"ar", LANG_ar}, {"az", LANG_az}, {"az_AZ", LANG_az}, // for back-compatibility {"bg", LANG_bg}, {"ca", LANG_ca}, {"crh", LANG_crh}, {"cs", LANG_cs}, {"da", LANG_da}, {"de", LANG_de}, {"el", LANG_el}, {"en", LANG_en}, {"es", LANG_es}, {"eu", LANG_eu}, {"gl", LANG_gl}, {"fr", LANG_fr}, {"hr", LANG_hr}, {"hu", LANG_hu}, {"hu_HU", LANG_hu}, // for back-compatibility {"it", LANG_it}, {"la", LANG_la}, {"lv", LANG_lv}, {"nl", LANG_nl}, {"pl", LANG_pl}, {"pt", LANG_pt}, {"sv", LANG_sv}, {"tr", LANG_tr}, {"tr_TR", LANG_tr}, // for back-compatibility {"ru", LANG_ru}, {"uk", LANG_uk}}; int get_lang_num(const std::string& lang) { int n = sizeof(lang2enc) / sizeof(lang2enc[0]); for (int i = 0; i < n; i++) { if (strcmp(lang.c_str(), lang2enc[i].lang) == 0) { return lang2enc[i].num; } } return LANG_xx; } #ifndef OPENOFFICEORG #ifndef MOZILLA_CLIENT void initialize_utf_tbl() { utf_tbl_count++; if (utf_tbl) return; utf_tbl = new unicode_info2[CONTSIZE]; for (size_t j = 0; j < CONTSIZE; ++j) { utf_tbl[j].cletter = 0; utf_tbl[j].clower = (unsigned short)j; utf_tbl[j].cupper = (unsigned short)j; } for (size_t j = 0; j < UTF_LST_LEN; ++j) { utf_tbl[utf_lst[j].c].cletter = 1; utf_tbl[utf_lst[j].c].clower = utf_lst[j].clower; utf_tbl[utf_lst[j].c].cupper = utf_lst[j].cupper; } } #endif #endif void free_utf_tbl() { if (utf_tbl_count > 0) utf_tbl_count--; if (utf_tbl && (utf_tbl_count == 0)) { delete[] utf_tbl; utf_tbl = NULL; } } unsigned short unicodetoupper(unsigned short c, int langnum) { // In Azeri and Turkish, I and i dictinct letters: // There are a dotless lower case i pair of upper `I', // and an upper I with dot pair of lower `i'. if (c == 0x0069 && ((langnum == LANG_az) || (langnum == LANG_tr) || (langnum == LANG_crh))) return 0x0130; #ifdef OPENOFFICEORG return static_cast(u_toupper(c)); #else #ifdef MOZILLA_CLIENT return ToUpperCase((char16_t)c); #else return (utf_tbl) ? utf_tbl[c].cupper : c; #endif #endif } unsigned short unicodetolower(unsigned short c, int langnum) { // In Azeri and Turkish, I and i dictinct letters: // There are a dotless lower case i pair of upper `I', // and an upper I with dot pair of lower `i'. if (c == 0x0049 && ((langnum == LANG_az) || (langnum == LANG_tr) || (langnum == LANG_crh))) return 0x0131; #ifdef OPENOFFICEORG return static_cast(u_tolower(c)); #else #ifdef MOZILLA_CLIENT return ToLowerCase((char16_t)c); #else return (utf_tbl) ? utf_tbl[c].clower : c; #endif #endif } int unicodeisalpha(unsigned short c) { #ifdef OPENOFFICEORG return u_isalpha(c); #else return (utf_tbl) ? utf_tbl[c].cletter : 0; #endif } /* get type of capitalization */ int get_captype(const std::string& word, cs_info* csconv) { // now determine the capitalization type of the first nl letters size_t ncap = 0; size_t nneutral = 0; size_t firstcap = 0; if (csconv == NULL) return NOCAP; for (std::string::const_iterator q = word.begin(); q != word.end(); ++q) { unsigned char nIndex = static_cast(*q); if (ccase(csconv, nIndex)) ncap++; if (cupper(csconv, nIndex) == clower(csconv, nIndex)) nneutral++; } if (ncap) { unsigned char nIndex = static_cast(word[0]); firstcap = csconv[nIndex].ccase; } // now finally set the captype if (ncap == 0) { return NOCAP; } else if ((ncap == 1) && firstcap) { return INITCAP; } else if ((ncap == word.size()) || ((ncap + nneutral) == word.size())) { return ALLCAP; } else if ((ncap > 1) && firstcap) { return HUHINITCAP; } return HUHCAP; } int get_captype_utf8(const std::vector& word, int langnum) { // now determine the capitalization type of the first nl letters size_t ncap = 0; size_t nneutral = 0; size_t firstcap = 0; std::vector::const_iterator it = word.begin(); std::vector::const_iterator it_end = word.end(); while (it != it_end) { unsigned short idx = (it->h << 8) + it->l; unsigned short lwridx = unicodetolower(idx, langnum); if (idx != lwridx) ncap++; if (unicodetoupper(idx, langnum) == lwridx) nneutral++; ++it; } if (ncap) { unsigned short idx = (word[0].h << 8) + word[0].l; firstcap = (idx != unicodetolower(idx, langnum)); } // now finally set the captype if (ncap == 0) { return NOCAP; } else if ((ncap == 1) && firstcap) { return INITCAP; } else if ((ncap == word.size()) || ((ncap + nneutral) == word.size())) { return ALLCAP; } else if ((ncap > 1) && firstcap) { return HUHINITCAP; } return HUHCAP; } // strip all ignored characters in the string size_t remove_ignored_chars_utf(std::string& word, const std::vector& ignored_chars) { std::vector w; std::vector w2; u8_u16(w, word); for (size_t i = 0; i < w.size(); ++i) { if (!std::binary_search(ignored_chars.begin(), ignored_chars.end(), w[i])) { w2.push_back(w[i]); } } u16_u8(word, w2); return w2.size(); } // strip all ignored characters in the string size_t remove_ignored_chars(std::string& word, const std::string& ignored_chars) { word.erase( std::remove_if(word.begin(), word.end(), is_any_of(ignored_chars)), word.end()); return word.size(); } bool parse_string(const std::string& line, std::string& out, int ln) { if (!out.empty()) { HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions\n", ln); return false; } int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { out.assign(start_piece, iter); np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", ln); return false; } return true; } bool parse_array(const std::string& line, std::string& out, std::vector& out_utf16, int utf8, int ln) { if (!parse_string(line, out, ln)) return false; if (utf8) { u8_u16(out_utf16, out); std::sort(out_utf16.begin(), out_utf16.end()); } return true; } nuspell-5.1.7/external/hunspell/hunspell/csutil.hxx000066400000000000000000000270611511132717100225550ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CSUTIL_HXX_ #define CSUTIL_HXX_ #include "hunvisapi.h" // First some base level utility routines #include #include #include #include #include "w_char.hxx" #include "htypes.hxx" #ifdef MOZILLA_CLIENT #include "nscore.h" // for mozalloc headers #endif // casing #define NOCAP 0 #define INITCAP 1 #define ALLCAP 2 #define HUHCAP 3 #define HUHINITCAP 4 // default encoding and keystring #define SPELL_ENCODING "ISO8859-1" #define SPELL_KEYSTRING "qwertyuiop|asdfghjkl|zxcvbnm" // default morphological fields #define MORPH_STEM "st:" #define MORPH_ALLOMORPH "al:" #define MORPH_POS "po:" #define MORPH_DERI_PFX "dp:" #define MORPH_INFL_PFX "ip:" #define MORPH_TERM_PFX "tp:" #define MORPH_DERI_SFX "ds:" #define MORPH_INFL_SFX "is:" #define MORPH_TERM_SFX "ts:" #define MORPH_SURF_PFX "sp:" #define MORPH_FREQ "fr:" #define MORPH_PHON "ph:" #define MORPH_HYPH "hy:" #define MORPH_PART "pa:" #define MORPH_FLAG "fl:" #define MORPH_HENTRY "_H:" #define MORPH_TAG_LEN strlen(MORPH_STEM) #define MSEP_FLD ' ' #define MSEP_REC '\n' #define MSEP_ALT '\v' // default flags #define DEFAULTFLAGS 65510 #define FORBIDDENWORD 65510 #define ONLYUPCASEFLAG 65511 // fix long pathname problem of WIN32 by using w_char std::fstream::open override LIBHUNSPELL_DLL_EXPORTED void myopen(std::ifstream& stream, const char* path, std::ios_base::openmode mode); // convert UTF-16 characters to UTF-8 LIBHUNSPELL_DLL_EXPORTED std::string& u16_u8(std::string& dest, const std::vector& src); // convert UTF-8 characters to UTF-16 LIBHUNSPELL_DLL_EXPORTED int u8_u16(std::vector& dest, const std::string& src); // remove end of line char(s) LIBHUNSPELL_DLL_EXPORTED void mychomp(std::string& s); // duplicate string LIBHUNSPELL_DLL_EXPORTED char* mystrdup(const char* s); // parse into tokens with char delimiter LIBHUNSPELL_DLL_EXPORTED std::string::const_iterator mystrsep(const std::string &str, std::string::const_iterator& start); // replace pat by rep in word and return word LIBHUNSPELL_DLL_EXPORTED std::string& mystrrep(std::string& str, const std::string& search, const std::string& replace); // append s to ends of every lines in text LIBHUNSPELL_DLL_EXPORTED std::string& strlinecat(std::string& str, const std::string& apd); // tokenize into lines with new line LIBHUNSPELL_DLL_EXPORTED std::vector line_tok(const std::string& text, char breakchar); // tokenize into lines with new line and uniq in place LIBHUNSPELL_DLL_EXPORTED void line_uniq(std::string& text, char breakchar); LIBHUNSPELL_DLL_EXPORTED void line_uniq_app(std::string& text, char breakchar); // reverse word LIBHUNSPELL_DLL_EXPORTED size_t reverseword(std::string& word); // reverse word LIBHUNSPELL_DLL_EXPORTED size_t reverseword_utf(std::string&); // remove duplicates LIBHUNSPELL_DLL_EXPORTED void uniqlist(std::vector& list); // character encoding information struct cs_info { unsigned char ccase; unsigned char clower; unsigned char cupper; }; LIBHUNSPELL_DLL_EXPORTED void initialize_utf_tbl(); LIBHUNSPELL_DLL_EXPORTED void free_utf_tbl(); LIBHUNSPELL_DLL_EXPORTED unsigned short unicodetoupper(unsigned short c, int langnum); LIBHUNSPELL_DLL_EXPORTED w_char upper_utf(w_char u, int langnum); LIBHUNSPELL_DLL_EXPORTED w_char lower_utf(w_char u, int langnum); LIBHUNSPELL_DLL_EXPORTED unsigned short unicodetolower(unsigned short c, int langnum); LIBHUNSPELL_DLL_EXPORTED int unicodeisalpha(unsigned short c); LIBHUNSPELL_DLL_EXPORTED struct cs_info* get_current_cs(const std::string& es); // get language identifiers of language codes LIBHUNSPELL_DLL_EXPORTED int get_lang_num(const std::string& lang); // get characters of the given 8bit encoding with lower- and uppercase forms LIBHUNSPELL_DLL_EXPORTED std::string get_casechars(const char* enc); // convert std::string to all caps LIBHUNSPELL_DLL_EXPORTED std::string& mkallcap(std::string& s, const struct cs_info* csconv); // convert null terminated string to all little LIBHUNSPELL_DLL_EXPORTED std::string& mkallsmall(std::string& s, const struct cs_info* csconv); // convert first letter of string to little LIBHUNSPELL_DLL_EXPORTED std::string& mkinitsmall(std::string& s, const struct cs_info* csconv); // convert first letter of string to capital LIBHUNSPELL_DLL_EXPORTED std::string& mkinitcap(std::string& s, const struct cs_info* csconv); // convert first letter of UTF-8 string to capital LIBHUNSPELL_DLL_EXPORTED std::vector& mkinitcap_utf(std::vector& u, int langnum); // convert UTF-8 string to little LIBHUNSPELL_DLL_EXPORTED std::vector& mkallsmall_utf(std::vector& u, int langnum); // convert first letter of UTF-8 string to little LIBHUNSPELL_DLL_EXPORTED std::vector& mkinitsmall_utf(std::vector& u, int langnum); // convert UTF-8 string to capital LIBHUNSPELL_DLL_EXPORTED std::vector& mkallcap_utf(std::vector& u, int langnum); // get type of capitalization LIBHUNSPELL_DLL_EXPORTED int get_captype(const std::string& q, cs_info*); // get type of capitalization (UTF-8) LIBHUNSPELL_DLL_EXPORTED int get_captype_utf8(const std::vector& q, int langnum); // strip all ignored characters in the string LIBHUNSPELL_DLL_EXPORTED size_t remove_ignored_chars_utf( std::string& word, const std::vector& ignored_chars); // strip all ignored characters in the string LIBHUNSPELL_DLL_EXPORTED size_t remove_ignored_chars( std::string& word, const std::string& ignored_chars); LIBHUNSPELL_DLL_EXPORTED bool parse_string(const std::string& line, std::string& out, int ln); LIBHUNSPELL_DLL_EXPORTED bool parse_array(const std::string& line, std::string& out, std::vector& out_utf16, int utf8, int ln); LIBHUNSPELL_DLL_EXPORTED int fieldlen(const char* r); LIBHUNSPELL_DLL_EXPORTED bool copy_field(std::string& dest, const std::string& morph, const std::string& var); // conversion function for protected memory LIBHUNSPELL_DLL_EXPORTED void store_pointer(char* dest, char* source); // conversion function for protected memory LIBHUNSPELL_DLL_EXPORTED char* get_stored_pointer(const char* s); // hash entry macros inline char* HENTRY_DATA(struct hentry* h) { char* ret; if (!h->var) ret = NULL; else if (h->var & H_OPT_ALIASM) ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); else ret = HENTRY_WORD(h) + h->blen + 1; return ret; } inline const char* HENTRY_DATA( const struct hentry* h) { const char* ret; if (!h->var) ret = NULL; else if (h->var & H_OPT_ALIASM) ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); else ret = HENTRY_WORD(h) + h->blen + 1; return ret; } // NULL-free version for warning-free OOo build inline const char* HENTRY_DATA2( const struct hentry* h) { const char* ret; if (!h->var) ret = ""; else if (h->var & H_OPT_ALIASM) ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); else ret = HENTRY_WORD(h) + h->blen + 1; return ret; } inline char* HENTRY_FIND(struct hentry* h, const char* p) { return (HENTRY_DATA(h) ? strstr(HENTRY_DATA(h), p) : NULL); } #endif nuspell-5.1.7/external/hunspell/hunspell/filemgr.cxx000066400000000000000000000106521511132717100226700ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "filemgr.hxx" #include "csutil.hxx" int FileMgr::fail(const char* err, const char* par) { fprintf(stderr, err, par); return -1; } FileMgr::FileMgr(const char* file, const char* key) : hin(NULL), linenum(0) { in[0] = '\0'; myopen(fin, file, std::ios_base::in); if (!fin.is_open()) { // check hzipped file std::string st(file); st.append(HZIP_EXTENSION); hin = new Hunzip(st.c_str(), key); } if (!fin.is_open() && !hin->is_open()) fail(MSG_OPEN, file); } FileMgr::~FileMgr() { delete hin; } bool FileMgr::getline(std::string& dest) { bool ret = false; ++linenum; if (fin.is_open()) { ret = static_cast(std::getline(fin, dest)); } else if (hin->is_open()) { ret = hin->getline(dest); } if (!ret) { --linenum; } return ret; } int FileMgr::getlinenum() { return linenum; } nuspell-5.1.7/external/hunspell/hunspell/filemgr.hxx000066400000000000000000000101341511132717100226700ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* file manager class - read lines of files [filename] OR [filename.hz] */ #ifndef FILEMGR_HXX_ #define FILEMGR_HXX_ #include "hunzip.hxx" #include #include #include class FileMgr { private: FileMgr(const FileMgr&); FileMgr& operator=(const FileMgr&); protected: std::ifstream fin; Hunzip* hin; char in[BUFSIZE + 50]; // input buffer int fail(const char* err, const char* par); int linenum; public: FileMgr(const char* filename, const char* key = NULL); ~FileMgr(); bool getline(std::string&); int getlinenum(); }; #endif nuspell-5.1.7/external/hunspell/hunspell/hashmgr.cxx000066400000000000000000001043751511132717100227020ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "hashmgr.hxx" #include "csutil.hxx" #include "atypes.hxx" // build a hash table from a munched word list HashMgr::HashMgr(const char* tpath, const char* apath, const char* key) : tablesize(0), tableptr(NULL), flag_mode(FLAG_CHAR), complexprefixes(0), utf8(0), forbiddenword(FORBIDDENWORD) // forbidden word signing flag , numaliasf(0), aliasf(NULL), aliasflen(0), numaliasm(0), aliasm(NULL) { langnum = 0; csconv = 0; load_config(apath, key); int ec = load_tables(tpath, key); if (ec) { /* error condition - what should we do here */ HUNSPELL_WARNING(stderr, "Hash Manager Error : %d\n", ec); free(tableptr); //keep tablesize to 1 to fix possible division with zero tablesize = 1; tableptr = (struct hentry**)calloc(tablesize, sizeof(struct hentry*)); if (!tableptr) { tablesize = 0; } } } HashMgr::~HashMgr() { if (tableptr) { // now pass through hash table freeing up everything // go through column by column of the table for (int i = 0; i < tablesize; i++) { struct hentry* pt = tableptr[i]; struct hentry* nt = NULL; while (pt) { nt = pt->next; if (pt->astr && (!aliasf || TESTAFF(pt->astr, ONLYUPCASEFLAG, pt->alen))) free(pt->astr); free(pt); pt = nt; } } free(tableptr); } tablesize = 0; if (aliasf) { for (int j = 0; j < (numaliasf); j++) free(aliasf[j]); free(aliasf); aliasf = NULL; if (aliasflen) { free(aliasflen); aliasflen = NULL; } } if (aliasm) { for (int j = 0; j < (numaliasm); j++) free(aliasm[j]); free(aliasm); aliasm = NULL; } #ifndef OPENOFFICEORG #ifndef MOZILLA_CLIENT if (utf8) free_utf_tbl(); #endif #endif #ifdef MOZILLA_CLIENT delete[] csconv; #endif } // lookup a root word in the hashtable struct hentry* HashMgr::lookup(const char* word) const { struct hentry* dp; if (tableptr) { dp = tableptr[hash(word)]; if (!dp) return NULL; for (; dp != NULL; dp = dp->next) { if (strcmp(word, dp->word) == 0) return dp; } } return NULL; } // add a word to the hash table (private) int HashMgr::add_word(const std::string& in_word, int wcl, unsigned short* aff, int al, const std::string* in_desc, bool onlyupcase) { const std::string* word = &in_word; const std::string* desc = in_desc; std::string *word_copy = NULL; std::string *desc_copy = NULL; if (!ignorechars.empty() || complexprefixes) { word_copy = new std::string(in_word); if (!ignorechars.empty()) { if (utf8) { wcl = remove_ignored_chars_utf(*word_copy, ignorechars_utf16); } else { remove_ignored_chars(*word_copy, ignorechars); } } if (complexprefixes) { if (utf8) wcl = reverseword_utf(*word_copy); else reverseword(*word_copy); if (in_desc && !aliasm) { desc_copy = new std::string(*in_desc); if (complexprefixes) { if (utf8) reverseword_utf(*desc_copy); else reverseword(*desc_copy); } desc = desc_copy; } } word = word_copy; } bool upcasehomonym = false; int descl = desc ? (aliasm ? sizeof(char*) : desc->size() + 1) : 0; // variable-length hash record with word and optional fields struct hentry* hp = (struct hentry*)malloc(sizeof(struct hentry) + word->size() + descl); if (!hp) { delete desc_copy; delete word_copy; return 1; } char* hpw = hp->word; strcpy(hpw, word->c_str()); int i = hash(hpw); hp->blen = (unsigned char)word->size(); hp->clen = (unsigned char)wcl; hp->alen = (short)al; hp->astr = aff; hp->next = NULL; hp->next_homonym = NULL; // store the description string or its pointer if (desc) { hp->var = H_OPT; if (aliasm) { hp->var += H_OPT_ALIASM; store_pointer(hpw + word->size() + 1, get_aliasm(atoi(desc->c_str()))); } else { strcpy(hpw + word->size() + 1, desc->c_str()); } if (strstr(HENTRY_DATA(hp), MORPH_PHON)) hp->var += H_OPT_PHON; } else hp->var = 0; struct hentry* dp = tableptr[i]; if (!dp) { tableptr[i] = hp; delete desc_copy; delete word_copy; return 0; } while (dp->next != NULL) { if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) { // remove hidden onlyupcase homonym if (!onlyupcase) { if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { free(dp->astr); dp->astr = hp->astr; dp->alen = hp->alen; free(hp); delete desc_copy; delete word_copy; return 0; } else { dp->next_homonym = hp; } } else { upcasehomonym = true; } } dp = dp->next; } if (strcmp(hp->word, dp->word) == 0) { // remove hidden onlyupcase homonym if (!onlyupcase) { if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { free(dp->astr); dp->astr = hp->astr; dp->alen = hp->alen; free(hp); delete desc_copy; delete word_copy; return 0; } else { dp->next_homonym = hp; } } else { upcasehomonym = true; } } if (!upcasehomonym) { dp->next = hp; } else { // remove hidden onlyupcase homonym if (hp->astr) free(hp->astr); free(hp); } delete desc_copy; delete word_copy; return 0; } int HashMgr::add_hidden_capitalized_word(const std::string& word, int wcl, unsigned short* flags, int flagslen, const std::string* dp, int captype) { if (flags == NULL) flagslen = 0; // add inner capitalized forms to handle the following allcap forms: // Mixed caps: OpenOffice.org -> OPENOFFICE.ORG // Allcaps with suffixes: CIA's -> CIA'S if (((captype == HUHCAP) || (captype == HUHINITCAP) || ((captype == ALLCAP) && (flagslen != 0))) && !((flagslen != 0) && TESTAFF(flags, forbiddenword, flagslen))) { unsigned short* flags2 = (unsigned short*)malloc(sizeof(unsigned short) * (flagslen + 1)); if (!flags2) return 1; if (flagslen) memcpy(flags2, flags, flagslen * sizeof(unsigned short)); flags2[flagslen] = ONLYUPCASEFLAG; if (utf8) { std::string st; std::vector w; u8_u16(w, word); mkallsmall_utf(w, langnum); mkinitcap_utf(w, langnum); u16_u8(st, w); return add_word(st, wcl, flags2, flagslen + 1, dp, true); } else { std::string new_word(word); mkallsmall(new_word, csconv); mkinitcap(new_word, csconv); int ret = add_word(new_word, wcl, flags2, flagslen + 1, dp, true); return ret; } } return 0; } // detect captype and modify word length for UTF-8 encoding int HashMgr::get_clen_and_captype(const std::string& word, int* captype, std::vector &workbuf) { int len; if (utf8) { len = u8_u16(workbuf, word); *captype = get_captype_utf8(workbuf, langnum); } else { len = word.size(); *captype = get_captype(word, csconv); } return len; } int HashMgr::get_clen_and_captype(const std::string& word, int* captype) { std::vector workbuf; return get_clen_and_captype(word, captype, workbuf); } // remove word (personal dictionary function for standalone applications) int HashMgr::remove(const std::string& word) { struct hentry* dp = lookup(word.c_str()); while (dp) { if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) { unsigned short* flags = (unsigned short*)malloc(sizeof(unsigned short) * (dp->alen + 1)); if (!flags) return 1; for (int i = 0; i < dp->alen; i++) flags[i] = dp->astr[i]; flags[dp->alen] = forbiddenword; free(dp->astr); dp->astr = flags; dp->alen++; std::sort(flags, flags + dp->alen); } dp = dp->next_homonym; } return 0; } /* remove forbidden flag to add a personal word to the hash */ int HashMgr::remove_forbidden_flag(const std::string& word) { struct hentry* dp = lookup(word.c_str()); if (!dp) return 1; while (dp) { if (dp->astr && TESTAFF(dp->astr, forbiddenword, dp->alen)) { if (dp->alen == 1) dp->alen = 0; // XXX forbidden words of personal dic. else { unsigned short* flags2 = (unsigned short*)malloc(sizeof(unsigned short) * (dp->alen - 1)); if (!flags2) return 1; int i, j = 0; for (i = 0; i < dp->alen; i++) { if (dp->astr[i] != forbiddenword) flags2[j++] = dp->astr[i]; } dp->alen--; free(dp->astr); dp->astr = flags2; // XXX allowed forbidden words } } dp = dp->next_homonym; } return 0; } // add a custom dic. word to the hash table (public) int HashMgr::add(const std::string& word) { if (remove_forbidden_flag(word)) { int captype; int al = 0; unsigned short* flags = NULL; int wcl = get_clen_and_captype(word, &captype); add_word(word, wcl, flags, al, NULL, false); return add_hidden_capitalized_word(word, wcl, flags, al, NULL, captype); } return 0; } int HashMgr::add_with_affix(const std::string& word, const std::string& example) { // detect captype and modify word length for UTF-8 encoding struct hentry* dp = lookup(example.c_str()); remove_forbidden_flag(word); if (dp && dp->astr) { int captype; int wcl = get_clen_and_captype(word, &captype); if (aliasf) { add_word(word, wcl, dp->astr, dp->alen, NULL, false); } else { unsigned short* flags = (unsigned short*)malloc(dp->alen * sizeof(unsigned short)); if (flags) { memcpy((void*)flags, (void*)dp->astr, dp->alen * sizeof(unsigned short)); add_word(word, wcl, flags, dp->alen, NULL, false); } else return 1; } return add_hidden_capitalized_word(word, wcl, dp->astr, dp->alen, NULL, captype); } return 1; } // walk the hash table entry by entry - null at end // initialize: col=-1; hp = NULL; hp = walk_hashtable(&col, hp); struct hentry* HashMgr::walk_hashtable(int& col, struct hentry* hp) const { if (hp && hp->next != NULL) return hp->next; for (col++; col < tablesize; col++) { if (tableptr[col]) return tableptr[col]; } // null at end and reset to start col = -1; return NULL; } // load a munched word list and build a hash table on the fly int HashMgr::load_tables(const char* tpath, const char* key) { // open dictionary file FileMgr* dict = new FileMgr(tpath, key); if (dict == NULL) return 1; // first read the first line of file to get hash table size */ std::string ts; if (!dict->getline(ts)) { HUNSPELL_WARNING(stderr, "error: empty dic file %s\n", tpath); delete dict; return 2; } mychomp(ts); /* remove byte order mark */ if (ts.compare(0, 3, "\xEF\xBB\xBF", 3) == 0) { ts.erase(0, 3); } tablesize = atoi(ts.c_str()); int nExtra = 5 + USERWORD; if (tablesize <= 0 || (tablesize >= (std::numeric_limits::max() - 1 - nExtra) / int(sizeof(struct hentry*)))) { HUNSPELL_WARNING( stderr, "error: line 1: missing or bad word count in the dic file\n"); delete dict; return 4; } tablesize += nExtra; if ((tablesize % 2) == 0) tablesize++; // allocate the hash table tableptr = (struct hentry**)calloc(tablesize, sizeof(struct hentry*)); if (!tableptr) { delete dict; return 3; } // loop through all words on much list and add to hash // table and create word and affix strings std::vector workbuf; while (dict->getline(ts)) { mychomp(ts); // split each line into word and morphological description size_t dp_pos = 0; while ((dp_pos = ts.find(':', dp_pos)) != std::string::npos) { if ((dp_pos > 3) && (ts[dp_pos - 3] == ' ' || ts[dp_pos - 3] == '\t')) { for (dp_pos -= 3; dp_pos > 0 && (ts[dp_pos-1] == ' ' || ts[dp_pos-1] == '\t'); --dp_pos) ; if (dp_pos == 0) { // missing word dp_pos = std::string::npos; } else { ++dp_pos; } break; } ++dp_pos; } // tabulator is the old morphological field separator size_t dp2_pos = ts.find('\t'); if (dp2_pos != std::string::npos && (dp_pos == std::string::npos || dp2_pos < dp_pos)) { dp_pos = dp2_pos + 1; } std::string dp; if (dp_pos != std::string::npos) { dp.assign(ts.substr(dp_pos)); ts.resize(dp_pos - 1); } // split each line into word and affix char strings // "\/" signs slash in words (not affix separator) // "/" at beginning of the line is word character (not affix separator) size_t ap_pos = ts.find('/'); while (ap_pos != std::string::npos) { if (ap_pos == 0) { ++ap_pos; continue; } else if (ts[ap_pos - 1] != '\\') break; // replace "\/" with "/" ts.erase(ap_pos - 1, 1); ap_pos = ts.find('/', ap_pos); } unsigned short* flags; int al; if (ap_pos != std::string::npos && ap_pos != ts.size()) { std::string ap(ts.substr(ap_pos + 1)); ts.resize(ap_pos); if (aliasf) { int index = atoi(ap.c_str()); al = get_aliasf(index, &flags, dict); if (!al) { HUNSPELL_WARNING(stderr, "error: line %d: bad flag vector alias\n", dict->getlinenum()); } } else { al = decode_flags(&flags, ap.c_str(), dict); if (al == -1) { HUNSPELL_WARNING(stderr, "Can't allocate memory.\n"); delete dict; return 6; } std::sort(flags, flags + al); } } else { al = 0; flags = NULL; } int captype; int wcl = get_clen_and_captype(ts, &captype, workbuf); const std::string *dp_str = dp.empty() ? NULL : &dp; // add the word and its index plus its capitalized form optionally if (add_word(ts, wcl, flags, al, dp_str, false) || add_hidden_capitalized_word(ts, wcl, flags, al, dp_str, captype)) { delete dict; return 5; } } delete dict; return 0; } // the hash function is a simple load and rotate // algorithm borrowed int HashMgr::hash(const char* word) const { unsigned long hv = 0; for (int i = 0; i < 4 && *word != 0; i++) hv = (hv << 8) | (*word++); while (*word != 0) { ROTATE(hv, ROTATE_LEN); hv ^= (*word++); } return (unsigned long)hv % tablesize; } int HashMgr::decode_flags(unsigned short** result, const std::string& flags, FileMgr* af) const { int len; if (flags.empty()) { *result = NULL; return 0; } switch (flag_mode) { case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz) len = flags.size(); if (len % 2 == 1) HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n", af->getlinenum()); len /= 2; *result = (unsigned short*)malloc(len * sizeof(unsigned short)); if (!*result) return -1; for (int i = 0; i < len; i++) { (*result)[i] = ((unsigned short)((unsigned char)flags[i * 2]) << 8) + (unsigned char)flags[i * 2 + 1]; } break; } case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 // 23 233) len = 1; unsigned short* dest; for (size_t i = 0; i < flags.size(); ++i) { if (flags[i] == ',') len++; } *result = (unsigned short*)malloc(len * sizeof(unsigned short)); if (!*result) return -1; dest = *result; const char* src = flags.c_str(); for (const char* p = src; *p; p++) { if (*p == ',') { int i = atoi(src); if (i >= DEFAULTFLAGS) HUNSPELL_WARNING( stderr, "error: line %d: flag id %d is too large (max: %d)\n", af->getlinenum(), i, DEFAULTFLAGS - 1); *dest = (unsigned short)i; if (*dest == 0) HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", af->getlinenum()); src = p + 1; dest++; } } int i = atoi(src); if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: line %d: flag id %d is too large (max: %d)\n", af->getlinenum(), i, DEFAULTFLAGS - 1); *dest = (unsigned short)i; if (*dest == 0) HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", af->getlinenum()); break; } case FLAG_UNI: { // UTF-8 characters std::vector w; u8_u16(w, flags); len = w.size(); *result = (unsigned short*)malloc(len * sizeof(unsigned short)); if (!*result) return -1; memcpy(*result, &w[0], len * sizeof(short)); break; } default: { // Ispell's one-character flags (erfg -> e r f g) unsigned short* dest; len = flags.size(); *result = (unsigned short*)malloc(len * sizeof(unsigned short)); if (!*result) return -1; dest = *result; for (size_t i = 0; i < flags.size(); ++i) { *dest = (unsigned char)flags[i]; dest++; } } } return len; } bool HashMgr::decode_flags(std::vector& result, const std::string& flags, FileMgr* af) const { if (flags.empty()) { return false; } switch (flag_mode) { case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz) size_t len = flags.size(); if (len % 2 == 1) HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n", af->getlinenum()); len /= 2; result.reserve(result.size() + len); for (size_t i = 0; i < len; ++i) { result.push_back(((unsigned short)((unsigned char)flags[i * 2]) << 8) + (unsigned char)flags[i * 2 + 1]); } break; } case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 // 23 233) const char* src = flags.c_str(); for (const char* p = src; *p; p++) { if (*p == ',') { int i = atoi(src); if (i >= DEFAULTFLAGS) HUNSPELL_WARNING( stderr, "error: line %d: flag id %d is too large (max: %d)\n", af->getlinenum(), i, DEFAULTFLAGS - 1); result.push_back((unsigned short)i); if (result.back() == 0) HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", af->getlinenum()); src = p + 1; } } int i = atoi(src); if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: line %d: flag id %d is too large (max: %d)\n", af->getlinenum(), i, DEFAULTFLAGS - 1); result.push_back((unsigned short)i); if (result.back() == 0) HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", af->getlinenum()); break; } case FLAG_UNI: { // UTF-8 characters std::vector w; u8_u16(w, flags); size_t len = w.size(); size_t origsize = result.size(); result.resize(origsize + len); memcpy(&result[origsize], &w[0], len * sizeof(short)); break; } default: { // Ispell's one-character flags (erfg -> e r f g) result.reserve(flags.size()); for (size_t i = 0; i < flags.size(); ++i) { result.push_back((unsigned char)flags[i]); } } } return true; } unsigned short HashMgr::decode_flag(const char* f) const { unsigned short s = 0; int i; switch (flag_mode) { case FLAG_LONG: s = ((unsigned short)((unsigned char)f[0]) << 8) + (unsigned char)f[1]; break; case FLAG_NUM: i = atoi(f); if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n", i, DEFAULTFLAGS - 1); s = (unsigned short)i; break; case FLAG_UNI: { std::vector w; u8_u16(w, f); if (!w.empty()) memcpy(&s, &w[0], 1 * sizeof(short)); break; } default: s = *(unsigned char*)f; } if (s == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); return s; } char* HashMgr::encode_flag(unsigned short f) const { if (f == 0) return mystrdup("(NULL)"); std::string ch; if (flag_mode == FLAG_LONG) { ch.push_back((unsigned char)(f >> 8)); ch.push_back((unsigned char)(f - ((f >> 8) << 8))); } else if (flag_mode == FLAG_NUM) { std::ostringstream stream; stream << f; ch = stream.str(); } else if (flag_mode == FLAG_UNI) { const w_char* w_c = (const w_char*)&f; std::vector w(w_c, w_c + 1); u16_u8(ch, w); } else { ch.push_back((unsigned char)(f)); } return mystrdup(ch.c_str()); } // read in aff file and set flag mode int HashMgr::load_config(const char* affpath, const char* key) { int firstline = 1; // open the affix file FileMgr* afflst = new FileMgr(affpath, key); if (!afflst) { HUNSPELL_WARNING( stderr, "Error - could not open affix description file %s\n", affpath); return 1; } // read in each line ignoring any that do not // start with a known line type indicator std::string line; while (afflst->getline(line)) { mychomp(line); /* remove byte order mark */ if (firstline) { firstline = 0; if (line.compare(0, 3, "\xEF\xBB\xBF", 3) == 0) { line.erase(0, 3); } } /* parse in the try string */ if ((line.compare(0, 4, "FLAG", 4) == 0) && line.size() > 4 && isspace(line[4])) { if (flag_mode != FLAG_CHAR) { HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions of the FLAG " "affix file parameter\n", afflst->getlinenum()); } if (line.find("long") != std::string::npos) flag_mode = FLAG_LONG; if (line.find("num") != std::string::npos) flag_mode = FLAG_NUM; if (line.find("UTF-8") != std::string::npos) flag_mode = FLAG_UNI; if (flag_mode == FLAG_CHAR) { HUNSPELL_WARNING( stderr, "error: line %d: FLAG needs `num', `long' or `UTF-8' parameter\n", afflst->getlinenum()); } } if (line.compare(0, 13, "FORBIDDENWORD", 13) == 0) { std::string st; if (!parse_string(line, st, afflst->getlinenum())) { delete afflst; return 1; } forbiddenword = decode_flag(st.c_str()); } if (line.compare(0, 3, "SET", 3) == 0) { if (!parse_string(line, enc, afflst->getlinenum())) { delete afflst; return 1; } if (enc == "UTF-8") { utf8 = 1; #ifndef OPENOFFICEORG #ifndef MOZILLA_CLIENT initialize_utf_tbl(); #endif #endif } else csconv = get_current_cs(enc); } if (line.compare(0, 4, "LANG", 4) == 0) { if (!parse_string(line, lang, afflst->getlinenum())) { delete afflst; return 1; } langnum = get_lang_num(lang); } /* parse in the ignored characters (for example, Arabic optional diacritics * characters */ if (line.compare(0, 6, "IGNORE", 6) == 0) { if (!parse_array(line, ignorechars, ignorechars_utf16, utf8, afflst->getlinenum())) { delete afflst; return 1; } } if ((line.compare(0, 2, "AF", 2) == 0) && line.size() > 2 && isspace(line[2])) { if (!parse_aliasf(line, afflst)) { delete afflst; return 1; } } if ((line.compare(0, 2, "AM", 2) == 0) && line.size() > 2 && isspace(line[2])) { if (!parse_aliasm(line, afflst)) { delete afflst; return 1; } } if (line.compare(0, 15, "COMPLEXPREFIXES", 15) == 0) complexprefixes = 1; if (((line.compare(0, 3, "SFX", 3) == 0) || (line.compare(0, 3, "PFX", 3) == 0)) && line.size() > 3 && isspace(line[3])) break; } if (csconv == NULL) csconv = get_current_cs(SPELL_ENCODING); delete afflst; return 0; } /* parse in the ALIAS table */ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) { if (numaliasf != 0) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { numaliasf = atoi(std::string(start_piece, iter).c_str()); if (numaliasf < 1) { numaliasf = 0; aliasf = NULL; aliasflen = NULL; HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); return false; } aliasf = (unsigned short**)malloc(numaliasf * sizeof(unsigned short*)); aliasflen = (unsigned short*)malloc(numaliasf * sizeof(unsigned short)); if (!aliasf || !aliasflen) { numaliasf = 0; if (aliasf) free(aliasf); if (aliasflen) free(aliasflen); aliasf = NULL; aliasflen = NULL; return false; } np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { numaliasf = 0; free(aliasf); free(aliasflen); aliasf = NULL; aliasflen = NULL; HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the numaliasf lines to read in the remainder of the table */ for (int j = 0; j < numaliasf; j++) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); i = 0; aliasf[j] = NULL; aliasflen[j] = 0; iter = nl.begin(); start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), 2, "AF", 2) != 0) { numaliasf = 0; free(aliasf); free(aliasflen); aliasf = NULL; aliasflen = NULL; HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } break; } case 1: { std::string piece(start_piece, iter); aliasflen[j] = (unsigned short)decode_flags(&(aliasf[j]), piece, af); std::sort(aliasf[j], aliasf[j] + aliasflen[j]); break; } default: break; } ++i; start_piece = mystrsep(nl, iter); } if (!aliasf[j]) { free(aliasf); free(aliasflen); aliasf = NULL; aliasflen = NULL; numaliasf = 0; HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } } return true; } int HashMgr::is_aliasf() const { return (aliasf != NULL); } int HashMgr::get_aliasf(int index, unsigned short** fvec, FileMgr* af) const { if ((index > 0) && (index <= numaliasf)) { *fvec = aliasf[index - 1]; return aliasflen[index - 1]; } HUNSPELL_WARNING(stderr, "error: line %d: bad flag alias index: %d\n", af->getlinenum(), index); *fvec = NULL; return 0; } /* parse morph alias definitions */ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) { if (numaliasm != 0) { HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); return false; } int i = 0; int np = 0; std::string::const_iterator iter = line.begin(); std::string::const_iterator start_piece = mystrsep(line, iter); while (start_piece != line.end()) { switch (i) { case 0: { np++; break; } case 1: { numaliasm = atoi(std::string(start_piece, iter).c_str()); if (numaliasm < 1) { HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); return false; } aliasm = (char**)malloc(numaliasm * sizeof(char*)); if (!aliasm) { numaliasm = 0; return false; } np++; break; } default: break; } ++i; start_piece = mystrsep(line, iter); } if (np != 2) { numaliasm = 0; free(aliasm); aliasm = NULL; HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); return false; } /* now parse the numaliasm lines to read in the remainder of the table */ for (int j = 0; j < numaliasm; j++) { std::string nl; if (!af->getline(nl)) return false; mychomp(nl); aliasm[j] = NULL; iter = nl.begin(); i = 0; start_piece = mystrsep(nl, iter); while (start_piece != nl.end()) { switch (i) { case 0: { if (nl.compare(start_piece - nl.begin(), 2, "AM", 2) != 0) { HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); numaliasm = 0; free(aliasm); aliasm = NULL; return false; } break; } case 1: { // add the remaining of the line std::string::const_iterator end = nl.end(); std::string chunk(start_piece, end); if (complexprefixes) { if (utf8) reverseword_utf(chunk); else reverseword(chunk); } aliasm[j] = mystrdup(chunk.c_str()); break; } default: break; } ++i; start_piece = mystrsep(nl, iter); } if (!aliasm[j]) { numaliasm = 0; free(aliasm); aliasm = NULL; HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); return false; } } return true; } int HashMgr::is_aliasm() const { return (aliasm != NULL); } char* HashMgr::get_aliasm(int index) const { if ((index > 0) && (index <= numaliasm)) return aliasm[index - 1]; HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index); return NULL; } nuspell-5.1.7/external/hunspell/hunspell/hashmgr.hxx000066400000000000000000000140031511132717100226730ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef HASHMGR_HXX_ #define HASHMGR_HXX_ #include #include #include #include "htypes.hxx" #include "filemgr.hxx" #include "w_char.hxx" enum flag { FLAG_CHAR, FLAG_LONG, FLAG_NUM, FLAG_UNI }; class HashMgr { int tablesize; struct hentry** tableptr; flag flag_mode; int complexprefixes; int utf8; unsigned short forbiddenword; int langnum; std::string enc; std::string lang; struct cs_info* csconv; std::string ignorechars; std::vector ignorechars_utf16; int numaliasf; // flag vector `compression' with aliases unsigned short** aliasf; unsigned short* aliasflen; int numaliasm; // morphological desciption `compression' with aliases char** aliasm; public: HashMgr(const char* tpath, const char* apath, const char* key = NULL); ~HashMgr(); struct hentry* lookup(const char*) const; int hash(const char*) const; struct hentry* walk_hashtable(int& col, struct hentry* hp) const; int add(const std::string& word); int add_with_affix(const std::string& word, const std::string& pattern); int remove(const std::string& word); int decode_flags(unsigned short** result, const std::string& flags, FileMgr* af) const; bool decode_flags(std::vector& result, const std::string& flags, FileMgr* af) const; unsigned short decode_flag(const char* flag) const; char* encode_flag(unsigned short flag) const; int is_aliasf() const; int get_aliasf(int index, unsigned short** fvec, FileMgr* af) const; int is_aliasm() const; char* get_aliasm(int index) const; private: int get_clen_and_captype(const std::string& word, int* captype); int get_clen_and_captype(const std::string& word, int* captype, std::vector &workbuf); int load_tables(const char* tpath, const char* key); int add_word(const std::string& word, int wcl, unsigned short* ap, int al, const std::string* desc, bool onlyupcase); int load_config(const char* affpath, const char* key); bool parse_aliasf(const std::string& line, FileMgr* af); int add_hidden_capitalized_word(const std::string& word, int wcl, unsigned short* flags, int al, const std::string* dp, int captype); bool parse_aliasm(const std::string& line, FileMgr* af); int remove_forbidden_flag(const std::string& word); }; #endif nuspell-5.1.7/external/hunspell/hunspell/htypes.hxx000066400000000000000000000054021511132717100225610ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef HTYPES_HXX_ #define HTYPES_HXX_ #define ROTATE_LEN 5 #define ROTATE(v, q) \ (v) = ((v) << (q)) | (((v) >> (32 - q)) & ((1 << (q)) - 1)); // hentry options #define H_OPT (1 << 0) #define H_OPT_ALIASM (1 << 1) #define H_OPT_PHON (1 << 2) // see also csutil.hxx #define HENTRY_WORD(h) &(h->word[0]) // approx. number of user defined words #define USERWORD 1000 struct hentry { unsigned char blen; // word length in bytes unsigned char clen; // word length in characters (different for UTF-8 enc.) short alen; // length of affix flag vector unsigned short* astr; // affix flag vector struct hentry* next; // next word with same hash code struct hentry* next_homonym; // next homonym word (with same hash code) char var; // variable fields (only for special pronounciation yet) char word[1]; // variable-length word (8-bit or UTF-8 encoding) }; #endif nuspell-5.1.7/external/hunspell/hunspell/hunspell.cxx000066400000000000000000001672441511132717100231070ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "affixmgr.hxx" #include "hunspell.hxx" #include "suggestmgr.hxx" #include "hunspell.h" #include "csutil.hxx" #include #include #define MAXWORDUTF8LEN (MAXWORDLEN * 3) class HunspellImpl { public: HunspellImpl(const char* affpath, const char* dpath, const char* key = NULL); ~HunspellImpl(); int add_dic(const char* dpath, const char* key = NULL); std::vector suffix_suggest(const std::string& root_word); std::vector generate(const std::string& word, const std::vector& pl); std::vector generate(const std::string& word, const std::string& pattern); std::vector stem(const std::string& word); std::vector stem(const std::vector& morph); std::vector analyze(const std::string& word); int get_langnum() const; bool input_conv(const std::string& word, std::string& dest); bool spell(const std::string& word, int* info = NULL, std::string* root = NULL); std::vector suggest(const std::string& word); const std::string& get_wordchars_cpp() const; const std::vector& get_wordchars_utf16() const; const std::string& get_dict_encoding() const; int add(const std::string& word); int add_with_affix(const std::string& word, const std::string& example); int remove(const std::string& word); const std::string& get_version_cpp() const; struct cs_info* get_csconv(); int spell(const char* word, int* info = NULL, char** root = NULL); int suggest(char*** slst, const char* word); int suffix_suggest(char*** slst, const char* root_word); void free_list(char*** slst, int n); char* get_dic_encoding(); int analyze(char*** slst, const char* word); int stem(char*** slst, const char* word); int stem(char*** slst, char** morph, int n); int generate(char*** slst, const char* word, const char* word2); int generate(char*** slst, const char* word, char** desc, int n); const char* get_wordchars() const; const char* get_version() const; int input_conv(const char* word, char* dest, size_t destsize); private: AffixMgr* pAMgr; std::vector m_HMgrs; SuggestMgr* pSMgr; char* affixpath; std::string encoding; struct cs_info* csconv; int langnum; int utf8; int complexprefixes; std::vector wordbreak; private: void cleanword(std::string& dest, const std::string&, int* pcaptype, int* pabbrev); size_t cleanword2(std::string& dest, std::vector& dest_u, const std::string& src, int* pcaptype, size_t* pabbrev); void mkinitcap(std::string& u8); int mkinitcap2(std::string& u8, std::vector& u16); int mkinitsmall2(std::string& u8, std::vector& u16); void mkallcap(std::string& u8); int mkallsmall2(std::string& u8, std::vector& u16); struct hentry* checkword(const std::string& source, int* info, std::string* root); std::string sharps_u8_l1(const std::string& source); hentry* spellsharps(std::string& base, size_t start_pos, int, int, int* info, std::string* root); int is_keepcase(const hentry* rv); void insert_sug(std::vector& slst, const std::string& word); void cat_result(std::string& result, const std::string& st); std::vector spellml(const std::string& word); std::string get_xml_par(const char* par); const char* get_xml_pos(const char* s, const char* attr); std::vector get_xml_list(const char* list, const char* tag); int check_xml_par(const char* q, const char* attr, const char* value); private: HunspellImpl(const HunspellImpl&); HunspellImpl& operator=(const HunspellImpl&); }; HunspellImpl::HunspellImpl(const char* affpath, const char* dpath, const char* key) { csconv = NULL; utf8 = 0; complexprefixes = 0; affixpath = mystrdup(affpath); /* first set up the hash manager */ m_HMgrs.push_back(new HashMgr(dpath, affpath, key)); /* next set up the affix manager */ /* it needs access to the hash manager lookup methods */ pAMgr = new AffixMgr(affpath, m_HMgrs, key); /* get the preferred try string and the dictionary */ /* encoding from the Affix Manager for that dictionary */ char* try_string = pAMgr->get_try_string(); encoding = pAMgr->get_encoding(); langnum = pAMgr->get_langnum(); utf8 = pAMgr->get_utf8(); if (!utf8) csconv = get_current_cs(encoding); complexprefixes = pAMgr->get_complexprefixes(); wordbreak = pAMgr->get_breaktable(); /* and finally set up the suggestion manager */ pSMgr = new SuggestMgr(try_string, MAXSUGGESTION, pAMgr); if (try_string) free(try_string); } HunspellImpl::~HunspellImpl() { delete pSMgr; delete pAMgr; for (size_t i = 0; i < m_HMgrs.size(); ++i) delete m_HMgrs[i]; pSMgr = NULL; pAMgr = NULL; #ifdef MOZILLA_CLIENT delete[] csconv; #endif csconv = NULL; if (affixpath) free(affixpath); affixpath = NULL; } // load extra dictionaries int HunspellImpl::add_dic(const char* dpath, const char* key) { if (!affixpath) return 1; m_HMgrs.push_back(new HashMgr(dpath, affixpath, key)); return 0; } // make a copy of src at destination while removing all leading // blanks and removing any trailing periods after recording // their presence with the abbreviation flag // also since already going through character by character, // set the capitalization type // return the length of the "cleaned" (and UTF-8 encoded) word size_t HunspellImpl::cleanword2(std::string& dest, std::vector& dest_utf, const std::string& src, int* pcaptype, size_t* pabbrev) { dest.clear(); dest_utf.clear(); const char* q = src.c_str(); // first skip over any leading blanks while (*q == ' ') ++q; // now strip off any trailing periods (recording their presence) *pabbrev = 0; int nl = strlen(q); while ((nl > 0) && (*(q + nl - 1) == '.')) { nl--; (*pabbrev)++; } // if no characters are left it can't be capitalized if (nl <= 0) { *pcaptype = NOCAP; return 0; } dest.append(q, nl); nl = dest.size(); if (utf8) { u8_u16(dest_utf, dest); *pcaptype = get_captype_utf8(dest_utf, langnum); } else { *pcaptype = get_captype(dest, csconv); } return nl; } void HunspellImpl::cleanword(std::string& dest, const std::string& src, int* pcaptype, int* pabbrev) { dest.clear(); const unsigned char* q = (const unsigned char*)src.c_str(); int firstcap = 0; // first skip over any leading blanks while (*q == ' ') ++q; // now strip off any trailing periods (recording their presence) *pabbrev = 0; int nl = strlen((const char*)q); while ((nl > 0) && (*(q + nl - 1) == '.')) { nl--; (*pabbrev)++; } // if no characters are left it can't be capitalized if (nl <= 0) { *pcaptype = NOCAP; return; } // now determine the capitalization type of the first nl letters int ncap = 0; int nneutral = 0; int nc = 0; if (!utf8) { while (nl > 0) { nc++; if (csconv[(*q)].ccase) ncap++; if (csconv[(*q)].cupper == csconv[(*q)].clower) nneutral++; dest.push_back(*q++); nl--; } // remember to terminate the destination string firstcap = csconv[static_cast(dest[0])].ccase; } else { std::vector t; u8_u16(t, src); for (size_t i = 0; i < t.size(); ++i) { unsigned short idx = (t[i].h << 8) + t[i].l; unsigned short low = unicodetolower(idx, langnum); if (idx != low) ncap++; if (unicodetoupper(idx, langnum) == low) nneutral++; } u16_u8(dest, t); if (ncap) { unsigned short idx = (t[0].h << 8) + t[0].l; firstcap = (idx != unicodetolower(idx, langnum)); } } // now finally set the captype if (ncap == 0) { *pcaptype = NOCAP; } else if ((ncap == 1) && firstcap) { *pcaptype = INITCAP; } else if ((ncap == nc) || ((ncap + nneutral) == nc)) { *pcaptype = ALLCAP; } else if ((ncap > 1) && firstcap) { *pcaptype = HUHINITCAP; } else { *pcaptype = HUHCAP; } } void HunspellImpl::mkallcap(std::string& u8) { if (utf8) { std::vector u16; u8_u16(u16, u8); ::mkallcap_utf(u16, langnum); u16_u8(u8, u16); } else { ::mkallcap(u8, csconv); } } int HunspellImpl::mkallsmall2(std::string& u8, std::vector& u16) { if (utf8) { ::mkallsmall_utf(u16, langnum); u16_u8(u8, u16); } else { ::mkallsmall(u8, csconv); } return u8.size(); } // convert UTF-8 sharp S codes to latin 1 std::string HunspellImpl::sharps_u8_l1(const std::string& source) { std::string dest(source); mystrrep(dest, "\xC3\x9F", "\xDF"); return dest; } // recursive search for right ss - sharp s permutations hentry* HunspellImpl::spellsharps(std::string& base, size_t n_pos, int n, int repnum, int* info, std::string* root) { size_t pos = base.find("ss", n_pos); if (pos != std::string::npos && (n < MAXSHARPS)) { base[pos] = '\xC3'; base[pos + 1] = '\x9F'; hentry* h = spellsharps(base, pos + 2, n + 1, repnum + 1, info, root); if (h) return h; base[pos] = 's'; base[pos + 1] = 's'; h = spellsharps(base, pos + 2, n + 1, repnum, info, root); if (h) return h; } else if (repnum > 0) { if (utf8) return checkword(base, info, root); std::string tmp(sharps_u8_l1(base)); return checkword(tmp, info, root); } return NULL; } int HunspellImpl::is_keepcase(const hentry* rv) { return pAMgr && rv->astr && pAMgr->get_keepcase() && TESTAFF(rv->astr, pAMgr->get_keepcase(), rv->alen); } /* insert a word to the beginning of the suggestion array */ void HunspellImpl::insert_sug(std::vector& slst, const std::string& word) { slst.insert(slst.begin(), word); } bool HunspellImpl::spell(const std::string& word, int* info, std::string* root) { struct hentry* rv = NULL; int info2 = 0; if (!info) info = &info2; else *info = 0; // Hunspell supports XML input of the simplified API (see manual) if (word == SPELL_XML) return true; if (utf8) { if (word.size() >= MAXWORDUTF8LEN) return false; } else { if (word.size() >= MAXWORDLEN) return false; } int captype = NOCAP; size_t abbv = 0; size_t wl = 0; std::string scw; std::vector sunicw; // input conversion RepList* rl = pAMgr ? pAMgr->get_iconvtable() : NULL; { std::string wspace; bool convstatus = rl ? rl->conv(word, wspace) : false; if (convstatus) wl = cleanword2(scw, sunicw, wspace, &captype, &abbv); else wl = cleanword2(scw, sunicw, word, &captype, &abbv); } #ifdef MOZILLA_CLIENT // accept the abbreviated words without dots // workaround for the incomplete tokenization of Mozilla abbv = 1; #endif if (wl == 0 || m_HMgrs.empty()) return true; if (root) root->clear(); // allow numbers with dots, dashes and commas (but forbid double separators: // "..", "--" etc.) enum { NBEGIN, NNUM, NSEP }; int nstate = NBEGIN; size_t i; for (i = 0; (i < wl); i++) { if ((scw[i] <= '9') && (scw[i] >= '0')) { nstate = NNUM; } else if ((scw[i] == ',') || (scw[i] == '.') || (scw[i] == '-')) { if ((nstate == NSEP) || (i == 0)) break; nstate = NSEP; } else break; } if ((i == wl) && (nstate == NNUM)) return true; switch (captype) { case HUHCAP: /* FALLTHROUGH */ case HUHINITCAP: *info += SPELL_ORIGCAP; /* FALLTHROUGH */ case NOCAP: rv = checkword(scw, info, root); if ((abbv) && !(rv)) { std::string u8buffer(scw); u8buffer.push_back('.'); rv = checkword(u8buffer, info, root); } break; case ALLCAP: { *info += SPELL_ORIGCAP; rv = checkword(scw, info, root); if (rv) break; if (abbv) { std::string u8buffer(scw); u8buffer.push_back('.'); rv = checkword(u8buffer, info, root); if (rv) break; } // Spec. prefix handling for Catalan, French, Italian: // prefixes separated by apostrophe (SANT'ELIA -> Sant'+Elia). size_t apos = pAMgr ? scw.find('\'') : std::string::npos; if (apos != std::string::npos) { mkallsmall2(scw, sunicw); //conversion may result in string with different len to pre-mkallsmall2 //so re-scan if (apos != std::string::npos && apos < scw.size() - 1) { std::string part1 = scw.substr(0, apos+1); std::string part2 = scw.substr(apos+1); if (utf8) { std::vector part1u, part2u; u8_u16(part1u, part1); u8_u16(part2u, part2); mkinitcap2(part2, part2u); scw = part1 + part2; sunicw = part1u; sunicw.insert(sunicw.end(), part2u.begin(), part2u.end()); rv = checkword(scw, info, root); if (rv) break; } else { mkinitcap2(part2, sunicw); scw = part1 + part2; rv = checkword(scw, info, root); if (rv) break; } mkinitcap2(scw, sunicw); rv = checkword(scw, info, root); if (rv) break; } } if (pAMgr && pAMgr->get_checksharps() && scw.find("SS") != std::string::npos) { mkallsmall2(scw, sunicw); std::string u8buffer(scw); rv = spellsharps(u8buffer, 0, 0, 0, info, root); if (!rv) { mkinitcap2(scw, sunicw); rv = spellsharps(scw, 0, 0, 0, info, root); } if ((abbv) && !(rv)) { u8buffer.push_back('.'); rv = spellsharps(u8buffer, 0, 0, 0, info, root); if (!rv) { u8buffer = std::string(scw); u8buffer.push_back('.'); rv = spellsharps(u8buffer, 0, 0, 0, info, root); } } if (rv) break; } } /* FALLTHROUGH */ case INITCAP: { // handle special capitalization of dotted I bool Idot = (utf8 && (unsigned char) scw[0] == 0xc4 && (unsigned char) scw[1] == 0xb0); *info += SPELL_ORIGCAP; if (captype == ALLCAP) { mkallsmall2(scw, sunicw); mkinitcap2(scw, sunicw); if (Idot) scw.replace(0, 1, "\xc4\xb0"); } if (captype == INITCAP) *info += SPELL_INITCAP; rv = checkword(scw, info, root); if (captype == INITCAP) *info -= SPELL_INITCAP; // forbid bad capitalization // (for example, ijs -> Ijs instead of IJs in Dutch) // use explicit forms in dic: Ijs/F (F = FORBIDDENWORD flag) if (*info & SPELL_FORBIDDEN) { rv = NULL; break; } if (rv && is_keepcase(rv) && (captype == ALLCAP)) rv = NULL; if (rv || (Idot && langnum != LANG_az && langnum != LANG_tr && langnum != LANG_crh)) break; mkallsmall2(scw, sunicw); std::string u8buffer(scw); mkinitcap2(scw, sunicw); rv = checkword(u8buffer, info, root); if (abbv && !rv) { u8buffer.push_back('.'); rv = checkword(u8buffer, info, root); if (!rv) { u8buffer = scw; u8buffer.push_back('.'); if (captype == INITCAP) *info += SPELL_INITCAP; rv = checkword(u8buffer, info, root); if (captype == INITCAP) *info -= SPELL_INITCAP; if (rv && is_keepcase(rv) && (captype == ALLCAP)) rv = NULL; break; } } if (rv && is_keepcase(rv) && ((captype == ALLCAP) || // if CHECKSHARPS: KEEPCASE words with \xDF are allowed // in INITCAP form, too. !(pAMgr->get_checksharps() && ((utf8 && u8buffer.find("\xC3\x9F") != std::string::npos) || (!utf8 && u8buffer.find('\xDF') != std::string::npos))))) rv = NULL; break; } } if (rv) { if (pAMgr && pAMgr->get_warn() && rv->astr && TESTAFF(rv->astr, pAMgr->get_warn(), rv->alen)) { *info += SPELL_WARN; if (pAMgr->get_forbidwarn()) return false; return true; } return true; } // recursive breaking at break points if (!wordbreak.empty() && !(*info & SPELL_FORBIDDEN)) { int nbr = 0; wl = scw.size(); // calculate break points for recursion limit for (size_t j = 0; j < wordbreak.size(); ++j) { size_t pos = 0; while ((pos = scw.find(wordbreak[j], pos)) != std::string::npos) { ++nbr; pos += wordbreak[j].size(); } } if (nbr >= 10) return false; // check boundary patterns (^begin and end$) for (size_t j = 0; j < wordbreak.size(); ++j) { size_t plen = wordbreak[j].size(); if (plen == 1 || plen > wl) continue; if (wordbreak[j][0] == '^' && scw.compare(0, plen - 1, wordbreak[j], 1, plen -1) == 0 && spell(scw.substr(plen - 1))) return true; if (wordbreak[j][plen - 1] == '$' && scw.compare(wl - plen + 1, plen - 1, wordbreak[j], 0, plen - 1) == 0) { std::string suffix(scw.substr(wl - plen + 1)); scw.resize(wl - plen + 1); if (spell(scw)) return true; scw.append(suffix); } } // other patterns for (size_t j = 0; j < wordbreak.size(); ++j) { size_t plen = wordbreak[j].size(); size_t found = scw.find(wordbreak[j]); if ((found > 0) && (found < wl - plen)) { if (!spell(scw.substr(found + plen))) continue; std::string suffix(scw.substr(found)); scw.resize(found); // examine 2 sides of the break point if (spell(scw)) return true; scw.append(suffix); // LANG_hu: spec. dash rule if (langnum == LANG_hu && wordbreak[j] == "-") { suffix = scw.substr(found + 1); scw.resize(found + 1); if (spell(scw)) return true; // check the first part with dash scw.append(suffix); } // end of LANG specific region } } } return false; } struct hentry* HunspellImpl::checkword(const std::string& w, int* info, std::string* root) { bool usebuffer = false; std::string w2; const char* word; int len; const char* ignoredchars = pAMgr ? pAMgr->get_ignore() : NULL; if (ignoredchars != NULL) { w2.assign(w); if (utf8) { const std::vector& ignoredchars_utf16 = pAMgr->get_ignore_utf16(); remove_ignored_chars_utf(w2, ignoredchars_utf16); } else { remove_ignored_chars(w2, ignoredchars); } word = w2.c_str(); len = w2.size(); usebuffer = true; } else { word = w.c_str(); len = w.size(); } if (!len) return NULL; // word reversing wrapper for complex prefixes if (complexprefixes) { if (!usebuffer) { w2.assign(word); usebuffer = true; } if (utf8) reverseword_utf(w2); else reverseword(w2); } if (usebuffer) { word = w2.c_str(); } // look word in hash table struct hentry* he = NULL; for (size_t i = 0; (i < m_HMgrs.size()) && !he; ++i) { he = m_HMgrs[i]->lookup(word); // check forbidden and onlyincompound words if ((he) && (he->astr) && (pAMgr) && TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) { if (info) *info += SPELL_FORBIDDEN; // LANG_hu section: set dash information for suggestions if (langnum == LANG_hu) { if (pAMgr->get_compoundflag() && TESTAFF(he->astr, pAMgr->get_compoundflag(), he->alen)) { if (info) *info += SPELL_COMPOUND; } } return NULL; } // he = next not needaffix, onlyincompound homonym or onlyupcase word while (he && (he->astr) && pAMgr && ((pAMgr->get_needaffix() && TESTAFF(he->astr, pAMgr->get_needaffix(), he->alen)) || (pAMgr->get_onlyincompound() && TESTAFF(he->astr, pAMgr->get_onlyincompound(), he->alen)) || (info && (*info & SPELL_INITCAP) && TESTAFF(he->astr, ONLYUPCASEFLAG, he->alen)))) he = he->next_homonym; } // check with affixes if (!he && pAMgr) { // try stripping off affixes */ he = pAMgr->affix_check(word, len, 0); // check compound restriction and onlyupcase if (he && he->astr && ((pAMgr->get_onlyincompound() && TESTAFF(he->astr, pAMgr->get_onlyincompound(), he->alen)) || (info && (*info & SPELL_INITCAP) && TESTAFF(he->astr, ONLYUPCASEFLAG, he->alen)))) { he = NULL; } if (he) { if ((he->astr) && (pAMgr) && TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) { if (info) *info += SPELL_FORBIDDEN; return NULL; } if (root) { root->assign(he->word); if (complexprefixes) { if (utf8) reverseword_utf(*root); else reverseword(*root); } } // try check compound word } else if (pAMgr->get_compound()) { struct hentry* rwords[100]; // buffer for COMPOUND pattern checking he = pAMgr->compound_check(word, 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, 0, info); // LANG_hu section: `moving rule' with last dash if ((!he) && (langnum == LANG_hu) && (word[len - 1] == '-')) { std::string dup(word, len - 1); he = pAMgr->compound_check(dup, -5, 0, 100, 0, NULL, (hentry**)&rwords, 1, 0, info); } // end of LANG specific region if (he) { if (root) { root->assign(he->word); if (complexprefixes) { if (utf8) reverseword_utf(*root); else reverseword(*root); } } if (info) *info += SPELL_COMPOUND; } } } return he; } std::vector HunspellImpl::suggest(const std::string& word) { std::vector slst; int onlycmpdsug = 0; if (!pSMgr || m_HMgrs.empty()) return slst; // process XML input of the simplified API (see manual) if (word.compare(0, sizeof(SPELL_XML) - 3, SPELL_XML, sizeof(SPELL_XML) - 3) == 0) { return spellml(word); } if (utf8) { if (word.size() >= MAXWORDUTF8LEN) return slst; } else { if (word.size() >= MAXWORDLEN) return slst; } int captype = NOCAP; size_t abbv = 0; size_t wl = 0; std::string scw; std::vector sunicw; // input conversion RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; { std::string wspace; bool convstatus = rl ? rl->conv(word, wspace) : false; if (convstatus) wl = cleanword2(scw, sunicw, wspace, &captype, &abbv); else wl = cleanword2(scw, sunicw, word, &captype, &abbv); if (wl == 0) return slst; } int capwords = 0; // check capitalized form for FORCEUCASE if (pAMgr && captype == NOCAP && pAMgr->get_forceucase()) { int info = SPELL_ORIGCAP; if (checkword(scw, &info, NULL)) { std::string form(scw); mkinitcap(form); slst.push_back(form); return slst; } } switch (captype) { case NOCAP: { pSMgr->suggest(slst, scw.c_str(), &onlycmpdsug); break; } case INITCAP: { capwords = 1; pSMgr->suggest(slst, scw.c_str(), &onlycmpdsug); std::string wspace(scw); mkallsmall2(wspace, sunicw); pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug); break; } case HUHINITCAP: capwords = 1; /* FALLTHROUGH */ case HUHCAP: { pSMgr->suggest(slst, scw.c_str(), &onlycmpdsug); // something.The -> something. The size_t dot_pos = scw.find('.'); if (dot_pos != std::string::npos) { std::string postdot = scw.substr(dot_pos + 1); int captype_; if (utf8) { std::vector postdotu; u8_u16(postdotu, postdot); captype_ = get_captype_utf8(postdotu, langnum); } else { captype_ = get_captype(postdot, csconv); } if (captype_ == INITCAP) { std::string str(scw); str.insert(dot_pos + 1, 1, ' '); insert_sug(slst, str); } } std::string wspace; if (captype == HUHINITCAP) { // TheOpenOffice.org -> The OpenOffice.org wspace = scw; mkinitsmall2(wspace, sunicw); pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug); } wspace = scw; mkallsmall2(wspace, sunicw); if (spell(wspace.c_str())) insert_sug(slst, wspace); size_t prevns = slst.size(); pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug); if (captype == HUHINITCAP) { mkinitcap2(wspace, sunicw); if (spell(wspace.c_str())) insert_sug(slst, wspace); pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug); } // aNew -> "a New" (instead of "a new") for (size_t j = prevns; j < slst.size(); ++j) { const char* space = strchr(slst[j].c_str(), ' '); if (space) { size_t slen = strlen(space + 1); // different case after space (need capitalisation) if ((slen < wl) && strcmp(scw.c_str() + wl - slen, space + 1)) { std::string first(slst[j].c_str(), space + 1); std::string second(space + 1); std::vector w; if (utf8) u8_u16(w, second); mkinitcap2(second, w); // set as first suggestion slst.erase(slst.begin() + j); slst.insert(slst.begin(), first + second); } } } break; } case ALLCAP: { std::string wspace(scw); mkallsmall2(wspace, sunicw); pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug); if (pAMgr && pAMgr->get_keepcase() && spell(wspace.c_str())) insert_sug(slst, wspace); mkinitcap2(wspace, sunicw); pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug); for (size_t j = 0; j < slst.size(); ++j) { mkallcap(slst[j]); if (pAMgr && pAMgr->get_checksharps()) { if (utf8) { mystrrep(slst[j], "\xC3\x9F", "SS"); } else { mystrrep(slst[j], "\xDF", "SS"); } } } break; } } // LANG_hu section: replace '-' with ' ' in Hungarian if (langnum == LANG_hu) { for (size_t j = 0; j < slst.size(); ++j) { size_t pos = slst[j].find('-'); if (pos != std::string::npos) { int info; std::string w(slst[j].substr(0, pos)); w.append(slst[j].substr(pos + 1)); (void)spell(w, &info, NULL); if ((info & SPELL_COMPOUND) && (info & SPELL_FORBIDDEN)) { slst[j][pos] = ' '; } else slst[j][pos] = '-'; } } } // END OF LANG_hu section // try ngram approach since found nothing or only compound words if (pAMgr && (slst.empty() || onlycmpdsug) && (pAMgr->get_maxngramsugs() != 0)) { switch (captype) { case NOCAP: { pSMgr->ngsuggest(slst, scw.c_str(), m_HMgrs); break; } case HUHINITCAP: capwords = 1; /* FALLTHROUGH */ case HUHCAP: { std::string wspace(scw); mkallsmall2(wspace, sunicw); pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs); break; } case INITCAP: { capwords = 1; std::string wspace(scw); mkallsmall2(wspace, sunicw); pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs); break; } case ALLCAP: { std::string wspace(scw); mkallsmall2(wspace, sunicw); size_t oldns = slst.size(); pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs); for (size_t j = oldns; j < slst.size(); ++j) { mkallcap(slst[j]); } break; } } } // try dash suggestion (Afo-American -> Afro-American) size_t dash_pos = scw.find('-'); if (dash_pos != std::string::npos) { int nodashsug = 1; for (size_t j = 0; j < slst.size() && nodashsug == 1; ++j) { if (slst[j].find('-') != std::string::npos) nodashsug = 0; } size_t prev_pos = 0; bool last = false; while (nodashsug && !last) { if (dash_pos == scw.size()) last = 1; std::string chunk = scw.substr(prev_pos, dash_pos - prev_pos); if (!spell(chunk.c_str())) { std::vector nlst = suggest(chunk.c_str()); for (std::vector::reverse_iterator j = nlst.rbegin(); j != nlst.rend(); ++j) { std::string wspace = scw.substr(0, prev_pos); wspace.append(*j); if (!last) { wspace.append("-"); wspace.append(scw.substr(dash_pos + 1)); } int info = 0; if (pAMgr && pAMgr->get_forbiddenword()) checkword(wspace, &info, NULL); if (!(info & SPELL_FORBIDDEN)) insert_sug(slst, wspace); } nodashsug = 0; } if (!last) { prev_pos = dash_pos + 1; dash_pos = scw.find('-', prev_pos); } if (dash_pos == std::string::npos) dash_pos = scw.size(); } } // word reversing wrapper for complex prefixes if (complexprefixes) { for (size_t j = 0; j < slst.size(); ++j) { if (utf8) reverseword_utf(slst[j]); else reverseword(slst[j]); } } // capitalize if (capwords) for (size_t j = 0; j < slst.size(); ++j) { mkinitcap(slst[j]); } // expand suggestions with dot(s) if (abbv && pAMgr && pAMgr->get_sugswithdots()) { for (size_t j = 0; j < slst.size(); ++j) { slst[j].append(word.substr(word.size() - abbv)); } } // remove bad capitalized and forbidden forms if (pAMgr && (pAMgr->get_keepcase() || pAMgr->get_forbiddenword())) { switch (captype) { case INITCAP: case ALLCAP: { size_t l = 0; for (size_t j = 0; j < slst.size(); ++j) { if (slst[j].find(' ') == std::string::npos && !spell(slst[j])) { std::string s; std::vector w; if (utf8) { u8_u16(w, slst[j]); } else { s = slst[j]; } mkallsmall2(s, w); if (spell(s)) { slst[l] = s; ++l; } else { mkinitcap2(s, w); if (spell(s)) { slst[l] = s; ++l; } } } else { slst[l] = slst[j]; ++l; } } slst.resize(l); } } } // remove duplications size_t l = 0; for (size_t j = 0; j < slst.size(); ++j) { slst[l] = slst[j]; for (size_t k = 0; k < l; ++k) { if (slst[k] == slst[j]) { --l; break; } } ++l; } slst.resize(l); // output conversion rl = (pAMgr) ? pAMgr->get_oconvtable() : NULL; for (size_t j = 0; rl && j < slst.size(); ++j) { std::string wspace; if (rl->conv(slst[j], wspace)) { slst[j] = wspace; } } return slst; } const std::string& HunspellImpl::get_dict_encoding() const { return encoding; } std::vector HunspellImpl::stem(const std::vector& desc) { std::vector slst; std::string result2; if (desc.empty()) return slst; for (size_t i = 0; i < desc.size(); ++i) { std::string result; // add compound word parts (except the last one) const char* s = desc[i].c_str(); const char* part = strstr(s, MORPH_PART); if (part) { const char* nextpart = strstr(part + 1, MORPH_PART); while (nextpart) { std::string field; copy_field(field, part, MORPH_PART); result.append(field); part = nextpart; nextpart = strstr(part + 1, MORPH_PART); } s = part; } std::string tok(s); size_t alt = 0; while ((alt = tok.find(" | ", alt)) != std::string::npos) { tok[alt + 1] = MSEP_ALT; } std::vector pl = line_tok(tok, MSEP_ALT); for (size_t k = 0; k < pl.size(); ++k) { // add derivational suffixes if (pl[k].find(MORPH_DERI_SFX) != std::string::npos) { // remove inflectional suffixes const size_t is = pl[k].find(MORPH_INFL_SFX); if (is != std::string::npos) pl[k].resize(is); std::vector singlepl; singlepl.push_back(pl[k]); std::string sg = pSMgr->suggest_gen(singlepl, pl[k]); if (!sg.empty()) { std::vector gen = line_tok(sg, MSEP_REC); for (size_t j = 0; j < gen.size(); ++j) { result2.push_back(MSEP_REC); result2.append(result); result2.append(gen[j]); } } } else { result2.push_back(MSEP_REC); result2.append(result); if (pl[k].find(MORPH_SURF_PFX) != std::string::npos) { std::string field; copy_field(field, pl[k], MORPH_SURF_PFX); result2.append(field); } std::string field; copy_field(field, pl[k], MORPH_STEM); result2.append(field); } } } slst = line_tok(result2, MSEP_REC); uniqlist(slst); return slst; } std::vector HunspellImpl::stem(const std::string& word) { return stem(analyze(word)); } const std::string& HunspellImpl::get_wordchars_cpp() const { return pAMgr->get_wordchars(); } const std::vector& HunspellImpl::get_wordchars_utf16() const { return pAMgr->get_wordchars_utf16(); } void HunspellImpl::mkinitcap(std::string& u8) { if (utf8) { std::vector u16; u8_u16(u16, u8); ::mkinitcap_utf(u16, langnum); u16_u8(u8, u16); } else { ::mkinitcap(u8, csconv); } } int HunspellImpl::mkinitcap2(std::string& u8, std::vector& u16) { if (utf8) { ::mkinitcap_utf(u16, langnum); u16_u8(u8, u16); } else { ::mkinitcap(u8, csconv); } return u8.size(); } int HunspellImpl::mkinitsmall2(std::string& u8, std::vector& u16) { if (utf8) { ::mkinitsmall_utf(u16, langnum); u16_u8(u8, u16); } else { ::mkinitsmall(u8, csconv); } return u8.size(); } int HunspellImpl::add(const std::string& word) { if (!m_HMgrs.empty()) return m_HMgrs[0]->add(word); return 0; } int HunspellImpl::add_with_affix(const std::string& word, const std::string& example) { if (!m_HMgrs.empty()) return m_HMgrs[0]->add_with_affix(word, example); return 0; } int HunspellImpl::remove(const std::string& word) { if (!m_HMgrs.empty()) return m_HMgrs[0]->remove(word); return 0; } const std::string& HunspellImpl::get_version_cpp() const { return pAMgr->get_version(); } struct cs_info* HunspellImpl::get_csconv() { return csconv; } void HunspellImpl::cat_result(std::string& result, const std::string& st) { if (!st.empty()) { if (!result.empty()) result.append("\n"); result.append(st); } } std::vector HunspellImpl::analyze(const std::string& word) { std::vector slst; if (!pSMgr || m_HMgrs.empty()) return slst; if (utf8) { if (word.size() >= MAXWORDUTF8LEN) return slst; } else { if (word.size() >= MAXWORDLEN) return slst; } int captype = NOCAP; size_t abbv = 0; size_t wl = 0; std::string scw; std::vector sunicw; // input conversion RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; { std::string wspace; bool convstatus = rl ? rl->conv(word, wspace) : false; if (convstatus) wl = cleanword2(scw, sunicw, wspace, &captype, &abbv); else wl = cleanword2(scw, sunicw, word, &captype, &abbv); } if (wl == 0) { if (abbv) { scw.clear(); for (wl = 0; wl < abbv; wl++) scw.push_back('.'); abbv = 0; } else return slst; } std::string result; size_t n = 0; // test numbers // LANG_hu section: set dash information for suggestions if (langnum == LANG_hu) { size_t n2 = 0; size_t n3 = 0; while ((n < wl) && (((scw[n] <= '9') && (scw[n] >= '0')) || (((scw[n] == '.') || (scw[n] == ',')) && (n > 0)))) { n++; if ((scw[n] == '.') || (scw[n] == ',')) { if (((n2 == 0) && (n > 3)) || ((n2 > 0) && ((scw[n - 1] == '.') || (scw[n - 1] == ',')))) break; n2++; n3 = n; } } if ((n == wl) && (n3 > 0) && (n - n3 > 3)) return slst; if ((n == wl) || ((n > 0) && ((scw[n] == '%') || (scw[n] == '\xB0')) && checkword(scw.substr(n), NULL, NULL))) { result.append(scw); result.resize(n - 1); if (n == wl) cat_result(result, pSMgr->suggest_morph(scw.substr(n - 1))); else { std::string chunk = scw.substr(n - 1, 1); cat_result(result, pSMgr->suggest_morph(chunk)); result.push_back('+'); // XXX SPEC. MORPHCODE cat_result(result, pSMgr->suggest_morph(scw.substr(n))); } return line_tok(result, MSEP_REC); } } // END OF LANG_hu section switch (captype) { case HUHCAP: case HUHINITCAP: case NOCAP: { cat_result(result, pSMgr->suggest_morph(scw)); if (abbv) { std::string u8buffer(scw); u8buffer.push_back('.'); cat_result(result, pSMgr->suggest_morph(u8buffer)); } break; } case INITCAP: { mkallsmall2(scw, sunicw); std::string u8buffer(scw); mkinitcap2(scw, sunicw); cat_result(result, pSMgr->suggest_morph(u8buffer)); cat_result(result, pSMgr->suggest_morph(scw)); if (abbv) { u8buffer.push_back('.'); cat_result(result, pSMgr->suggest_morph(u8buffer)); u8buffer = scw; u8buffer.push_back('.'); cat_result(result, pSMgr->suggest_morph(u8buffer)); } break; } case ALLCAP: { cat_result(result, pSMgr->suggest_morph(scw)); if (abbv) { std::string u8buffer(scw); u8buffer.push_back('.'); cat_result(result, pSMgr->suggest_morph(u8buffer)); } mkallsmall2(scw, sunicw); std::string u8buffer(scw); mkinitcap2(scw, sunicw); cat_result(result, pSMgr->suggest_morph(u8buffer)); cat_result(result, pSMgr->suggest_morph(scw)); if (abbv) { u8buffer.push_back('.'); cat_result(result, pSMgr->suggest_morph(u8buffer)); u8buffer = scw; u8buffer.push_back('.'); cat_result(result, pSMgr->suggest_morph(u8buffer)); } break; } } if (!result.empty()) { // word reversing wrapper for complex prefixes if (complexprefixes) { if (utf8) reverseword_utf(result); else reverseword(result); } return line_tok(result, MSEP_REC); } // compound word with dash (HU) I18n // LANG_hu section: set dash information for suggestions size_t dash_pos = langnum == LANG_hu ? scw.find('-') : std::string::npos; if (dash_pos != std::string::npos) { int nresult = 0; std::string part1 = scw.substr(0, dash_pos); std::string part2 = scw.substr(dash_pos+1); // examine 2 sides of the dash if (part2.empty()) { // base word ending with dash if (spell(part1)) { std::string p = pSMgr->suggest_morph(part1); if (!p.empty()) { slst = line_tok(p, MSEP_REC); return slst; } } } else if (part2.size() == 1 && part2[0] == 'e') { // XXX (HU) -e hat. if (spell(part1) && (spell("-e"))) { std::string st = pSMgr->suggest_morph(part1); if (!st.empty()) { result.append(st); } result.push_back('+'); // XXX spec. separator in MORPHCODE st = pSMgr->suggest_morph("-e"); if (!st.empty()) { result.append(st); } return line_tok(result, MSEP_REC); } } else { // first word ending with dash: word- XXX ??? part1.push_back(' '); nresult = spell(part1); part1.erase(part1.size() - 1); if (nresult && spell(part2) && ((part2.size() > 1) || ((part2[0] > '0') && (part2[0] < '9')))) { std::string st = pSMgr->suggest_morph(part1); if (!st.empty()) { result.append(st); result.push_back('+'); // XXX spec. separator in MORPHCODE } st = pSMgr->suggest_morph(part2); if (!st.empty()) { result.append(st); } return line_tok(result, MSEP_REC); } } // affixed number in correct word if (nresult && (dash_pos > 0) && (((scw[dash_pos - 1] <= '9') && (scw[dash_pos - 1] >= '0')) || (scw[dash_pos - 1] == '.'))) { n = 1; if (scw[dash_pos - n] == '.') n++; // search first not a number character to left from dash while ((dash_pos >= n) && ((scw[dash_pos - n] == '0') || (n < 3)) && (n < 6)) { n++; } if (dash_pos < n) n--; // numbers: valami1000000-hoz // examine 100000-hoz, 10000-hoz 1000-hoz, 10-hoz, // 56-hoz, 6-hoz for (; n >= 1; n--) { if (scw[dash_pos - n] < '0' || scw[dash_pos - n] > '9') { continue; } std::string chunk = scw.substr(dash_pos - n); if (checkword(chunk, NULL, NULL)) { result.append(chunk); std::string st = pSMgr->suggest_morph(chunk); if (!st.empty()) { result.append(st); } return line_tok(result, MSEP_REC); } } } } return slst; } std::vector HunspellImpl::generate(const std::string& word, const std::vector& pl) { std::vector slst; if (!pSMgr || pl.empty()) return slst; std::vector pl2 = analyze(word); int captype = NOCAP; int abbv = 0; std::string cw; cleanword(cw, word, &captype, &abbv); std::string result; for (size_t i = 0; i < pl.size(); ++i) { cat_result(result, pSMgr->suggest_gen(pl2, pl[i])); } if (!result.empty()) { // allcap if (captype == ALLCAP) mkallcap(result); // line split slst = line_tok(result, MSEP_REC); // capitalize if (captype == INITCAP || captype == HUHINITCAP) { for (size_t j = 0; j < slst.size(); ++j) { mkinitcap(slst[j]); } } // temporary filtering of prefix related errors (eg. // generate("undrinkable", "eats") --> "undrinkables" and "*undrinks") std::vector::iterator it = slst.begin(); while (it != slst.end()) { if (!spell(*it)) { it = slst.erase(it); } else { ++it; } } } return slst; } std::vector HunspellImpl::generate(const std::string& word, const std::string& pattern) { std::vector pl = analyze(pattern); std::vector slst = generate(word, pl); uniqlist(slst); return slst; } // minimal XML parser functions std::string HunspellImpl::get_xml_par(const char* par) { std::string dest; if (!par) return dest; char end = *par; if (end == '>') end = '<'; else if (end != '\'' && end != '"') return dest; // bad XML for (par++; *par != '\0' && *par != end; ++par) { dest.push_back(*par); } mystrrep(dest, "<", "<"); mystrrep(dest, "&", "&"); return dest; } int HunspellImpl::get_langnum() const { return langnum; } bool HunspellImpl::input_conv(const std::string& word, std::string& dest) { RepList* rl = pAMgr ? pAMgr->get_iconvtable() : NULL; if (rl) { return rl->conv(word, dest); } dest.assign(word); return false; } // return the beginning of the element (attr == NULL) or the attribute const char* HunspellImpl::get_xml_pos(const char* s, const char* attr) { const char* end = strchr(s, '>'); if (attr == NULL) return end; const char* p = s; while (1) { p = strstr(p, attr); if (!p || p >= end) return 0; if (*(p - 1) == ' ' || *(p - 1) == '\n') break; p += strlen(attr); } return p + strlen(attr); } int HunspellImpl::check_xml_par(const char* q, const char* attr, const char* value) { std::string cw = get_xml_par(get_xml_pos(q, attr)); if (cw == value) return 1; return 0; } std::vector HunspellImpl::get_xml_list(const char* list, const char* tag) { std::vector slst; if (!list) return slst; const char* p = list; for (size_t n = 0; ((p = strstr(p, tag)) != NULL); ++p, ++n) { std::string cw = get_xml_par(p + strlen(tag) - 1); if (cw.empty()) { break; } slst.push_back(cw); } return slst; } std::vector HunspellImpl::spellml(const std::string& in_word) { std::vector slst; const char* word = in_word.c_str(); const char* q = strstr(word, "'); if (!q2) return slst; // bad XML input q2 = strstr(q2, "')); if (!cw.empty()) slst = analyze(cw); if (slst.empty()) return slst; // convert the result to ana1ana2 format std::string r; r.append(""); for (size_t i = 0; i < slst.size(); ++i) { r.append(""); std::string entry(slst[i]); mystrrep(entry, "\t", " "); mystrrep(entry, "&", "&"); mystrrep(entry, "<", "<"); r.append(entry); r.append(""); } r.append(""); slst.clear(); slst.push_back(r); return slst; } else if (check_xml_par(q, "type=", "stem")) { std::string cw = get_xml_par(strchr(q2, '>')); if (!cw.empty()) return stem(cw); } else if (check_xml_par(q, "type=", "generate")) { std::string cw = get_xml_par(strchr(q2, '>')); if (cw.empty()) return slst; const char* q3 = strstr(q2 + 1, "')); if (!cw2.empty()) { return generate(cw, cw2); } } else { if ((q2 = strstr(q2 + 1, " slst2 = get_xml_list(strchr(q2, '>'), ""); if (!slst2.empty()) { slst = generate(cw, slst2); uniqlist(slst); return slst; } } } } else if (check_xml_par(q, "type=", "add")) { std::string cw = get_xml_par(strchr(q2, '>')); if (cw.empty()) return slst; const char* q3 = strstr(q2 + 1, "')); if (!cw2.empty()) { add_with_affix(cw, cw2); } else { add(cw); } } else { add(cw); } } return slst; } std::vector HunspellImpl::suffix_suggest(const std::string& root_word) { std::vector slst; struct hentry* he = NULL; int len; std::string w2; const char* word; const char* ignoredchars = pAMgr->get_ignore(); if (ignoredchars != NULL) { w2.assign(root_word); if (utf8) { const std::vector& ignoredchars_utf16 = pAMgr->get_ignore_utf16(); remove_ignored_chars_utf(w2, ignoredchars_utf16); } else { remove_ignored_chars(w2, ignoredchars); } word = w2.c_str(); } else word = root_word.c_str(); len = strlen(word); if (!len) return slst; for (size_t i = 0; (i < m_HMgrs.size()) && !he; ++i) { he = m_HMgrs[i]->lookup(word); } if (he) { slst = pAMgr->get_suffix_words(he->astr, he->alen, root_word.c_str()); } return slst; } namespace { int munge_vector(char*** slst, const std::vector& items) { if (items.empty()) { *slst = NULL; return 0; } else { *slst = (char**)malloc(sizeof(char*) * items.size()); if (!*slst) return 0; for (size_t i = 0; i < items.size(); ++i) (*slst)[i] = mystrdup(items[i].c_str()); } return items.size(); } } int HunspellImpl::spell(const char* word, int* info, char** root) { std::string sroot; bool ret = spell(word, info, root ? &sroot : NULL); if (root) { if (sroot.empty()) { *root = NULL; } else { *root = mystrdup(sroot.c_str()); } } return ret; } int HunspellImpl::suggest(char*** slst, const char* word) { std::vector suggests = suggest(word); return munge_vector(slst, suggests); } int HunspellImpl::suffix_suggest(char*** slst, const char* root_word) { std::vector stems = suffix_suggest(root_word); return munge_vector(slst, stems); } void HunspellImpl::free_list(char*** slst, int n) { if (slst && *slst) { for (int i = 0; i < n; i++) free((*slst)[i]); free(*slst); *slst = NULL; } } char* HunspellImpl::get_dic_encoding() { return &encoding[0]; } int HunspellImpl::analyze(char*** slst, const char* word) { std::vector stems = analyze(word); return munge_vector(slst, stems); } int HunspellImpl::stem(char*** slst, const char* word) { std::vector stems = stem(word); return munge_vector(slst, stems); } int HunspellImpl::stem(char*** slst, char** desc, int n) { std::vector morph; for (int i = 0; i < n; ++i) morph.push_back(desc[i]); std::vector stems = stem(morph); return munge_vector(slst, stems); } int HunspellImpl::generate(char*** slst, const char* word, const char* pattern) { std::vector stems = generate(word, pattern); return munge_vector(slst, stems); } int HunspellImpl::generate(char*** slst, const char* word, char** pl, int pln) { std::vector morph; for (int i = 0; i < pln; ++i) morph.push_back(pl[i]); std::vector stems = generate(word, morph); return munge_vector(slst, stems); } const char* HunspellImpl::get_wordchars() const { return get_wordchars_cpp().c_str(); } const char* HunspellImpl::get_version() const { return get_version_cpp().c_str(); } int HunspellImpl::input_conv(const char* word, char* dest, size_t destsize) { std::string d; bool ret = input_conv(word, d); if (ret && d.size() < destsize) { strncpy(dest, d.c_str(), destsize); return 1; } return 0; } Hunspell::Hunspell(const char* affpath, const char* dpath, const char* key) : m_Impl(new HunspellImpl(affpath, dpath, key)) { } Hunspell::~Hunspell() { delete m_Impl; } // load extra dictionaries int Hunspell::add_dic(const char* dpath, const char* key) { return m_Impl->add_dic(dpath, key); } bool Hunspell::spell(const std::string& word, int* info, std::string* root) { return m_Impl->spell(word, info, root); } std::vector Hunspell::suggest(const std::string& word) { return m_Impl->suggest(word); } std::vector Hunspell::suffix_suggest(const std::string& root_word) { return m_Impl->suffix_suggest(root_word); } const std::string& Hunspell::get_dict_encoding() const { return m_Impl->get_dict_encoding(); } std::vector Hunspell::stem(const std::vector& desc) { return m_Impl->stem(desc); } std::vector Hunspell::stem(const std::string& word) { return m_Impl->stem(word); } const std::string& Hunspell::get_wordchars_cpp() const { return m_Impl->get_wordchars_cpp(); } const std::vector& Hunspell::get_wordchars_utf16() const { return m_Impl->get_wordchars_utf16(); } int Hunspell::add(const std::string& word) { return m_Impl->add(word); } int Hunspell::add_with_affix(const std::string& word, const std::string& example) { return m_Impl->add_with_affix(word, example); } int Hunspell::remove(const std::string& word) { return m_Impl->remove(word); } const std::string& Hunspell::get_version_cpp() const { return m_Impl->get_version_cpp(); } struct cs_info* Hunspell::get_csconv() { return m_Impl->get_csconv(); } std::vector Hunspell::analyze(const std::string& word) { return m_Impl->analyze(word); } std::vector Hunspell::generate(const std::string& word, const std::vector& pl) { return m_Impl->generate(word, pl); } std::vector Hunspell::generate(const std::string& word, const std::string& pattern) { return m_Impl->generate(word, pattern); } int Hunspell::get_langnum() const { return m_Impl->get_langnum(); } bool Hunspell::input_conv(const std::string& word, std::string& dest) { return m_Impl->input_conv(word, dest); } int Hunspell::spell(const char* word, int* info, char** root) { return m_Impl->spell(word, info, root); } int Hunspell::suggest(char*** slst, const char* word) { return m_Impl->suggest(slst, word); } int Hunspell::suffix_suggest(char*** slst, const char* root_word) { return m_Impl->suffix_suggest(slst, root_word); } void Hunspell::free_list(char*** slst, int n) { m_Impl->free_list(slst, n); } char* Hunspell::get_dic_encoding() { return m_Impl->get_dic_encoding(); } int Hunspell::analyze(char*** slst, const char* word) { return m_Impl->analyze(slst, word); } int Hunspell::stem(char*** slst, const char* word) { return m_Impl->stem(slst, word); } int Hunspell::stem(char*** slst, char** desc, int n) { return m_Impl->stem(slst, desc, n); } int Hunspell::generate(char*** slst, const char* word, const char* pattern) { return m_Impl->generate(slst, word, pattern); } int Hunspell::generate(char*** slst, const char* word, char** pl, int pln) { return m_Impl->generate(slst, word, pl, pln); } const char* Hunspell::get_wordchars() const { return m_Impl->get_wordchars(); } const char* Hunspell::get_version() const { return m_Impl->get_version(); } int Hunspell::input_conv(const char* word, char* dest, size_t destsize) { return m_Impl->input_conv(word, dest, destsize); } Hunhandle* Hunspell_create(const char* affpath, const char* dpath) { return reinterpret_cast(new HunspellImpl(affpath, dpath)); } Hunhandle* Hunspell_create_key(const char* affpath, const char* dpath, const char* key) { return reinterpret_cast(new HunspellImpl(affpath, dpath, key)); } void Hunspell_destroy(Hunhandle* pHunspell) { delete reinterpret_cast(pHunspell); } int Hunspell_add_dic(Hunhandle* pHunspell, const char* dpath) { return reinterpret_cast(pHunspell)->add_dic(dpath); } int Hunspell_spell(Hunhandle* pHunspell, const char* word) { return reinterpret_cast(pHunspell)->spell(word); } char* Hunspell_get_dic_encoding(Hunhandle* pHunspell) { return reinterpret_cast(pHunspell)->get_dic_encoding(); } int Hunspell_suggest(Hunhandle* pHunspell, char*** slst, const char* word) { return reinterpret_cast(pHunspell)->suggest(slst, word); } int Hunspell_analyze(Hunhandle* pHunspell, char*** slst, const char* word) { return reinterpret_cast(pHunspell)->analyze(slst, word); } int Hunspell_stem(Hunhandle* pHunspell, char*** slst, const char* word) { return reinterpret_cast(pHunspell)->stem(slst, word); } int Hunspell_stem2(Hunhandle* pHunspell, char*** slst, char** desc, int n) { return reinterpret_cast(pHunspell)->stem(slst, desc, n); } int Hunspell_generate(Hunhandle* pHunspell, char*** slst, const char* word, const char* pattern) { return reinterpret_cast(pHunspell)->generate(slst, word, pattern); } int Hunspell_generate2(Hunhandle* pHunspell, char*** slst, const char* word, char** desc, int n) { return reinterpret_cast(pHunspell)->generate(slst, word, desc, n); } /* functions for run-time modification of the dictionary */ /* add word to the run-time dictionary */ int Hunspell_add(Hunhandle* pHunspell, const char* word) { return reinterpret_cast(pHunspell)->add(word); } /* add word to the run-time dictionary with affix flags of * the example (a dictionary word): Hunspell will recognize * affixed forms of the new word, too. */ int Hunspell_add_with_affix(Hunhandle* pHunspell, const char* word, const char* example) { return reinterpret_cast(pHunspell)->add_with_affix(word, example); } /* remove word from the run-time dictionary */ int Hunspell_remove(Hunhandle* pHunspell, const char* word) { return reinterpret_cast(pHunspell)->remove(word); } void Hunspell_free_list(Hunhandle* pHunspell, char*** list, int n) { reinterpret_cast(pHunspell)->free_list(list, n); } nuspell-5.1.7/external/hunspell/hunspell/hunspell.h000066400000000000000000000150431511132717100225210ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Hunspell, based on MySpell. * * The Initial Developers of the Original Code are * Kevin Hendricks (MySpell) and Németh László (Hunspell). * Portions created by the Initial Developers are Copyright (C) 2002-2005 * the Initial Developers. All Rights Reserved. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef MYSPELLMGR_H_ #define MYSPELLMGR_H_ #include "hunvisapi.h" #ifdef __cplusplus extern "C" { #endif typedef struct Hunhandle Hunhandle; LIBHUNSPELL_DLL_EXPORTED Hunhandle* Hunspell_create(const char* affpath, const char* dpath); LIBHUNSPELL_DLL_EXPORTED Hunhandle* Hunspell_create_key(const char* affpath, const char* dpath, const char* key); LIBHUNSPELL_DLL_EXPORTED void Hunspell_destroy(Hunhandle* pHunspell); /* load extra dictionaries (only dic files) * output: 0 = additional dictionary slots available, 1 = slots are now full*/ LIBHUNSPELL_DLL_EXPORTED int Hunspell_add_dic(Hunhandle* pHunspell, const char* dpath); /* spell(word) - spellcheck word * output: 0 = bad word, not 0 = good word */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_spell(Hunhandle* pHunspell, const char*); LIBHUNSPELL_DLL_EXPORTED char* Hunspell_get_dic_encoding(Hunhandle* pHunspell); /* suggest(suggestions, word) - search suggestions * input: pointer to an array of strings pointer and the (bad) word * array of strings pointer (here *slst) may not be initialized * output: number of suggestions in string array, and suggestions in * a newly allocated array of strings (*slts will be NULL when number * of suggestion equals 0.) */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_suggest(Hunhandle* pHunspell, char*** slst, const char* word); /* morphological functions */ /* analyze(result, word) - morphological analysis of the word */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_analyze(Hunhandle* pHunspell, char*** slst, const char* word); /* stem(result, word) - stemmer function */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_stem(Hunhandle* pHunspell, char*** slst, const char* word); /* stem(result, analysis, n) - get stems from a morph. analysis * example: * char ** result, result2; * int n1 = Hunspell_analyze(result, "words"); * int n2 = Hunspell_stem2(result2, result, n1); */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_stem2(Hunhandle* pHunspell, char*** slst, char** desc, int n); /* generate(result, word, word2) - morphological generation by example(s) */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_generate(Hunhandle* pHunspell, char*** slst, const char* word, const char* word2); /* generate(result, word, desc, n) - generation by morph. description(s) * example: * char ** result; * char * affix = "is:plural"; // description depends from dictionaries, too * int n = Hunspell_generate2(result, "word", &affix, 1); * for (int i = 0; i < n; i++) printf("%s\n", result[i]); */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_generate2(Hunhandle* pHunspell, char*** slst, const char* word, char** desc, int n); /* functions for run-time modification of the dictionary */ /* add word to the run-time dictionary */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_add(Hunhandle* pHunspell, const char* word); /* add word to the run-time dictionary with affix flags of * the example (a dictionary word): Hunspell will recognize * affixed forms of the new word, too. */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_add_with_affix(Hunhandle* pHunspell, const char* word, const char* example); /* remove word from the run-time dictionary */ LIBHUNSPELL_DLL_EXPORTED int Hunspell_remove(Hunhandle* pHunspell, const char* word); /* free suggestion lists */ LIBHUNSPELL_DLL_EXPORTED void Hunspell_free_list(Hunhandle* pHunspell, char*** slst, int n); #ifdef __cplusplus } #endif #endif nuspell-5.1.7/external/hunspell/hunspell/hunspell.hxx000066400000000000000000000216271511132717100231060ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef MYSPELLMGR_HXX_ #define MYSPELLMGR_HXX_ #include "hunvisapi.h" #include "w_char.hxx" #include "atypes.hxx" #include #include #define SPELL_XML "" #define MAXSUGGESTION 15 #define MAXSHARPS 5 #ifndef MAXWORDLEN #define MAXWORDLEN 100 #endif #if defined __GNUC__ && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) # define H_DEPRECATED __attribute__((__deprecated__)) #elif defined(_MSC_VER) && (_MSC_VER >= 1300) # define H_DEPRECATED __declspec(deprecated) #else # define H_DEPRECATED #endif class HunspellImpl; class LIBHUNSPELL_DLL_EXPORTED Hunspell { private: Hunspell(const Hunspell&); Hunspell& operator=(const Hunspell&); private: HunspellImpl* m_Impl; public: /* Hunspell(aff, dic) - constructor of Hunspell class * input: path of affix file and dictionary file * * In WIN32 environment, use UTF-8 encoded paths started with the long path * prefix \\\\?\\ to handle system-independent character encoding and very * long path names (without the long path prefix Hunspell will use fopen() * with system-dependent character encoding instead of _wfopen()). */ Hunspell(const char* affpath, const char* dpath, const char* key = NULL); ~Hunspell(); /* load extra dictionaries (only dic files) */ int add_dic(const char* dpath, const char* key = NULL); /* spell(word) - spellcheck word * output: false = bad word, true = good word * * plus output: * info: information bit array, fields: * SPELL_COMPOUND = a compound word * SPELL_FORBIDDEN = an explicit forbidden word * root: root (stem), when input is a word with affix(es) */ bool spell(const std::string& word, int* info = NULL, std::string* root = NULL); H_DEPRECATED int spell(const char* word, int* info = NULL, char** root = NULL); /* suggest(suggestions, word) - search suggestions * input: pointer to an array of strings pointer and the (bad) word * array of strings pointer (here *slst) may not be initialized * output: number of suggestions in string array, and suggestions in * a newly allocated array of strings (*slts will be NULL when number * of suggestion equals 0.) */ std::vector suggest(const std::string& word); H_DEPRECATED int suggest(char*** slst, const char* word); /* Suggest words from suffix rules * suffix_suggest(suggestions, root_word) * input: pointer to an array of strings pointer and the word * array of strings pointer (here *slst) may not be initialized * output: number of suggestions in string array, and suggestions in * a newly allocated array of strings (*slts will be NULL when number * of suggestion equals 0.) */ std::vector suffix_suggest(const std::string& root_word); H_DEPRECATED int suffix_suggest(char*** slst, const char* root_word); /* deallocate suggestion lists */ H_DEPRECATED void free_list(char*** slst, int n); const std::string& get_dict_encoding() const; char* get_dic_encoding(); /* morphological functions */ /* analyze(result, word) - morphological analysis of the word */ std::vector analyze(const std::string& word); H_DEPRECATED int analyze(char*** slst, const char* word); /* stem(word) - stemmer function */ std::vector stem(const std::string& word); H_DEPRECATED int stem(char*** slst, const char* word); /* stem(analysis, n) - get stems from a morph. analysis * example: * char ** result, result2; * int n1 = analyze(&result, "words"); * int n2 = stem(&result2, result, n1); */ std::vector stem(const std::vector& morph); H_DEPRECATED int stem(char*** slst, char** morph, int n); /* generate(result, word, word2) - morphological generation by example(s) */ std::vector generate(const std::string& word, const std::string& word2); H_DEPRECATED int generate(char*** slst, const char* word, const char* word2); /* generate(result, word, desc, n) - generation by morph. description(s) * example: * char ** result; * char * affix = "is:plural"; // description depends from dictionaries, too * int n = generate(&result, "word", &affix, 1); * for (int i = 0; i < n; i++) printf("%s\n", result[i]); */ std::vector generate(const std::string& word, const std::vector& pl); H_DEPRECATED int generate(char*** slst, const char* word, char** desc, int n); /* functions for run-time modification of the dictionary */ /* add word to the run-time dictionary */ int add(const std::string& word); /* add word to the run-time dictionary with affix flags of * the example (a dictionary word): Hunspell will recognize * affixed forms of the new word, too. */ int add_with_affix(const std::string& word, const std::string& example); /* remove word from the run-time dictionary */ int remove(const std::string& word); /* other */ /* get extra word characters definied in affix file for tokenization */ const char* get_wordchars() const; const std::string& get_wordchars_cpp() const; const std::vector& get_wordchars_utf16() const; struct cs_info* get_csconv(); const char* get_version() const; const std::string& get_version_cpp() const; int get_langnum() const; /* need for putdic */ bool input_conv(const std::string& word, std::string& dest); H_DEPRECATED int input_conv(const char* word, char* dest, size_t destsize); }; #endif nuspell-5.1.7/external/hunspell/hunspell/hunvisapi.h000066400000000000000000000007611511132717100226760ustar00rootroot00000000000000#ifndef HUNSPELL_VISIBILITY_H_ #define HUNSPELL_VISIBILITY_H_ #if defined(HUNSPELL_STATIC) # define LIBHUNSPELL_DLL_EXPORTED #elif defined(_WIN32) || defined(__CYGWIN__) # if defined(BUILDING_LIBHUNSPELL) # define LIBHUNSPELL_DLL_EXPORTED __declspec(dllexport) # else # define LIBHUNSPELL_DLL_EXPORTED __declspec(dllimport) # endif #elif __GNUC__ >= 4 # define LIBHUNSPELL_DLL_EXPORTED __attribute__((__visibility__("default"))) #else # define LIBHUNSPELL_DLL_EXPORTED #endif #endif nuspell-5.1.7/external/hunspell/hunspell/hunzip.cxx000066400000000000000000000152661511132717100225660ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include "hunzip.hxx" #include "csutil.hxx" #define CODELEN 65536 #define BASEBITREC 5000 #define UNCOMPRESSED '\002' #define MAGIC "hz0" #define MAGIC_ENCRYPT "hz1" #define MAGICLEN (sizeof(MAGIC) - 1) int Hunzip::fail(const char* err, const char* par) { fprintf(stderr, err, par); return -1; } Hunzip::Hunzip(const char* file, const char* key) : bufsiz(0), lastbit(0), inc(0), inbits(0), outc(0) { in[0] = out[0] = line[0] = '\0'; filename = mystrdup(file); if (getcode(key) == -1) bufsiz = -1; else bufsiz = getbuf(); } int Hunzip::getcode(const char* key) { unsigned char c[2]; int i, j, n; int allocatedbit = BASEBITREC; const char* enc = key; if (!filename) return -1; myopen(fin, filename, std::ios_base::in | std::ios_base::binary); if (!fin.is_open()) return -1; // read magic number if (!fin.read(in, 3) || !(strncmp(MAGIC, in, MAGICLEN) == 0 || strncmp(MAGIC_ENCRYPT, in, MAGICLEN) == 0)) { return fail(MSG_FORMAT, filename); } // check encryption if (strncmp(MAGIC_ENCRYPT, in, MAGICLEN) == 0) { unsigned char cs; if (!key) return fail(MSG_KEY, filename); if (!fin.read(reinterpret_cast(c), 1)) return fail(MSG_FORMAT, filename); for (cs = 0; *enc; enc++) cs ^= *enc; if (cs != c[0]) return fail(MSG_KEY, filename); enc = key; } else key = NULL; // read record count if (!fin.read(reinterpret_cast(c), 2)) return fail(MSG_FORMAT, filename); if (key) { c[0] ^= *enc; if (*(++enc) == '\0') enc = key; c[1] ^= *enc; } n = ((int)c[0] << 8) + c[1]; dec.resize(BASEBITREC); dec[0].v[0] = 0; dec[0].v[1] = 0; // read codes for (i = 0; i < n; i++) { unsigned char l; if (!fin.read(reinterpret_cast(c), 2)) return fail(MSG_FORMAT, filename); if (key) { if (*(++enc) == '\0') enc = key; c[0] ^= *enc; if (*(++enc) == '\0') enc = key; c[1] ^= *enc; } if (!fin.read(reinterpret_cast(&l), 1)) return fail(MSG_FORMAT, filename); if (key) { if (*(++enc) == '\0') enc = key; l ^= *enc; } if (!fin.read(in, l / 8 + 1)) return fail(MSG_FORMAT, filename); if (key) for (j = 0; j <= l / 8; j++) { if (*(++enc) == '\0') enc = key; in[j] ^= *enc; } int p = 0; for (j = 0; j < l; j++) { int b = (in[j / 8] & (1 << (7 - (j % 8)))) ? 1 : 0; int oldp = p; p = dec[p].v[b]; if (p == 0) { lastbit++; if (lastbit == allocatedbit) { allocatedbit += BASEBITREC; dec.resize(allocatedbit); } dec[lastbit].v[0] = 0; dec[lastbit].v[1] = 0; dec[oldp].v[b] = lastbit; p = lastbit; } } dec[p].c[0] = c[0]; dec[p].c[1] = c[1]; } return 0; } Hunzip::~Hunzip() { if (filename) free(filename); } int Hunzip::getbuf() { int p = 0; int o = 0; do { if (inc == 0) { fin.read(in, BUFSIZE); inbits = fin.gcount() * 8; } for (; inc < inbits; inc++) { int b = (in[inc / 8] & (1 << (7 - (inc % 8)))) ? 1 : 0; int oldp = p; p = dec[p].v[b]; if (p == 0) { if (oldp == lastbit) { fin.close(); // add last odd byte if (dec[lastbit].c[0]) out[o++] = dec[lastbit].c[1]; return o; } out[o++] = dec[oldp].c[0]; out[o++] = dec[oldp].c[1]; if (o == BUFSIZE) return o; p = dec[p].v[b]; } } inc = 0; } while (inbits == BUFSIZE * 8); return fail(MSG_FORMAT, filename); } bool Hunzip::getline(std::string& dest) { char linebuf[BUFSIZE]; int l = 0, eol = 0, left = 0, right = 0; if (bufsiz == -1) return false; while (l < bufsiz && !eol) { linebuf[l++] = out[outc]; switch (out[outc]) { case '\t': break; case 31: { // escape if (++outc == bufsiz) { bufsiz = getbuf(); outc = 0; } linebuf[l - 1] = out[outc]; break; } case ' ': break; default: if (((unsigned char)out[outc]) < 47) { if (out[outc] > 32) { right = out[outc] - 31; if (++outc == bufsiz) { bufsiz = getbuf(); outc = 0; } } if (out[outc] == 30) left = 9; else left = out[outc]; linebuf[l - 1] = '\n'; eol = 1; } } if (++outc == bufsiz) { outc = 0; bufsiz = fin.is_open() ? getbuf() : -1; } } if (right) strcpy(linebuf + l - 1, line + strlen(line) - right - 1); else linebuf[l] = '\0'; strcpy(line + left, linebuf); dest.assign(line); return true; } nuspell-5.1.7/external/hunspell/hunspell/hunzip.hxx000066400000000000000000000061011511132717100225570ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* hunzip: file decompression for sorted dictionaries with optional encryption, * algorithm: prefix-suffix encoding and 16-bit Huffman encoding */ #ifndef HUNZIP_HXX_ #define HUNZIP_HXX_ #include "hunvisapi.h" #include #include #include #define BUFSIZE 65536 #define HZIP_EXTENSION ".hz" #define MSG_OPEN "error: %s: cannot open\n" #define MSG_FORMAT "error: %s: not in hzip format\n" #define MSG_MEMORY "error: %s: missing memory\n" #define MSG_KEY "error: %s: missing or bad password\n" struct bit { unsigned char c[2]; int v[2]; }; class LIBHUNSPELL_DLL_EXPORTED Hunzip { private: Hunzip(const Hunzip&); Hunzip& operator=(const Hunzip&); protected: char* filename; std::ifstream fin; int bufsiz, lastbit, inc, inbits, outc; std::vector dec; // code table char in[BUFSIZE]; // input buffer char out[BUFSIZE + 1]; // Huffman-decoded buffer char line[BUFSIZE + 50]; // decoded line int getcode(const char* key); int getbuf(); int fail(const char* err, const char* par); public: Hunzip(const char* filename, const char* key = NULL); ~Hunzip(); bool is_open() { return fin.is_open(); } bool getline(std::string& dest); }; #endif nuspell-5.1.7/external/hunspell/hunspell/langnum.hxx000066400000000000000000000050561511132717100227130ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef LANGNUM_HXX_ #define LANGNUM_HXX_ /* language numbers for language specific codes see https://wiki.openoffice.org/w/index.php?title=Languages&oldid=230199 */ enum { LANG_ar = 96, LANG_az = 100, // custom number LANG_bg = 41, LANG_ca = 37, LANG_crh = 102, // custom number LANG_cs = 42, LANG_da = 45, LANG_de = 49, LANG_el = 30, LANG_en = 01, LANG_es = 34, LANG_eu = 10, LANG_fr = 02, LANG_gl = 38, LANG_hr = 78, LANG_hu = 36, LANG_it = 39, LANG_la = 99, // custom number LANG_lv = 101, // custom number LANG_nl = 31, LANG_pl = 48, LANG_pt = 03, LANG_ru = 07, LANG_sv = 50, LANG_tr = 90, LANG_uk = 80, LANG_xx = 999 }; #endif nuspell-5.1.7/external/hunspell/hunspell/phonet.cxx000066400000000000000000000212021511132717100225310ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * phonetic.c - generic replacement aglogithms for phonetic transformation * Copyright (C) 2000 Bjoern Jacke * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include "csutil.hxx" #include "phonet.hxx" void init_phonet_hash(phonetable& parms) { for (int i = 0; i < HASHSIZE; i++) { parms.hash[i] = -1; } for (int i = 0; parms.rules[i][0] != '\0'; i += 2) { /** set hash value **/ int k = (unsigned char)parms.rules[i][0]; if (parms.hash[k] < 0) { parms.hash[k] = i; } } } // like strcpy but safe if the strings overlap // but only if dest < src static inline void strmove(char* dest, char* src) { while (*src) *dest++ = *src++; *dest = '\0'; } static int myisalpha(char ch) { if ((unsigned char)ch < 128) return isalpha(ch); return 1; } /* Do phonetic transformation. */ /* phonetic transcription algorithm */ /* see: http://aspell.net/man-html/Phonetic-Code.html */ /* convert string to uppercase before this call */ std::string phonet(const std::string& inword, phonetable& parms) { int i, k = 0, p, z; int k0, n0, p0 = -333; char c; typedef unsigned char uchar; size_t len = inword.size(); if (len > MAXPHONETUTF8LEN) return std::string(); char word[MAXPHONETUTF8LEN + 1]; strncpy(word, inword.c_str(), MAXPHONETUTF8LEN); word[MAXPHONETUTF8LEN] = '\0'; std::string target; /** check word **/ i = z = 0; while ((c = word[i]) != '\0') { int n = parms.hash[(uchar)c]; int z0 = 0; if (n >= 0 && !parms.rules[n].empty()) { /** check all rules for the same letter **/ while (parms.rules[n][0] == c) { /** check whole string **/ k = 1; /** number of found letters **/ p = 5; /** default priority **/ const char*s = parms.rules[n].c_str(); s++; /** important for (see below) "*(s-1)" **/ while (*s != '\0' && word[i + k] == *s && !isdigit((unsigned char)*s) && strchr("(-<^$", *s) == NULL) { k++; s++; } if (*s == '(') { /** check letters in "(..)" **/ if (myisalpha(word[i + k]) // ...could be implied? && strchr(s + 1, word[i + k]) != NULL) { k++; while (*s != ')') s++; s++; } } p0 = (int)*s; k0 = k; while (*s == '-' && k > 1) { k--; s++; } if (*s == '<') s++; if (isdigit((unsigned char)*s)) { /** determine priority **/ p = *s - '0'; s++; } if (*s == '^' && *(s + 1) == '^') s++; if (*s == '\0' || (*s == '^' && (i == 0 || !myisalpha(word[i - 1])) && (*(s + 1) != '$' || (!myisalpha(word[i + k0])))) || (*s == '$' && i > 0 && myisalpha(word[i - 1]) && (!myisalpha(word[i + k0])))) { /** search for followup rules, if: **/ /** parms.followup and k > 1 and NO '-' in searchstring **/ char c0 = word[i + k - 1]; n0 = parms.hash[(uchar)c0]; // if (parms.followup && k > 1 && n0 >= 0 if (k > 1 && n0 >= 0 && p0 != (int)'-' && word[i + k] != '\0' && !parms.rules[n0].empty()) { /** test follow-up rule for "word[i+k]" **/ while (parms.rules[n0][0] == c0) { /** check whole string **/ k0 = k; p0 = 5; s = parms.rules[n0].c_str(); s++; while (*s != '\0' && word[i + k0] == *s && !isdigit((unsigned char)*s) && strchr("(-<^$", *s) == NULL) { k0++; s++; } if (*s == '(') { /** check letters **/ if (myisalpha(word[i + k0]) && strchr(s + 1, word[i + k0]) != NULL) { k0++; while (*s != ')' && *s != '\0') s++; if (*s == ')') s++; } } while (*s == '-') { /** "k0" gets NOT reduced **/ /** because "if (k0 == k)" **/ s++; } if (*s == '<') s++; if (isdigit((unsigned char)*s)) { p0 = *s - '0'; s++; } if (*s == '\0' /** *s == '^' cuts **/ || (*s == '$' && !myisalpha(word[i + k0]))) { if (k0 == k) { /** this is just a piece of the string **/ n0 += 2; continue; } if (p0 < p) { /** priority too low **/ n0 += 2; continue; } /** rule fits; stop search **/ break; } n0 += 2; } /** End of "while (parms.rules[n0][0] == c0)" **/ if (p0 >= p && parms.rules[n0][0] == c0) { n += 2; continue; } } /** end of follow-up stuff **/ /** replace string **/ s = parms.rules[n + 1].c_str(); p0 = (!parms.rules[n].empty() && strchr(parms.rules[n].c_str() + 1, '<') != NULL) ? 1 : 0; if (p0 == 1 && z == 0) { /** rule with '<' is used **/ if (!target.empty() && *s != '\0' && (target[target.size()-1] == c || target[target.size()-1] == *s)) { target.erase(target.size() - 1); } z0 = 1; z = 1; k0 = 0; while (*s != '\0' && word[i + k0] != '\0') { word[i + k0] = *s; k0++; s++; } if (k > k0) strmove(&word[0] + i + k0, &word[0] + i + k); /** new "actual letter" **/ c = word[i]; } else { /** no '<' rule used **/ i += k - 1; z = 0; while (*s != '\0' && *(s + 1) != '\0' && target.size() < len) { if (target.empty() || target[target.size()-1] != *s) { target.push_back(*s); } s++; } /** new "actual letter" **/ c = *s; if (!parms.rules[n].empty() && strstr(parms.rules[n].c_str() + 1, "^^") != NULL) { if (c != '\0') { target.push_back(c); } strmove(&word[0], &word[0] + i + 1); i = 0; z0 = 1; } } break; } /** end of follow-up stuff **/ n += 2; } /** end of while (parms.rules[n][0] == c) **/ } /** end of if (n >= 0) **/ if (z0 == 0) { if (k && !p0 && target.size() < len && c != '\0') { /** condense only double letters **/ target.push_back(c); /// printf("\n setting \n"); } i++; z = 0; k = 0; } } /** end of while ((c = word[i]) != '\0') **/ return target; } /** end of function "phonet" **/ nuspell-5.1.7/external/hunspell/hunspell/phonet.hxx000066400000000000000000000037141511132717100225460ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * phonetic.c - generic replacement aglogithms for phonetic transformation * Copyright (C) 2000 Bjoern Jacke * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * ***** END LICENSE BLOCK ***** */ #ifndef PHONET_HXX_ #define PHONET_HXX_ #define HASHSIZE 256 #define MAXPHONETLEN 256 #define MAXPHONETUTF8LEN (MAXPHONETLEN * 4) #include "hunvisapi.h" struct phonetable { char utf8; std::vector rules; int hash[HASHSIZE]; }; LIBHUNSPELL_DLL_EXPORTED void init_phonet_hash(phonetable& parms); LIBHUNSPELL_DLL_EXPORTED std::string phonet(const std::string& inword, phonetable& phone); #endif nuspell-5.1.7/external/hunspell/hunspell/replist.cxx000066400000000000000000000143741511132717100227320ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "replist.hxx" #include "csutil.hxx" RepList::RepList(int n) { dat = (replentry**)malloc(sizeof(replentry*) * n); if (dat == 0) size = 0; else size = n; pos = 0; } RepList::~RepList() { for (int i = 0; i < pos; i++) { delete dat[i]; } free(dat); } replentry* RepList::item(int n) { return dat[n]; } int RepList::find(const char* word) { int p1 = 0; int p2 = pos - 1; int ret = -1; while (p1 <= p2) { int m = ((unsigned)p1 + (unsigned)p2) >> 1; int c = strncmp(word, dat[m]->pattern.c_str(), dat[m]->pattern.size()); if (c < 0) p2 = m - 1; else if (c > 0) p1 = m + 1; else { // scan in the right half for a longer match ret = m; p1 = m + 1; } } return ret; } std::string RepList::replace(const char* word, int ind, bool atstart) { int type = atstart ? 1 : 0; if (ind < 0) return std::string(); if (strlen(word) == dat[ind]->pattern.size()) type = atstart ? 3 : 2; while (type && dat[ind]->outstrings[type].empty()) type = (type == 2 && !atstart) ? 0 : type - 1; return dat[ind]->outstrings[type]; } int RepList::add(const std::string& in_pat1, const std::string& pat2) { if (pos >= size || in_pat1.empty() || pat2.empty()) { return 1; } // analyse word context int type = 0; std::string pat1(in_pat1); if (pat1[0] == '_') { pat1.erase(0, 1); type = 1; } if (!pat1.empty() && pat1[pat1.size() - 1] == '_') { type = type + 2; pat1.erase(pat1.size() - 1); } mystrrep(pat1, "_", " "); // find existing entry int m = find(pat1.c_str()); if (m >= 0 && dat[m]->pattern == pat1) { // since already used dat[m]->outstrings[type] = pat2; mystrrep(dat[m]->outstrings[type], "_", " "); return 0; } // make a new entry if none exists replentry* r = new replentry; if (r == NULL) return 1; r->pattern = pat1; r->outstrings[type] = pat2; mystrrep(r->outstrings[type], "_", " "); dat[pos++] = r; // sort to the right place in the list int i; for (i = pos - 1; i > 0; i--) { if (strcmp(r->pattern.c_str(), dat[i - 1]->pattern.c_str()) < 0) { dat[i] = dat[i - 1]; } else break; } dat[i] = r; return 0; } bool RepList::conv(const std::string& in_word, std::string& dest) { dest.clear(); size_t wordlen = in_word.size(); const char* word = in_word.c_str(); bool change = false; for (size_t i = 0; i < wordlen; ++i) { int n = find(word + i); std::string l = replace(word + i, n, i == 0); if (!l.empty()) { dest.append(l); i += dat[n]->pattern.size() - 1; change = true; } else { dest.push_back(word[i]); } } return change; } nuspell-5.1.7/external/hunspell/hunspell/replist.hxx000066400000000000000000000101361511132717100227270ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* string replacement list class */ #ifndef REPLIST_HXX_ #define REPLIST_HXX_ #include "w_char.hxx" #include #include class RepList { private: RepList(const RepList&); RepList& operator=(const RepList&); protected: replentry** dat; int size; int pos; public: explicit RepList(int n); ~RepList(); int add(const std::string& pat1, const std::string& pat2); replentry* item(int n); int find(const char* word); std::string replace(const char* word, int n, bool atstart); bool conv(const std::string& word, std::string& dest); }; #endif nuspell-5.1.7/external/hunspell/hunspell/suggestmgr.cxx000066400000000000000000002003221511132717100234250ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "suggestmgr.hxx" #include "htypes.hxx" #include "csutil.hxx" const w_char W_VLINE = {'\0', '|'}; SuggestMgr::SuggestMgr(const char* tryme, unsigned int maxn, AffixMgr* aptr) { // register affix manager and check in string of chars to // try when building candidate suggestions pAMgr = aptr; csconv = NULL; ckeyl = 0; ckey = NULL; ctryl = 0; ctry = NULL; utf8 = 0; langnum = 0; complexprefixes = 0; maxSug = maxn; nosplitsugs = 0; maxngramsugs = MAXNGRAMSUGS; maxcpdsugs = MAXCOMPOUNDSUGS; if (pAMgr) { langnum = pAMgr->get_langnum(); ckey = pAMgr->get_key_string(); nosplitsugs = pAMgr->get_nosplitsugs(); if (pAMgr->get_maxngramsugs() >= 0) maxngramsugs = pAMgr->get_maxngramsugs(); utf8 = pAMgr->get_utf8(); if (pAMgr->get_maxcpdsugs() >= 0) maxcpdsugs = pAMgr->get_maxcpdsugs(); if (!utf8) { csconv = get_current_cs(pAMgr->get_encoding()); } complexprefixes = pAMgr->get_complexprefixes(); } if (ckey) { if (utf8) { ckeyl = u8_u16(ckey_utf, ckey); } else { ckeyl = strlen(ckey); } } if (tryme) { ctry = mystrdup(tryme); if (ctry) ctryl = strlen(ctry); if (ctry && utf8) { ctryl = u8_u16(ctry_utf, tryme); } } } SuggestMgr::~SuggestMgr() { pAMgr = NULL; if (ckey) free(ckey); ckey = NULL; ckeyl = 0; if (ctry) free(ctry); ctry = NULL; ctryl = 0; maxSug = 0; #ifdef MOZILLA_CLIENT delete[] csconv; #endif } void SuggestMgr::testsug(std::vector& wlst, const std::string& candidate, int cpdsuggest, int* timer, clock_t* timelimit) { int cwrd = 1; if (wlst.size() == maxSug) return; for (size_t k = 0; k < wlst.size(); ++k) { if (wlst[k] == candidate) { cwrd = 0; break; } } if ((cwrd) && checkword(candidate, cpdsuggest, timer, timelimit)) { wlst.push_back(candidate); } } // generate suggestions for a misspelled word // pass in address of array of char * pointers // onlycompoundsug: probably bad suggestions (need for ngram sugs, too) void SuggestMgr::suggest(std::vector& slst, const char* w, int* onlycompoundsug) { int nocompoundtwowords = 0; std::vector word_utf; int wl = 0; size_t nsugorig = slst.size(); std::string w2; const char* word = w; size_t oldSug = 0; // word reversing wrapper for complex prefixes if (complexprefixes) { w2.assign(w); if (utf8) reverseword_utf(w2); else reverseword(w2); word = w2.c_str(); } if (utf8) { wl = u8_u16(word_utf, word); if (wl == -1) { return; } } for (int cpdsuggest = 0; (cpdsuggest < 2) && (nocompoundtwowords == 0); cpdsuggest++) { // limit compound suggestion if (cpdsuggest > 0) oldSug = slst.size(); // suggestions for an uppercase word (html -> HTML) if (slst.size() < maxSug) { if (utf8) capchars_utf(slst, &word_utf[0], wl, cpdsuggest); else capchars(slst, word, cpdsuggest); } // perhaps we made a typical fault of spelling if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { replchars(slst, word, cpdsuggest); } // perhaps we made chose the wrong char from a related set if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { mapchars(slst, word, cpdsuggest); } // only suggest compound words when no other suggestion if ((cpdsuggest == 0) && (slst.size() > nsugorig)) nocompoundtwowords = 1; // did we swap the order of chars by mistake if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { if (utf8) swapchar_utf(slst, &word_utf[0], wl, cpdsuggest); else swapchar(slst, word, cpdsuggest); } // did we swap the order of non adjacent chars by mistake if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { if (utf8) longswapchar_utf(slst, &word_utf[0], wl, cpdsuggest); else longswapchar(slst, word, cpdsuggest); } // did we just hit the wrong key in place of a good char (case and keyboard) if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { if (utf8) badcharkey_utf(slst, &word_utf[0], wl, cpdsuggest); else badcharkey(slst, word, cpdsuggest); } // did we add a char that should not be there if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { if (utf8) extrachar_utf(slst, &word_utf[0], wl, cpdsuggest); else extrachar(slst, word, cpdsuggest); } // did we forgot a char if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { if (utf8) forgotchar_utf(slst, &word_utf[0], wl, cpdsuggest); else forgotchar(slst, word, cpdsuggest); } // did we move a char if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { if (utf8) movechar_utf(slst, &word_utf[0], wl, cpdsuggest); else movechar(slst, word, cpdsuggest); } // did we just hit the wrong key in place of a good char if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { if (utf8) badchar_utf(slst, &word_utf[0], wl, cpdsuggest); else badchar(slst, word, cpdsuggest); } // did we double two characters if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { if (utf8) doubletwochars_utf(slst, &word_utf[0], wl, cpdsuggest); else doubletwochars(slst, word, cpdsuggest); } // perhaps we forgot to hit space and two words ran together if (!nosplitsugs && (slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { twowords(slst, word, cpdsuggest); } } // repeating ``for'' statement compounding support if (!nocompoundtwowords && (!slst.empty()) && onlycompoundsug) *onlycompoundsug = 1; } // suggestions for an uppercase word (html -> HTML) void SuggestMgr::capchars_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { std::vector candidate_utf(word, word + wl); mkallcap_utf(candidate_utf, langnum); std::string candidate; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } // suggestions for an uppercase word (html -> HTML) void SuggestMgr::capchars(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate(word); mkallcap(candidate, csconv); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } // suggestions for when chose the wrong char out of a related set int SuggestMgr::mapchars(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate; clock_t timelimit; int timer; int wl = strlen(word); if (wl < 2 || !pAMgr) return wlst.size(); const std::vector& maptable = pAMgr->get_maptable(); if (maptable.empty()) return wlst.size(); timelimit = clock(); timer = MINTIMER; return map_related(word, candidate, 0, wlst, cpdsuggest, maptable, &timer, &timelimit); } int SuggestMgr::map_related(const char* word, std::string& candidate, int wn, std::vector& wlst, int cpdsuggest, const std::vector& maptable, int* timer, clock_t* timelimit) { if (*(word + wn) == '\0') { int cwrd = 1; for (size_t m = 0; m < wlst.size(); ++m) { if (wlst[m] == candidate) { cwrd = 0; break; } } if ((cwrd) && checkword(candidate, cpdsuggest, timer, timelimit)) { if (wlst.size() < maxSug) { wlst.push_back(candidate); } } return wlst.size(); } int in_map = 0; for (size_t j = 0; j < maptable.size(); ++j) { for (size_t k = 0; k < maptable[j].size(); ++k) { size_t len = maptable[j][k].size(); if (strncmp(maptable[j][k].c_str(), word + wn, len) == 0) { in_map = 1; size_t cn = candidate.size(); for (size_t l = 0; l < maptable[j].size(); ++l) { candidate.resize(cn); candidate.append(maptable[j][l]); map_related(word, candidate, wn + len, wlst, cpdsuggest, maptable, timer, timelimit); if (!(*timer)) return wlst.size(); } } } } if (!in_map) { candidate.push_back(*(word + wn)); map_related(word, candidate, wn + 1, wlst, cpdsuggest, maptable, timer, timelimit); } return wlst.size(); } // suggestions for a typical fault of spelling, that // differs with more, than 1 letter from the right form. int SuggestMgr::replchars(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate; int wl = strlen(word); if (wl < 2 || !pAMgr) return wlst.size(); const std::vector& reptable = pAMgr->get_reptable(); for (size_t i = 0; i < reptable.size(); ++i) { const char* r = word; // search every occurence of the pattern in the word while ((r = strstr(r, reptable[i].pattern.c_str())) != NULL) { int type = (r == word) ? 1 : 0; if (r - word + reptable[i].pattern.size() == strlen(word)) type += 2; while (type && reptable[i].outstrings[type].empty()) type = (type == 2 && r != word) ? 0 : type - 1; const std::string&out = reptable[i].outstrings[type]; if (out.empty()) { ++r; continue; } candidate.assign(word); candidate.resize(r - word); candidate.append(reptable[i].outstrings[type]); candidate.append(r + reptable[i].pattern.size()); testsug(wlst, candidate, cpdsuggest, NULL, NULL); // check REP suggestions with space size_t sp = candidate.find(' '); if (sp != std::string::npos) { size_t prev = 0; while (sp != std::string::npos) { std::string prev_chunk = candidate.substr(prev, sp - prev); if (checkword(prev_chunk, 0, NULL, NULL)) { size_t oldns = wlst.size(); std::string post_chunk = candidate.substr(sp + 1); testsug(wlst, post_chunk, cpdsuggest, NULL, NULL); if (oldns < wlst.size()) { wlst[wlst.size() - 1] = candidate; } } prev = sp + 1; sp = candidate.find(' ', prev); } } r++; // search for the next letter } } return wlst.size(); } // perhaps we doubled two characters (pattern aba -> ababa, for example vacation // -> vacacation) int SuggestMgr::doubletwochars(std::vector& wlst, const char* word, int cpdsuggest) { int state = 0; int wl = strlen(word); if (wl < 5 || !pAMgr) return wlst.size(); for (int i = 2; i < wl; i++) { if (word[i] == word[i - 2]) { state++; if (state == 3) { std::string candidate(word, word + i - 1); candidate.insert(candidate.end(), word + i + 1, word + wl); testsug(wlst, candidate, cpdsuggest, NULL, NULL); state = 0; } } else { state = 0; } } return wlst.size(); } // perhaps we doubled two characters (pattern aba -> ababa, for example vacation // -> vacacation) int SuggestMgr::doubletwochars_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { int state = 0; if (wl < 5 || !pAMgr) return wlst.size(); for (int i = 2; i < wl; i++) { if (word[i] == word[i - 2]) { state++; if (state == 3) { std::vector candidate_utf(word, word + i - 1); candidate_utf.insert(candidate_utf.end(), word + i + 1, word + wl); std::string candidate; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); state = 0; } } else { state = 0; } } return wlst.size(); } // error is wrong char in place of correct one (case and keyboard related // version) int SuggestMgr::badcharkey(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate(word); // swap out each char one by one and try uppercase and neighbor // keyboard chars in its place to see if that makes a good word for (size_t i = 0; i < candidate.size(); ++i) { char tmpc = candidate[i]; // check with uppercase letters candidate[i] = csconv[((unsigned char)tmpc)].cupper; if (tmpc != candidate[i]) { testsug(wlst, candidate, cpdsuggest, NULL, NULL); candidate[i] = tmpc; } // check neighbor characters in keyboard string if (!ckey) continue; char* loc = strchr(ckey, tmpc); while (loc) { if ((loc > ckey) && (*(loc - 1) != '|')) { candidate[i] = *(loc - 1); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } if ((*(loc + 1) != '|') && (*(loc + 1) != '\0')) { candidate[i] = *(loc + 1); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } loc = strchr(loc + 1, tmpc); } candidate[i] = tmpc; } return wlst.size(); } // error is wrong char in place of correct one (case and keyboard related // version) int SuggestMgr::badcharkey_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { std::string candidate; std::vector candidate_utf(word, word + wl); // swap out each char one by one and try all the tryme // chars in its place to see if that makes a good word for (int i = 0; i < wl; i++) { w_char tmpc = candidate_utf[i]; // check with uppercase letters candidate_utf[i] = upper_utf(candidate_utf[i], 1); if (tmpc != candidate_utf[i]) { u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); candidate_utf[i] = tmpc; } // check neighbor characters in keyboard string if (!ckey) continue; size_t loc = 0; while ((loc < ckeyl) && ckey_utf[loc] != tmpc) ++loc; while (loc < ckeyl) { if ((loc > 0) && ckey_utf[loc - 1] != W_VLINE) { candidate_utf[i] = ckey_utf[loc - 1]; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } if (((loc + 1) < ckeyl) && (ckey_utf[loc + 1] != W_VLINE)) { candidate_utf[i] = ckey_utf[loc + 1]; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } do { loc++; } while ((loc < ckeyl) && ckey_utf[loc] != tmpc); } candidate_utf[i] = tmpc; } return wlst.size(); } // error is wrong char in place of correct one int SuggestMgr::badchar(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate(word); clock_t timelimit = clock(); int timer = MINTIMER; // swap out each char one by one and try all the tryme // chars in its place to see if that makes a good word for (size_t j = 0; j < ctryl; ++j) { for (std::string::reverse_iterator aI = candidate.rbegin(), aEnd = candidate.rend(); aI != aEnd; ++aI) { char tmpc = *aI; if (ctry[j] == tmpc) continue; *aI = ctry[j]; testsug(wlst, candidate, cpdsuggest, &timer, &timelimit); if (!timer) return wlst.size(); *aI = tmpc; } } return wlst.size(); } // error is wrong char in place of correct one int SuggestMgr::badchar_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { std::vector candidate_utf(word, word + wl); std::string candidate; clock_t timelimit = clock(); int timer = MINTIMER; // swap out each char one by one and try all the tryme // chars in its place to see if that makes a good word for (size_t j = 0; j < ctryl; ++j) { for (int i = wl - 1; i >= 0; i--) { w_char tmpc = candidate_utf[i]; if (tmpc == ctry_utf[j]) continue; candidate_utf[i] = ctry_utf[j]; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, &timer, &timelimit); if (!timer) return wlst.size(); candidate_utf[i] = tmpc; } } return wlst.size(); } // error is word has an extra letter it does not need int SuggestMgr::extrachar_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { std::vector candidate_utf(word, word + wl); if (candidate_utf.size() < 2) return wlst.size(); // try omitting one char of word at a time for (size_t i = 0; i < candidate_utf.size(); ++i) { size_t index = candidate_utf.size() - 1 - i; w_char tmpc = candidate_utf[index]; candidate_utf.erase(candidate_utf.begin() + index); std::string candidate; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); candidate_utf.insert(candidate_utf.begin() + index, tmpc); } return wlst.size(); } // error is word has an extra letter it does not need int SuggestMgr::extrachar(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate(word); if (candidate.size() < 2) return wlst.size(); // try omitting one char of word at a time for (size_t i = 0; i < candidate.size(); ++i) { size_t index = candidate.size() - 1 - i; char tmpc = candidate[index]; candidate.erase(candidate.begin() + index); testsug(wlst, candidate, cpdsuggest, NULL, NULL); candidate.insert(candidate.begin() + index, tmpc); } return wlst.size(); } // error is missing a letter it needs int SuggestMgr::forgotchar(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate(word); clock_t timelimit = clock(); int timer = MINTIMER; // try inserting a tryme character before every letter (and the null // terminator) for (size_t k = 0; k < ctryl; ++k) { for (size_t i = 0; i <= candidate.size(); ++i) { size_t index = candidate.size() - i; candidate.insert(candidate.begin() + index, ctry[k]); testsug(wlst, candidate, cpdsuggest, &timer, &timelimit); if (!timer) return wlst.size(); candidate.erase(candidate.begin() + index); } } return wlst.size(); } // error is missing a letter it needs int SuggestMgr::forgotchar_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { std::vector candidate_utf(word, word + wl); clock_t timelimit = clock(); int timer = MINTIMER; // try inserting a tryme character at the end of the word and before every // letter for (size_t k = 0; k < ctryl; ++k) { for (size_t i = 0; i <= candidate_utf.size(); ++i) { size_t index = candidate_utf.size() - i; candidate_utf.insert(candidate_utf.begin() + index, ctry_utf[k]); std::string candidate; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, &timer, &timelimit); if (!timer) return wlst.size(); candidate_utf.erase(candidate_utf.begin() + index); } } return wlst.size(); } /* error is should have been two words */ int SuggestMgr::twowords(std::vector& wlst, const char* word, int cpdsuggest) { int c2; int forbidden = 0; int cwrd; int wl = strlen(word); if (wl < 3) return wlst.size(); if (langnum == LANG_hu) forbidden = check_forbidden(word, wl); char* candidate = (char*)malloc(wl + 2); strcpy(candidate + 1, word); // split the string into two pieces after every char // if both pieces are good words make them a suggestion for (char* p = candidate + 1; p[1] != '\0'; p++) { p[-1] = *p; // go to end of the UTF-8 character while (utf8 && ((p[1] & 0xc0) == 0x80)) { *p = p[1]; p++; } if (utf8 && p[1] == '\0') break; // last UTF-8 character *p = '\0'; int c1 = checkword(candidate, cpdsuggest, NULL, NULL); if (c1) { c2 = checkword((p + 1), cpdsuggest, NULL, NULL); if (c2) { *p = ' '; // spec. Hungarian code (need a better compound word support) if ((langnum == LANG_hu) && !forbidden && // if 3 repeating letter, use - instead of space (((p[-1] == p[1]) && (((p > candidate + 1) && (p[-1] == p[-2])) || (p[-1] == p[2]))) || // or multiple compounding, with more, than 6 syllables ((c1 == 3) && (c2 >= 2)))) *p = '-'; cwrd = 1; for (size_t k = 0; k < wlst.size(); ++k) { if (wlst[k] == candidate) { cwrd = 0; break; } } if (wlst.size() < maxSug) { if (cwrd) { wlst.push_back(candidate); } } else { free(candidate); return wlst.size(); } // add two word suggestion with dash, if TRY string contains // "a" or "-" // Note that cwrd doesn't modified for REP twoword sugg. if (ctry && (strchr(ctry, 'a') || strchr(ctry, '-')) && mystrlen(p + 1) > 1 && mystrlen(candidate) - mystrlen(p) > 1) { *p = '-'; for (size_t k = 0; k < wlst.size(); ++k) { if (wlst[k] == candidate) { cwrd = 0; break; } } if (wlst.size() < maxSug) { if (cwrd) { wlst.push_back(candidate); } } else { free(candidate); return wlst.size(); } } } } } free(candidate); return wlst.size(); } // error is adjacent letter were swapped int SuggestMgr::swapchar(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate(word); if (candidate.size() < 2) return wlst.size(); // try swapping adjacent chars one by one for (size_t i = 0; i < candidate.size() - 1; ++i) { std::swap(candidate[i], candidate[i+1]); testsug(wlst, candidate, cpdsuggest, NULL, NULL); std::swap(candidate[i], candidate[i+1]); } // try double swaps for short words // ahev -> have, owudl -> would if (candidate.size() == 4 || candidate.size() == 5) { candidate[0] = word[1]; candidate[1] = word[0]; candidate[2] = word[2]; candidate[candidate.size() - 2] = word[candidate.size() - 1]; candidate[candidate.size() - 1] = word[candidate.size() - 2]; testsug(wlst, candidate, cpdsuggest, NULL, NULL); if (candidate.size() == 5) { candidate[0] = word[0]; candidate[1] = word[2]; candidate[2] = word[1]; testsug(wlst, candidate, cpdsuggest, NULL, NULL); } } return wlst.size(); } // error is adjacent letter were swapped int SuggestMgr::swapchar_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { std::vector candidate_utf(word, word + wl); if (candidate_utf.size() < 2) return wlst.size(); std::string candidate; // try swapping adjacent chars one by one for (size_t i = 0; i < candidate_utf.size() - 1; ++i) { std::swap(candidate_utf[i], candidate_utf[i+1]); u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); std::swap(candidate_utf[i], candidate_utf[i+1]); } // try double swaps for short words // ahev -> have, owudl -> would, suodn -> sound if (candidate_utf.size() == 4 || candidate_utf.size() == 5) { candidate_utf[0] = word[1]; candidate_utf[1] = word[0]; candidate_utf[2] = word[2]; candidate_utf[candidate_utf.size() - 2] = word[candidate_utf.size() - 1]; candidate_utf[candidate_utf.size() - 1] = word[candidate_utf.size() - 2]; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); if (candidate_utf.size() == 5) { candidate_utf[0] = word[0]; candidate_utf[1] = word[2]; candidate_utf[2] = word[1]; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } } return wlst.size(); } // error is not adjacent letter were swapped int SuggestMgr::longswapchar(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate(word); // try swapping not adjacent chars one by one for (std::string::iterator p = candidate.begin(); p < candidate.end(); ++p) { for (std::string::iterator q = candidate.begin(); q < candidate.end(); ++q) { if (std::abs(std::distance(q, p)) > 1) { std::swap(*p, *q); testsug(wlst, candidate, cpdsuggest, NULL, NULL); std::swap(*p, *q); } } } return wlst.size(); } // error is adjacent letter were swapped int SuggestMgr::longswapchar_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { std::vector candidate_utf(word, word + wl); // try swapping not adjacent chars for (std::vector::iterator p = candidate_utf.begin(); p < candidate_utf.end(); ++p) { for (std::vector::iterator q = candidate_utf.begin(); q < candidate_utf.end(); ++q) { if (std::abs(std::distance(q, p)) > 1) { std::swap(*p, *q); std::string candidate; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); std::swap(*p, *q); } } } return wlst.size(); } // error is a letter was moved int SuggestMgr::movechar(std::vector& wlst, const char* word, int cpdsuggest) { std::string candidate(word); if (candidate.size() < 2) return wlst.size(); // try moving a char for (std::string::iterator p = candidate.begin(); p < candidate.end(); ++p) { for (std::string::iterator q = p + 1; q < candidate.end() && std::distance(p, q) < 10; ++q) { std::swap(*q, *(q - 1)); if (std::distance(p, q) < 2) continue; // omit swap char testsug(wlst, candidate, cpdsuggest, NULL, NULL); } std::copy(word, word + candidate.size(), candidate.begin()); } for (std::string::reverse_iterator p = candidate.rbegin(), pEnd = candidate.rend() - 1; p != pEnd; ++p) { for (std::string::reverse_iterator q = p + 1, qEnd = candidate.rend(); q != qEnd && std::distance(p, q) < 10; ++q) { std::swap(*q, *(q - 1)); if (std::distance(p, q) < 2) continue; // omit swap char testsug(wlst, candidate, cpdsuggest, NULL, NULL); } std::copy(word, word + candidate.size(), candidate.begin()); } return wlst.size(); } // error is a letter was moved int SuggestMgr::movechar_utf(std::vector& wlst, const w_char* word, int wl, int cpdsuggest) { std::vector candidate_utf(word, word + wl); if (candidate_utf.size() < 2) return wlst.size(); // try moving a char for (std::vector::iterator p = candidate_utf.begin(); p < candidate_utf.end(); ++p) { for (std::vector::iterator q = p + 1; q < candidate_utf.end() && std::distance(p, q) < 10; ++q) { std::swap(*q, *(q - 1)); if (std::distance(p, q) < 2) continue; // omit swap char std::string candidate; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } std::copy(word, word + candidate_utf.size(), candidate_utf.begin()); } for (std::vector::reverse_iterator p = candidate_utf.rbegin(); p < candidate_utf.rend(); ++p) { for (std::vector::reverse_iterator q = p + 1; q < candidate_utf.rend() && std::distance(p, q) < 10; ++q) { std::swap(*q, *(q - 1)); if (std::distance(p, q) < 2) continue; // omit swap char std::string candidate; u16_u8(candidate, candidate_utf); testsug(wlst, candidate, cpdsuggest, NULL, NULL); } std::copy(word, word + candidate_utf.size(), candidate_utf.begin()); } return wlst.size(); } // generate a set of suggestions for very poorly spelled words void SuggestMgr::ngsuggest(std::vector& wlst, const char* w, const std::vector& rHMgr) { int lval; int sc; int lp, lpphon; int nonbmp = 0; // exhaustively search through all root words // keeping track of the MAX_ROOTS most similar root words struct hentry* roots[MAX_ROOTS]; char* rootsphon[MAX_ROOTS]; int scores[MAX_ROOTS]; int scoresphon[MAX_ROOTS]; for (int i = 0; i < MAX_ROOTS; i++) { roots[i] = NULL; scores[i] = -100 * i; rootsphon[i] = NULL; scoresphon[i] = -100 * i; } lp = MAX_ROOTS - 1; lpphon = MAX_ROOTS - 1; int low = NGRAM_LOWERING; std::string w2; const char* word = w; // word reversing wrapper for complex prefixes if (complexprefixes) { w2.assign(w); if (utf8) reverseword_utf(w2); else reverseword(w2); word = w2.c_str(); } std::vector u8; int nc = strlen(word); int n = (utf8) ? u8_u16(u8, word) : nc; // set character based ngram suggestion for words with non-BMP Unicode // characters if (n == -1) { utf8 = 0; // XXX not state-free n = nc; nonbmp = 1; low = 0; } struct hentry* hp = NULL; int col = -1; phonetable* ph = (pAMgr) ? pAMgr->get_phonetable() : NULL; std::string target; std::string candidate; std::vector w_candidate; if (ph) { if (utf8) { u8_u16(w_candidate, word); mkallcap_utf(w_candidate, langnum); u16_u8(candidate, w_candidate); } else { candidate.assign(word); if (!nonbmp) mkallcap(candidate, csconv); } target = phonet(candidate, *ph); // XXX phonet() is 8-bit (nc, not n) } FLAG forbiddenword = pAMgr ? pAMgr->get_forbiddenword() : FLAG_NULL; FLAG nosuggest = pAMgr ? pAMgr->get_nosuggest() : FLAG_NULL; FLAG nongramsuggest = pAMgr ? pAMgr->get_nongramsuggest() : FLAG_NULL; FLAG onlyincompound = pAMgr ? pAMgr->get_onlyincompound() : FLAG_NULL; std::vector w_word, w_target; if (utf8) { u8_u16(w_word, word); u8_u16(w_target, target); } std::string f; std::vector w_f; for (size_t i = 0; i < rHMgr.size(); ++i) { while (0 != (hp = rHMgr[i]->walk_hashtable(col, hp))) { if ((hp->astr) && (pAMgr) && (TESTAFF(hp->astr, forbiddenword, hp->alen) || TESTAFF(hp->astr, ONLYUPCASEFLAG, hp->alen) || TESTAFF(hp->astr, nosuggest, hp->alen) || TESTAFF(hp->astr, nongramsuggest, hp->alen) || TESTAFF(hp->astr, onlyincompound, hp->alen))) continue; if (utf8) { u8_u16(w_f, HENTRY_WORD(hp)); int leftcommon = leftcommonsubstring(w_word, w_f); if (low) { // lowering dictionary word mkallsmall_utf(w_f, langnum); } sc = ngram(3, w_word, w_f, NGRAM_LONGER_WORSE) + leftcommon; } else { f.assign(HENTRY_WORD(hp)); int leftcommon = leftcommonsubstring(word, f.c_str()); if (low) { // lowering dictionary word mkallsmall(f, csconv); } sc = ngram(3, word, f, NGRAM_LONGER_WORSE) + leftcommon; } // check special pronounciation f.clear(); if ((hp->var & H_OPT_PHON) && copy_field(f, HENTRY_DATA(hp), MORPH_PHON)) { int sc2; if (utf8) { u8_u16(w_f, f); int leftcommon = leftcommonsubstring(w_word, w_f); if (low) { // lowering dictionary word mkallsmall_utf(w_f, langnum); } sc2 = ngram(3, w_word, w_f, NGRAM_LONGER_WORSE) + leftcommon; } else { int leftcommon = leftcommonsubstring(word, f.c_str()); if (low) { // lowering dictionary word mkallsmall(f, csconv); } sc2 = ngram(3, word, f, NGRAM_LONGER_WORSE) + leftcommon; } if (sc2 > sc) sc = sc2; } int scphon = -20000; if (ph && (sc > 2) && (abs(n - (int)hp->clen) <= 3)) { if (utf8) { u8_u16(w_candidate, HENTRY_WORD(hp)); mkallcap_utf(w_candidate, langnum); u16_u8(candidate, w_candidate); } else { candidate = HENTRY_WORD(hp); mkallcap(candidate, csconv); } f = phonet(candidate, *ph); if (utf8) { u8_u16(w_f, f); scphon = 2 * ngram(3, w_target, w_f, NGRAM_LONGER_WORSE); } else { scphon = 2 * ngram(3, target, f, NGRAM_LONGER_WORSE); } } if (sc > scores[lp]) { scores[lp] = sc; roots[lp] = hp; lval = sc; for (int j = 0; j < MAX_ROOTS; j++) if (scores[j] < lval) { lp = j; lval = scores[j]; } } if (scphon > scoresphon[lpphon]) { scoresphon[lpphon] = scphon; rootsphon[lpphon] = HENTRY_WORD(hp); lval = scphon; for (int j = 0; j < MAX_ROOTS; j++) if (scoresphon[j] < lval) { lpphon = j; lval = scoresphon[j]; } } } } // find minimum threshold for a passable suggestion // mangle original word three differnt ways // and score them to generate a minimum acceptable score std::vector w_mw; int thresh = 0; for (int sp = 1; sp < 4; sp++) { if (utf8) { w_mw = w_word; for (int k = sp; k < n; k += 4) { w_mw[k].l = '*'; w_mw[k].h = 0; } if (low) { // lowering dictionary word mkallsmall_utf(w_mw, langnum); } thresh += ngram(n, w_word, w_mw, NGRAM_ANY_MISMATCH); } else { std::string mw = word; for (int k = sp; k < n; k += 4) mw[k] = '*'; if (low) { // lowering dictionary word mkallsmall(mw, csconv); } thresh += ngram(n, word, mw, NGRAM_ANY_MISMATCH); } } thresh = thresh / 3; thresh--; // now expand affixes on each of these root words and // and use length adjusted ngram scores to select // possible suggestions char* guess[MAX_GUESS]; char* guessorig[MAX_GUESS]; int gscore[MAX_GUESS]; for (int i = 0; i < MAX_GUESS; i++) { guess[i] = NULL; guessorig[i] = NULL; gscore[i] = -100 * i; } lp = MAX_GUESS - 1; struct guessword* glst; glst = (struct guessword*)calloc(MAX_WORDS, sizeof(struct guessword)); if (!glst) { if (nonbmp) utf8 = 1; return; } for (int i = 0; i < MAX_ROOTS; i++) { if (roots[i]) { struct hentry* rp = roots[i]; f.clear(); const char *field = NULL; if ((rp->var & H_OPT_PHON) && copy_field(f, HENTRY_DATA(rp), MORPH_PHON)) field = f.c_str(); int nw = pAMgr->expand_rootword( glst, MAX_WORDS, HENTRY_WORD(rp), rp->blen, rp->astr, rp->alen, word, nc, field); for (int k = 0; k < nw; k++) { if (utf8) { u8_u16(w_f, glst[k].word); int leftcommon = leftcommonsubstring(w_word, w_f); if (low) { // lowering dictionary word mkallsmall_utf(w_f, langnum); } sc = ngram(n, w_word, w_f, NGRAM_ANY_MISMATCH) + leftcommon; } else { f = glst[k].word; int leftcommon = leftcommonsubstring(word, f.c_str()); if (low) { // lowering dictionary word mkallsmall(f, csconv); } sc = ngram(n, word, f, NGRAM_ANY_MISMATCH) + leftcommon; } if (sc > thresh) { if (sc > gscore[lp]) { if (guess[lp]) { free(guess[lp]); if (guessorig[lp]) { free(guessorig[lp]); guessorig[lp] = NULL; } } gscore[lp] = sc; guess[lp] = glst[k].word; guessorig[lp] = glst[k].orig; lval = sc; for (int j = 0; j < MAX_GUESS; j++) if (gscore[j] < lval) { lp = j; lval = gscore[j]; } } else { free(glst[k].word); if (glst[k].orig) free(glst[k].orig); } } else { free(glst[k].word); if (glst[k].orig) free(glst[k].orig); } } } } free(glst); // now we are done generating guesses // sort in order of decreasing score bubblesort(&guess[0], &guessorig[0], &gscore[0], MAX_GUESS); if (ph) bubblesort(&rootsphon[0], NULL, &scoresphon[0], MAX_ROOTS); // weight suggestions with a similarity index, based on // the longest common subsequent algorithm and resort int is_swap = 0; int re = 0; double fact = 1.0; if (pAMgr) { int maxd = pAMgr->get_maxdiff(); if (maxd >= 0) fact = (10.0 - maxd) / 5.0; } std::vector w_gl; for (int i = 0; i < MAX_GUESS; i++) { if (guess[i]) { // lowering guess[i] std::string gl; int len; if (utf8) { len = u8_u16(w_gl, guess[i]); mkallsmall_utf(w_gl, langnum); u16_u8(gl, w_gl); } else { gl.assign(guess[i]); if (!nonbmp) mkallsmall(gl, csconv); len = strlen(guess[i]); } int _lcs = lcslen(word, gl.c_str()); // same characters with different casing if ((n == len) && (n == _lcs)) { gscore[i] += 2000; break; } // using 2-gram instead of 3, and other weightening if (utf8) { u8_u16(w_gl, gl); //w_gl is lowercase already at this point re = ngram(2, w_word, w_gl, NGRAM_ANY_MISMATCH + NGRAM_WEIGHTED); if (low) { w_f = w_word; // lowering dictionary word mkallsmall_utf(w_f, langnum); re += ngram(2, w_gl, w_f, NGRAM_ANY_MISMATCH + NGRAM_WEIGHTED); } else { re += ngram(2, w_gl, w_word, NGRAM_ANY_MISMATCH + NGRAM_WEIGHTED); } } else { //gl is lowercase already at this point re = ngram(2, word, gl, NGRAM_ANY_MISMATCH + NGRAM_WEIGHTED); if (low) { f = word; // lowering dictionary word mkallsmall(f, csconv); re += ngram(2, gl, f, NGRAM_ANY_MISMATCH + NGRAM_WEIGHTED); } else { re += ngram(2, gl, word, NGRAM_ANY_MISMATCH + NGRAM_WEIGHTED); } } int ngram_score, leftcommon_score; if (utf8) { //w_gl is lowercase already at this point ngram_score = ngram(4, w_word, w_gl, NGRAM_ANY_MISMATCH); leftcommon_score = leftcommonsubstring(w_word, w_gl); } else { //gl is lowercase already at this point ngram_score = ngram(4, word, gl, NGRAM_ANY_MISMATCH); leftcommon_score = leftcommonsubstring(word, gl.c_str()); } gscore[i] = // length of longest common subsequent minus length difference 2 * _lcs - abs((int)(n - len)) + // weight length of the left common substring leftcommon_score + // weight equal character positions (!nonbmp && commoncharacterpositions(word, gl.c_str(), &is_swap) ? 1 : 0) + // swap character (not neighboring) ((is_swap) ? 10 : 0) + // ngram ngram_score + // weighted ngrams re + // different limit for dictionaries with PHONE rules (ph ? (re < len * fact ? -1000 : 0) : (re < (n + len) * fact ? -1000 : 0)); } } bubblesort(&guess[0], &guessorig[0], &gscore[0], MAX_GUESS); // phonetic version if (ph) for (int i = 0; i < MAX_ROOTS; i++) { if (rootsphon[i]) { // lowering rootphon[i] std::string gl; int len; if (utf8) { len = u8_u16(w_gl, rootsphon[i]); mkallsmall_utf(w_gl, langnum); u16_u8(gl, w_gl); } else { gl.assign(rootsphon[i]); if (!nonbmp) mkallsmall(gl, csconv); len = strlen(rootsphon[i]); } // weight length of the left common substring int leftcommon_score; if (utf8) leftcommon_score = leftcommonsubstring(w_word, w_gl); else leftcommon_score = leftcommonsubstring(word, gl.c_str()); // heuristic weigthing of ngram scores scoresphon[i] += 2 * lcslen(word, gl) - abs((int)(n - len)) + leftcommon_score; } } if (ph) bubblesort(&rootsphon[0], NULL, &scoresphon[0], MAX_ROOTS); // copy over size_t oldns = wlst.size(); int same = 0; for (int i = 0; i < MAX_GUESS; i++) { if (guess[i]) { if ((wlst.size() < oldns + maxngramsugs) && (wlst.size() < maxSug) && (!same || (gscore[i] > 1000))) { int unique = 1; // leave only excellent suggestions, if exists if (gscore[i] > 1000) same = 1; else if (gscore[i] < -100) { same = 1; // keep the best ngram suggestions, unless in ONLYMAXDIFF mode if (wlst.size() > oldns || (pAMgr && pAMgr->get_onlymaxdiff())) { free(guess[i]); if (guessorig[i]) free(guessorig[i]); continue; } } for (size_t j = 0; j < wlst.size(); ++j) { // don't suggest previous suggestions or a previous suggestion with // prefixes or affixes if ((!guessorig[i] && strstr(guess[i], wlst[j].c_str())) || (guessorig[i] && strstr(guessorig[i], wlst[j].c_str())) || // check forbidden words !checkword(guess[i], 0, NULL, NULL)) { unique = 0; break; } } if (unique) { if (guessorig[i]) { wlst.push_back(guessorig[i]); } else { wlst.push_back(guess[i]); } } free(guess[i]); if (guessorig[i]) free(guessorig[i]); } else { free(guess[i]); if (guessorig[i]) free(guessorig[i]); } } } oldns = wlst.size(); if (ph) for (int i = 0; i < MAX_ROOTS; i++) { if (rootsphon[i]) { if ((wlst.size() < oldns + MAXPHONSUGS) && (wlst.size() < maxSug)) { int unique = 1; for (size_t j = 0; j < wlst.size(); ++j) { // don't suggest previous suggestions or a previous suggestion with // prefixes or affixes if (strstr(rootsphon[i], wlst[j].c_str()) || // check forbidden words !checkword(rootsphon[i], 0, NULL, NULL)) { unique = 0; break; } } if (unique) { wlst.push_back(rootsphon[i]); } } } } if (nonbmp) utf8 = 1; } // see if a candidate suggestion is spelled correctly // needs to check both root words and words with affixes // obsolote MySpell-HU modifications: // return value 2 and 3 marks compounding with hyphen (-) // `3' marks roots without suffix int SuggestMgr::checkword(const std::string& word, int cpdsuggest, int* timer, clock_t* timelimit) { // check time limit if (timer) { (*timer)--; if (!(*timer) && timelimit) { if ((clock() - *timelimit) > TIMELIMIT) return 0; *timer = MAXPLUSTIMER; } } if (pAMgr) { struct hentry* rv = NULL; int nosuffix = 0; if (cpdsuggest == 1) { if (pAMgr->get_compound()) { struct hentry* rv2 = NULL; struct hentry* rwords[100]; // buffer for COMPOUND pattern checking rv = pAMgr->compound_check(word, 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, 1, 0); // EXT if (rv && (!(rv2 = pAMgr->lookup(word.c_str())) || !rv2->astr || !(TESTAFF(rv2->astr, pAMgr->get_forbiddenword(), rv2->alen) || TESTAFF(rv2->astr, pAMgr->get_nosuggest(), rv2->alen)))) return 3; // XXX obsolote categorisation + only ICONV needs affix // flag check? } return 0; } rv = pAMgr->lookup(word.c_str()); if (rv) { if ((rv->astr) && (TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen))) return 0; while (rv) { if (rv->astr && (TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) { rv = rv->next_homonym; } else break; } } else rv = pAMgr->prefix_check(word.c_str(), word.size(), 0); // only prefix, and prefix + suffix XXX if (rv) { nosuffix = 1; } else { rv = pAMgr->suffix_check(word.c_str(), word.size(), 0, NULL, FLAG_NULL, FLAG_NULL, IN_CPD_NOT); // only suffix } if (!rv && pAMgr->have_contclass()) { rv = pAMgr->suffix_check_twosfx(word.c_str(), word.size(), 0, NULL, FLAG_NULL); if (!rv) rv = pAMgr->prefix_check_twosfx(word.c_str(), word.size(), 1, FLAG_NULL); } // check forbidden words if ((rv) && (rv->astr) && (TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen) || TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) return 0; if (rv) { // XXX obsolote if ((pAMgr->get_compoundflag()) && TESTAFF(rv->astr, pAMgr->get_compoundflag(), rv->alen)) return 2 + nosuffix; return 1; } } return 0; } int SuggestMgr::check_forbidden(const char* word, int len) { if (pAMgr) { struct hentry* rv = pAMgr->lookup(word); if (rv && rv->astr && (TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) rv = NULL; if (!(pAMgr->prefix_check(word, len, 1))) rv = pAMgr->suffix_check(word, len, 0, NULL, FLAG_NULL, FLAG_NULL, IN_CPD_NOT); // prefix+suffix, suffix // check forbidden words if ((rv) && (rv->astr) && TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen)) return 1; } return 0; } std::string SuggestMgr::suggest_morph(const std::string& in_w) { std::string result; struct hentry* rv = NULL; if (!pAMgr) return std::string(); std::string w(in_w); // word reversing wrapper for complex prefixes if (complexprefixes) { if (utf8) reverseword_utf(w); else reverseword(w); } rv = pAMgr->lookup(w.c_str()); while (rv) { if ((!rv->astr) || !(TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) { if (!HENTRY_FIND(rv, MORPH_STEM)) { result.append(" "); result.append(MORPH_STEM); result.append(w); } if (HENTRY_DATA(rv)) { result.append(" "); result.append(HENTRY_DATA2(rv)); } result.append("\n"); } rv = rv->next_homonym; } std::string st = pAMgr->affix_check_morph(w.c_str(), w.size()); if (!st.empty()) { result.append(st); } if (pAMgr->get_compound() && result.empty()) { struct hentry* rwords[100]; // buffer for COMPOUND pattern checking pAMgr->compound_check_morph(w.c_str(), w.size(), 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, result, NULL); } line_uniq(result, MSEP_REC); return result; } static int get_sfxcount(const char* morph) { if (!morph || !*morph) return 0; int n = 0; const char* old = morph; morph = strstr(morph, MORPH_DERI_SFX); if (!morph) morph = strstr(old, MORPH_INFL_SFX); if (!morph) morph = strstr(old, MORPH_TERM_SFX); while (morph) { n++; old = morph; morph = strstr(morph + 1, MORPH_DERI_SFX); if (!morph) morph = strstr(old + 1, MORPH_INFL_SFX); if (!morph) morph = strstr(old + 1, MORPH_TERM_SFX); } return n; } /* affixation */ std::string SuggestMgr::suggest_hentry_gen(hentry* rv, const char* pattern) { std::string result; int sfxcount = get_sfxcount(pattern); if (get_sfxcount(HENTRY_DATA(rv)) > sfxcount) return result; if (HENTRY_DATA(rv)) { std::string aff = pAMgr->morphgen(HENTRY_WORD(rv), rv->blen, rv->astr, rv->alen, HENTRY_DATA(rv), pattern, 0); if (!aff.empty()) { result.append(aff); result.append("\n"); } } // check all allomorphs char* p = NULL; if (HENTRY_DATA(rv)) p = (char*)strstr(HENTRY_DATA2(rv), MORPH_ALLOMORPH); while (p) { p += MORPH_TAG_LEN; int plen = fieldlen(p); std::string allomorph(p, plen); struct hentry* rv2 = pAMgr->lookup(allomorph.c_str()); while (rv2) { // if (HENTRY_DATA(rv2) && get_sfxcount(HENTRY_DATA(rv2)) <= // sfxcount) { if (HENTRY_DATA(rv2)) { char* st = (char*)strstr(HENTRY_DATA2(rv2), MORPH_STEM); if (st && (strncmp(st + MORPH_TAG_LEN, HENTRY_WORD(rv), fieldlen(st + MORPH_TAG_LEN)) == 0)) { std::string aff = pAMgr->morphgen(HENTRY_WORD(rv2), rv2->blen, rv2->astr, rv2->alen, HENTRY_DATA(rv2), pattern, 0); if (!aff.empty()) { result.append(aff); result.append("\n"); } } } rv2 = rv2->next_homonym; } p = strstr(p + plen, MORPH_ALLOMORPH); } return result; } std::string SuggestMgr::suggest_gen(const std::vector& desc, const std::string& in_pattern) { if (desc.empty() || !pAMgr) return std::string(); const char* pattern = in_pattern.c_str(); std::string result2; std::string newpattern; struct hentry* rv = NULL; // search affixed forms with and without derivational suffixes while (1) { for (size_t k = 0; k < desc.size(); ++k) { std::string result; // add compound word parts (except the last one) const char* s = desc[k].c_str(); const char* part = strstr(s, MORPH_PART); if (part) { const char* nextpart = strstr(part + 1, MORPH_PART); while (nextpart) { std::string field; copy_field(field, part, MORPH_PART); result.append(field); part = nextpart; nextpart = strstr(part + 1, MORPH_PART); } s = part; } std::string tok(s); size_t pos = tok.find(" | "); while (pos != std::string::npos) { tok[pos + 1] = MSEP_ALT; pos = tok.find(" | ", pos); } std::vector pl = line_tok(tok, MSEP_ALT); for (size_t i = 0; i < pl.size(); ++i) { // remove inflectional and terminal suffixes size_t is = pl[i].find(MORPH_INFL_SFX); if (is != std::string::npos) pl[i].resize(is); size_t ts = pl[i].find(MORPH_TERM_SFX); while (ts != std::string::npos) { pl[i][ts] = '_'; ts = pl[i].find(MORPH_TERM_SFX); } const char* st = strstr(s, MORPH_STEM); if (st) { copy_field(tok, st, MORPH_STEM); rv = pAMgr->lookup(tok.c_str()); while (rv) { std::string newpat(pl[i]); newpat.append(pattern); std::string sg = suggest_hentry_gen(rv, newpat.c_str()); if (sg.empty()) sg = suggest_hentry_gen(rv, pattern); if (!sg.empty()) { std::vector gen = line_tok(sg, MSEP_REC); for (size_t j = 0; j < gen.size(); ++j) { result2.push_back(MSEP_REC); result2.append(result); if (pl[i].find(MORPH_SURF_PFX) != std::string::npos) { std::string field; copy_field(field, pl[i], MORPH_SURF_PFX); result2.append(field); } result2.append(gen[j]); } } rv = rv->next_homonym; } } } } if (!result2.empty() || !strstr(pattern, MORPH_DERI_SFX)) break; newpattern.assign(pattern); mystrrep(newpattern, MORPH_DERI_SFX, MORPH_TERM_SFX); pattern = newpattern.c_str(); } return result2; } // generate an n-gram score comparing s1 and s2, UTF16 version int SuggestMgr::ngram(int n, const std::vector& su1, const std::vector& su2, int opt) { int nscore = 0; int ns; int l1; int l2; int test = 0; l1 = su1.size(); l2 = su2.size(); if (l2 == 0) return 0; for (int j = 1; j <= n; j++) { ns = 0; for (int i = 0; i <= (l1 - j); i++) { int k = 0; for (int l = 0; l <= (l2 - j); l++) { for (k = 0; k < j; k++) { const w_char& c1 = su1[i + k]; const w_char& c2 = su2[l + k]; if ((c1.l != c2.l) || (c1.h != c2.h)) break; } if (k == j) { ns++; break; } } if (k != j && opt & NGRAM_WEIGHTED) { ns--; test++; if (i == 0 || i == l1 - j) ns--; // side weight } } nscore = nscore + ns; if (ns < 2 && !(opt & NGRAM_WEIGHTED)) break; } ns = 0; if (opt & NGRAM_LONGER_WORSE) ns = (l2 - l1) - 2; if (opt & NGRAM_ANY_MISMATCH) ns = abs(l2 - l1) - 2; ns = (nscore - ((ns > 0) ? ns : 0)); return ns; } // generate an n-gram score comparing s1 and s2, non-UTF16 version int SuggestMgr::ngram(int n, const std::string& s1, const std::string& s2, int opt) { int nscore = 0; int ns; int l1; int l2; int test = 0; l2 = s2.size(); if (l2 == 0) return 0; l1 = s1.size(); for (int j = 1; j <= n; j++) { ns = 0; for (int i = 0; i <= (l1 - j); i++) { //s2 is haystack, s1[i..i+j) is needle if (s2.find(s1.c_str()+i, 0, j) != std::string::npos) { ns++; } else if (opt & NGRAM_WEIGHTED) { ns--; test++; if (i == 0 || i == l1 - j) ns--; // side weight } } nscore = nscore + ns; if (ns < 2 && !(opt & NGRAM_WEIGHTED)) break; } ns = 0; if (opt & NGRAM_LONGER_WORSE) ns = (l2 - l1) - 2; if (opt & NGRAM_ANY_MISMATCH) ns = abs(l2 - l1) - 2; ns = (nscore - ((ns > 0) ? ns : 0)); return ns; } // length of the left common substring of s1 and (decapitalised) s2, UTF version int SuggestMgr::leftcommonsubstring( const std::vector& su1, const std::vector& su2) { int l1 = su1.size(); int l2 = su2.size(); // decapitalize dictionary word if (complexprefixes) { if (su1[l1 - 1] == su2[l2 - 1]) return 1; } else { unsigned short idx = su2.empty() ? 0 : (su2[0].h << 8) + su2[0].l; unsigned short otheridx = su1.empty() ? 0 : (su1[0].h << 8) + su1[0].l; if (otheridx != idx && (otheridx != unicodetolower(idx, langnum))) return 0; int i; for (i = 1; (i < l1) && (i < l2) && (su1[i].l == su2[i].l) && (su1[i].h == su2[i].h); i++) ; return i; } return 0; } // length of the left common substring of s1 and (decapitalised) s2, non-UTF int SuggestMgr::leftcommonsubstring( const char* s1, const char* s2) { if (complexprefixes) { int l1 = strlen(s1); int l2 = strlen(s2); if (l1 <= l2 && s2[l1 - 1] == s2[l2 - 1]) return 1; } else if (csconv) { const char* olds = s1; // decapitalise dictionary word if ((*s1 != *s2) && (*s1 != csconv[((unsigned char)*s2)].clower)) return 0; do { s1++; s2++; } while ((*s1 == *s2) && (*s1 != '\0')); return (int)(s1 - olds); } return 0; } int SuggestMgr::commoncharacterpositions(const char* s1, const char* s2, int* is_swap) { int num = 0; int diff = 0; int diffpos[2]; *is_swap = 0; if (utf8) { std::vector su1; std::vector su2; int l1 = u8_u16(su1, s1); int l2 = u8_u16(su2, s2); if (l1 <= 0 || l2 <= 0) return 0; // decapitalize dictionary word if (complexprefixes) { su2[l2 - 1] = lower_utf(su2[l2 - 1], langnum); } else { su2[0] = lower_utf(su2[0], langnum); } for (int i = 0; (i < l1) && (i < l2); i++) { if (su1[i] == su2[i]) { num++; } else { if (diff < 2) diffpos[diff] = i; diff++; } } if ((diff == 2) && (l1 == l2) && (su1[diffpos[0]] == su2[diffpos[1]]) && (su1[diffpos[1]] == su2[diffpos[0]])) *is_swap = 1; } else { size_t i; std::string t(s2); // decapitalize dictionary word if (complexprefixes) { size_t l2 = t.size(); t[l2 - 1] = csconv[(unsigned char)t[l2 - 1]].clower; } else { mkallsmall(t, csconv); } for (i = 0; i < t.size() && (*(s1 + i) != 0); ++i) { if (*(s1 + i) == t[i]) { num++; } else { if (diff < 2) diffpos[diff] = i; diff++; } } if ((diff == 2) && (*(s1 + i) == 0) && i == t.size() && (*(s1 + diffpos[0]) == t[diffpos[1]]) && (*(s1 + diffpos[1]) == t[diffpos[0]])) *is_swap = 1; } return num; } int SuggestMgr::mystrlen(const char* word) { if (utf8) { std::vector w; return u8_u16(w, word); } else return strlen(word); } // sort in decreasing order of score void SuggestMgr::bubblesort(char** rword, char** rword2, int* rsc, int n) { int m = 1; while (m < n) { int j = m; while (j > 0) { if (rsc[j - 1] < rsc[j]) { int sctmp = rsc[j - 1]; char* wdtmp = rword[j - 1]; rsc[j - 1] = rsc[j]; rword[j - 1] = rword[j]; rsc[j] = sctmp; rword[j] = wdtmp; if (rword2) { wdtmp = rword2[j - 1]; rword2[j - 1] = rword2[j]; rword2[j] = wdtmp; } j--; } else break; } m++; } return; } // longest common subsequence void SuggestMgr::lcs(const char* s, const char* s2, int* l1, int* l2, char** result) { int n, m; std::vector su; std::vector su2; char* b; char* c; int i; int j; if (utf8) { m = u8_u16(su, s); n = u8_u16(su2, s2); } else { m = strlen(s); n = strlen(s2); } c = (char*)malloc((m + 1) * (n + 1)); b = (char*)malloc((m + 1) * (n + 1)); if (!c || !b) { if (c) free(c); if (b) free(b); *result = NULL; return; } for (i = 1; i <= m; i++) c[i * (n + 1)] = 0; for (j = 0; j <= n; j++) c[j] = 0; for (i = 1; i <= m; i++) { for (j = 1; j <= n; j++) { if (((utf8) && (su[i - 1] == su2[j - 1])) || ((!utf8) && (s[i - 1] == s2[j - 1]))) { c[i * (n + 1) + j] = c[(i - 1) * (n + 1) + j - 1] + 1; b[i * (n + 1) + j] = LCS_UPLEFT; } else if (c[(i - 1) * (n + 1) + j] >= c[i * (n + 1) + j - 1]) { c[i * (n + 1) + j] = c[(i - 1) * (n + 1) + j]; b[i * (n + 1) + j] = LCS_UP; } else { c[i * (n + 1) + j] = c[i * (n + 1) + j - 1]; b[i * (n + 1) + j] = LCS_LEFT; } } } *result = b; free(c); *l1 = m; *l2 = n; } int SuggestMgr::lcslen(const char* s, const char* s2) { int m; int n; int i; int j; char* result; int len = 0; lcs(s, s2, &m, &n, &result); if (!result) return 0; i = m; j = n; while ((i != 0) && (j != 0)) { if (result[i * (n + 1) + j] == LCS_UPLEFT) { len++; i--; j--; } else if (result[i * (n + 1) + j] == LCS_UP) { i--; } else j--; } free(result); return len; } int SuggestMgr::lcslen(const std::string& s, const std::string& s2) { return lcslen(s.c_str(), s2.c_str()); } nuspell-5.1.7/external/hunspell/hunspell/suggestmgr.hxx000066400000000000000000000173101511132717100234350ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada * And Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All modifications to the source code must be clearly marked as * such. Binary redistributions based on modified source code * must be clearly marked as modified versions in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef SUGGESTMGR_HXX_ #define SUGGESTMGR_HXX_ #define MAX_ROOTS 100 #define MAX_WORDS 100 #define MAX_GUESS 200 #define MAXNGRAMSUGS 4 #define MAXPHONSUGS 2 #define MAXCOMPOUNDSUGS 3 // timelimit: max ~1/4 sec (process time on Linux) for a time consuming function #define TIMELIMIT (CLOCKS_PER_SEC / 4) #define MINTIMER 100 #define MAXPLUSTIMER 100 #define NGRAM_LONGER_WORSE (1 << 0) #define NGRAM_ANY_MISMATCH (1 << 1) #define NGRAM_LOWERING (1 << 2) #define NGRAM_WEIGHTED (1 << 3) #include "atypes.hxx" #include "affixmgr.hxx" #include "hashmgr.hxx" #include "langnum.hxx" #include enum { LCS_UP, LCS_LEFT, LCS_UPLEFT }; class SuggestMgr { private: SuggestMgr(const SuggestMgr&); SuggestMgr& operator=(const SuggestMgr&); private: char* ckey; size_t ckeyl; std::vector ckey_utf; char* ctry; size_t ctryl; std::vector ctry_utf; AffixMgr* pAMgr; unsigned int maxSug; struct cs_info* csconv; int utf8; int langnum; int nosplitsugs; int maxngramsugs; int maxcpdsugs; int complexprefixes; public: SuggestMgr(const char* tryme, unsigned int maxn, AffixMgr* aptr); ~SuggestMgr(); void suggest(std::vector& slst, const char* word, int* onlycmpdsug); void ngsuggest(std::vector& slst, const char* word, const std::vector& rHMgr); std::string suggest_morph(const std::string& word); std::string suggest_gen(const std::vector& pl, const std::string& pattern); private: void testsug(std::vector& wlst, const std::string& candidate, int cpdsuggest, int* timer, clock_t* timelimit); int checkword(const std::string& word, int, int*, clock_t*); int check_forbidden(const char*, int); void capchars(std::vector&, const char*, int); int replchars(std::vector&, const char*, int); int doubletwochars(std::vector&, const char*, int); int forgotchar(std::vector&, const char*, int); int swapchar(std::vector&, const char*, int); int longswapchar(std::vector&, const char*, int); int movechar(std::vector&, const char*, int); int extrachar(std::vector&, const char*, int); int badcharkey(std::vector&, const char*, int); int badchar(std::vector&, const char*, int); int twowords(std::vector&, const char*, int); void capchars_utf(std::vector&, const w_char*, int wl, int); int doubletwochars_utf(std::vector&, const w_char*, int wl, int); int forgotchar_utf(std::vector&, const w_char*, int wl, int); int extrachar_utf(std::vector&, const w_char*, int wl, int); int badcharkey_utf(std::vector&, const w_char*, int wl, int); int badchar_utf(std::vector&, const w_char*, int wl, int); int swapchar_utf(std::vector&, const w_char*, int wl, int); int longswapchar_utf(std::vector&, const w_char*, int, int); int movechar_utf(std::vector&, const w_char*, int, int); int mapchars(std::vector&, const char*, int); int map_related(const char*, std::string&, int, std::vector& wlst, int, const std::vector&, int*, clock_t*); int ngram(int n, const std::vector& su1, const std::vector& su2, int opt); int ngram(int n, const std::string& s1, const std::string& s2, int opt); int mystrlen(const char* word); int leftcommonsubstring(const std::vector& su1, const std::vector& su2); int leftcommonsubstring(const char* s1, const char* s2); int commoncharacterpositions(const char* s1, const char* s2, int* is_swap); void bubblesort(char** rwd, char** rwd2, int* rsc, int n); void lcs(const char* s, const char* s2, int* l1, int* l2, char** result); int lcslen(const char* s, const char* s2); int lcslen(const std::string& s, const std::string& s2); std::string suggest_hentry_gen(hentry* rv, const char* pattern); }; #endif nuspell-5.1.7/external/hunspell/hunspell/utf_info.hxx000066400000000000000000020677771511132717100231070ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ // Unicode character encoding information struct unicode_info { unsigned short c; unsigned short cupper; unsigned short clower; }; /* fields: Unicode letter, toupper, tolower */ static const struct unicode_info utf_lst[] = { {0x0041, 0x0041, 0x0061}, {0x0042, 0x0042, 0x0062}, {0x0043, 0x0043, 0x0063}, {0x0044, 0x0044, 0x0064}, {0x0045, 0x0045, 0x0065}, {0x0046, 0x0046, 0x0066}, {0x0047, 0x0047, 0x0067}, {0x0048, 0x0048, 0x0068}, {0x0049, 0x0049, 0x0069}, {0x004A, 0x004A, 0x006A}, {0x004B, 0x004B, 0x006B}, {0x004C, 0x004C, 0x006C}, {0x004D, 0x004D, 0x006D}, {0x004E, 0x004E, 0x006E}, {0x004F, 0x004F, 0x006F}, {0x0050, 0x0050, 0x0070}, {0x0051, 0x0051, 0x0071}, {0x0052, 0x0052, 0x0072}, {0x0053, 0x0053, 0x0073}, {0x0054, 0x0054, 0x0074}, {0x0055, 0x0055, 0x0075}, {0x0056, 0x0056, 0x0076}, {0x0057, 0x0057, 0x0077}, {0x0058, 0x0058, 0x0078}, {0x0059, 0x0059, 0x0079}, {0x005A, 0x005A, 0x007A}, {0x0061, 0x0041, 0x0061}, {0x0062, 0x0042, 0x0062}, {0x0063, 0x0043, 0x0063}, {0x0064, 0x0044, 0x0064}, {0x0065, 0x0045, 0x0065}, {0x0066, 0x0046, 0x0066}, {0x0067, 0x0047, 0x0067}, {0x0068, 0x0048, 0x0068}, {0x0069, 0x0049, 0x0069}, {0x006A, 0x004A, 0x006A}, {0x006B, 0x004B, 0x006B}, {0x006C, 0x004C, 0x006C}, {0x006D, 0x004D, 0x006D}, {0x006E, 0x004E, 0x006E}, {0x006F, 0x004F, 0x006F}, {0x0070, 0x0050, 0x0070}, {0x0071, 0x0051, 0x0071}, {0x0072, 0x0052, 0x0072}, {0x0073, 0x0053, 0x0073}, {0x0074, 0x0054, 0x0074}, {0x0075, 0x0055, 0x0075}, {0x0076, 0x0056, 0x0076}, {0x0077, 0x0057, 0x0077}, {0x0078, 0x0058, 0x0078}, {0x0079, 0x0059, 0x0079}, {0x007A, 0x005A, 0x007A}, {0x00AA, 0x00AA, 0x00AA}, {0x00B5, 0x039C, 0x00B5}, {0x00BA, 0x00BA, 0x00BA}, {0x00C0, 0x00C0, 0x00E0}, {0x00C1, 0x00C1, 0x00E1}, {0x00C2, 0x00C2, 0x00E2}, {0x00C3, 0x00C3, 0x00E3}, {0x00C4, 0x00C4, 0x00E4}, {0x00C5, 0x00C5, 0x00E5}, {0x00C6, 0x00C6, 0x00E6}, {0x00C7, 0x00C7, 0x00E7}, {0x00C8, 0x00C8, 0x00E8}, {0x00C9, 0x00C9, 0x00E9}, {0x00CA, 0x00CA, 0x00EA}, {0x00CB, 0x00CB, 0x00EB}, {0x00CC, 0x00CC, 0x00EC}, {0x00CD, 0x00CD, 0x00ED}, {0x00CE, 0x00CE, 0x00EE}, {0x00CF, 0x00CF, 0x00EF}, {0x00D0, 0x00D0, 0x00F0}, {0x00D1, 0x00D1, 0x00F1}, {0x00D2, 0x00D2, 0x00F2}, {0x00D3, 0x00D3, 0x00F3}, {0x00D4, 0x00D4, 0x00F4}, {0x00D5, 0x00D5, 0x00F5}, {0x00D6, 0x00D6, 0x00F6}, {0x00D8, 0x00D8, 0x00F8}, {0x00D9, 0x00D9, 0x00F9}, {0x00DA, 0x00DA, 0x00FA}, {0x00DB, 0x00DB, 0x00FB}, {0x00DC, 0x00DC, 0x00FC}, {0x00DD, 0x00DD, 0x00FD}, {0x00DE, 0x00DE, 0x00FE}, {0x00DF, 0x00DF, 0x00DF}, {0x00E0, 0x00C0, 0x00E0}, {0x00E1, 0x00C1, 0x00E1}, {0x00E2, 0x00C2, 0x00E2}, {0x00E3, 0x00C3, 0x00E3}, {0x00E4, 0x00C4, 0x00E4}, {0x00E5, 0x00C5, 0x00E5}, {0x00E6, 0x00C6, 0x00E6}, {0x00E7, 0x00C7, 0x00E7}, {0x00E8, 0x00C8, 0x00E8}, {0x00E9, 0x00C9, 0x00E9}, {0x00EA, 0x00CA, 0x00EA}, {0x00EB, 0x00CB, 0x00EB}, {0x00EC, 0x00CC, 0x00EC}, {0x00ED, 0x00CD, 0x00ED}, {0x00EE, 0x00CE, 0x00EE}, {0x00EF, 0x00CF, 0x00EF}, {0x00F0, 0x00D0, 0x00F0}, {0x00F1, 0x00D1, 0x00F1}, {0x00F2, 0x00D2, 0x00F2}, {0x00F3, 0x00D3, 0x00F3}, {0x00F4, 0x00D4, 0x00F4}, {0x00F5, 0x00D5, 0x00F5}, {0x00F6, 0x00D6, 0x00F6}, {0x00F8, 0x00D8, 0x00F8}, {0x00F9, 0x00D9, 0x00F9}, {0x00FA, 0x00DA, 0x00FA}, {0x00FB, 0x00DB, 0x00FB}, {0x00FC, 0x00DC, 0x00FC}, {0x00FD, 0x00DD, 0x00FD}, {0x00FE, 0x00DE, 0x00FE}, {0x00FF, 0x0178, 0x00FF}, {0x0100, 0x0100, 0x0101}, {0x0101, 0x0100, 0x0101}, {0x0102, 0x0102, 0x0103}, {0x0103, 0x0102, 0x0103}, {0x0104, 0x0104, 0x0105}, {0x0105, 0x0104, 0x0105}, {0x0106, 0x0106, 0x0107}, {0x0107, 0x0106, 0x0107}, {0x0108, 0x0108, 0x0109}, {0x0109, 0x0108, 0x0109}, {0x010A, 0x010A, 0x010B}, {0x010B, 0x010A, 0x010B}, {0x010C, 0x010C, 0x010D}, {0x010D, 0x010C, 0x010D}, {0x010E, 0x010E, 0x010F}, {0x010F, 0x010E, 0x010F}, {0x0110, 0x0110, 0x0111}, {0x0111, 0x0110, 0x0111}, {0x0112, 0x0112, 0x0113}, {0x0113, 0x0112, 0x0113}, {0x0114, 0x0114, 0x0115}, {0x0115, 0x0114, 0x0115}, {0x0116, 0x0116, 0x0117}, {0x0117, 0x0116, 0x0117}, {0x0118, 0x0118, 0x0119}, {0x0119, 0x0118, 0x0119}, {0x011A, 0x011A, 0x011B}, {0x011B, 0x011A, 0x011B}, {0x011C, 0x011C, 0x011D}, {0x011D, 0x011C, 0x011D}, {0x011E, 0x011E, 0x011F}, {0x011F, 0x011E, 0x011F}, {0x0120, 0x0120, 0x0121}, {0x0121, 0x0120, 0x0121}, {0x0122, 0x0122, 0x0123}, {0x0123, 0x0122, 0x0123}, {0x0124, 0x0124, 0x0125}, {0x0125, 0x0124, 0x0125}, {0x0126, 0x0126, 0x0127}, {0x0127, 0x0126, 0x0127}, {0x0128, 0x0128, 0x0129}, {0x0129, 0x0128, 0x0129}, {0x012A, 0x012A, 0x012B}, {0x012B, 0x012A, 0x012B}, {0x012C, 0x012C, 0x012D}, {0x012D, 0x012C, 0x012D}, {0x012E, 0x012E, 0x012F}, {0x012F, 0x012E, 0x012F}, {0x0130, 0x0130, 0x0069}, {0x0131, 0x0049, 0x0131}, {0x0132, 0x0132, 0x0133}, {0x0133, 0x0132, 0x0133}, {0x0134, 0x0134, 0x0135}, {0x0135, 0x0134, 0x0135}, {0x0136, 0x0136, 0x0137}, {0x0137, 0x0136, 0x0137}, {0x0138, 0x0138, 0x0138}, {0x0139, 0x0139, 0x013A}, {0x013A, 0x0139, 0x013A}, {0x013B, 0x013B, 0x013C}, {0x013C, 0x013B, 0x013C}, {0x013D, 0x013D, 0x013E}, {0x013E, 0x013D, 0x013E}, {0x013F, 0x013F, 0x0140}, {0x0140, 0x013F, 0x0140}, {0x0141, 0x0141, 0x0142}, {0x0142, 0x0141, 0x0142}, {0x0143, 0x0143, 0x0144}, {0x0144, 0x0143, 0x0144}, {0x0145, 0x0145, 0x0146}, {0x0146, 0x0145, 0x0146}, {0x0147, 0x0147, 0x0148}, {0x0148, 0x0147, 0x0148}, {0x0149, 0x0149, 0x0149}, {0x014A, 0x014A, 0x014B}, {0x014B, 0x014A, 0x014B}, {0x014C, 0x014C, 0x014D}, {0x014D, 0x014C, 0x014D}, {0x014E, 0x014E, 0x014F}, {0x014F, 0x014E, 0x014F}, {0x0150, 0x0150, 0x0151}, {0x0151, 0x0150, 0x0151}, {0x0152, 0x0152, 0x0153}, {0x0153, 0x0152, 0x0153}, {0x0154, 0x0154, 0x0155}, {0x0155, 0x0154, 0x0155}, {0x0156, 0x0156, 0x0157}, {0x0157, 0x0156, 0x0157}, {0x0158, 0x0158, 0x0159}, {0x0159, 0x0158, 0x0159}, {0x015A, 0x015A, 0x015B}, {0x015B, 0x015A, 0x015B}, {0x015C, 0x015C, 0x015D}, {0x015D, 0x015C, 0x015D}, {0x015E, 0x015E, 0x015F}, {0x015F, 0x015E, 0x015F}, {0x0160, 0x0160, 0x0161}, {0x0161, 0x0160, 0x0161}, {0x0162, 0x0162, 0x0163}, {0x0163, 0x0162, 0x0163}, {0x0164, 0x0164, 0x0165}, {0x0165, 0x0164, 0x0165}, {0x0166, 0x0166, 0x0167}, {0x0167, 0x0166, 0x0167}, {0x0168, 0x0168, 0x0169}, {0x0169, 0x0168, 0x0169}, {0x016A, 0x016A, 0x016B}, {0x016B, 0x016A, 0x016B}, {0x016C, 0x016C, 0x016D}, {0x016D, 0x016C, 0x016D}, {0x016E, 0x016E, 0x016F}, {0x016F, 0x016E, 0x016F}, {0x0170, 0x0170, 0x0171}, {0x0171, 0x0170, 0x0171}, {0x0172, 0x0172, 0x0173}, {0x0173, 0x0172, 0x0173}, {0x0174, 0x0174, 0x0175}, {0x0175, 0x0174, 0x0175}, {0x0176, 0x0176, 0x0177}, {0x0177, 0x0176, 0x0177}, {0x0178, 0x0178, 0x00FF}, {0x0179, 0x0179, 0x017A}, {0x017A, 0x0179, 0x017A}, {0x017B, 0x017B, 0x017C}, {0x017C, 0x017B, 0x017C}, {0x017D, 0x017D, 0x017E}, {0x017E, 0x017D, 0x017E}, {0x017F, 0x0053, 0x017F}, {0x0180, 0x0180, 0x0180}, {0x0181, 0x0181, 0x0253}, {0x0182, 0x0182, 0x0183}, {0x0183, 0x0182, 0x0183}, {0x0184, 0x0184, 0x0185}, {0x0185, 0x0184, 0x0185}, {0x0186, 0x0186, 0x0254}, {0x0187, 0x0187, 0x0188}, {0x0188, 0x0187, 0x0188}, {0x0189, 0x0189, 0x0256}, {0x018A, 0x018A, 0x0257}, {0x018B, 0x018B, 0x018C}, {0x018C, 0x018B, 0x018C}, {0x018D, 0x018D, 0x018D}, {0x018E, 0x018E, 0x01DD}, {0x018F, 0x018F, 0x0259}, {0x0190, 0x0190, 0x025B}, {0x0191, 0x0191, 0x0192}, {0x0192, 0x0191, 0x0192}, {0x0193, 0x0193, 0x0260}, {0x0194, 0x0194, 0x0263}, {0x0195, 0x01F6, 0x0195}, {0x0196, 0x0196, 0x0269}, {0x0197, 0x0197, 0x0268}, {0x0198, 0x0198, 0x0199}, {0x0199, 0x0198, 0x0199}, {0x019A, 0x023D, 0x019A}, {0x019B, 0x019B, 0x019B}, {0x019C, 0x019C, 0x026F}, {0x019D, 0x019D, 0x0272}, {0x019E, 0x0220, 0x019E}, {0x019F, 0x019F, 0x0275}, {0x01A0, 0x01A0, 0x01A1}, {0x01A1, 0x01A0, 0x01A1}, {0x01A2, 0x01A2, 0x01A3}, {0x01A3, 0x01A2, 0x01A3}, {0x01A4, 0x01A4, 0x01A5}, {0x01A5, 0x01A4, 0x01A5}, {0x01A6, 0x01A6, 0x0280}, {0x01A7, 0x01A7, 0x01A8}, {0x01A8, 0x01A7, 0x01A8}, {0x01A9, 0x01A9, 0x0283}, {0x01AA, 0x01AA, 0x01AA}, {0x01AB, 0x01AB, 0x01AB}, {0x01AC, 0x01AC, 0x01AD}, {0x01AD, 0x01AC, 0x01AD}, {0x01AE, 0x01AE, 0x0288}, {0x01AF, 0x01AF, 0x01B0}, {0x01B0, 0x01AF, 0x01B0}, {0x01B1, 0x01B1, 0x028A}, {0x01B2, 0x01B2, 0x028B}, {0x01B3, 0x01B3, 0x01B4}, {0x01B4, 0x01B3, 0x01B4}, {0x01B5, 0x01B5, 0x01B6}, {0x01B6, 0x01B5, 0x01B6}, {0x01B7, 0x01B7, 0x0292}, {0x01B8, 0x01B8, 0x01B9}, {0x01B9, 0x01B8, 0x01B9}, {0x01BA, 0x01BA, 0x01BA}, {0x01BB, 0x01BB, 0x01BB}, {0x01BC, 0x01BC, 0x01BD}, {0x01BD, 0x01BC, 0x01BD}, {0x01BE, 0x01BE, 0x01BE}, {0x01BF, 0x01F7, 0x01BF}, {0x01C0, 0x01C0, 0x01C0}, {0x01C1, 0x01C1, 0x01C1}, {0x01C2, 0x01C2, 0x01C2}, {0x01C3, 0x01C3, 0x01C3}, {0x01C4, 0x01C4, 0x01C6}, {0x01C5, 0x01C4, 0x01C6}, {0x01C6, 0x01C4, 0x01C6}, {0x01C7, 0x01C7, 0x01C9}, {0x01C8, 0x01C7, 0x01C9}, {0x01C9, 0x01C7, 0x01C9}, {0x01CA, 0x01CA, 0x01CC}, {0x01CB, 0x01CA, 0x01CC}, {0x01CC, 0x01CA, 0x01CC}, {0x01CD, 0x01CD, 0x01CE}, {0x01CE, 0x01CD, 0x01CE}, {0x01CF, 0x01CF, 0x01D0}, {0x01D0, 0x01CF, 0x01D0}, {0x01D1, 0x01D1, 0x01D2}, {0x01D2, 0x01D1, 0x01D2}, {0x01D3, 0x01D3, 0x01D4}, {0x01D4, 0x01D3, 0x01D4}, {0x01D5, 0x01D5, 0x01D6}, {0x01D6, 0x01D5, 0x01D6}, {0x01D7, 0x01D7, 0x01D8}, {0x01D8, 0x01D7, 0x01D8}, {0x01D9, 0x01D9, 0x01DA}, {0x01DA, 0x01D9, 0x01DA}, {0x01DB, 0x01DB, 0x01DC}, {0x01DC, 0x01DB, 0x01DC}, {0x01DD, 0x018E, 0x01DD}, {0x01DE, 0x01DE, 0x01DF}, {0x01DF, 0x01DE, 0x01DF}, {0x01E0, 0x01E0, 0x01E1}, {0x01E1, 0x01E0, 0x01E1}, {0x01E2, 0x01E2, 0x01E3}, {0x01E3, 0x01E2, 0x01E3}, {0x01E4, 0x01E4, 0x01E5}, {0x01E5, 0x01E4, 0x01E5}, {0x01E6, 0x01E6, 0x01E7}, {0x01E7, 0x01E6, 0x01E7}, {0x01E8, 0x01E8, 0x01E9}, {0x01E9, 0x01E8, 0x01E9}, {0x01EA, 0x01EA, 0x01EB}, {0x01EB, 0x01EA, 0x01EB}, {0x01EC, 0x01EC, 0x01ED}, {0x01ED, 0x01EC, 0x01ED}, {0x01EE, 0x01EE, 0x01EF}, {0x01EF, 0x01EE, 0x01EF}, {0x01F0, 0x01F0, 0x01F0}, {0x01F1, 0x01F1, 0x01F3}, {0x01F2, 0x01F1, 0x01F3}, {0x01F3, 0x01F1, 0x01F3}, {0x01F4, 0x01F4, 0x01F5}, {0x01F5, 0x01F4, 0x01F5}, {0x01F6, 0x01F6, 0x0195}, {0x01F7, 0x01F7, 0x01BF}, {0x01F8, 0x01F8, 0x01F9}, {0x01F9, 0x01F8, 0x01F9}, {0x01FA, 0x01FA, 0x01FB}, {0x01FB, 0x01FA, 0x01FB}, {0x01FC, 0x01FC, 0x01FD}, {0x01FD, 0x01FC, 0x01FD}, {0x01FE, 0x01FE, 0x01FF}, {0x01FF, 0x01FE, 0x01FF}, {0x0200, 0x0200, 0x0201}, {0x0201, 0x0200, 0x0201}, {0x0202, 0x0202, 0x0203}, {0x0203, 0x0202, 0x0203}, {0x0204, 0x0204, 0x0205}, {0x0205, 0x0204, 0x0205}, {0x0206, 0x0206, 0x0207}, {0x0207, 0x0206, 0x0207}, {0x0208, 0x0208, 0x0209}, {0x0209, 0x0208, 0x0209}, {0x020A, 0x020A, 0x020B}, {0x020B, 0x020A, 0x020B}, {0x020C, 0x020C, 0x020D}, {0x020D, 0x020C, 0x020D}, {0x020E, 0x020E, 0x020F}, {0x020F, 0x020E, 0x020F}, {0x0210, 0x0210, 0x0211}, {0x0211, 0x0210, 0x0211}, {0x0212, 0x0212, 0x0213}, {0x0213, 0x0212, 0x0213}, {0x0214, 0x0214, 0x0215}, {0x0215, 0x0214, 0x0215}, {0x0216, 0x0216, 0x0217}, {0x0217, 0x0216, 0x0217}, {0x0218, 0x0218, 0x0219}, {0x0219, 0x0218, 0x0219}, {0x021A, 0x021A, 0x021B}, {0x021B, 0x021A, 0x021B}, {0x021C, 0x021C, 0x021D}, {0x021D, 0x021C, 0x021D}, {0x021E, 0x021E, 0x021F}, {0x021F, 0x021E, 0x021F}, {0x0220, 0x0220, 0x019E}, {0x0221, 0x0221, 0x0221}, {0x0222, 0x0222, 0x0223}, {0x0223, 0x0222, 0x0223}, {0x0224, 0x0224, 0x0225}, {0x0225, 0x0224, 0x0225}, {0x0226, 0x0226, 0x0227}, {0x0227, 0x0226, 0x0227}, {0x0228, 0x0228, 0x0229}, {0x0229, 0x0228, 0x0229}, {0x022A, 0x022A, 0x022B}, {0x022B, 0x022A, 0x022B}, {0x022C, 0x022C, 0x022D}, {0x022D, 0x022C, 0x022D}, {0x022E, 0x022E, 0x022F}, {0x022F, 0x022E, 0x022F}, {0x0230, 0x0230, 0x0231}, {0x0231, 0x0230, 0x0231}, {0x0232, 0x0232, 0x0233}, {0x0233, 0x0232, 0x0233}, {0x0234, 0x0234, 0x0234}, {0x0235, 0x0235, 0x0235}, {0x0236, 0x0236, 0x0236}, {0x0237, 0x0237, 0x0237}, {0x0238, 0x0238, 0x0238}, {0x0239, 0x0239, 0x0239}, {0x023A, 0x023A, 0x023A}, {0x023B, 0x023B, 0x023C}, {0x023C, 0x023B, 0x023C}, {0x023D, 0x023D, 0x019A}, {0x023E, 0x023E, 0x023E}, {0x023F, 0x023F, 0x023F}, {0x0240, 0x0240, 0x0240}, {0x0241, 0x0241, 0x0294}, {0x0250, 0x0250, 0x0250}, {0x0251, 0x0251, 0x0251}, {0x0252, 0x0252, 0x0252}, {0x0253, 0x0181, 0x0253}, {0x0254, 0x0186, 0x0254}, {0x0255, 0x0255, 0x0255}, {0x0256, 0x0189, 0x0256}, {0x0257, 0x018A, 0x0257}, {0x0258, 0x0258, 0x0258}, {0x0259, 0x018F, 0x0259}, {0x025A, 0x025A, 0x025A}, {0x025B, 0x0190, 0x025B}, {0x025C, 0x025C, 0x025C}, {0x025D, 0x025D, 0x025D}, {0x025E, 0x025E, 0x025E}, {0x025F, 0x025F, 0x025F}, {0x0260, 0x0193, 0x0260}, {0x0261, 0x0261, 0x0261}, {0x0262, 0x0262, 0x0262}, {0x0263, 0x0194, 0x0263}, {0x0264, 0x0264, 0x0264}, {0x0265, 0x0265, 0x0265}, {0x0266, 0x0266, 0x0266}, {0x0267, 0x0267, 0x0267}, {0x0268, 0x0197, 0x0268}, {0x0269, 0x0196, 0x0269}, {0x026A, 0x026A, 0x026A}, {0x026B, 0x026B, 0x026B}, {0x026C, 0x026C, 0x026C}, {0x026D, 0x026D, 0x026D}, {0x026E, 0x026E, 0x026E}, {0x026F, 0x019C, 0x026F}, {0x0270, 0x0270, 0x0270}, {0x0271, 0x0271, 0x0271}, {0x0272, 0x019D, 0x0272}, {0x0273, 0x0273, 0x0273}, {0x0274, 0x0274, 0x0274}, {0x0275, 0x019F, 0x0275}, {0x0276, 0x0276, 0x0276}, {0x0277, 0x0277, 0x0277}, {0x0278, 0x0278, 0x0278}, {0x0279, 0x0279, 0x0279}, {0x027A, 0x027A, 0x027A}, {0x027B, 0x027B, 0x027B}, {0x027C, 0x027C, 0x027C}, {0x027D, 0x027D, 0x027D}, {0x027E, 0x027E, 0x027E}, {0x027F, 0x027F, 0x027F}, {0x0280, 0x01A6, 0x0280}, {0x0281, 0x0281, 0x0281}, {0x0282, 0x0282, 0x0282}, {0x0283, 0x01A9, 0x0283}, {0x0284, 0x0284, 0x0284}, {0x0285, 0x0285, 0x0285}, {0x0286, 0x0286, 0x0286}, {0x0287, 0x0287, 0x0287}, {0x0288, 0x01AE, 0x0288}, {0x0289, 0x0289, 0x0289}, {0x028A, 0x01B1, 0x028A}, {0x028B, 0x01B2, 0x028B}, {0x028C, 0x028C, 0x028C}, {0x028D, 0x028D, 0x028D}, {0x028E, 0x028E, 0x028E}, {0x028F, 0x028F, 0x028F}, {0x0290, 0x0290, 0x0290}, {0x0291, 0x0291, 0x0291}, {0x0292, 0x01B7, 0x0292}, {0x0293, 0x0293, 0x0293}, {0x0294, 0x0241, 0x0294}, {0x0295, 0x0295, 0x0295}, {0x0296, 0x0296, 0x0296}, {0x0297, 0x0297, 0x0297}, {0x0298, 0x0298, 0x0298}, {0x0299, 0x0299, 0x0299}, {0x029A, 0x029A, 0x029A}, {0x029B, 0x029B, 0x029B}, {0x029C, 0x029C, 0x029C}, {0x029D, 0x029D, 0x029D}, {0x029E, 0x029E, 0x029E}, {0x029F, 0x029F, 0x029F}, {0x02A0, 0x02A0, 0x02A0}, {0x02A1, 0x02A1, 0x02A1}, {0x02A2, 0x02A2, 0x02A2}, {0x02A3, 0x02A3, 0x02A3}, {0x02A4, 0x02A4, 0x02A4}, {0x02A5, 0x02A5, 0x02A5}, {0x02A6, 0x02A6, 0x02A6}, {0x02A7, 0x02A7, 0x02A7}, {0x02A8, 0x02A8, 0x02A8}, {0x02A9, 0x02A9, 0x02A9}, {0x02AA, 0x02AA, 0x02AA}, {0x02AB, 0x02AB, 0x02AB}, {0x02AC, 0x02AC, 0x02AC}, {0x02AD, 0x02AD, 0x02AD}, {0x02AE, 0x02AE, 0x02AE}, {0x02AF, 0x02AF, 0x02AF}, {0x02B0, 0x02B0, 0x02B0}, {0x02B1, 0x02B1, 0x02B1}, {0x02B2, 0x02B2, 0x02B2}, {0x02B3, 0x02B3, 0x02B3}, {0x02B4, 0x02B4, 0x02B4}, {0x02B5, 0x02B5, 0x02B5}, {0x02B6, 0x02B6, 0x02B6}, {0x02B7, 0x02B7, 0x02B7}, {0x02B8, 0x02B8, 0x02B8}, {0x02B9, 0x02B9, 0x02B9}, {0x02BA, 0x02BA, 0x02BA}, {0x02BB, 0x02BB, 0x02BB}, {0x02BC, 0x02BC, 0x02BC}, {0x02BD, 0x02BD, 0x02BD}, {0x02BE, 0x02BE, 0x02BE}, {0x02BF, 0x02BF, 0x02BF}, {0x02C0, 0x02C0, 0x02C0}, {0x02C1, 0x02C1, 0x02C1}, {0x02C6, 0x02C6, 0x02C6}, {0x02C7, 0x02C7, 0x02C7}, {0x02C8, 0x02C8, 0x02C8}, {0x02C9, 0x02C9, 0x02C9}, {0x02CA, 0x02CA, 0x02CA}, {0x02CB, 0x02CB, 0x02CB}, {0x02CC, 0x02CC, 0x02CC}, {0x02CD, 0x02CD, 0x02CD}, {0x02CE, 0x02CE, 0x02CE}, {0x02CF, 0x02CF, 0x02CF}, {0x02D0, 0x02D0, 0x02D0}, {0x02D1, 0x02D1, 0x02D1}, {0x02E0, 0x02E0, 0x02E0}, {0x02E1, 0x02E1, 0x02E1}, {0x02E2, 0x02E2, 0x02E2}, {0x02E3, 0x02E3, 0x02E3}, {0x02E4, 0x02E4, 0x02E4}, {0x02EE, 0x02EE, 0x02EE}, {0x0300, 0x0300, 0x0300}, {0x0301, 0x0301, 0x0301}, {0x0302, 0x0302, 0x0302}, {0x0303, 0x0303, 0x0303}, {0x0304, 0x0304, 0x0304}, {0x0305, 0x0305, 0x0305}, {0x0306, 0x0306, 0x0306}, {0x0307, 0x0307, 0x0307}, {0x0308, 0x0308, 0x0308}, {0x0309, 0x0309, 0x0309}, {0x030A, 0x030A, 0x030A}, {0x030B, 0x030B, 0x030B}, {0x030C, 0x030C, 0x030C}, {0x030D, 0x030D, 0x030D}, {0x030E, 0x030E, 0x030E}, {0x030F, 0x030F, 0x030F}, {0x0310, 0x0310, 0x0310}, {0x0311, 0x0311, 0x0311}, {0x0312, 0x0312, 0x0312}, {0x0313, 0x0313, 0x0313}, {0x0314, 0x0314, 0x0314}, {0x0315, 0x0315, 0x0315}, {0x0316, 0x0316, 0x0316}, {0x0317, 0x0317, 0x0317}, {0x0318, 0x0318, 0x0318}, {0x0319, 0x0319, 0x0319}, {0x031A, 0x031A, 0x031A}, {0x031B, 0x031B, 0x031B}, {0x031C, 0x031C, 0x031C}, {0x031D, 0x031D, 0x031D}, {0x031E, 0x031E, 0x031E}, {0x031F, 0x031F, 0x031F}, {0x0320, 0x0320, 0x0320}, {0x0321, 0x0321, 0x0321}, {0x0322, 0x0322, 0x0322}, {0x0323, 0x0323, 0x0323}, {0x0324, 0x0324, 0x0324}, {0x0325, 0x0325, 0x0325}, {0x0326, 0x0326, 0x0326}, {0x0327, 0x0327, 0x0327}, {0x0328, 0x0328, 0x0328}, {0x0329, 0x0329, 0x0329}, {0x032A, 0x032A, 0x032A}, {0x032B, 0x032B, 0x032B}, {0x032C, 0x032C, 0x032C}, {0x032D, 0x032D, 0x032D}, {0x032E, 0x032E, 0x032E}, {0x032F, 0x032F, 0x032F}, {0x0330, 0x0330, 0x0330}, {0x0331, 0x0331, 0x0331}, {0x0332, 0x0332, 0x0332}, {0x0333, 0x0333, 0x0333}, {0x0334, 0x0334, 0x0334}, {0x0335, 0x0335, 0x0335}, {0x0336, 0x0336, 0x0336}, {0x0337, 0x0337, 0x0337}, {0x0338, 0x0338, 0x0338}, {0x0339, 0x0339, 0x0339}, {0x033A, 0x033A, 0x033A}, {0x033B, 0x033B, 0x033B}, {0x033C, 0x033C, 0x033C}, {0x033D, 0x033D, 0x033D}, {0x033E, 0x033E, 0x033E}, {0x033F, 0x033F, 0x033F}, {0x0340, 0x0340, 0x0340}, {0x0341, 0x0341, 0x0341}, {0x0342, 0x0342, 0x0342}, {0x0343, 0x0343, 0x0343}, {0x0344, 0x0344, 0x0344}, {0x0345, 0x0399, 0x0345}, {0x0346, 0x0346, 0x0346}, {0x0347, 0x0347, 0x0347}, {0x0348, 0x0348, 0x0348}, {0x0349, 0x0349, 0x0349}, {0x034A, 0x034A, 0x034A}, {0x034B, 0x034B, 0x034B}, {0x034C, 0x034C, 0x034C}, {0x034D, 0x034D, 0x034D}, {0x034E, 0x034E, 0x034E}, {0x034F, 0x034F, 0x034F}, {0x0350, 0x0350, 0x0350}, {0x0351, 0x0351, 0x0351}, {0x0352, 0x0352, 0x0352}, {0x0353, 0x0353, 0x0353}, {0x0354, 0x0354, 0x0354}, {0x0355, 0x0355, 0x0355}, {0x0356, 0x0356, 0x0356}, {0x0357, 0x0357, 0x0357}, {0x0358, 0x0358, 0x0358}, {0x0359, 0x0359, 0x0359}, {0x035A, 0x035A, 0x035A}, {0x035B, 0x035B, 0x035B}, {0x035C, 0x035C, 0x035C}, {0x035D, 0x035D, 0x035D}, {0x035E, 0x035E, 0x035E}, {0x035F, 0x035F, 0x035F}, {0x0360, 0x0360, 0x0360}, {0x0361, 0x0361, 0x0361}, {0x0362, 0x0362, 0x0362}, {0x0363, 0x0363, 0x0363}, {0x0364, 0x0364, 0x0364}, {0x0365, 0x0365, 0x0365}, {0x0366, 0x0366, 0x0366}, {0x0367, 0x0367, 0x0367}, {0x0368, 0x0368, 0x0368}, {0x0369, 0x0369, 0x0369}, {0x036A, 0x036A, 0x036A}, {0x036B, 0x036B, 0x036B}, {0x036C, 0x036C, 0x036C}, {0x036D, 0x036D, 0x036D}, {0x036E, 0x036E, 0x036E}, {0x036F, 0x036F, 0x036F}, {0x037A, 0x037A, 0x037A}, {0x0386, 0x0386, 0x03AC}, {0x0388, 0x0388, 0x03AD}, {0x0389, 0x0389, 0x03AE}, {0x038A, 0x038A, 0x03AF}, {0x038C, 0x038C, 0x03CC}, {0x038E, 0x038E, 0x03CD}, {0x038F, 0x038F, 0x03CE}, {0x0390, 0x0390, 0x0390}, {0x0391, 0x0391, 0x03B1}, {0x0392, 0x0392, 0x03B2}, {0x0393, 0x0393, 0x03B3}, {0x0394, 0x0394, 0x03B4}, {0x0395, 0x0395, 0x03B5}, {0x0396, 0x0396, 0x03B6}, {0x0397, 0x0397, 0x03B7}, {0x0398, 0x0398, 0x03B8}, {0x0399, 0x0399, 0x03B9}, {0x039A, 0x039A, 0x03BA}, {0x039B, 0x039B, 0x03BB}, {0x039C, 0x039C, 0x03BC}, {0x039D, 0x039D, 0x03BD}, {0x039E, 0x039E, 0x03BE}, {0x039F, 0x039F, 0x03BF}, {0x03A0, 0x03A0, 0x03C0}, {0x03A1, 0x03A1, 0x03C1}, {0x03A3, 0x03A3, 0x03C3}, {0x03A4, 0x03A4, 0x03C4}, {0x03A5, 0x03A5, 0x03C5}, {0x03A6, 0x03A6, 0x03C6}, {0x03A7, 0x03A7, 0x03C7}, {0x03A8, 0x03A8, 0x03C8}, {0x03A9, 0x03A9, 0x03C9}, {0x03AA, 0x03AA, 0x03CA}, {0x03AB, 0x03AB, 0x03CB}, {0x03AC, 0x0386, 0x03AC}, {0x03AD, 0x0388, 0x03AD}, {0x03AE, 0x0389, 0x03AE}, {0x03AF, 0x038A, 0x03AF}, {0x03B0, 0x03B0, 0x03B0}, {0x03B1, 0x0391, 0x03B1}, {0x03B2, 0x0392, 0x03B2}, {0x03B3, 0x0393, 0x03B3}, {0x03B4, 0x0394, 0x03B4}, {0x03B5, 0x0395, 0x03B5}, {0x03B6, 0x0396, 0x03B6}, {0x03B7, 0x0397, 0x03B7}, {0x03B8, 0x0398, 0x03B8}, {0x03B9, 0x0399, 0x03B9}, {0x03BA, 0x039A, 0x03BA}, {0x03BB, 0x039B, 0x03BB}, {0x03BC, 0x039C, 0x03BC}, {0x03BD, 0x039D, 0x03BD}, {0x03BE, 0x039E, 0x03BE}, {0x03BF, 0x039F, 0x03BF}, {0x03C0, 0x03A0, 0x03C0}, {0x03C1, 0x03A1, 0x03C1}, {0x03C2, 0x03A3, 0x03C2}, {0x03C3, 0x03A3, 0x03C3}, {0x03C4, 0x03A4, 0x03C4}, {0x03C5, 0x03A5, 0x03C5}, {0x03C6, 0x03A6, 0x03C6}, {0x03C7, 0x03A7, 0x03C7}, {0x03C8, 0x03A8, 0x03C8}, {0x03C9, 0x03A9, 0x03C9}, {0x03CA, 0x03AA, 0x03CA}, {0x03CB, 0x03AB, 0x03CB}, {0x03CC, 0x038C, 0x03CC}, {0x03CD, 0x038E, 0x03CD}, {0x03CE, 0x038F, 0x03CE}, {0x03D0, 0x0392, 0x03D0}, {0x03D1, 0x0398, 0x03D1}, {0x03D2, 0x03D2, 0x03D2}, {0x03D3, 0x03D3, 0x03D3}, {0x03D4, 0x03D4, 0x03D4}, {0x03D5, 0x03A6, 0x03D5}, {0x03D6, 0x03A0, 0x03D6}, {0x03D7, 0x03D7, 0x03D7}, {0x03D8, 0x03D8, 0x03D9}, {0x03D9, 0x03D8, 0x03D9}, {0x03DA, 0x03DA, 0x03DB}, {0x03DB, 0x03DA, 0x03DB}, {0x03DC, 0x03DC, 0x03DD}, {0x03DD, 0x03DC, 0x03DD}, {0x03DE, 0x03DE, 0x03DF}, {0x03DF, 0x03DE, 0x03DF}, {0x03E0, 0x03E0, 0x03E1}, {0x03E1, 0x03E0, 0x03E1}, {0x03E2, 0x03E2, 0x03E3}, {0x03E3, 0x03E2, 0x03E3}, {0x03E4, 0x03E4, 0x03E5}, {0x03E5, 0x03E4, 0x03E5}, {0x03E6, 0x03E6, 0x03E7}, {0x03E7, 0x03E6, 0x03E7}, {0x03E8, 0x03E8, 0x03E9}, {0x03E9, 0x03E8, 0x03E9}, {0x03EA, 0x03EA, 0x03EB}, {0x03EB, 0x03EA, 0x03EB}, {0x03EC, 0x03EC, 0x03ED}, {0x03ED, 0x03EC, 0x03ED}, {0x03EE, 0x03EE, 0x03EF}, {0x03EF, 0x03EE, 0x03EF}, {0x03F0, 0x039A, 0x03F0}, {0x03F1, 0x03A1, 0x03F1}, {0x03F2, 0x03F9, 0x03F2}, {0x03F3, 0x03F3, 0x03F3}, {0x03F4, 0x03F4, 0x03B8}, {0x03F5, 0x0395, 0x03F5}, {0x03F7, 0x03F7, 0x03F8}, {0x03F8, 0x03F7, 0x03F8}, {0x03F9, 0x03F9, 0x03F2}, {0x03FA, 0x03FA, 0x03FB}, {0x03FB, 0x03FA, 0x03FB}, {0x03FC, 0x03FC, 0x03FC}, {0x03FD, 0x03FD, 0x03FD}, {0x03FE, 0x03FE, 0x03FE}, {0x03FF, 0x03FF, 0x03FF}, {0x0400, 0x0400, 0x0450}, {0x0401, 0x0401, 0x0451}, {0x0402, 0x0402, 0x0452}, {0x0403, 0x0403, 0x0453}, {0x0404, 0x0404, 0x0454}, {0x0405, 0x0405, 0x0455}, {0x0406, 0x0406, 0x0456}, {0x0407, 0x0407, 0x0457}, {0x0408, 0x0408, 0x0458}, {0x0409, 0x0409, 0x0459}, {0x040A, 0x040A, 0x045A}, {0x040B, 0x040B, 0x045B}, {0x040C, 0x040C, 0x045C}, {0x040D, 0x040D, 0x045D}, {0x040E, 0x040E, 0x045E}, {0x040F, 0x040F, 0x045F}, {0x0410, 0x0410, 0x0430}, {0x0411, 0x0411, 0x0431}, {0x0412, 0x0412, 0x0432}, {0x0413, 0x0413, 0x0433}, {0x0414, 0x0414, 0x0434}, {0x0415, 0x0415, 0x0435}, {0x0416, 0x0416, 0x0436}, {0x0417, 0x0417, 0x0437}, {0x0418, 0x0418, 0x0438}, {0x0419, 0x0419, 0x0439}, {0x041A, 0x041A, 0x043A}, {0x041B, 0x041B, 0x043B}, {0x041C, 0x041C, 0x043C}, {0x041D, 0x041D, 0x043D}, {0x041E, 0x041E, 0x043E}, {0x041F, 0x041F, 0x043F}, {0x0420, 0x0420, 0x0440}, {0x0421, 0x0421, 0x0441}, {0x0422, 0x0422, 0x0442}, {0x0423, 0x0423, 0x0443}, {0x0424, 0x0424, 0x0444}, {0x0425, 0x0425, 0x0445}, {0x0426, 0x0426, 0x0446}, {0x0427, 0x0427, 0x0447}, {0x0428, 0x0428, 0x0448}, {0x0429, 0x0429, 0x0449}, {0x042A, 0x042A, 0x044A}, {0x042B, 0x042B, 0x044B}, {0x042C, 0x042C, 0x044C}, {0x042D, 0x042D, 0x044D}, {0x042E, 0x042E, 0x044E}, {0x042F, 0x042F, 0x044F}, {0x0430, 0x0410, 0x0430}, {0x0431, 0x0411, 0x0431}, {0x0432, 0x0412, 0x0432}, {0x0433, 0x0413, 0x0433}, {0x0434, 0x0414, 0x0434}, {0x0435, 0x0415, 0x0435}, {0x0436, 0x0416, 0x0436}, {0x0437, 0x0417, 0x0437}, {0x0438, 0x0418, 0x0438}, {0x0439, 0x0419, 0x0439}, {0x043A, 0x041A, 0x043A}, {0x043B, 0x041B, 0x043B}, {0x043C, 0x041C, 0x043C}, {0x043D, 0x041D, 0x043D}, {0x043E, 0x041E, 0x043E}, {0x043F, 0x041F, 0x043F}, {0x0440, 0x0420, 0x0440}, {0x0441, 0x0421, 0x0441}, {0x0442, 0x0422, 0x0442}, {0x0443, 0x0423, 0x0443}, {0x0444, 0x0424, 0x0444}, {0x0445, 0x0425, 0x0445}, {0x0446, 0x0426, 0x0446}, {0x0447, 0x0427, 0x0447}, {0x0448, 0x0428, 0x0448}, {0x0449, 0x0429, 0x0449}, {0x044A, 0x042A, 0x044A}, {0x044B, 0x042B, 0x044B}, {0x044C, 0x042C, 0x044C}, {0x044D, 0x042D, 0x044D}, {0x044E, 0x042E, 0x044E}, {0x044F, 0x042F, 0x044F}, {0x0450, 0x0400, 0x0450}, {0x0451, 0x0401, 0x0451}, {0x0452, 0x0402, 0x0452}, {0x0453, 0x0403, 0x0453}, {0x0454, 0x0404, 0x0454}, {0x0455, 0x0405, 0x0455}, {0x0456, 0x0406, 0x0456}, {0x0457, 0x0407, 0x0457}, {0x0458, 0x0408, 0x0458}, {0x0459, 0x0409, 0x0459}, {0x045A, 0x040A, 0x045A}, {0x045B, 0x040B, 0x045B}, {0x045C, 0x040C, 0x045C}, {0x045D, 0x040D, 0x045D}, {0x045E, 0x040E, 0x045E}, {0x045F, 0x040F, 0x045F}, {0x0460, 0x0460, 0x0461}, {0x0461, 0x0460, 0x0461}, {0x0462, 0x0462, 0x0463}, {0x0463, 0x0462, 0x0463}, {0x0464, 0x0464, 0x0465}, {0x0465, 0x0464, 0x0465}, {0x0466, 0x0466, 0x0467}, {0x0467, 0x0466, 0x0467}, {0x0468, 0x0468, 0x0469}, {0x0469, 0x0468, 0x0469}, {0x046A, 0x046A, 0x046B}, {0x046B, 0x046A, 0x046B}, {0x046C, 0x046C, 0x046D}, {0x046D, 0x046C, 0x046D}, {0x046E, 0x046E, 0x046F}, {0x046F, 0x046E, 0x046F}, {0x0470, 0x0470, 0x0471}, {0x0471, 0x0470, 0x0471}, {0x0472, 0x0472, 0x0473}, {0x0473, 0x0472, 0x0473}, {0x0474, 0x0474, 0x0475}, {0x0475, 0x0474, 0x0475}, {0x0476, 0x0476, 0x0477}, {0x0477, 0x0476, 0x0477}, {0x0478, 0x0478, 0x0479}, {0x0479, 0x0478, 0x0479}, {0x047A, 0x047A, 0x047B}, {0x047B, 0x047A, 0x047B}, {0x047C, 0x047C, 0x047D}, {0x047D, 0x047C, 0x047D}, {0x047E, 0x047E, 0x047F}, {0x047F, 0x047E, 0x047F}, {0x0480, 0x0480, 0x0481}, {0x0481, 0x0480, 0x0481}, {0x0483, 0x0483, 0x0483}, {0x0484, 0x0484, 0x0484}, {0x0485, 0x0485, 0x0485}, {0x0486, 0x0486, 0x0486}, {0x048A, 0x048A, 0x048B}, {0x048B, 0x048A, 0x048B}, {0x048C, 0x048C, 0x048D}, {0x048D, 0x048C, 0x048D}, {0x048E, 0x048E, 0x048F}, {0x048F, 0x048E, 0x048F}, {0x0490, 0x0490, 0x0491}, {0x0491, 0x0490, 0x0491}, {0x0492, 0x0492, 0x0493}, {0x0493, 0x0492, 0x0493}, {0x0494, 0x0494, 0x0495}, {0x0495, 0x0494, 0x0495}, {0x0496, 0x0496, 0x0497}, {0x0497, 0x0496, 0x0497}, {0x0498, 0x0498, 0x0499}, {0x0499, 0x0498, 0x0499}, {0x049A, 0x049A, 0x049B}, {0x049B, 0x049A, 0x049B}, {0x049C, 0x049C, 0x049D}, {0x049D, 0x049C, 0x049D}, {0x049E, 0x049E, 0x049F}, {0x049F, 0x049E, 0x049F}, {0x04A0, 0x04A0, 0x04A1}, {0x04A1, 0x04A0, 0x04A1}, {0x04A2, 0x04A2, 0x04A3}, {0x04A3, 0x04A2, 0x04A3}, {0x04A4, 0x04A4, 0x04A5}, {0x04A5, 0x04A4, 0x04A5}, {0x04A6, 0x04A6, 0x04A7}, {0x04A7, 0x04A6, 0x04A7}, {0x04A8, 0x04A8, 0x04A9}, {0x04A9, 0x04A8, 0x04A9}, {0x04AA, 0x04AA, 0x04AB}, {0x04AB, 0x04AA, 0x04AB}, {0x04AC, 0x04AC, 0x04AD}, {0x04AD, 0x04AC, 0x04AD}, {0x04AE, 0x04AE, 0x04AF}, {0x04AF, 0x04AE, 0x04AF}, {0x04B0, 0x04B0, 0x04B1}, {0x04B1, 0x04B0, 0x04B1}, {0x04B2, 0x04B2, 0x04B3}, {0x04B3, 0x04B2, 0x04B3}, {0x04B4, 0x04B4, 0x04B5}, {0x04B5, 0x04B4, 0x04B5}, {0x04B6, 0x04B6, 0x04B7}, {0x04B7, 0x04B6, 0x04B7}, {0x04B8, 0x04B8, 0x04B9}, {0x04B9, 0x04B8, 0x04B9}, {0x04BA, 0x04BA, 0x04BB}, {0x04BB, 0x04BA, 0x04BB}, {0x04BC, 0x04BC, 0x04BD}, {0x04BD, 0x04BC, 0x04BD}, {0x04BE, 0x04BE, 0x04BF}, {0x04BF, 0x04BE, 0x04BF}, {0x04C0, 0x04C0, 0x04C0}, {0x04C1, 0x04C1, 0x04C2}, {0x04C2, 0x04C1, 0x04C2}, {0x04C3, 0x04C3, 0x04C4}, {0x04C4, 0x04C3, 0x04C4}, {0x04C5, 0x04C5, 0x04C6}, {0x04C6, 0x04C5, 0x04C6}, {0x04C7, 0x04C7, 0x04C8}, {0x04C8, 0x04C7, 0x04C8}, {0x04C9, 0x04C9, 0x04CA}, {0x04CA, 0x04C9, 0x04CA}, {0x04CB, 0x04CB, 0x04CC}, {0x04CC, 0x04CB, 0x04CC}, {0x04CD, 0x04CD, 0x04CE}, {0x04CE, 0x04CD, 0x04CE}, {0x04D0, 0x04D0, 0x04D1}, {0x04D1, 0x04D0, 0x04D1}, {0x04D2, 0x04D2, 0x04D3}, {0x04D3, 0x04D2, 0x04D3}, {0x04D4, 0x04D4, 0x04D5}, {0x04D5, 0x04D4, 0x04D5}, {0x04D6, 0x04D6, 0x04D7}, {0x04D7, 0x04D6, 0x04D7}, {0x04D8, 0x04D8, 0x04D9}, {0x04D9, 0x04D8, 0x04D9}, {0x04DA, 0x04DA, 0x04DB}, {0x04DB, 0x04DA, 0x04DB}, {0x04DC, 0x04DC, 0x04DD}, {0x04DD, 0x04DC, 0x04DD}, {0x04DE, 0x04DE, 0x04DF}, {0x04DF, 0x04DE, 0x04DF}, {0x04E0, 0x04E0, 0x04E1}, {0x04E1, 0x04E0, 0x04E1}, {0x04E2, 0x04E2, 0x04E3}, {0x04E3, 0x04E2, 0x04E3}, {0x04E4, 0x04E4, 0x04E5}, {0x04E5, 0x04E4, 0x04E5}, {0x04E6, 0x04E6, 0x04E7}, {0x04E7, 0x04E6, 0x04E7}, {0x04E8, 0x04E8, 0x04E9}, {0x04E9, 0x04E8, 0x04E9}, {0x04EA, 0x04EA, 0x04EB}, {0x04EB, 0x04EA, 0x04EB}, {0x04EC, 0x04EC, 0x04ED}, {0x04ED, 0x04EC, 0x04ED}, {0x04EE, 0x04EE, 0x04EF}, {0x04EF, 0x04EE, 0x04EF}, {0x04F0, 0x04F0, 0x04F1}, {0x04F1, 0x04F0, 0x04F1}, {0x04F2, 0x04F2, 0x04F3}, {0x04F3, 0x04F2, 0x04F3}, {0x04F4, 0x04F4, 0x04F5}, {0x04F5, 0x04F4, 0x04F5}, {0x04F6, 0x04F6, 0x04F7}, {0x04F7, 0x04F6, 0x04F7}, {0x04F8, 0x04F8, 0x04F9}, {0x04F9, 0x04F8, 0x04F9}, {0x0500, 0x0500, 0x0501}, {0x0501, 0x0500, 0x0501}, {0x0502, 0x0502, 0x0503}, {0x0503, 0x0502, 0x0503}, {0x0504, 0x0504, 0x0505}, {0x0505, 0x0504, 0x0505}, {0x0506, 0x0506, 0x0507}, {0x0507, 0x0506, 0x0507}, {0x0508, 0x0508, 0x0509}, {0x0509, 0x0508, 0x0509}, {0x050A, 0x050A, 0x050B}, {0x050B, 0x050A, 0x050B}, {0x050C, 0x050C, 0x050D}, {0x050D, 0x050C, 0x050D}, {0x050E, 0x050E, 0x050F}, {0x050F, 0x050E, 0x050F}, {0x0531, 0x0531, 0x0561}, {0x0532, 0x0532, 0x0562}, {0x0533, 0x0533, 0x0563}, {0x0534, 0x0534, 0x0564}, {0x0535, 0x0535, 0x0565}, {0x0536, 0x0536, 0x0566}, {0x0537, 0x0537, 0x0567}, {0x0538, 0x0538, 0x0568}, {0x0539, 0x0539, 0x0569}, {0x053A, 0x053A, 0x056A}, {0x053B, 0x053B, 0x056B}, {0x053C, 0x053C, 0x056C}, {0x053D, 0x053D, 0x056D}, {0x053E, 0x053E, 0x056E}, {0x053F, 0x053F, 0x056F}, {0x0540, 0x0540, 0x0570}, {0x0541, 0x0541, 0x0571}, {0x0542, 0x0542, 0x0572}, {0x0543, 0x0543, 0x0573}, {0x0544, 0x0544, 0x0574}, {0x0545, 0x0545, 0x0575}, {0x0546, 0x0546, 0x0576}, {0x0547, 0x0547, 0x0577}, {0x0548, 0x0548, 0x0578}, {0x0549, 0x0549, 0x0579}, {0x054A, 0x054A, 0x057A}, {0x054B, 0x054B, 0x057B}, {0x054C, 0x054C, 0x057C}, {0x054D, 0x054D, 0x057D}, {0x054E, 0x054E, 0x057E}, {0x054F, 0x054F, 0x057F}, {0x0550, 0x0550, 0x0580}, {0x0551, 0x0551, 0x0581}, {0x0552, 0x0552, 0x0582}, {0x0553, 0x0553, 0x0583}, {0x0554, 0x0554, 0x0584}, {0x0555, 0x0555, 0x0585}, {0x0556, 0x0556, 0x0586}, {0x0559, 0x0559, 0x0559}, {0x0561, 0x0531, 0x0561}, {0x0562, 0x0532, 0x0562}, {0x0563, 0x0533, 0x0563}, {0x0564, 0x0534, 0x0564}, {0x0565, 0x0535, 0x0565}, {0x0566, 0x0536, 0x0566}, {0x0567, 0x0537, 0x0567}, {0x0568, 0x0538, 0x0568}, {0x0569, 0x0539, 0x0569}, {0x056A, 0x053A, 0x056A}, {0x056B, 0x053B, 0x056B}, {0x056C, 0x053C, 0x056C}, {0x056D, 0x053D, 0x056D}, {0x056E, 0x053E, 0x056E}, {0x056F, 0x053F, 0x056F}, {0x0570, 0x0540, 0x0570}, {0x0571, 0x0541, 0x0571}, {0x0572, 0x0542, 0x0572}, {0x0573, 0x0543, 0x0573}, {0x0574, 0x0544, 0x0574}, {0x0575, 0x0545, 0x0575}, {0x0576, 0x0546, 0x0576}, {0x0577, 0x0547, 0x0577}, {0x0578, 0x0548, 0x0578}, {0x0579, 0x0549, 0x0579}, {0x057A, 0x054A, 0x057A}, {0x057B, 0x054B, 0x057B}, {0x057C, 0x054C, 0x057C}, {0x057D, 0x054D, 0x057D}, {0x057E, 0x054E, 0x057E}, {0x057F, 0x054F, 0x057F}, {0x0580, 0x0550, 0x0580}, {0x0581, 0x0551, 0x0581}, {0x0582, 0x0552, 0x0582}, {0x0583, 0x0553, 0x0583}, {0x0584, 0x0554, 0x0584}, {0x0585, 0x0555, 0x0585}, {0x0586, 0x0556, 0x0586}, {0x0587, 0x0587, 0x0587}, {0x0591, 0x0591, 0x0591}, {0x0592, 0x0592, 0x0592}, {0x0593, 0x0593, 0x0593}, {0x0594, 0x0594, 0x0594}, {0x0595, 0x0595, 0x0595}, {0x0596, 0x0596, 0x0596}, {0x0597, 0x0597, 0x0597}, {0x0598, 0x0598, 0x0598}, {0x0599, 0x0599, 0x0599}, {0x059A, 0x059A, 0x059A}, {0x059B, 0x059B, 0x059B}, {0x059C, 0x059C, 0x059C}, {0x059D, 0x059D, 0x059D}, {0x059E, 0x059E, 0x059E}, {0x059F, 0x059F, 0x059F}, {0x05A0, 0x05A0, 0x05A0}, {0x05A1, 0x05A1, 0x05A1}, {0x05A2, 0x05A2, 0x05A2}, {0x05A3, 0x05A3, 0x05A3}, {0x05A4, 0x05A4, 0x05A4}, {0x05A5, 0x05A5, 0x05A5}, {0x05A6, 0x05A6, 0x05A6}, {0x05A7, 0x05A7, 0x05A7}, {0x05A8, 0x05A8, 0x05A8}, {0x05A9, 0x05A9, 0x05A9}, {0x05AA, 0x05AA, 0x05AA}, {0x05AB, 0x05AB, 0x05AB}, {0x05AC, 0x05AC, 0x05AC}, {0x05AD, 0x05AD, 0x05AD}, {0x05AE, 0x05AE, 0x05AE}, {0x05AF, 0x05AF, 0x05AF}, {0x05B0, 0x05B0, 0x05B0}, {0x05B1, 0x05B1, 0x05B1}, {0x05B2, 0x05B2, 0x05B2}, {0x05B3, 0x05B3, 0x05B3}, {0x05B4, 0x05B4, 0x05B4}, {0x05B5, 0x05B5, 0x05B5}, {0x05B6, 0x05B6, 0x05B6}, {0x05B7, 0x05B7, 0x05B7}, {0x05B8, 0x05B8, 0x05B8}, {0x05B9, 0x05B9, 0x05B9}, {0x05BB, 0x05BB, 0x05BB}, {0x05BC, 0x05BC, 0x05BC}, {0x05BD, 0x05BD, 0x05BD}, {0x05BF, 0x05BF, 0x05BF}, {0x05C1, 0x05C1, 0x05C1}, {0x05C2, 0x05C2, 0x05C2}, {0x05C4, 0x05C4, 0x05C4}, {0x05C5, 0x05C5, 0x05C5}, {0x05C7, 0x05C7, 0x05C7}, {0x05D0, 0x05D0, 0x05D0}, {0x05D1, 0x05D1, 0x05D1}, {0x05D2, 0x05D2, 0x05D2}, {0x05D3, 0x05D3, 0x05D3}, {0x05D4, 0x05D4, 0x05D4}, {0x05D5, 0x05D5, 0x05D5}, {0x05D6, 0x05D6, 0x05D6}, {0x05D7, 0x05D7, 0x05D7}, {0x05D8, 0x05D8, 0x05D8}, {0x05D9, 0x05D9, 0x05D9}, {0x05DA, 0x05DA, 0x05DA}, {0x05DB, 0x05DB, 0x05DB}, {0x05DC, 0x05DC, 0x05DC}, {0x05DD, 0x05DD, 0x05DD}, {0x05DE, 0x05DE, 0x05DE}, {0x05DF, 0x05DF, 0x05DF}, {0x05E0, 0x05E0, 0x05E0}, {0x05E1, 0x05E1, 0x05E1}, {0x05E2, 0x05E2, 0x05E2}, {0x05E3, 0x05E3, 0x05E3}, {0x05E4, 0x05E4, 0x05E4}, {0x05E5, 0x05E5, 0x05E5}, {0x05E6, 0x05E6, 0x05E6}, {0x05E7, 0x05E7, 0x05E7}, {0x05E8, 0x05E8, 0x05E8}, {0x05E9, 0x05E9, 0x05E9}, {0x05EA, 0x05EA, 0x05EA}, {0x05F0, 0x05F0, 0x05F0}, {0x05F1, 0x05F1, 0x05F1}, {0x05F2, 0x05F2, 0x05F2}, {0x0610, 0x0610, 0x0610}, {0x0611, 0x0611, 0x0611}, {0x0612, 0x0612, 0x0612}, {0x0613, 0x0613, 0x0613}, {0x0614, 0x0614, 0x0614}, {0x0615, 0x0615, 0x0615}, {0x0621, 0x0621, 0x0621}, {0x0622, 0x0622, 0x0622}, {0x0623, 0x0623, 0x0623}, {0x0624, 0x0624, 0x0624}, {0x0625, 0x0625, 0x0625}, {0x0626, 0x0626, 0x0626}, {0x0627, 0x0627, 0x0627}, {0x0628, 0x0628, 0x0628}, {0x0629, 0x0629, 0x0629}, {0x062A, 0x062A, 0x062A}, {0x062B, 0x062B, 0x062B}, {0x062C, 0x062C, 0x062C}, {0x062D, 0x062D, 0x062D}, {0x062E, 0x062E, 0x062E}, {0x062F, 0x062F, 0x062F}, {0x0630, 0x0630, 0x0630}, {0x0631, 0x0631, 0x0631}, {0x0632, 0x0632, 0x0632}, {0x0633, 0x0633, 0x0633}, {0x0634, 0x0634, 0x0634}, {0x0635, 0x0635, 0x0635}, {0x0636, 0x0636, 0x0636}, {0x0637, 0x0637, 0x0637}, {0x0638, 0x0638, 0x0638}, {0x0639, 0x0639, 0x0639}, {0x063A, 0x063A, 0x063A}, {0x0640, 0x0640, 0x0640}, {0x0641, 0x0641, 0x0641}, {0x0642, 0x0642, 0x0642}, {0x0643, 0x0643, 0x0643}, {0x0644, 0x0644, 0x0644}, {0x0645, 0x0645, 0x0645}, {0x0646, 0x0646, 0x0646}, {0x0647, 0x0647, 0x0647}, {0x0648, 0x0648, 0x0648}, {0x0649, 0x0649, 0x0649}, {0x064A, 0x064A, 0x064A}, {0x064B, 0x064B, 0x064B}, {0x064C, 0x064C, 0x064C}, {0x064D, 0x064D, 0x064D}, {0x064E, 0x064E, 0x064E}, {0x064F, 0x064F, 0x064F}, {0x0650, 0x0650, 0x0650}, {0x0651, 0x0651, 0x0651}, {0x0652, 0x0652, 0x0652}, {0x0653, 0x0653, 0x0653}, {0x0654, 0x0654, 0x0654}, {0x0655, 0x0655, 0x0655}, {0x0656, 0x0656, 0x0656}, {0x0657, 0x0657, 0x0657}, {0x0658, 0x0658, 0x0658}, {0x0659, 0x0659, 0x0659}, {0x065A, 0x065A, 0x065A}, {0x065B, 0x065B, 0x065B}, {0x065C, 0x065C, 0x065C}, {0x065D, 0x065D, 0x065D}, {0x065E, 0x065E, 0x065E}, {0x066E, 0x066E, 0x066E}, {0x066F, 0x066F, 0x066F}, {0x0670, 0x0670, 0x0670}, {0x0671, 0x0671, 0x0671}, {0x0672, 0x0672, 0x0672}, {0x0673, 0x0673, 0x0673}, {0x0674, 0x0674, 0x0674}, {0x0675, 0x0675, 0x0675}, {0x0676, 0x0676, 0x0676}, {0x0677, 0x0677, 0x0677}, {0x0678, 0x0678, 0x0678}, {0x0679, 0x0679, 0x0679}, {0x067A, 0x067A, 0x067A}, {0x067B, 0x067B, 0x067B}, {0x067C, 0x067C, 0x067C}, {0x067D, 0x067D, 0x067D}, {0x067E, 0x067E, 0x067E}, {0x067F, 0x067F, 0x067F}, {0x0680, 0x0680, 0x0680}, {0x0681, 0x0681, 0x0681}, {0x0682, 0x0682, 0x0682}, {0x0683, 0x0683, 0x0683}, {0x0684, 0x0684, 0x0684}, {0x0685, 0x0685, 0x0685}, {0x0686, 0x0686, 0x0686}, {0x0687, 0x0687, 0x0687}, {0x0688, 0x0688, 0x0688}, {0x0689, 0x0689, 0x0689}, {0x068A, 0x068A, 0x068A}, {0x068B, 0x068B, 0x068B}, {0x068C, 0x068C, 0x068C}, {0x068D, 0x068D, 0x068D}, {0x068E, 0x068E, 0x068E}, {0x068F, 0x068F, 0x068F}, {0x0690, 0x0690, 0x0690}, {0x0691, 0x0691, 0x0691}, {0x0692, 0x0692, 0x0692}, {0x0693, 0x0693, 0x0693}, {0x0694, 0x0694, 0x0694}, {0x0695, 0x0695, 0x0695}, {0x0696, 0x0696, 0x0696}, {0x0697, 0x0697, 0x0697}, {0x0698, 0x0698, 0x0698}, {0x0699, 0x0699, 0x0699}, {0x069A, 0x069A, 0x069A}, {0x069B, 0x069B, 0x069B}, {0x069C, 0x069C, 0x069C}, {0x069D, 0x069D, 0x069D}, {0x069E, 0x069E, 0x069E}, {0x069F, 0x069F, 0x069F}, {0x06A0, 0x06A0, 0x06A0}, {0x06A1, 0x06A1, 0x06A1}, {0x06A2, 0x06A2, 0x06A2}, {0x06A3, 0x06A3, 0x06A3}, {0x06A4, 0x06A4, 0x06A4}, {0x06A5, 0x06A5, 0x06A5}, {0x06A6, 0x06A6, 0x06A6}, {0x06A7, 0x06A7, 0x06A7}, {0x06A8, 0x06A8, 0x06A8}, {0x06A9, 0x06A9, 0x06A9}, {0x06AA, 0x06AA, 0x06AA}, {0x06AB, 0x06AB, 0x06AB}, {0x06AC, 0x06AC, 0x06AC}, {0x06AD, 0x06AD, 0x06AD}, {0x06AE, 0x06AE, 0x06AE}, {0x06AF, 0x06AF, 0x06AF}, {0x06B0, 0x06B0, 0x06B0}, {0x06B1, 0x06B1, 0x06B1}, {0x06B2, 0x06B2, 0x06B2}, {0x06B3, 0x06B3, 0x06B3}, {0x06B4, 0x06B4, 0x06B4}, {0x06B5, 0x06B5, 0x06B5}, {0x06B6, 0x06B6, 0x06B6}, {0x06B7, 0x06B7, 0x06B7}, {0x06B8, 0x06B8, 0x06B8}, {0x06B9, 0x06B9, 0x06B9}, {0x06BA, 0x06BA, 0x06BA}, {0x06BB, 0x06BB, 0x06BB}, {0x06BC, 0x06BC, 0x06BC}, {0x06BD, 0x06BD, 0x06BD}, {0x06BE, 0x06BE, 0x06BE}, {0x06BF, 0x06BF, 0x06BF}, {0x06C0, 0x06C0, 0x06C0}, {0x06C1, 0x06C1, 0x06C1}, {0x06C2, 0x06C2, 0x06C2}, {0x06C3, 0x06C3, 0x06C3}, {0x06C4, 0x06C4, 0x06C4}, {0x06C5, 0x06C5, 0x06C5}, {0x06C6, 0x06C6, 0x06C6}, {0x06C7, 0x06C7, 0x06C7}, {0x06C8, 0x06C8, 0x06C8}, {0x06C9, 0x06C9, 0x06C9}, {0x06CA, 0x06CA, 0x06CA}, {0x06CB, 0x06CB, 0x06CB}, {0x06CC, 0x06CC, 0x06CC}, {0x06CD, 0x06CD, 0x06CD}, {0x06CE, 0x06CE, 0x06CE}, {0x06CF, 0x06CF, 0x06CF}, {0x06D0, 0x06D0, 0x06D0}, {0x06D1, 0x06D1, 0x06D1}, {0x06D2, 0x06D2, 0x06D2}, {0x06D3, 0x06D3, 0x06D3}, {0x06D5, 0x06D5, 0x06D5}, {0x06D6, 0x06D6, 0x06D6}, {0x06D7, 0x06D7, 0x06D7}, {0x06D8, 0x06D8, 0x06D8}, {0x06D9, 0x06D9, 0x06D9}, {0x06DA, 0x06DA, 0x06DA}, {0x06DB, 0x06DB, 0x06DB}, {0x06DC, 0x06DC, 0x06DC}, {0x06DF, 0x06DF, 0x06DF}, {0x06E0, 0x06E0, 0x06E0}, {0x06E1, 0x06E1, 0x06E1}, {0x06E2, 0x06E2, 0x06E2}, {0x06E3, 0x06E3, 0x06E3}, {0x06E4, 0x06E4, 0x06E4}, {0x06E5, 0x06E5, 0x06E5}, {0x06E6, 0x06E6, 0x06E6}, {0x06E7, 0x06E7, 0x06E7}, {0x06E8, 0x06E8, 0x06E8}, {0x06EA, 0x06EA, 0x06EA}, {0x06EB, 0x06EB, 0x06EB}, {0x06EC, 0x06EC, 0x06EC}, {0x06ED, 0x06ED, 0x06ED}, {0x06EE, 0x06EE, 0x06EE}, {0x06EF, 0x06EF, 0x06EF}, {0x06FA, 0x06FA, 0x06FA}, {0x06FB, 0x06FB, 0x06FB}, {0x06FC, 0x06FC, 0x06FC}, {0x06FF, 0x06FF, 0x06FF}, {0x0710, 0x0710, 0x0710}, {0x0711, 0x0711, 0x0711}, {0x0712, 0x0712, 0x0712}, {0x0713, 0x0713, 0x0713}, {0x0714, 0x0714, 0x0714}, {0x0715, 0x0715, 0x0715}, {0x0716, 0x0716, 0x0716}, {0x0717, 0x0717, 0x0717}, {0x0718, 0x0718, 0x0718}, {0x0719, 0x0719, 0x0719}, {0x071A, 0x071A, 0x071A}, {0x071B, 0x071B, 0x071B}, {0x071C, 0x071C, 0x071C}, {0x071D, 0x071D, 0x071D}, {0x071E, 0x071E, 0x071E}, {0x071F, 0x071F, 0x071F}, {0x0720, 0x0720, 0x0720}, {0x0721, 0x0721, 0x0721}, {0x0722, 0x0722, 0x0722}, {0x0723, 0x0723, 0x0723}, {0x0724, 0x0724, 0x0724}, {0x0725, 0x0725, 0x0725}, {0x0726, 0x0726, 0x0726}, {0x0727, 0x0727, 0x0727}, {0x0728, 0x0728, 0x0728}, {0x0729, 0x0729, 0x0729}, {0x072A, 0x072A, 0x072A}, {0x072B, 0x072B, 0x072B}, {0x072C, 0x072C, 0x072C}, {0x072D, 0x072D, 0x072D}, {0x072E, 0x072E, 0x072E}, {0x072F, 0x072F, 0x072F}, {0x0730, 0x0730, 0x0730}, {0x0731, 0x0731, 0x0731}, {0x0732, 0x0732, 0x0732}, {0x0733, 0x0733, 0x0733}, {0x0734, 0x0734, 0x0734}, {0x0735, 0x0735, 0x0735}, {0x0736, 0x0736, 0x0736}, {0x0737, 0x0737, 0x0737}, {0x0738, 0x0738, 0x0738}, {0x0739, 0x0739, 0x0739}, {0x073A, 0x073A, 0x073A}, {0x073B, 0x073B, 0x073B}, {0x073C, 0x073C, 0x073C}, {0x073D, 0x073D, 0x073D}, {0x073E, 0x073E, 0x073E}, {0x073F, 0x073F, 0x073F}, {0x0740, 0x0740, 0x0740}, {0x0741, 0x0741, 0x0741}, {0x0742, 0x0742, 0x0742}, {0x0743, 0x0743, 0x0743}, {0x0744, 0x0744, 0x0744}, {0x0745, 0x0745, 0x0745}, {0x0746, 0x0746, 0x0746}, {0x0747, 0x0747, 0x0747}, {0x0748, 0x0748, 0x0748}, {0x0749, 0x0749, 0x0749}, {0x074A, 0x074A, 0x074A}, {0x074D, 0x074D, 0x074D}, {0x074E, 0x074E, 0x074E}, {0x074F, 0x074F, 0x074F}, {0x0750, 0x0750, 0x0750}, {0x0751, 0x0751, 0x0751}, {0x0752, 0x0752, 0x0752}, {0x0753, 0x0753, 0x0753}, {0x0754, 0x0754, 0x0754}, {0x0755, 0x0755, 0x0755}, {0x0756, 0x0756, 0x0756}, {0x0757, 0x0757, 0x0757}, {0x0758, 0x0758, 0x0758}, {0x0759, 0x0759, 0x0759}, {0x075A, 0x075A, 0x075A}, {0x075B, 0x075B, 0x075B}, {0x075C, 0x075C, 0x075C}, {0x075D, 0x075D, 0x075D}, {0x075E, 0x075E, 0x075E}, {0x075F, 0x075F, 0x075F}, {0x0760, 0x0760, 0x0760}, {0x0761, 0x0761, 0x0761}, {0x0762, 0x0762, 0x0762}, {0x0763, 0x0763, 0x0763}, {0x0764, 0x0764, 0x0764}, {0x0765, 0x0765, 0x0765}, {0x0766, 0x0766, 0x0766}, {0x0767, 0x0767, 0x0767}, {0x0768, 0x0768, 0x0768}, {0x0769, 0x0769, 0x0769}, {0x076A, 0x076A, 0x076A}, {0x076B, 0x076B, 0x076B}, {0x076C, 0x076C, 0x076C}, {0x076D, 0x076D, 0x076D}, {0x0780, 0x0780, 0x0780}, {0x0781, 0x0781, 0x0781}, {0x0782, 0x0782, 0x0782}, {0x0783, 0x0783, 0x0783}, {0x0784, 0x0784, 0x0784}, {0x0785, 0x0785, 0x0785}, {0x0786, 0x0786, 0x0786}, {0x0787, 0x0787, 0x0787}, {0x0788, 0x0788, 0x0788}, {0x0789, 0x0789, 0x0789}, {0x078A, 0x078A, 0x078A}, {0x078B, 0x078B, 0x078B}, {0x078C, 0x078C, 0x078C}, {0x078D, 0x078D, 0x078D}, {0x078E, 0x078E, 0x078E}, {0x078F, 0x078F, 0x078F}, {0x0790, 0x0790, 0x0790}, {0x0791, 0x0791, 0x0791}, {0x0792, 0x0792, 0x0792}, {0x0793, 0x0793, 0x0793}, {0x0794, 0x0794, 0x0794}, {0x0795, 0x0795, 0x0795}, {0x0796, 0x0796, 0x0796}, {0x0797, 0x0797, 0x0797}, {0x0798, 0x0798, 0x0798}, {0x0799, 0x0799, 0x0799}, {0x079A, 0x079A, 0x079A}, {0x079B, 0x079B, 0x079B}, {0x079C, 0x079C, 0x079C}, {0x079D, 0x079D, 0x079D}, {0x079E, 0x079E, 0x079E}, {0x079F, 0x079F, 0x079F}, {0x07A0, 0x07A0, 0x07A0}, {0x07A1, 0x07A1, 0x07A1}, {0x07A2, 0x07A2, 0x07A2}, {0x07A3, 0x07A3, 0x07A3}, {0x07A4, 0x07A4, 0x07A4}, {0x07A5, 0x07A5, 0x07A5}, {0x07A6, 0x07A6, 0x07A6}, {0x07A7, 0x07A7, 0x07A7}, {0x07A8, 0x07A8, 0x07A8}, {0x07A9, 0x07A9, 0x07A9}, {0x07AA, 0x07AA, 0x07AA}, {0x07AB, 0x07AB, 0x07AB}, {0x07AC, 0x07AC, 0x07AC}, {0x07AD, 0x07AD, 0x07AD}, {0x07AE, 0x07AE, 0x07AE}, {0x07AF, 0x07AF, 0x07AF}, {0x07B0, 0x07B0, 0x07B0}, {0x07B1, 0x07B1, 0x07B1}, {0x0901, 0x0901, 0x0901}, {0x0902, 0x0902, 0x0902}, {0x0904, 0x0904, 0x0904}, {0x0905, 0x0905, 0x0905}, {0x0906, 0x0906, 0x0906}, {0x0907, 0x0907, 0x0907}, {0x0908, 0x0908, 0x0908}, {0x0909, 0x0909, 0x0909}, {0x090A, 0x090A, 0x090A}, {0x090B, 0x090B, 0x090B}, {0x090C, 0x090C, 0x090C}, {0x090D, 0x090D, 0x090D}, {0x090E, 0x090E, 0x090E}, {0x090F, 0x090F, 0x090F}, {0x0910, 0x0910, 0x0910}, {0x0911, 0x0911, 0x0911}, {0x0912, 0x0912, 0x0912}, {0x0913, 0x0913, 0x0913}, {0x0914, 0x0914, 0x0914}, {0x0915, 0x0915, 0x0915}, {0x0916, 0x0916, 0x0916}, {0x0917, 0x0917, 0x0917}, {0x0918, 0x0918, 0x0918}, {0x0919, 0x0919, 0x0919}, {0x091A, 0x091A, 0x091A}, {0x091B, 0x091B, 0x091B}, {0x091C, 0x091C, 0x091C}, {0x091D, 0x091D, 0x091D}, {0x091E, 0x091E, 0x091E}, {0x091F, 0x091F, 0x091F}, {0x0920, 0x0920, 0x0920}, {0x0921, 0x0921, 0x0921}, {0x0922, 0x0922, 0x0922}, {0x0923, 0x0923, 0x0923}, {0x0924, 0x0924, 0x0924}, {0x0925, 0x0925, 0x0925}, {0x0926, 0x0926, 0x0926}, {0x0927, 0x0927, 0x0927}, {0x0928, 0x0928, 0x0928}, {0x0929, 0x0929, 0x0929}, {0x092A, 0x092A, 0x092A}, {0x092B, 0x092B, 0x092B}, {0x092C, 0x092C, 0x092C}, {0x092D, 0x092D, 0x092D}, {0x092E, 0x092E, 0x092E}, {0x092F, 0x092F, 0x092F}, {0x0930, 0x0930, 0x0930}, {0x0931, 0x0931, 0x0931}, {0x0932, 0x0932, 0x0932}, {0x0933, 0x0933, 0x0933}, {0x0934, 0x0934, 0x0934}, {0x0935, 0x0935, 0x0935}, {0x0936, 0x0936, 0x0936}, {0x0937, 0x0937, 0x0937}, {0x0938, 0x0938, 0x0938}, {0x0939, 0x0939, 0x0939}, {0x093C, 0x093C, 0x093C}, {0x093D, 0x093D, 0x093D}, {0x0941, 0x0941, 0x0941}, {0x0942, 0x0942, 0x0942}, {0x0943, 0x0943, 0x0943}, {0x0944, 0x0944, 0x0944}, {0x0945, 0x0945, 0x0945}, {0x0946, 0x0946, 0x0946}, {0x0947, 0x0947, 0x0947}, {0x0948, 0x0948, 0x0948}, {0x094D, 0x094D, 0x094D}, {0x0950, 0x0950, 0x0950}, {0x0951, 0x0951, 0x0951}, {0x0952, 0x0952, 0x0952}, {0x0953, 0x0953, 0x0953}, {0x0954, 0x0954, 0x0954}, {0x0958, 0x0958, 0x0958}, {0x0959, 0x0959, 0x0959}, {0x095A, 0x095A, 0x095A}, {0x095B, 0x095B, 0x095B}, {0x095C, 0x095C, 0x095C}, {0x095D, 0x095D, 0x095D}, {0x095E, 0x095E, 0x095E}, {0x095F, 0x095F, 0x095F}, {0x0960, 0x0960, 0x0960}, {0x0961, 0x0961, 0x0961}, {0x0962, 0x0962, 0x0962}, {0x0963, 0x0963, 0x0963}, {0x097D, 0x097D, 0x097D}, {0x0981, 0x0981, 0x0981}, {0x0985, 0x0985, 0x0985}, {0x0986, 0x0986, 0x0986}, {0x0987, 0x0987, 0x0987}, {0x0988, 0x0988, 0x0988}, {0x0989, 0x0989, 0x0989}, {0x098A, 0x098A, 0x098A}, {0x098B, 0x098B, 0x098B}, {0x098C, 0x098C, 0x098C}, {0x098F, 0x098F, 0x098F}, {0x0990, 0x0990, 0x0990}, {0x0993, 0x0993, 0x0993}, {0x0994, 0x0994, 0x0994}, {0x0995, 0x0995, 0x0995}, {0x0996, 0x0996, 0x0996}, {0x0997, 0x0997, 0x0997}, {0x0998, 0x0998, 0x0998}, {0x0999, 0x0999, 0x0999}, {0x099A, 0x099A, 0x099A}, {0x099B, 0x099B, 0x099B}, {0x099C, 0x099C, 0x099C}, {0x099D, 0x099D, 0x099D}, {0x099E, 0x099E, 0x099E}, {0x099F, 0x099F, 0x099F}, {0x09A0, 0x09A0, 0x09A0}, {0x09A1, 0x09A1, 0x09A1}, {0x09A2, 0x09A2, 0x09A2}, {0x09A3, 0x09A3, 0x09A3}, {0x09A4, 0x09A4, 0x09A4}, {0x09A5, 0x09A5, 0x09A5}, {0x09A6, 0x09A6, 0x09A6}, {0x09A7, 0x09A7, 0x09A7}, {0x09A8, 0x09A8, 0x09A8}, {0x09AA, 0x09AA, 0x09AA}, {0x09AB, 0x09AB, 0x09AB}, {0x09AC, 0x09AC, 0x09AC}, {0x09AD, 0x09AD, 0x09AD}, {0x09AE, 0x09AE, 0x09AE}, {0x09AF, 0x09AF, 0x09AF}, {0x09B0, 0x09B0, 0x09B0}, {0x09B2, 0x09B2, 0x09B2}, {0x09B6, 0x09B6, 0x09B6}, {0x09B7, 0x09B7, 0x09B7}, {0x09B8, 0x09B8, 0x09B8}, {0x09B9, 0x09B9, 0x09B9}, {0x09BC, 0x09BC, 0x09BC}, {0x09BD, 0x09BD, 0x09BD}, {0x09C1, 0x09C1, 0x09C1}, {0x09C2, 0x09C2, 0x09C2}, {0x09C3, 0x09C3, 0x09C3}, {0x09C4, 0x09C4, 0x09C4}, {0x09CD, 0x09CD, 0x09CD}, {0x09CE, 0x09CE, 0x09CE}, {0x09DC, 0x09DC, 0x09DC}, {0x09DD, 0x09DD, 0x09DD}, {0x09DF, 0x09DF, 0x09DF}, {0x09E0, 0x09E0, 0x09E0}, {0x09E1, 0x09E1, 0x09E1}, {0x09E2, 0x09E2, 0x09E2}, {0x09E3, 0x09E3, 0x09E3}, {0x09F0, 0x09F0, 0x09F0}, {0x09F1, 0x09F1, 0x09F1}, {0x0A01, 0x0A01, 0x0A01}, {0x0A02, 0x0A02, 0x0A02}, {0x0A05, 0x0A05, 0x0A05}, {0x0A06, 0x0A06, 0x0A06}, {0x0A07, 0x0A07, 0x0A07}, {0x0A08, 0x0A08, 0x0A08}, {0x0A09, 0x0A09, 0x0A09}, {0x0A0A, 0x0A0A, 0x0A0A}, {0x0A0F, 0x0A0F, 0x0A0F}, {0x0A10, 0x0A10, 0x0A10}, {0x0A13, 0x0A13, 0x0A13}, {0x0A14, 0x0A14, 0x0A14}, {0x0A15, 0x0A15, 0x0A15}, {0x0A16, 0x0A16, 0x0A16}, {0x0A17, 0x0A17, 0x0A17}, {0x0A18, 0x0A18, 0x0A18}, {0x0A19, 0x0A19, 0x0A19}, {0x0A1A, 0x0A1A, 0x0A1A}, {0x0A1B, 0x0A1B, 0x0A1B}, {0x0A1C, 0x0A1C, 0x0A1C}, {0x0A1D, 0x0A1D, 0x0A1D}, {0x0A1E, 0x0A1E, 0x0A1E}, {0x0A1F, 0x0A1F, 0x0A1F}, {0x0A20, 0x0A20, 0x0A20}, {0x0A21, 0x0A21, 0x0A21}, {0x0A22, 0x0A22, 0x0A22}, {0x0A23, 0x0A23, 0x0A23}, {0x0A24, 0x0A24, 0x0A24}, {0x0A25, 0x0A25, 0x0A25}, {0x0A26, 0x0A26, 0x0A26}, {0x0A27, 0x0A27, 0x0A27}, {0x0A28, 0x0A28, 0x0A28}, {0x0A2A, 0x0A2A, 0x0A2A}, {0x0A2B, 0x0A2B, 0x0A2B}, {0x0A2C, 0x0A2C, 0x0A2C}, {0x0A2D, 0x0A2D, 0x0A2D}, {0x0A2E, 0x0A2E, 0x0A2E}, {0x0A2F, 0x0A2F, 0x0A2F}, {0x0A30, 0x0A30, 0x0A30}, {0x0A32, 0x0A32, 0x0A32}, {0x0A33, 0x0A33, 0x0A33}, {0x0A35, 0x0A35, 0x0A35}, {0x0A36, 0x0A36, 0x0A36}, {0x0A38, 0x0A38, 0x0A38}, {0x0A39, 0x0A39, 0x0A39}, {0x0A3C, 0x0A3C, 0x0A3C}, {0x0A41, 0x0A41, 0x0A41}, {0x0A42, 0x0A42, 0x0A42}, {0x0A47, 0x0A47, 0x0A47}, {0x0A48, 0x0A48, 0x0A48}, {0x0A4B, 0x0A4B, 0x0A4B}, {0x0A4C, 0x0A4C, 0x0A4C}, {0x0A4D, 0x0A4D, 0x0A4D}, {0x0A59, 0x0A59, 0x0A59}, {0x0A5A, 0x0A5A, 0x0A5A}, {0x0A5B, 0x0A5B, 0x0A5B}, {0x0A5C, 0x0A5C, 0x0A5C}, {0x0A5E, 0x0A5E, 0x0A5E}, {0x0A70, 0x0A70, 0x0A70}, {0x0A71, 0x0A71, 0x0A71}, {0x0A72, 0x0A72, 0x0A72}, {0x0A73, 0x0A73, 0x0A73}, {0x0A74, 0x0A74, 0x0A74}, {0x0A81, 0x0A81, 0x0A81}, {0x0A82, 0x0A82, 0x0A82}, {0x0A85, 0x0A85, 0x0A85}, {0x0A86, 0x0A86, 0x0A86}, {0x0A87, 0x0A87, 0x0A87}, {0x0A88, 0x0A88, 0x0A88}, {0x0A89, 0x0A89, 0x0A89}, {0x0A8A, 0x0A8A, 0x0A8A}, {0x0A8B, 0x0A8B, 0x0A8B}, {0x0A8C, 0x0A8C, 0x0A8C}, {0x0A8D, 0x0A8D, 0x0A8D}, {0x0A8F, 0x0A8F, 0x0A8F}, {0x0A90, 0x0A90, 0x0A90}, {0x0A91, 0x0A91, 0x0A91}, {0x0A93, 0x0A93, 0x0A93}, {0x0A94, 0x0A94, 0x0A94}, {0x0A95, 0x0A95, 0x0A95}, {0x0A96, 0x0A96, 0x0A96}, {0x0A97, 0x0A97, 0x0A97}, {0x0A98, 0x0A98, 0x0A98}, {0x0A99, 0x0A99, 0x0A99}, {0x0A9A, 0x0A9A, 0x0A9A}, {0x0A9B, 0x0A9B, 0x0A9B}, {0x0A9C, 0x0A9C, 0x0A9C}, {0x0A9D, 0x0A9D, 0x0A9D}, {0x0A9E, 0x0A9E, 0x0A9E}, {0x0A9F, 0x0A9F, 0x0A9F}, {0x0AA0, 0x0AA0, 0x0AA0}, {0x0AA1, 0x0AA1, 0x0AA1}, {0x0AA2, 0x0AA2, 0x0AA2}, {0x0AA3, 0x0AA3, 0x0AA3}, {0x0AA4, 0x0AA4, 0x0AA4}, {0x0AA5, 0x0AA5, 0x0AA5}, {0x0AA6, 0x0AA6, 0x0AA6}, {0x0AA7, 0x0AA7, 0x0AA7}, {0x0AA8, 0x0AA8, 0x0AA8}, {0x0AAA, 0x0AAA, 0x0AAA}, {0x0AAB, 0x0AAB, 0x0AAB}, {0x0AAC, 0x0AAC, 0x0AAC}, {0x0AAD, 0x0AAD, 0x0AAD}, {0x0AAE, 0x0AAE, 0x0AAE}, {0x0AAF, 0x0AAF, 0x0AAF}, {0x0AB0, 0x0AB0, 0x0AB0}, {0x0AB2, 0x0AB2, 0x0AB2}, {0x0AB3, 0x0AB3, 0x0AB3}, {0x0AB5, 0x0AB5, 0x0AB5}, {0x0AB6, 0x0AB6, 0x0AB6}, {0x0AB7, 0x0AB7, 0x0AB7}, {0x0AB8, 0x0AB8, 0x0AB8}, {0x0AB9, 0x0AB9, 0x0AB9}, {0x0ABC, 0x0ABC, 0x0ABC}, {0x0ABD, 0x0ABD, 0x0ABD}, {0x0AC1, 0x0AC1, 0x0AC1}, {0x0AC2, 0x0AC2, 0x0AC2}, {0x0AC3, 0x0AC3, 0x0AC3}, {0x0AC4, 0x0AC4, 0x0AC4}, {0x0AC5, 0x0AC5, 0x0AC5}, {0x0AC7, 0x0AC7, 0x0AC7}, {0x0AC8, 0x0AC8, 0x0AC8}, {0x0ACD, 0x0ACD, 0x0ACD}, {0x0AD0, 0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE0, 0x0AE0}, {0x0AE1, 0x0AE1, 0x0AE1}, {0x0AE2, 0x0AE2, 0x0AE2}, {0x0AE3, 0x0AE3, 0x0AE3}, {0x0B01, 0x0B01, 0x0B01}, {0x0B05, 0x0B05, 0x0B05}, {0x0B06, 0x0B06, 0x0B06}, {0x0B07, 0x0B07, 0x0B07}, {0x0B08, 0x0B08, 0x0B08}, {0x0B09, 0x0B09, 0x0B09}, {0x0B0A, 0x0B0A, 0x0B0A}, {0x0B0B, 0x0B0B, 0x0B0B}, {0x0B0C, 0x0B0C, 0x0B0C}, {0x0B0F, 0x0B0F, 0x0B0F}, {0x0B10, 0x0B10, 0x0B10}, {0x0B13, 0x0B13, 0x0B13}, {0x0B14, 0x0B14, 0x0B14}, {0x0B15, 0x0B15, 0x0B15}, {0x0B16, 0x0B16, 0x0B16}, {0x0B17, 0x0B17, 0x0B17}, {0x0B18, 0x0B18, 0x0B18}, {0x0B19, 0x0B19, 0x0B19}, {0x0B1A, 0x0B1A, 0x0B1A}, {0x0B1B, 0x0B1B, 0x0B1B}, {0x0B1C, 0x0B1C, 0x0B1C}, {0x0B1D, 0x0B1D, 0x0B1D}, {0x0B1E, 0x0B1E, 0x0B1E}, {0x0B1F, 0x0B1F, 0x0B1F}, {0x0B20, 0x0B20, 0x0B20}, {0x0B21, 0x0B21, 0x0B21}, {0x0B22, 0x0B22, 0x0B22}, {0x0B23, 0x0B23, 0x0B23}, {0x0B24, 0x0B24, 0x0B24}, {0x0B25, 0x0B25, 0x0B25}, {0x0B26, 0x0B26, 0x0B26}, {0x0B27, 0x0B27, 0x0B27}, {0x0B28, 0x0B28, 0x0B28}, {0x0B2A, 0x0B2A, 0x0B2A}, {0x0B2B, 0x0B2B, 0x0B2B}, {0x0B2C, 0x0B2C, 0x0B2C}, {0x0B2D, 0x0B2D, 0x0B2D}, {0x0B2E, 0x0B2E, 0x0B2E}, {0x0B2F, 0x0B2F, 0x0B2F}, {0x0B30, 0x0B30, 0x0B30}, {0x0B32, 0x0B32, 0x0B32}, {0x0B33, 0x0B33, 0x0B33}, {0x0B35, 0x0B35, 0x0B35}, {0x0B36, 0x0B36, 0x0B36}, {0x0B37, 0x0B37, 0x0B37}, {0x0B38, 0x0B38, 0x0B38}, {0x0B39, 0x0B39, 0x0B39}, {0x0B3C, 0x0B3C, 0x0B3C}, {0x0B3D, 0x0B3D, 0x0B3D}, {0x0B3F, 0x0B3F, 0x0B3F}, {0x0B41, 0x0B41, 0x0B41}, {0x0B42, 0x0B42, 0x0B42}, {0x0B43, 0x0B43, 0x0B43}, {0x0B4D, 0x0B4D, 0x0B4D}, {0x0B56, 0x0B56, 0x0B56}, {0x0B5C, 0x0B5C, 0x0B5C}, {0x0B5D, 0x0B5D, 0x0B5D}, {0x0B5F, 0x0B5F, 0x0B5F}, {0x0B60, 0x0B60, 0x0B60}, {0x0B61, 0x0B61, 0x0B61}, {0x0B71, 0x0B71, 0x0B71}, {0x0B82, 0x0B82, 0x0B82}, {0x0B83, 0x0B83, 0x0B83}, {0x0B85, 0x0B85, 0x0B85}, {0x0B86, 0x0B86, 0x0B86}, {0x0B87, 0x0B87, 0x0B87}, {0x0B88, 0x0B88, 0x0B88}, {0x0B89, 0x0B89, 0x0B89}, {0x0B8A, 0x0B8A, 0x0B8A}, {0x0B8E, 0x0B8E, 0x0B8E}, {0x0B8F, 0x0B8F, 0x0B8F}, {0x0B90, 0x0B90, 0x0B90}, {0x0B92, 0x0B92, 0x0B92}, {0x0B93, 0x0B93, 0x0B93}, {0x0B94, 0x0B94, 0x0B94}, {0x0B95, 0x0B95, 0x0B95}, {0x0B99, 0x0B99, 0x0B99}, {0x0B9A, 0x0B9A, 0x0B9A}, {0x0B9C, 0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9E, 0x0B9E}, {0x0B9F, 0x0B9F, 0x0B9F}, {0x0BA3, 0x0BA3, 0x0BA3}, {0x0BA4, 0x0BA4, 0x0BA4}, {0x0BA8, 0x0BA8, 0x0BA8}, {0x0BA9, 0x0BA9, 0x0BA9}, {0x0BAA, 0x0BAA, 0x0BAA}, {0x0BAE, 0x0BAE, 0x0BAE}, {0x0BAF, 0x0BAF, 0x0BAF}, {0x0BB0, 0x0BB0, 0x0BB0}, {0x0BB1, 0x0BB1, 0x0BB1}, {0x0BB2, 0x0BB2, 0x0BB2}, {0x0BB3, 0x0BB3, 0x0BB3}, {0x0BB4, 0x0BB4, 0x0BB4}, {0x0BB5, 0x0BB5, 0x0BB5}, {0x0BB6, 0x0BB6, 0x0BB6}, {0x0BB7, 0x0BB7, 0x0BB7}, {0x0BB8, 0x0BB8, 0x0BB8}, {0x0BB9, 0x0BB9, 0x0BB9}, {0x0BC0, 0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD, 0x0BCD}, {0x0C05, 0x0C05, 0x0C05}, {0x0C06, 0x0C06, 0x0C06}, {0x0C07, 0x0C07, 0x0C07}, {0x0C08, 0x0C08, 0x0C08}, {0x0C09, 0x0C09, 0x0C09}, {0x0C0A, 0x0C0A, 0x0C0A}, {0x0C0B, 0x0C0B, 0x0C0B}, {0x0C0C, 0x0C0C, 0x0C0C}, {0x0C0E, 0x0C0E, 0x0C0E}, {0x0C0F, 0x0C0F, 0x0C0F}, {0x0C10, 0x0C10, 0x0C10}, {0x0C12, 0x0C12, 0x0C12}, {0x0C13, 0x0C13, 0x0C13}, {0x0C14, 0x0C14, 0x0C14}, {0x0C15, 0x0C15, 0x0C15}, {0x0C16, 0x0C16, 0x0C16}, {0x0C17, 0x0C17, 0x0C17}, {0x0C18, 0x0C18, 0x0C18}, {0x0C19, 0x0C19, 0x0C19}, {0x0C1A, 0x0C1A, 0x0C1A}, {0x0C1B, 0x0C1B, 0x0C1B}, {0x0C1C, 0x0C1C, 0x0C1C}, {0x0C1D, 0x0C1D, 0x0C1D}, {0x0C1E, 0x0C1E, 0x0C1E}, {0x0C1F, 0x0C1F, 0x0C1F}, {0x0C20, 0x0C20, 0x0C20}, {0x0C21, 0x0C21, 0x0C21}, {0x0C22, 0x0C22, 0x0C22}, {0x0C23, 0x0C23, 0x0C23}, {0x0C24, 0x0C24, 0x0C24}, {0x0C25, 0x0C25, 0x0C25}, {0x0C26, 0x0C26, 0x0C26}, {0x0C27, 0x0C27, 0x0C27}, {0x0C28, 0x0C28, 0x0C28}, {0x0C2A, 0x0C2A, 0x0C2A}, {0x0C2B, 0x0C2B, 0x0C2B}, {0x0C2C, 0x0C2C, 0x0C2C}, {0x0C2D, 0x0C2D, 0x0C2D}, {0x0C2E, 0x0C2E, 0x0C2E}, {0x0C2F, 0x0C2F, 0x0C2F}, {0x0C30, 0x0C30, 0x0C30}, {0x0C31, 0x0C31, 0x0C31}, {0x0C32, 0x0C32, 0x0C32}, {0x0C33, 0x0C33, 0x0C33}, {0x0C35, 0x0C35, 0x0C35}, {0x0C36, 0x0C36, 0x0C36}, {0x0C37, 0x0C37, 0x0C37}, {0x0C38, 0x0C38, 0x0C38}, {0x0C39, 0x0C39, 0x0C39}, {0x0C3E, 0x0C3E, 0x0C3E}, {0x0C3F, 0x0C3F, 0x0C3F}, {0x0C40, 0x0C40, 0x0C40}, {0x0C46, 0x0C46, 0x0C46}, {0x0C47, 0x0C47, 0x0C47}, {0x0C48, 0x0C48, 0x0C48}, {0x0C4A, 0x0C4A, 0x0C4A}, {0x0C4B, 0x0C4B, 0x0C4B}, {0x0C4C, 0x0C4C, 0x0C4C}, {0x0C4D, 0x0C4D, 0x0C4D}, {0x0C55, 0x0C55, 0x0C55}, {0x0C56, 0x0C56, 0x0C56}, {0x0C60, 0x0C60, 0x0C60}, {0x0C61, 0x0C61, 0x0C61}, {0x0C85, 0x0C85, 0x0C85}, {0x0C86, 0x0C86, 0x0C86}, {0x0C87, 0x0C87, 0x0C87}, {0x0C88, 0x0C88, 0x0C88}, {0x0C89, 0x0C89, 0x0C89}, {0x0C8A, 0x0C8A, 0x0C8A}, {0x0C8B, 0x0C8B, 0x0C8B}, {0x0C8C, 0x0C8C, 0x0C8C}, {0x0C8E, 0x0C8E, 0x0C8E}, {0x0C8F, 0x0C8F, 0x0C8F}, {0x0C90, 0x0C90, 0x0C90}, {0x0C92, 0x0C92, 0x0C92}, {0x0C93, 0x0C93, 0x0C93}, {0x0C94, 0x0C94, 0x0C94}, {0x0C95, 0x0C95, 0x0C95}, {0x0C96, 0x0C96, 0x0C96}, {0x0C97, 0x0C97, 0x0C97}, {0x0C98, 0x0C98, 0x0C98}, {0x0C99, 0x0C99, 0x0C99}, {0x0C9A, 0x0C9A, 0x0C9A}, {0x0C9B, 0x0C9B, 0x0C9B}, {0x0C9C, 0x0C9C, 0x0C9C}, {0x0C9D, 0x0C9D, 0x0C9D}, {0x0C9E, 0x0C9E, 0x0C9E}, {0x0C9F, 0x0C9F, 0x0C9F}, {0x0CA0, 0x0CA0, 0x0CA0}, {0x0CA1, 0x0CA1, 0x0CA1}, {0x0CA2, 0x0CA2, 0x0CA2}, {0x0CA3, 0x0CA3, 0x0CA3}, {0x0CA4, 0x0CA4, 0x0CA4}, {0x0CA5, 0x0CA5, 0x0CA5}, {0x0CA6, 0x0CA6, 0x0CA6}, {0x0CA7, 0x0CA7, 0x0CA7}, {0x0CA8, 0x0CA8, 0x0CA8}, {0x0CAA, 0x0CAA, 0x0CAA}, {0x0CAB, 0x0CAB, 0x0CAB}, {0x0CAC, 0x0CAC, 0x0CAC}, {0x0CAD, 0x0CAD, 0x0CAD}, {0x0CAE, 0x0CAE, 0x0CAE}, {0x0CAF, 0x0CAF, 0x0CAF}, {0x0CB0, 0x0CB0, 0x0CB0}, {0x0CB1, 0x0CB1, 0x0CB1}, {0x0CB2, 0x0CB2, 0x0CB2}, {0x0CB3, 0x0CB3, 0x0CB3}, {0x0CB5, 0x0CB5, 0x0CB5}, {0x0CB6, 0x0CB6, 0x0CB6}, {0x0CB7, 0x0CB7, 0x0CB7}, {0x0CB8, 0x0CB8, 0x0CB8}, {0x0CB9, 0x0CB9, 0x0CB9}, {0x0CBC, 0x0CBC, 0x0CBC}, {0x0CBD, 0x0CBD, 0x0CBD}, {0x0CBF, 0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCC, 0x0CCC}, {0x0CCD, 0x0CCD, 0x0CCD}, {0x0CDE, 0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE0, 0x0CE0}, {0x0CE1, 0x0CE1, 0x0CE1}, {0x0D05, 0x0D05, 0x0D05}, {0x0D06, 0x0D06, 0x0D06}, {0x0D07, 0x0D07, 0x0D07}, {0x0D08, 0x0D08, 0x0D08}, {0x0D09, 0x0D09, 0x0D09}, {0x0D0A, 0x0D0A, 0x0D0A}, {0x0D0B, 0x0D0B, 0x0D0B}, {0x0D0C, 0x0D0C, 0x0D0C}, {0x0D0E, 0x0D0E, 0x0D0E}, {0x0D0F, 0x0D0F, 0x0D0F}, {0x0D10, 0x0D10, 0x0D10}, {0x0D12, 0x0D12, 0x0D12}, {0x0D13, 0x0D13, 0x0D13}, {0x0D14, 0x0D14, 0x0D14}, {0x0D15, 0x0D15, 0x0D15}, {0x0D16, 0x0D16, 0x0D16}, {0x0D17, 0x0D17, 0x0D17}, {0x0D18, 0x0D18, 0x0D18}, {0x0D19, 0x0D19, 0x0D19}, {0x0D1A, 0x0D1A, 0x0D1A}, {0x0D1B, 0x0D1B, 0x0D1B}, {0x0D1C, 0x0D1C, 0x0D1C}, {0x0D1D, 0x0D1D, 0x0D1D}, {0x0D1E, 0x0D1E, 0x0D1E}, {0x0D1F, 0x0D1F, 0x0D1F}, {0x0D20, 0x0D20, 0x0D20}, {0x0D21, 0x0D21, 0x0D21}, {0x0D22, 0x0D22, 0x0D22}, {0x0D23, 0x0D23, 0x0D23}, {0x0D24, 0x0D24, 0x0D24}, {0x0D25, 0x0D25, 0x0D25}, {0x0D26, 0x0D26, 0x0D26}, {0x0D27, 0x0D27, 0x0D27}, {0x0D28, 0x0D28, 0x0D28}, {0x0D2A, 0x0D2A, 0x0D2A}, {0x0D2B, 0x0D2B, 0x0D2B}, {0x0D2C, 0x0D2C, 0x0D2C}, {0x0D2D, 0x0D2D, 0x0D2D}, {0x0D2E, 0x0D2E, 0x0D2E}, {0x0D2F, 0x0D2F, 0x0D2F}, {0x0D30, 0x0D30, 0x0D30}, {0x0D31, 0x0D31, 0x0D31}, {0x0D32, 0x0D32, 0x0D32}, {0x0D33, 0x0D33, 0x0D33}, {0x0D34, 0x0D34, 0x0D34}, {0x0D35, 0x0D35, 0x0D35}, {0x0D36, 0x0D36, 0x0D36}, {0x0D37, 0x0D37, 0x0D37}, {0x0D38, 0x0D38, 0x0D38}, {0x0D39, 0x0D39, 0x0D39}, {0x0D41, 0x0D41, 0x0D41}, {0x0D42, 0x0D42, 0x0D42}, {0x0D43, 0x0D43, 0x0D43}, {0x0D4D, 0x0D4D, 0x0D4D}, {0x0D60, 0x0D60, 0x0D60}, {0x0D61, 0x0D61, 0x0D61}, {0x0D85, 0x0D85, 0x0D85}, {0x0D86, 0x0D86, 0x0D86}, {0x0D87, 0x0D87, 0x0D87}, {0x0D88, 0x0D88, 0x0D88}, {0x0D89, 0x0D89, 0x0D89}, {0x0D8A, 0x0D8A, 0x0D8A}, {0x0D8B, 0x0D8B, 0x0D8B}, {0x0D8C, 0x0D8C, 0x0D8C}, {0x0D8D, 0x0D8D, 0x0D8D}, {0x0D8E, 0x0D8E, 0x0D8E}, {0x0D8F, 0x0D8F, 0x0D8F}, {0x0D90, 0x0D90, 0x0D90}, {0x0D91, 0x0D91, 0x0D91}, {0x0D92, 0x0D92, 0x0D92}, {0x0D93, 0x0D93, 0x0D93}, {0x0D94, 0x0D94, 0x0D94}, {0x0D95, 0x0D95, 0x0D95}, {0x0D96, 0x0D96, 0x0D96}, {0x0D9A, 0x0D9A, 0x0D9A}, {0x0D9B, 0x0D9B, 0x0D9B}, {0x0D9C, 0x0D9C, 0x0D9C}, {0x0D9D, 0x0D9D, 0x0D9D}, {0x0D9E, 0x0D9E, 0x0D9E}, {0x0D9F, 0x0D9F, 0x0D9F}, {0x0DA0, 0x0DA0, 0x0DA0}, {0x0DA1, 0x0DA1, 0x0DA1}, {0x0DA2, 0x0DA2, 0x0DA2}, {0x0DA3, 0x0DA3, 0x0DA3}, {0x0DA4, 0x0DA4, 0x0DA4}, {0x0DA5, 0x0DA5, 0x0DA5}, {0x0DA6, 0x0DA6, 0x0DA6}, {0x0DA7, 0x0DA7, 0x0DA7}, {0x0DA8, 0x0DA8, 0x0DA8}, {0x0DA9, 0x0DA9, 0x0DA9}, {0x0DAA, 0x0DAA, 0x0DAA}, {0x0DAB, 0x0DAB, 0x0DAB}, {0x0DAC, 0x0DAC, 0x0DAC}, {0x0DAD, 0x0DAD, 0x0DAD}, {0x0DAE, 0x0DAE, 0x0DAE}, {0x0DAF, 0x0DAF, 0x0DAF}, {0x0DB0, 0x0DB0, 0x0DB0}, {0x0DB1, 0x0DB1, 0x0DB1}, {0x0DB3, 0x0DB3, 0x0DB3}, {0x0DB4, 0x0DB4, 0x0DB4}, {0x0DB5, 0x0DB5, 0x0DB5}, {0x0DB6, 0x0DB6, 0x0DB6}, {0x0DB7, 0x0DB7, 0x0DB7}, {0x0DB8, 0x0DB8, 0x0DB8}, {0x0DB9, 0x0DB9, 0x0DB9}, {0x0DBA, 0x0DBA, 0x0DBA}, {0x0DBB, 0x0DBB, 0x0DBB}, {0x0DBD, 0x0DBD, 0x0DBD}, {0x0DC0, 0x0DC0, 0x0DC0}, {0x0DC1, 0x0DC1, 0x0DC1}, {0x0DC2, 0x0DC2, 0x0DC2}, {0x0DC3, 0x0DC3, 0x0DC3}, {0x0DC4, 0x0DC4, 0x0DC4}, {0x0DC5, 0x0DC5, 0x0DC5}, {0x0DC6, 0x0DC6, 0x0DC6}, {0x0DCA, 0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD2, 0x0DD2}, {0x0DD3, 0x0DD3, 0x0DD3}, {0x0DD4, 0x0DD4, 0x0DD4}, {0x0DD6, 0x0DD6, 0x0DD6}, {0x0E01, 0x0E01, 0x0E01}, {0x0E02, 0x0E02, 0x0E02}, {0x0E03, 0x0E03, 0x0E03}, {0x0E04, 0x0E04, 0x0E04}, {0x0E05, 0x0E05, 0x0E05}, {0x0E06, 0x0E06, 0x0E06}, {0x0E07, 0x0E07, 0x0E07}, {0x0E08, 0x0E08, 0x0E08}, {0x0E09, 0x0E09, 0x0E09}, {0x0E0A, 0x0E0A, 0x0E0A}, {0x0E0B, 0x0E0B, 0x0E0B}, {0x0E0C, 0x0E0C, 0x0E0C}, {0x0E0D, 0x0E0D, 0x0E0D}, {0x0E0E, 0x0E0E, 0x0E0E}, {0x0E0F, 0x0E0F, 0x0E0F}, {0x0E10, 0x0E10, 0x0E10}, {0x0E11, 0x0E11, 0x0E11}, {0x0E12, 0x0E12, 0x0E12}, {0x0E13, 0x0E13, 0x0E13}, {0x0E14, 0x0E14, 0x0E14}, {0x0E15, 0x0E15, 0x0E15}, {0x0E16, 0x0E16, 0x0E16}, {0x0E17, 0x0E17, 0x0E17}, {0x0E18, 0x0E18, 0x0E18}, {0x0E19, 0x0E19, 0x0E19}, {0x0E1A, 0x0E1A, 0x0E1A}, {0x0E1B, 0x0E1B, 0x0E1B}, {0x0E1C, 0x0E1C, 0x0E1C}, {0x0E1D, 0x0E1D, 0x0E1D}, {0x0E1E, 0x0E1E, 0x0E1E}, {0x0E1F, 0x0E1F, 0x0E1F}, {0x0E20, 0x0E20, 0x0E20}, {0x0E21, 0x0E21, 0x0E21}, {0x0E22, 0x0E22, 0x0E22}, {0x0E23, 0x0E23, 0x0E23}, {0x0E24, 0x0E24, 0x0E24}, {0x0E25, 0x0E25, 0x0E25}, {0x0E26, 0x0E26, 0x0E26}, {0x0E27, 0x0E27, 0x0E27}, {0x0E28, 0x0E28, 0x0E28}, {0x0E29, 0x0E29, 0x0E29}, {0x0E2A, 0x0E2A, 0x0E2A}, {0x0E2B, 0x0E2B, 0x0E2B}, {0x0E2C, 0x0E2C, 0x0E2C}, {0x0E2D, 0x0E2D, 0x0E2D}, {0x0E2E, 0x0E2E, 0x0E2E}, {0x0E2F, 0x0E2F, 0x0E2F}, {0x0E30, 0x0E30, 0x0E30}, {0x0E31, 0x0E31, 0x0E31}, {0x0E32, 0x0E32, 0x0E32}, {0x0E33, 0x0E33, 0x0E33}, {0x0E34, 0x0E34, 0x0E34}, {0x0E35, 0x0E35, 0x0E35}, {0x0E36, 0x0E36, 0x0E36}, {0x0E37, 0x0E37, 0x0E37}, {0x0E38, 0x0E38, 0x0E38}, {0x0E39, 0x0E39, 0x0E39}, {0x0E3A, 0x0E3A, 0x0E3A}, {0x0E40, 0x0E40, 0x0E40}, {0x0E41, 0x0E41, 0x0E41}, {0x0E42, 0x0E42, 0x0E42}, {0x0E43, 0x0E43, 0x0E43}, {0x0E44, 0x0E44, 0x0E44}, {0x0E45, 0x0E45, 0x0E45}, {0x0E46, 0x0E46, 0x0E46}, {0x0E47, 0x0E47, 0x0E47}, {0x0E48, 0x0E48, 0x0E48}, {0x0E49, 0x0E49, 0x0E49}, {0x0E4A, 0x0E4A, 0x0E4A}, {0x0E4B, 0x0E4B, 0x0E4B}, {0x0E4C, 0x0E4C, 0x0E4C}, {0x0E4D, 0x0E4D, 0x0E4D}, {0x0E4E, 0x0E4E, 0x0E4E}, {0x0E81, 0x0E81, 0x0E81}, {0x0E82, 0x0E82, 0x0E82}, {0x0E84, 0x0E84, 0x0E84}, {0x0E87, 0x0E87, 0x0E87}, {0x0E88, 0x0E88, 0x0E88}, {0x0E8A, 0x0E8A, 0x0E8A}, {0x0E8D, 0x0E8D, 0x0E8D}, {0x0E94, 0x0E94, 0x0E94}, {0x0E95, 0x0E95, 0x0E95}, {0x0E96, 0x0E96, 0x0E96}, {0x0E97, 0x0E97, 0x0E97}, {0x0E99, 0x0E99, 0x0E99}, {0x0E9A, 0x0E9A, 0x0E9A}, {0x0E9B, 0x0E9B, 0x0E9B}, {0x0E9C, 0x0E9C, 0x0E9C}, {0x0E9D, 0x0E9D, 0x0E9D}, {0x0E9E, 0x0E9E, 0x0E9E}, {0x0E9F, 0x0E9F, 0x0E9F}, {0x0EA1, 0x0EA1, 0x0EA1}, {0x0EA2, 0x0EA2, 0x0EA2}, {0x0EA3, 0x0EA3, 0x0EA3}, {0x0EA5, 0x0EA5, 0x0EA5}, {0x0EA7, 0x0EA7, 0x0EA7}, {0x0EAA, 0x0EAA, 0x0EAA}, {0x0EAB, 0x0EAB, 0x0EAB}, {0x0EAD, 0x0EAD, 0x0EAD}, {0x0EAE, 0x0EAE, 0x0EAE}, {0x0EAF, 0x0EAF, 0x0EAF}, {0x0EB0, 0x0EB0, 0x0EB0}, {0x0EB1, 0x0EB1, 0x0EB1}, {0x0EB2, 0x0EB2, 0x0EB2}, {0x0EB3, 0x0EB3, 0x0EB3}, {0x0EB4, 0x0EB4, 0x0EB4}, {0x0EB5, 0x0EB5, 0x0EB5}, {0x0EB6, 0x0EB6, 0x0EB6}, {0x0EB7, 0x0EB7, 0x0EB7}, {0x0EB8, 0x0EB8, 0x0EB8}, {0x0EB9, 0x0EB9, 0x0EB9}, {0x0EBB, 0x0EBB, 0x0EBB}, {0x0EBC, 0x0EBC, 0x0EBC}, {0x0EBD, 0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC0, 0x0EC0}, {0x0EC1, 0x0EC1, 0x0EC1}, {0x0EC2, 0x0EC2, 0x0EC2}, {0x0EC3, 0x0EC3, 0x0EC3}, {0x0EC4, 0x0EC4, 0x0EC4}, {0x0EC6, 0x0EC6, 0x0EC6}, {0x0EC8, 0x0EC8, 0x0EC8}, {0x0EC9, 0x0EC9, 0x0EC9}, {0x0ECA, 0x0ECA, 0x0ECA}, {0x0ECB, 0x0ECB, 0x0ECB}, {0x0ECC, 0x0ECC, 0x0ECC}, {0x0ECD, 0x0ECD, 0x0ECD}, {0x0EDC, 0x0EDC, 0x0EDC}, {0x0EDD, 0x0EDD, 0x0EDD}, {0x0F00, 0x0F00, 0x0F00}, {0x0F18, 0x0F18, 0x0F18}, {0x0F19, 0x0F19, 0x0F19}, {0x0F35, 0x0F35, 0x0F35}, {0x0F37, 0x0F37, 0x0F37}, {0x0F39, 0x0F39, 0x0F39}, {0x0F40, 0x0F40, 0x0F40}, {0x0F41, 0x0F41, 0x0F41}, {0x0F42, 0x0F42, 0x0F42}, {0x0F43, 0x0F43, 0x0F43}, {0x0F44, 0x0F44, 0x0F44}, {0x0F45, 0x0F45, 0x0F45}, {0x0F46, 0x0F46, 0x0F46}, {0x0F47, 0x0F47, 0x0F47}, {0x0F49, 0x0F49, 0x0F49}, {0x0F4A, 0x0F4A, 0x0F4A}, {0x0F4B, 0x0F4B, 0x0F4B}, {0x0F4C, 0x0F4C, 0x0F4C}, {0x0F4D, 0x0F4D, 0x0F4D}, {0x0F4E, 0x0F4E, 0x0F4E}, {0x0F4F, 0x0F4F, 0x0F4F}, {0x0F50, 0x0F50, 0x0F50}, {0x0F51, 0x0F51, 0x0F51}, {0x0F52, 0x0F52, 0x0F52}, {0x0F53, 0x0F53, 0x0F53}, {0x0F54, 0x0F54, 0x0F54}, {0x0F55, 0x0F55, 0x0F55}, {0x0F56, 0x0F56, 0x0F56}, {0x0F57, 0x0F57, 0x0F57}, {0x0F58, 0x0F58, 0x0F58}, {0x0F59, 0x0F59, 0x0F59}, {0x0F5A, 0x0F5A, 0x0F5A}, {0x0F5B, 0x0F5B, 0x0F5B}, {0x0F5C, 0x0F5C, 0x0F5C}, {0x0F5D, 0x0F5D, 0x0F5D}, {0x0F5E, 0x0F5E, 0x0F5E}, {0x0F5F, 0x0F5F, 0x0F5F}, {0x0F60, 0x0F60, 0x0F60}, {0x0F61, 0x0F61, 0x0F61}, {0x0F62, 0x0F62, 0x0F62}, {0x0F63, 0x0F63, 0x0F63}, {0x0F64, 0x0F64, 0x0F64}, {0x0F65, 0x0F65, 0x0F65}, {0x0F66, 0x0F66, 0x0F66}, {0x0F67, 0x0F67, 0x0F67}, {0x0F68, 0x0F68, 0x0F68}, {0x0F69, 0x0F69, 0x0F69}, {0x0F6A, 0x0F6A, 0x0F6A}, {0x0F71, 0x0F71, 0x0F71}, {0x0F72, 0x0F72, 0x0F72}, {0x0F73, 0x0F73, 0x0F73}, {0x0F74, 0x0F74, 0x0F74}, {0x0F75, 0x0F75, 0x0F75}, {0x0F76, 0x0F76, 0x0F76}, {0x0F77, 0x0F77, 0x0F77}, {0x0F78, 0x0F78, 0x0F78}, {0x0F79, 0x0F79, 0x0F79}, {0x0F7A, 0x0F7A, 0x0F7A}, {0x0F7B, 0x0F7B, 0x0F7B}, {0x0F7C, 0x0F7C, 0x0F7C}, {0x0F7D, 0x0F7D, 0x0F7D}, {0x0F7E, 0x0F7E, 0x0F7E}, {0x0F80, 0x0F80, 0x0F80}, {0x0F81, 0x0F81, 0x0F81}, {0x0F82, 0x0F82, 0x0F82}, {0x0F83, 0x0F83, 0x0F83}, {0x0F84, 0x0F84, 0x0F84}, {0x0F86, 0x0F86, 0x0F86}, {0x0F87, 0x0F87, 0x0F87}, {0x0F88, 0x0F88, 0x0F88}, {0x0F89, 0x0F89, 0x0F89}, {0x0F8A, 0x0F8A, 0x0F8A}, {0x0F8B, 0x0F8B, 0x0F8B}, {0x0F90, 0x0F90, 0x0F90}, {0x0F91, 0x0F91, 0x0F91}, {0x0F92, 0x0F92, 0x0F92}, {0x0F93, 0x0F93, 0x0F93}, {0x0F94, 0x0F94, 0x0F94}, {0x0F95, 0x0F95, 0x0F95}, {0x0F96, 0x0F96, 0x0F96}, {0x0F97, 0x0F97, 0x0F97}, {0x0F99, 0x0F99, 0x0F99}, {0x0F9A, 0x0F9A, 0x0F9A}, {0x0F9B, 0x0F9B, 0x0F9B}, {0x0F9C, 0x0F9C, 0x0F9C}, {0x0F9D, 0x0F9D, 0x0F9D}, {0x0F9E, 0x0F9E, 0x0F9E}, {0x0F9F, 0x0F9F, 0x0F9F}, {0x0FA0, 0x0FA0, 0x0FA0}, {0x0FA1, 0x0FA1, 0x0FA1}, {0x0FA2, 0x0FA2, 0x0FA2}, {0x0FA3, 0x0FA3, 0x0FA3}, {0x0FA4, 0x0FA4, 0x0FA4}, {0x0FA5, 0x0FA5, 0x0FA5}, {0x0FA6, 0x0FA6, 0x0FA6}, {0x0FA7, 0x0FA7, 0x0FA7}, {0x0FA8, 0x0FA8, 0x0FA8}, {0x0FA9, 0x0FA9, 0x0FA9}, {0x0FAA, 0x0FAA, 0x0FAA}, {0x0FAB, 0x0FAB, 0x0FAB}, {0x0FAC, 0x0FAC, 0x0FAC}, {0x0FAD, 0x0FAD, 0x0FAD}, {0x0FAE, 0x0FAE, 0x0FAE}, {0x0FAF, 0x0FAF, 0x0FAF}, {0x0FB0, 0x0FB0, 0x0FB0}, {0x0FB1, 0x0FB1, 0x0FB1}, {0x0FB2, 0x0FB2, 0x0FB2}, {0x0FB3, 0x0FB3, 0x0FB3}, {0x0FB4, 0x0FB4, 0x0FB4}, {0x0FB5, 0x0FB5, 0x0FB5}, {0x0FB6, 0x0FB6, 0x0FB6}, {0x0FB7, 0x0FB7, 0x0FB7}, {0x0FB8, 0x0FB8, 0x0FB8}, {0x0FB9, 0x0FB9, 0x0FB9}, {0x0FBA, 0x0FBA, 0x0FBA}, {0x0FBB, 0x0FBB, 0x0FBB}, {0x0FBC, 0x0FBC, 0x0FBC}, {0x0FC6, 0x0FC6, 0x0FC6}, {0x1000, 0x1000, 0x1000}, {0x1001, 0x1001, 0x1001}, {0x1002, 0x1002, 0x1002}, {0x1003, 0x1003, 0x1003}, {0x1004, 0x1004, 0x1004}, {0x1005, 0x1005, 0x1005}, {0x1006, 0x1006, 0x1006}, {0x1007, 0x1007, 0x1007}, {0x1008, 0x1008, 0x1008}, {0x1009, 0x1009, 0x1009}, {0x100A, 0x100A, 0x100A}, {0x100B, 0x100B, 0x100B}, {0x100C, 0x100C, 0x100C}, {0x100D, 0x100D, 0x100D}, {0x100E, 0x100E, 0x100E}, {0x100F, 0x100F, 0x100F}, {0x1010, 0x1010, 0x1010}, {0x1011, 0x1011, 0x1011}, {0x1012, 0x1012, 0x1012}, {0x1013, 0x1013, 0x1013}, {0x1014, 0x1014, 0x1014}, {0x1015, 0x1015, 0x1015}, {0x1016, 0x1016, 0x1016}, {0x1017, 0x1017, 0x1017}, {0x1018, 0x1018, 0x1018}, {0x1019, 0x1019, 0x1019}, {0x101A, 0x101A, 0x101A}, {0x101B, 0x101B, 0x101B}, {0x101C, 0x101C, 0x101C}, {0x101D, 0x101D, 0x101D}, {0x101E, 0x101E, 0x101E}, {0x101F, 0x101F, 0x101F}, {0x1020, 0x1020, 0x1020}, {0x1021, 0x1021, 0x1021}, {0x1023, 0x1023, 0x1023}, {0x1024, 0x1024, 0x1024}, {0x1025, 0x1025, 0x1025}, {0x1026, 0x1026, 0x1026}, {0x1027, 0x1027, 0x1027}, {0x1029, 0x1029, 0x1029}, {0x102A, 0x102A, 0x102A}, {0x102D, 0x102D, 0x102D}, {0x102E, 0x102E, 0x102E}, {0x102F, 0x102F, 0x102F}, {0x1030, 0x1030, 0x1030}, {0x1032, 0x1032, 0x1032}, {0x1036, 0x1036, 0x1036}, {0x1037, 0x1037, 0x1037}, {0x1039, 0x1039, 0x1039}, {0x1050, 0x1050, 0x1050}, {0x1051, 0x1051, 0x1051}, {0x1052, 0x1052, 0x1052}, {0x1053, 0x1053, 0x1053}, {0x1054, 0x1054, 0x1054}, {0x1055, 0x1055, 0x1055}, {0x1058, 0x1058, 0x1058}, {0x1059, 0x1059, 0x1059}, {0x10A0, 0x10A0, 0x2D00}, {0x10A1, 0x10A1, 0x2D01}, {0x10A2, 0x10A2, 0x2D02}, {0x10A3, 0x10A3, 0x2D03}, {0x10A4, 0x10A4, 0x2D04}, {0x10A5, 0x10A5, 0x2D05}, {0x10A6, 0x10A6, 0x2D06}, {0x10A7, 0x10A7, 0x2D07}, {0x10A8, 0x10A8, 0x2D08}, {0x10A9, 0x10A9, 0x2D09}, {0x10AA, 0x10AA, 0x2D0A}, {0x10AB, 0x10AB, 0x2D0B}, {0x10AC, 0x10AC, 0x2D0C}, {0x10AD, 0x10AD, 0x2D0D}, {0x10AE, 0x10AE, 0x2D0E}, {0x10AF, 0x10AF, 0x2D0F}, {0x10B0, 0x10B0, 0x2D10}, {0x10B1, 0x10B1, 0x2D11}, {0x10B2, 0x10B2, 0x2D12}, {0x10B3, 0x10B3, 0x2D13}, {0x10B4, 0x10B4, 0x2D14}, {0x10B5, 0x10B5, 0x2D15}, {0x10B6, 0x10B6, 0x2D16}, {0x10B7, 0x10B7, 0x2D17}, {0x10B8, 0x10B8, 0x2D18}, {0x10B9, 0x10B9, 0x2D19}, {0x10BA, 0x10BA, 0x2D1A}, {0x10BB, 0x10BB, 0x2D1B}, {0x10BC, 0x10BC, 0x2D1C}, {0x10BD, 0x10BD, 0x2D1D}, {0x10BE, 0x10BE, 0x2D1E}, {0x10BF, 0x10BF, 0x2D1F}, {0x10C0, 0x10C0, 0x2D20}, {0x10C1, 0x10C1, 0x2D21}, {0x10C2, 0x10C2, 0x2D22}, {0x10C3, 0x10C3, 0x2D23}, {0x10C4, 0x10C4, 0x2D24}, {0x10C5, 0x10C5, 0x2D25}, {0x10D0, 0x10D0, 0x10D0}, {0x10D1, 0x10D1, 0x10D1}, {0x10D2, 0x10D2, 0x10D2}, {0x10D3, 0x10D3, 0x10D3}, {0x10D4, 0x10D4, 0x10D4}, {0x10D5, 0x10D5, 0x10D5}, {0x10D6, 0x10D6, 0x10D6}, {0x10D7, 0x10D7, 0x10D7}, {0x10D8, 0x10D8, 0x10D8}, {0x10D9, 0x10D9, 0x10D9}, {0x10DA, 0x10DA, 0x10DA}, {0x10DB, 0x10DB, 0x10DB}, {0x10DC, 0x10DC, 0x10DC}, {0x10DD, 0x10DD, 0x10DD}, {0x10DE, 0x10DE, 0x10DE}, {0x10DF, 0x10DF, 0x10DF}, {0x10E0, 0x10E0, 0x10E0}, {0x10E1, 0x10E1, 0x10E1}, {0x10E2, 0x10E2, 0x10E2}, {0x10E3, 0x10E3, 0x10E3}, {0x10E4, 0x10E4, 0x10E4}, {0x10E5, 0x10E5, 0x10E5}, {0x10E6, 0x10E6, 0x10E6}, {0x10E7, 0x10E7, 0x10E7}, {0x10E8, 0x10E8, 0x10E8}, {0x10E9, 0x10E9, 0x10E9}, {0x10EA, 0x10EA, 0x10EA}, {0x10EB, 0x10EB, 0x10EB}, {0x10EC, 0x10EC, 0x10EC}, {0x10ED, 0x10ED, 0x10ED}, {0x10EE, 0x10EE, 0x10EE}, {0x10EF, 0x10EF, 0x10EF}, {0x10F0, 0x10F0, 0x10F0}, {0x10F1, 0x10F1, 0x10F1}, {0x10F2, 0x10F2, 0x10F2}, {0x10F3, 0x10F3, 0x10F3}, {0x10F4, 0x10F4, 0x10F4}, {0x10F5, 0x10F5, 0x10F5}, {0x10F6, 0x10F6, 0x10F6}, {0x10F7, 0x10F7, 0x10F7}, {0x10F8, 0x10F8, 0x10F8}, {0x10F9, 0x10F9, 0x10F9}, {0x10FA, 0x10FA, 0x10FA}, {0x10FC, 0x10FC, 0x10FC}, {0x1100, 0x1100, 0x1100}, {0x1101, 0x1101, 0x1101}, {0x1102, 0x1102, 0x1102}, {0x1103, 0x1103, 0x1103}, {0x1104, 0x1104, 0x1104}, {0x1105, 0x1105, 0x1105}, {0x1106, 0x1106, 0x1106}, {0x1107, 0x1107, 0x1107}, {0x1108, 0x1108, 0x1108}, {0x1109, 0x1109, 0x1109}, {0x110A, 0x110A, 0x110A}, {0x110B, 0x110B, 0x110B}, {0x110C, 0x110C, 0x110C}, {0x110D, 0x110D, 0x110D}, {0x110E, 0x110E, 0x110E}, {0x110F, 0x110F, 0x110F}, {0x1110, 0x1110, 0x1110}, {0x1111, 0x1111, 0x1111}, {0x1112, 0x1112, 0x1112}, {0x1113, 0x1113, 0x1113}, {0x1114, 0x1114, 0x1114}, {0x1115, 0x1115, 0x1115}, {0x1116, 0x1116, 0x1116}, {0x1117, 0x1117, 0x1117}, {0x1118, 0x1118, 0x1118}, {0x1119, 0x1119, 0x1119}, {0x111A, 0x111A, 0x111A}, {0x111B, 0x111B, 0x111B}, {0x111C, 0x111C, 0x111C}, {0x111D, 0x111D, 0x111D}, {0x111E, 0x111E, 0x111E}, {0x111F, 0x111F, 0x111F}, {0x1120, 0x1120, 0x1120}, {0x1121, 0x1121, 0x1121}, {0x1122, 0x1122, 0x1122}, {0x1123, 0x1123, 0x1123}, {0x1124, 0x1124, 0x1124}, {0x1125, 0x1125, 0x1125}, {0x1126, 0x1126, 0x1126}, {0x1127, 0x1127, 0x1127}, {0x1128, 0x1128, 0x1128}, {0x1129, 0x1129, 0x1129}, {0x112A, 0x112A, 0x112A}, {0x112B, 0x112B, 0x112B}, {0x112C, 0x112C, 0x112C}, {0x112D, 0x112D, 0x112D}, {0x112E, 0x112E, 0x112E}, {0x112F, 0x112F, 0x112F}, {0x1130, 0x1130, 0x1130}, {0x1131, 0x1131, 0x1131}, {0x1132, 0x1132, 0x1132}, {0x1133, 0x1133, 0x1133}, {0x1134, 0x1134, 0x1134}, {0x1135, 0x1135, 0x1135}, {0x1136, 0x1136, 0x1136}, {0x1137, 0x1137, 0x1137}, {0x1138, 0x1138, 0x1138}, {0x1139, 0x1139, 0x1139}, {0x113A, 0x113A, 0x113A}, {0x113B, 0x113B, 0x113B}, {0x113C, 0x113C, 0x113C}, {0x113D, 0x113D, 0x113D}, {0x113E, 0x113E, 0x113E}, {0x113F, 0x113F, 0x113F}, {0x1140, 0x1140, 0x1140}, {0x1141, 0x1141, 0x1141}, {0x1142, 0x1142, 0x1142}, {0x1143, 0x1143, 0x1143}, {0x1144, 0x1144, 0x1144}, {0x1145, 0x1145, 0x1145}, {0x1146, 0x1146, 0x1146}, {0x1147, 0x1147, 0x1147}, {0x1148, 0x1148, 0x1148}, {0x1149, 0x1149, 0x1149}, {0x114A, 0x114A, 0x114A}, {0x114B, 0x114B, 0x114B}, {0x114C, 0x114C, 0x114C}, {0x114D, 0x114D, 0x114D}, {0x114E, 0x114E, 0x114E}, {0x114F, 0x114F, 0x114F}, {0x1150, 0x1150, 0x1150}, {0x1151, 0x1151, 0x1151}, {0x1152, 0x1152, 0x1152}, {0x1153, 0x1153, 0x1153}, {0x1154, 0x1154, 0x1154}, {0x1155, 0x1155, 0x1155}, {0x1156, 0x1156, 0x1156}, {0x1157, 0x1157, 0x1157}, {0x1158, 0x1158, 0x1158}, {0x1159, 0x1159, 0x1159}, {0x115F, 0x115F, 0x115F}, {0x1160, 0x1160, 0x1160}, {0x1161, 0x1161, 0x1161}, {0x1162, 0x1162, 0x1162}, {0x1163, 0x1163, 0x1163}, {0x1164, 0x1164, 0x1164}, {0x1165, 0x1165, 0x1165}, {0x1166, 0x1166, 0x1166}, {0x1167, 0x1167, 0x1167}, {0x1168, 0x1168, 0x1168}, {0x1169, 0x1169, 0x1169}, {0x116A, 0x116A, 0x116A}, {0x116B, 0x116B, 0x116B}, {0x116C, 0x116C, 0x116C}, {0x116D, 0x116D, 0x116D}, {0x116E, 0x116E, 0x116E}, {0x116F, 0x116F, 0x116F}, {0x1170, 0x1170, 0x1170}, {0x1171, 0x1171, 0x1171}, {0x1172, 0x1172, 0x1172}, {0x1173, 0x1173, 0x1173}, {0x1174, 0x1174, 0x1174}, {0x1175, 0x1175, 0x1175}, {0x1176, 0x1176, 0x1176}, {0x1177, 0x1177, 0x1177}, {0x1178, 0x1178, 0x1178}, {0x1179, 0x1179, 0x1179}, {0x117A, 0x117A, 0x117A}, {0x117B, 0x117B, 0x117B}, {0x117C, 0x117C, 0x117C}, {0x117D, 0x117D, 0x117D}, {0x117E, 0x117E, 0x117E}, {0x117F, 0x117F, 0x117F}, {0x1180, 0x1180, 0x1180}, {0x1181, 0x1181, 0x1181}, {0x1182, 0x1182, 0x1182}, {0x1183, 0x1183, 0x1183}, {0x1184, 0x1184, 0x1184}, {0x1185, 0x1185, 0x1185}, {0x1186, 0x1186, 0x1186}, {0x1187, 0x1187, 0x1187}, {0x1188, 0x1188, 0x1188}, {0x1189, 0x1189, 0x1189}, {0x118A, 0x118A, 0x118A}, {0x118B, 0x118B, 0x118B}, {0x118C, 0x118C, 0x118C}, {0x118D, 0x118D, 0x118D}, {0x118E, 0x118E, 0x118E}, {0x118F, 0x118F, 0x118F}, {0x1190, 0x1190, 0x1190}, {0x1191, 0x1191, 0x1191}, {0x1192, 0x1192, 0x1192}, {0x1193, 0x1193, 0x1193}, {0x1194, 0x1194, 0x1194}, {0x1195, 0x1195, 0x1195}, {0x1196, 0x1196, 0x1196}, {0x1197, 0x1197, 0x1197}, {0x1198, 0x1198, 0x1198}, {0x1199, 0x1199, 0x1199}, {0x119A, 0x119A, 0x119A}, {0x119B, 0x119B, 0x119B}, {0x119C, 0x119C, 0x119C}, {0x119D, 0x119D, 0x119D}, {0x119E, 0x119E, 0x119E}, {0x119F, 0x119F, 0x119F}, {0x11A0, 0x11A0, 0x11A0}, {0x11A1, 0x11A1, 0x11A1}, {0x11A2, 0x11A2, 0x11A2}, {0x11A8, 0x11A8, 0x11A8}, {0x11A9, 0x11A9, 0x11A9}, {0x11AA, 0x11AA, 0x11AA}, {0x11AB, 0x11AB, 0x11AB}, {0x11AC, 0x11AC, 0x11AC}, {0x11AD, 0x11AD, 0x11AD}, {0x11AE, 0x11AE, 0x11AE}, {0x11AF, 0x11AF, 0x11AF}, {0x11B0, 0x11B0, 0x11B0}, {0x11B1, 0x11B1, 0x11B1}, {0x11B2, 0x11B2, 0x11B2}, {0x11B3, 0x11B3, 0x11B3}, {0x11B4, 0x11B4, 0x11B4}, {0x11B5, 0x11B5, 0x11B5}, {0x11B6, 0x11B6, 0x11B6}, {0x11B7, 0x11B7, 0x11B7}, {0x11B8, 0x11B8, 0x11B8}, {0x11B9, 0x11B9, 0x11B9}, {0x11BA, 0x11BA, 0x11BA}, {0x11BB, 0x11BB, 0x11BB}, {0x11BC, 0x11BC, 0x11BC}, {0x11BD, 0x11BD, 0x11BD}, {0x11BE, 0x11BE, 0x11BE}, {0x11BF, 0x11BF, 0x11BF}, {0x11C0, 0x11C0, 0x11C0}, {0x11C1, 0x11C1, 0x11C1}, {0x11C2, 0x11C2, 0x11C2}, {0x11C3, 0x11C3, 0x11C3}, {0x11C4, 0x11C4, 0x11C4}, {0x11C5, 0x11C5, 0x11C5}, {0x11C6, 0x11C6, 0x11C6}, {0x11C7, 0x11C7, 0x11C7}, {0x11C8, 0x11C8, 0x11C8}, {0x11C9, 0x11C9, 0x11C9}, {0x11CA, 0x11CA, 0x11CA}, {0x11CB, 0x11CB, 0x11CB}, {0x11CC, 0x11CC, 0x11CC}, {0x11CD, 0x11CD, 0x11CD}, {0x11CE, 0x11CE, 0x11CE}, {0x11CF, 0x11CF, 0x11CF}, {0x11D0, 0x11D0, 0x11D0}, {0x11D1, 0x11D1, 0x11D1}, {0x11D2, 0x11D2, 0x11D2}, {0x11D3, 0x11D3, 0x11D3}, {0x11D4, 0x11D4, 0x11D4}, {0x11D5, 0x11D5, 0x11D5}, {0x11D6, 0x11D6, 0x11D6}, {0x11D7, 0x11D7, 0x11D7}, {0x11D8, 0x11D8, 0x11D8}, {0x11D9, 0x11D9, 0x11D9}, {0x11DA, 0x11DA, 0x11DA}, {0x11DB, 0x11DB, 0x11DB}, {0x11DC, 0x11DC, 0x11DC}, {0x11DD, 0x11DD, 0x11DD}, {0x11DE, 0x11DE, 0x11DE}, {0x11DF, 0x11DF, 0x11DF}, {0x11E0, 0x11E0, 0x11E0}, {0x11E1, 0x11E1, 0x11E1}, {0x11E2, 0x11E2, 0x11E2}, {0x11E3, 0x11E3, 0x11E3}, {0x11E4, 0x11E4, 0x11E4}, {0x11E5, 0x11E5, 0x11E5}, {0x11E6, 0x11E6, 0x11E6}, {0x11E7, 0x11E7, 0x11E7}, {0x11E8, 0x11E8, 0x11E8}, {0x11E9, 0x11E9, 0x11E9}, {0x11EA, 0x11EA, 0x11EA}, {0x11EB, 0x11EB, 0x11EB}, {0x11EC, 0x11EC, 0x11EC}, {0x11ED, 0x11ED, 0x11ED}, {0x11EE, 0x11EE, 0x11EE}, {0x11EF, 0x11EF, 0x11EF}, {0x11F0, 0x11F0, 0x11F0}, {0x11F1, 0x11F1, 0x11F1}, {0x11F2, 0x11F2, 0x11F2}, {0x11F3, 0x11F3, 0x11F3}, {0x11F4, 0x11F4, 0x11F4}, {0x11F5, 0x11F5, 0x11F5}, {0x11F6, 0x11F6, 0x11F6}, {0x11F7, 0x11F7, 0x11F7}, {0x11F8, 0x11F8, 0x11F8}, {0x11F9, 0x11F9, 0x11F9}, {0x1200, 0x1200, 0x1200}, {0x1201, 0x1201, 0x1201}, {0x1202, 0x1202, 0x1202}, {0x1203, 0x1203, 0x1203}, {0x1204, 0x1204, 0x1204}, {0x1205, 0x1205, 0x1205}, {0x1206, 0x1206, 0x1206}, {0x1207, 0x1207, 0x1207}, {0x1208, 0x1208, 0x1208}, {0x1209, 0x1209, 0x1209}, {0x120A, 0x120A, 0x120A}, {0x120B, 0x120B, 0x120B}, {0x120C, 0x120C, 0x120C}, {0x120D, 0x120D, 0x120D}, {0x120E, 0x120E, 0x120E}, {0x120F, 0x120F, 0x120F}, {0x1210, 0x1210, 0x1210}, {0x1211, 0x1211, 0x1211}, {0x1212, 0x1212, 0x1212}, {0x1213, 0x1213, 0x1213}, {0x1214, 0x1214, 0x1214}, {0x1215, 0x1215, 0x1215}, {0x1216, 0x1216, 0x1216}, {0x1217, 0x1217, 0x1217}, {0x1218, 0x1218, 0x1218}, {0x1219, 0x1219, 0x1219}, {0x121A, 0x121A, 0x121A}, {0x121B, 0x121B, 0x121B}, {0x121C, 0x121C, 0x121C}, {0x121D, 0x121D, 0x121D}, {0x121E, 0x121E, 0x121E}, {0x121F, 0x121F, 0x121F}, {0x1220, 0x1220, 0x1220}, {0x1221, 0x1221, 0x1221}, {0x1222, 0x1222, 0x1222}, {0x1223, 0x1223, 0x1223}, {0x1224, 0x1224, 0x1224}, {0x1225, 0x1225, 0x1225}, {0x1226, 0x1226, 0x1226}, {0x1227, 0x1227, 0x1227}, {0x1228, 0x1228, 0x1228}, {0x1229, 0x1229, 0x1229}, {0x122A, 0x122A, 0x122A}, {0x122B, 0x122B, 0x122B}, {0x122C, 0x122C, 0x122C}, {0x122D, 0x122D, 0x122D}, {0x122E, 0x122E, 0x122E}, {0x122F, 0x122F, 0x122F}, {0x1230, 0x1230, 0x1230}, {0x1231, 0x1231, 0x1231}, {0x1232, 0x1232, 0x1232}, {0x1233, 0x1233, 0x1233}, {0x1234, 0x1234, 0x1234}, {0x1235, 0x1235, 0x1235}, {0x1236, 0x1236, 0x1236}, {0x1237, 0x1237, 0x1237}, {0x1238, 0x1238, 0x1238}, {0x1239, 0x1239, 0x1239}, {0x123A, 0x123A, 0x123A}, {0x123B, 0x123B, 0x123B}, {0x123C, 0x123C, 0x123C}, {0x123D, 0x123D, 0x123D}, {0x123E, 0x123E, 0x123E}, {0x123F, 0x123F, 0x123F}, {0x1240, 0x1240, 0x1240}, {0x1241, 0x1241, 0x1241}, {0x1242, 0x1242, 0x1242}, {0x1243, 0x1243, 0x1243}, {0x1244, 0x1244, 0x1244}, {0x1245, 0x1245, 0x1245}, {0x1246, 0x1246, 0x1246}, {0x1247, 0x1247, 0x1247}, {0x1248, 0x1248, 0x1248}, {0x124A, 0x124A, 0x124A}, {0x124B, 0x124B, 0x124B}, {0x124C, 0x124C, 0x124C}, {0x124D, 0x124D, 0x124D}, {0x1250, 0x1250, 0x1250}, {0x1251, 0x1251, 0x1251}, {0x1252, 0x1252, 0x1252}, {0x1253, 0x1253, 0x1253}, {0x1254, 0x1254, 0x1254}, {0x1255, 0x1255, 0x1255}, {0x1256, 0x1256, 0x1256}, {0x1258, 0x1258, 0x1258}, {0x125A, 0x125A, 0x125A}, {0x125B, 0x125B, 0x125B}, {0x125C, 0x125C, 0x125C}, {0x125D, 0x125D, 0x125D}, {0x1260, 0x1260, 0x1260}, {0x1261, 0x1261, 0x1261}, {0x1262, 0x1262, 0x1262}, {0x1263, 0x1263, 0x1263}, {0x1264, 0x1264, 0x1264}, {0x1265, 0x1265, 0x1265}, {0x1266, 0x1266, 0x1266}, {0x1267, 0x1267, 0x1267}, {0x1268, 0x1268, 0x1268}, {0x1269, 0x1269, 0x1269}, {0x126A, 0x126A, 0x126A}, {0x126B, 0x126B, 0x126B}, {0x126C, 0x126C, 0x126C}, {0x126D, 0x126D, 0x126D}, {0x126E, 0x126E, 0x126E}, {0x126F, 0x126F, 0x126F}, {0x1270, 0x1270, 0x1270}, {0x1271, 0x1271, 0x1271}, {0x1272, 0x1272, 0x1272}, {0x1273, 0x1273, 0x1273}, {0x1274, 0x1274, 0x1274}, {0x1275, 0x1275, 0x1275}, {0x1276, 0x1276, 0x1276}, {0x1277, 0x1277, 0x1277}, {0x1278, 0x1278, 0x1278}, {0x1279, 0x1279, 0x1279}, {0x127A, 0x127A, 0x127A}, {0x127B, 0x127B, 0x127B}, {0x127C, 0x127C, 0x127C}, {0x127D, 0x127D, 0x127D}, {0x127E, 0x127E, 0x127E}, {0x127F, 0x127F, 0x127F}, {0x1280, 0x1280, 0x1280}, {0x1281, 0x1281, 0x1281}, {0x1282, 0x1282, 0x1282}, {0x1283, 0x1283, 0x1283}, {0x1284, 0x1284, 0x1284}, {0x1285, 0x1285, 0x1285}, {0x1286, 0x1286, 0x1286}, {0x1287, 0x1287, 0x1287}, {0x1288, 0x1288, 0x1288}, {0x128A, 0x128A, 0x128A}, {0x128B, 0x128B, 0x128B}, {0x128C, 0x128C, 0x128C}, {0x128D, 0x128D, 0x128D}, {0x1290, 0x1290, 0x1290}, {0x1291, 0x1291, 0x1291}, {0x1292, 0x1292, 0x1292}, {0x1293, 0x1293, 0x1293}, {0x1294, 0x1294, 0x1294}, {0x1295, 0x1295, 0x1295}, {0x1296, 0x1296, 0x1296}, {0x1297, 0x1297, 0x1297}, {0x1298, 0x1298, 0x1298}, {0x1299, 0x1299, 0x1299}, {0x129A, 0x129A, 0x129A}, {0x129B, 0x129B, 0x129B}, {0x129C, 0x129C, 0x129C}, {0x129D, 0x129D, 0x129D}, {0x129E, 0x129E, 0x129E}, {0x129F, 0x129F, 0x129F}, {0x12A0, 0x12A0, 0x12A0}, {0x12A1, 0x12A1, 0x12A1}, {0x12A2, 0x12A2, 0x12A2}, {0x12A3, 0x12A3, 0x12A3}, {0x12A4, 0x12A4, 0x12A4}, {0x12A5, 0x12A5, 0x12A5}, {0x12A6, 0x12A6, 0x12A6}, {0x12A7, 0x12A7, 0x12A7}, {0x12A8, 0x12A8, 0x12A8}, {0x12A9, 0x12A9, 0x12A9}, {0x12AA, 0x12AA, 0x12AA}, {0x12AB, 0x12AB, 0x12AB}, {0x12AC, 0x12AC, 0x12AC}, {0x12AD, 0x12AD, 0x12AD}, {0x12AE, 0x12AE, 0x12AE}, {0x12AF, 0x12AF, 0x12AF}, {0x12B0, 0x12B0, 0x12B0}, {0x12B2, 0x12B2, 0x12B2}, {0x12B3, 0x12B3, 0x12B3}, {0x12B4, 0x12B4, 0x12B4}, {0x12B5, 0x12B5, 0x12B5}, {0x12B8, 0x12B8, 0x12B8}, {0x12B9, 0x12B9, 0x12B9}, {0x12BA, 0x12BA, 0x12BA}, {0x12BB, 0x12BB, 0x12BB}, {0x12BC, 0x12BC, 0x12BC}, {0x12BD, 0x12BD, 0x12BD}, {0x12BE, 0x12BE, 0x12BE}, {0x12C0, 0x12C0, 0x12C0}, {0x12C2, 0x12C2, 0x12C2}, {0x12C3, 0x12C3, 0x12C3}, {0x12C4, 0x12C4, 0x12C4}, {0x12C5, 0x12C5, 0x12C5}, {0x12C8, 0x12C8, 0x12C8}, {0x12C9, 0x12C9, 0x12C9}, {0x12CA, 0x12CA, 0x12CA}, {0x12CB, 0x12CB, 0x12CB}, {0x12CC, 0x12CC, 0x12CC}, {0x12CD, 0x12CD, 0x12CD}, {0x12CE, 0x12CE, 0x12CE}, {0x12CF, 0x12CF, 0x12CF}, {0x12D0, 0x12D0, 0x12D0}, {0x12D1, 0x12D1, 0x12D1}, {0x12D2, 0x12D2, 0x12D2}, {0x12D3, 0x12D3, 0x12D3}, {0x12D4, 0x12D4, 0x12D4}, {0x12D5, 0x12D5, 0x12D5}, {0x12D6, 0x12D6, 0x12D6}, {0x12D8, 0x12D8, 0x12D8}, {0x12D9, 0x12D9, 0x12D9}, {0x12DA, 0x12DA, 0x12DA}, {0x12DB, 0x12DB, 0x12DB}, {0x12DC, 0x12DC, 0x12DC}, {0x12DD, 0x12DD, 0x12DD}, {0x12DE, 0x12DE, 0x12DE}, {0x12DF, 0x12DF, 0x12DF}, {0x12E0, 0x12E0, 0x12E0}, {0x12E1, 0x12E1, 0x12E1}, {0x12E2, 0x12E2, 0x12E2}, {0x12E3, 0x12E3, 0x12E3}, {0x12E4, 0x12E4, 0x12E4}, {0x12E5, 0x12E5, 0x12E5}, {0x12E6, 0x12E6, 0x12E6}, {0x12E7, 0x12E7, 0x12E7}, {0x12E8, 0x12E8, 0x12E8}, {0x12E9, 0x12E9, 0x12E9}, {0x12EA, 0x12EA, 0x12EA}, {0x12EB, 0x12EB, 0x12EB}, {0x12EC, 0x12EC, 0x12EC}, {0x12ED, 0x12ED, 0x12ED}, {0x12EE, 0x12EE, 0x12EE}, {0x12EF, 0x12EF, 0x12EF}, {0x12F0, 0x12F0, 0x12F0}, {0x12F1, 0x12F1, 0x12F1}, {0x12F2, 0x12F2, 0x12F2}, {0x12F3, 0x12F3, 0x12F3}, {0x12F4, 0x12F4, 0x12F4}, {0x12F5, 0x12F5, 0x12F5}, {0x12F6, 0x12F6, 0x12F6}, {0x12F7, 0x12F7, 0x12F7}, {0x12F8, 0x12F8, 0x12F8}, {0x12F9, 0x12F9, 0x12F9}, {0x12FA, 0x12FA, 0x12FA}, {0x12FB, 0x12FB, 0x12FB}, {0x12FC, 0x12FC, 0x12FC}, {0x12FD, 0x12FD, 0x12FD}, {0x12FE, 0x12FE, 0x12FE}, {0x12FF, 0x12FF, 0x12FF}, {0x1300, 0x1300, 0x1300}, {0x1301, 0x1301, 0x1301}, {0x1302, 0x1302, 0x1302}, {0x1303, 0x1303, 0x1303}, {0x1304, 0x1304, 0x1304}, {0x1305, 0x1305, 0x1305}, {0x1306, 0x1306, 0x1306}, {0x1307, 0x1307, 0x1307}, {0x1308, 0x1308, 0x1308}, {0x1309, 0x1309, 0x1309}, {0x130A, 0x130A, 0x130A}, {0x130B, 0x130B, 0x130B}, {0x130C, 0x130C, 0x130C}, {0x130D, 0x130D, 0x130D}, {0x130E, 0x130E, 0x130E}, {0x130F, 0x130F, 0x130F}, {0x1310, 0x1310, 0x1310}, {0x1312, 0x1312, 0x1312}, {0x1313, 0x1313, 0x1313}, {0x1314, 0x1314, 0x1314}, {0x1315, 0x1315, 0x1315}, {0x1318, 0x1318, 0x1318}, {0x1319, 0x1319, 0x1319}, {0x131A, 0x131A, 0x131A}, {0x131B, 0x131B, 0x131B}, {0x131C, 0x131C, 0x131C}, {0x131D, 0x131D, 0x131D}, {0x131E, 0x131E, 0x131E}, {0x131F, 0x131F, 0x131F}, {0x1320, 0x1320, 0x1320}, {0x1321, 0x1321, 0x1321}, {0x1322, 0x1322, 0x1322}, {0x1323, 0x1323, 0x1323}, {0x1324, 0x1324, 0x1324}, {0x1325, 0x1325, 0x1325}, {0x1326, 0x1326, 0x1326}, {0x1327, 0x1327, 0x1327}, {0x1328, 0x1328, 0x1328}, {0x1329, 0x1329, 0x1329}, {0x132A, 0x132A, 0x132A}, {0x132B, 0x132B, 0x132B}, {0x132C, 0x132C, 0x132C}, {0x132D, 0x132D, 0x132D}, {0x132E, 0x132E, 0x132E}, {0x132F, 0x132F, 0x132F}, {0x1330, 0x1330, 0x1330}, {0x1331, 0x1331, 0x1331}, {0x1332, 0x1332, 0x1332}, {0x1333, 0x1333, 0x1333}, {0x1334, 0x1334, 0x1334}, {0x1335, 0x1335, 0x1335}, {0x1336, 0x1336, 0x1336}, {0x1337, 0x1337, 0x1337}, {0x1338, 0x1338, 0x1338}, {0x1339, 0x1339, 0x1339}, {0x133A, 0x133A, 0x133A}, {0x133B, 0x133B, 0x133B}, {0x133C, 0x133C, 0x133C}, {0x133D, 0x133D, 0x133D}, {0x133E, 0x133E, 0x133E}, {0x133F, 0x133F, 0x133F}, {0x1340, 0x1340, 0x1340}, {0x1341, 0x1341, 0x1341}, {0x1342, 0x1342, 0x1342}, {0x1343, 0x1343, 0x1343}, {0x1344, 0x1344, 0x1344}, {0x1345, 0x1345, 0x1345}, {0x1346, 0x1346, 0x1346}, {0x1347, 0x1347, 0x1347}, {0x1348, 0x1348, 0x1348}, {0x1349, 0x1349, 0x1349}, {0x134A, 0x134A, 0x134A}, {0x134B, 0x134B, 0x134B}, {0x134C, 0x134C, 0x134C}, {0x134D, 0x134D, 0x134D}, {0x134E, 0x134E, 0x134E}, {0x134F, 0x134F, 0x134F}, {0x1350, 0x1350, 0x1350}, {0x1351, 0x1351, 0x1351}, {0x1352, 0x1352, 0x1352}, {0x1353, 0x1353, 0x1353}, {0x1354, 0x1354, 0x1354}, {0x1355, 0x1355, 0x1355}, {0x1356, 0x1356, 0x1356}, {0x1357, 0x1357, 0x1357}, {0x1358, 0x1358, 0x1358}, {0x1359, 0x1359, 0x1359}, {0x135A, 0x135A, 0x135A}, {0x135F, 0x135F, 0x135F}, {0x1380, 0x1380, 0x1380}, {0x1381, 0x1381, 0x1381}, {0x1382, 0x1382, 0x1382}, {0x1383, 0x1383, 0x1383}, {0x1384, 0x1384, 0x1384}, {0x1385, 0x1385, 0x1385}, {0x1386, 0x1386, 0x1386}, {0x1387, 0x1387, 0x1387}, {0x1388, 0x1388, 0x1388}, {0x1389, 0x1389, 0x1389}, {0x138A, 0x138A, 0x138A}, {0x138B, 0x138B, 0x138B}, {0x138C, 0x138C, 0x138C}, {0x138D, 0x138D, 0x138D}, {0x138E, 0x138E, 0x138E}, {0x138F, 0x138F, 0x138F}, {0x13A0, 0x13A0, 0x13A0}, {0x13A1, 0x13A1, 0x13A1}, {0x13A2, 0x13A2, 0x13A2}, {0x13A3, 0x13A3, 0x13A3}, {0x13A4, 0x13A4, 0x13A4}, {0x13A5, 0x13A5, 0x13A5}, {0x13A6, 0x13A6, 0x13A6}, {0x13A7, 0x13A7, 0x13A7}, {0x13A8, 0x13A8, 0x13A8}, {0x13A9, 0x13A9, 0x13A9}, {0x13AA, 0x13AA, 0x13AA}, {0x13AB, 0x13AB, 0x13AB}, {0x13AC, 0x13AC, 0x13AC}, {0x13AD, 0x13AD, 0x13AD}, {0x13AE, 0x13AE, 0x13AE}, {0x13AF, 0x13AF, 0x13AF}, {0x13B0, 0x13B0, 0x13B0}, {0x13B1, 0x13B1, 0x13B1}, {0x13B2, 0x13B2, 0x13B2}, {0x13B3, 0x13B3, 0x13B3}, {0x13B4, 0x13B4, 0x13B4}, {0x13B5, 0x13B5, 0x13B5}, {0x13B6, 0x13B6, 0x13B6}, {0x13B7, 0x13B7, 0x13B7}, {0x13B8, 0x13B8, 0x13B8}, {0x13B9, 0x13B9, 0x13B9}, {0x13BA, 0x13BA, 0x13BA}, {0x13BB, 0x13BB, 0x13BB}, {0x13BC, 0x13BC, 0x13BC}, {0x13BD, 0x13BD, 0x13BD}, {0x13BE, 0x13BE, 0x13BE}, {0x13BF, 0x13BF, 0x13BF}, {0x13C0, 0x13C0, 0x13C0}, {0x13C1, 0x13C1, 0x13C1}, {0x13C2, 0x13C2, 0x13C2}, {0x13C3, 0x13C3, 0x13C3}, {0x13C4, 0x13C4, 0x13C4}, {0x13C5, 0x13C5, 0x13C5}, {0x13C6, 0x13C6, 0x13C6}, {0x13C7, 0x13C7, 0x13C7}, {0x13C8, 0x13C8, 0x13C8}, {0x13C9, 0x13C9, 0x13C9}, {0x13CA, 0x13CA, 0x13CA}, {0x13CB, 0x13CB, 0x13CB}, {0x13CC, 0x13CC, 0x13CC}, {0x13CD, 0x13CD, 0x13CD}, {0x13CE, 0x13CE, 0x13CE}, {0x13CF, 0x13CF, 0x13CF}, {0x13D0, 0x13D0, 0x13D0}, {0x13D1, 0x13D1, 0x13D1}, {0x13D2, 0x13D2, 0x13D2}, {0x13D3, 0x13D3, 0x13D3}, {0x13D4, 0x13D4, 0x13D4}, {0x13D5, 0x13D5, 0x13D5}, {0x13D6, 0x13D6, 0x13D6}, {0x13D7, 0x13D7, 0x13D7}, {0x13D8, 0x13D8, 0x13D8}, {0x13D9, 0x13D9, 0x13D9}, {0x13DA, 0x13DA, 0x13DA}, {0x13DB, 0x13DB, 0x13DB}, {0x13DC, 0x13DC, 0x13DC}, {0x13DD, 0x13DD, 0x13DD}, {0x13DE, 0x13DE, 0x13DE}, {0x13DF, 0x13DF, 0x13DF}, {0x13E0, 0x13E0, 0x13E0}, {0x13E1, 0x13E1, 0x13E1}, {0x13E2, 0x13E2, 0x13E2}, {0x13E3, 0x13E3, 0x13E3}, {0x13E4, 0x13E4, 0x13E4}, {0x13E5, 0x13E5, 0x13E5}, {0x13E6, 0x13E6, 0x13E6}, {0x13E7, 0x13E7, 0x13E7}, {0x13E8, 0x13E8, 0x13E8}, {0x13E9, 0x13E9, 0x13E9}, {0x13EA, 0x13EA, 0x13EA}, {0x13EB, 0x13EB, 0x13EB}, {0x13EC, 0x13EC, 0x13EC}, {0x13ED, 0x13ED, 0x13ED}, {0x13EE, 0x13EE, 0x13EE}, {0x13EF, 0x13EF, 0x13EF}, {0x13F0, 0x13F0, 0x13F0}, {0x13F1, 0x13F1, 0x13F1}, {0x13F2, 0x13F2, 0x13F2}, {0x13F3, 0x13F3, 0x13F3}, {0x13F4, 0x13F4, 0x13F4}, {0x1401, 0x1401, 0x1401}, {0x1402, 0x1402, 0x1402}, {0x1403, 0x1403, 0x1403}, {0x1404, 0x1404, 0x1404}, {0x1405, 0x1405, 0x1405}, {0x1406, 0x1406, 0x1406}, {0x1407, 0x1407, 0x1407}, {0x1408, 0x1408, 0x1408}, {0x1409, 0x1409, 0x1409}, {0x140A, 0x140A, 0x140A}, {0x140B, 0x140B, 0x140B}, {0x140C, 0x140C, 0x140C}, {0x140D, 0x140D, 0x140D}, {0x140E, 0x140E, 0x140E}, {0x140F, 0x140F, 0x140F}, {0x1410, 0x1410, 0x1410}, {0x1411, 0x1411, 0x1411}, {0x1412, 0x1412, 0x1412}, {0x1413, 0x1413, 0x1413}, {0x1414, 0x1414, 0x1414}, {0x1415, 0x1415, 0x1415}, {0x1416, 0x1416, 0x1416}, {0x1417, 0x1417, 0x1417}, {0x1418, 0x1418, 0x1418}, {0x1419, 0x1419, 0x1419}, {0x141A, 0x141A, 0x141A}, {0x141B, 0x141B, 0x141B}, {0x141C, 0x141C, 0x141C}, {0x141D, 0x141D, 0x141D}, {0x141E, 0x141E, 0x141E}, {0x141F, 0x141F, 0x141F}, {0x1420, 0x1420, 0x1420}, {0x1421, 0x1421, 0x1421}, {0x1422, 0x1422, 0x1422}, {0x1423, 0x1423, 0x1423}, {0x1424, 0x1424, 0x1424}, {0x1425, 0x1425, 0x1425}, {0x1426, 0x1426, 0x1426}, {0x1427, 0x1427, 0x1427}, {0x1428, 0x1428, 0x1428}, {0x1429, 0x1429, 0x1429}, {0x142A, 0x142A, 0x142A}, {0x142B, 0x142B, 0x142B}, {0x142C, 0x142C, 0x142C}, {0x142D, 0x142D, 0x142D}, {0x142E, 0x142E, 0x142E}, {0x142F, 0x142F, 0x142F}, {0x1430, 0x1430, 0x1430}, {0x1431, 0x1431, 0x1431}, {0x1432, 0x1432, 0x1432}, {0x1433, 0x1433, 0x1433}, {0x1434, 0x1434, 0x1434}, {0x1435, 0x1435, 0x1435}, {0x1436, 0x1436, 0x1436}, {0x1437, 0x1437, 0x1437}, {0x1438, 0x1438, 0x1438}, {0x1439, 0x1439, 0x1439}, {0x143A, 0x143A, 0x143A}, {0x143B, 0x143B, 0x143B}, {0x143C, 0x143C, 0x143C}, {0x143D, 0x143D, 0x143D}, {0x143E, 0x143E, 0x143E}, {0x143F, 0x143F, 0x143F}, {0x1440, 0x1440, 0x1440}, {0x1441, 0x1441, 0x1441}, {0x1442, 0x1442, 0x1442}, {0x1443, 0x1443, 0x1443}, {0x1444, 0x1444, 0x1444}, {0x1445, 0x1445, 0x1445}, {0x1446, 0x1446, 0x1446}, {0x1447, 0x1447, 0x1447}, {0x1448, 0x1448, 0x1448}, {0x1449, 0x1449, 0x1449}, {0x144A, 0x144A, 0x144A}, {0x144B, 0x144B, 0x144B}, {0x144C, 0x144C, 0x144C}, {0x144D, 0x144D, 0x144D}, {0x144E, 0x144E, 0x144E}, {0x144F, 0x144F, 0x144F}, {0x1450, 0x1450, 0x1450}, {0x1451, 0x1451, 0x1451}, {0x1452, 0x1452, 0x1452}, {0x1453, 0x1453, 0x1453}, {0x1454, 0x1454, 0x1454}, {0x1455, 0x1455, 0x1455}, {0x1456, 0x1456, 0x1456}, {0x1457, 0x1457, 0x1457}, {0x1458, 0x1458, 0x1458}, {0x1459, 0x1459, 0x1459}, {0x145A, 0x145A, 0x145A}, {0x145B, 0x145B, 0x145B}, {0x145C, 0x145C, 0x145C}, {0x145D, 0x145D, 0x145D}, {0x145E, 0x145E, 0x145E}, {0x145F, 0x145F, 0x145F}, {0x1460, 0x1460, 0x1460}, {0x1461, 0x1461, 0x1461}, {0x1462, 0x1462, 0x1462}, {0x1463, 0x1463, 0x1463}, {0x1464, 0x1464, 0x1464}, {0x1465, 0x1465, 0x1465}, {0x1466, 0x1466, 0x1466}, {0x1467, 0x1467, 0x1467}, {0x1468, 0x1468, 0x1468}, {0x1469, 0x1469, 0x1469}, {0x146A, 0x146A, 0x146A}, {0x146B, 0x146B, 0x146B}, {0x146C, 0x146C, 0x146C}, {0x146D, 0x146D, 0x146D}, {0x146E, 0x146E, 0x146E}, {0x146F, 0x146F, 0x146F}, {0x1470, 0x1470, 0x1470}, {0x1471, 0x1471, 0x1471}, {0x1472, 0x1472, 0x1472}, {0x1473, 0x1473, 0x1473}, {0x1474, 0x1474, 0x1474}, {0x1475, 0x1475, 0x1475}, {0x1476, 0x1476, 0x1476}, {0x1477, 0x1477, 0x1477}, {0x1478, 0x1478, 0x1478}, {0x1479, 0x1479, 0x1479}, {0x147A, 0x147A, 0x147A}, {0x147B, 0x147B, 0x147B}, {0x147C, 0x147C, 0x147C}, {0x147D, 0x147D, 0x147D}, {0x147E, 0x147E, 0x147E}, {0x147F, 0x147F, 0x147F}, {0x1480, 0x1480, 0x1480}, {0x1481, 0x1481, 0x1481}, {0x1482, 0x1482, 0x1482}, {0x1483, 0x1483, 0x1483}, {0x1484, 0x1484, 0x1484}, {0x1485, 0x1485, 0x1485}, {0x1486, 0x1486, 0x1486}, {0x1487, 0x1487, 0x1487}, {0x1488, 0x1488, 0x1488}, {0x1489, 0x1489, 0x1489}, {0x148A, 0x148A, 0x148A}, {0x148B, 0x148B, 0x148B}, {0x148C, 0x148C, 0x148C}, {0x148D, 0x148D, 0x148D}, {0x148E, 0x148E, 0x148E}, {0x148F, 0x148F, 0x148F}, {0x1490, 0x1490, 0x1490}, {0x1491, 0x1491, 0x1491}, {0x1492, 0x1492, 0x1492}, {0x1493, 0x1493, 0x1493}, {0x1494, 0x1494, 0x1494}, {0x1495, 0x1495, 0x1495}, {0x1496, 0x1496, 0x1496}, {0x1497, 0x1497, 0x1497}, {0x1498, 0x1498, 0x1498}, {0x1499, 0x1499, 0x1499}, {0x149A, 0x149A, 0x149A}, {0x149B, 0x149B, 0x149B}, {0x149C, 0x149C, 0x149C}, {0x149D, 0x149D, 0x149D}, {0x149E, 0x149E, 0x149E}, {0x149F, 0x149F, 0x149F}, {0x14A0, 0x14A0, 0x14A0}, {0x14A1, 0x14A1, 0x14A1}, {0x14A2, 0x14A2, 0x14A2}, {0x14A3, 0x14A3, 0x14A3}, {0x14A4, 0x14A4, 0x14A4}, {0x14A5, 0x14A5, 0x14A5}, {0x14A6, 0x14A6, 0x14A6}, {0x14A7, 0x14A7, 0x14A7}, {0x14A8, 0x14A8, 0x14A8}, {0x14A9, 0x14A9, 0x14A9}, {0x14AA, 0x14AA, 0x14AA}, {0x14AB, 0x14AB, 0x14AB}, {0x14AC, 0x14AC, 0x14AC}, {0x14AD, 0x14AD, 0x14AD}, {0x14AE, 0x14AE, 0x14AE}, {0x14AF, 0x14AF, 0x14AF}, {0x14B0, 0x14B0, 0x14B0}, {0x14B1, 0x14B1, 0x14B1}, {0x14B2, 0x14B2, 0x14B2}, {0x14B3, 0x14B3, 0x14B3}, {0x14B4, 0x14B4, 0x14B4}, {0x14B5, 0x14B5, 0x14B5}, {0x14B6, 0x14B6, 0x14B6}, {0x14B7, 0x14B7, 0x14B7}, {0x14B8, 0x14B8, 0x14B8}, {0x14B9, 0x14B9, 0x14B9}, {0x14BA, 0x14BA, 0x14BA}, {0x14BB, 0x14BB, 0x14BB}, {0x14BC, 0x14BC, 0x14BC}, {0x14BD, 0x14BD, 0x14BD}, {0x14BE, 0x14BE, 0x14BE}, {0x14BF, 0x14BF, 0x14BF}, {0x14C0, 0x14C0, 0x14C0}, {0x14C1, 0x14C1, 0x14C1}, {0x14C2, 0x14C2, 0x14C2}, {0x14C3, 0x14C3, 0x14C3}, {0x14C4, 0x14C4, 0x14C4}, {0x14C5, 0x14C5, 0x14C5}, {0x14C6, 0x14C6, 0x14C6}, {0x14C7, 0x14C7, 0x14C7}, {0x14C8, 0x14C8, 0x14C8}, {0x14C9, 0x14C9, 0x14C9}, {0x14CA, 0x14CA, 0x14CA}, {0x14CB, 0x14CB, 0x14CB}, {0x14CC, 0x14CC, 0x14CC}, {0x14CD, 0x14CD, 0x14CD}, {0x14CE, 0x14CE, 0x14CE}, {0x14CF, 0x14CF, 0x14CF}, {0x14D0, 0x14D0, 0x14D0}, {0x14D1, 0x14D1, 0x14D1}, {0x14D2, 0x14D2, 0x14D2}, {0x14D3, 0x14D3, 0x14D3}, {0x14D4, 0x14D4, 0x14D4}, {0x14D5, 0x14D5, 0x14D5}, {0x14D6, 0x14D6, 0x14D6}, {0x14D7, 0x14D7, 0x14D7}, {0x14D8, 0x14D8, 0x14D8}, {0x14D9, 0x14D9, 0x14D9}, {0x14DA, 0x14DA, 0x14DA}, {0x14DB, 0x14DB, 0x14DB}, {0x14DC, 0x14DC, 0x14DC}, {0x14DD, 0x14DD, 0x14DD}, {0x14DE, 0x14DE, 0x14DE}, {0x14DF, 0x14DF, 0x14DF}, {0x14E0, 0x14E0, 0x14E0}, {0x14E1, 0x14E1, 0x14E1}, {0x14E2, 0x14E2, 0x14E2}, {0x14E3, 0x14E3, 0x14E3}, {0x14E4, 0x14E4, 0x14E4}, {0x14E5, 0x14E5, 0x14E5}, {0x14E6, 0x14E6, 0x14E6}, {0x14E7, 0x14E7, 0x14E7}, {0x14E8, 0x14E8, 0x14E8}, {0x14E9, 0x14E9, 0x14E9}, {0x14EA, 0x14EA, 0x14EA}, {0x14EB, 0x14EB, 0x14EB}, {0x14EC, 0x14EC, 0x14EC}, {0x14ED, 0x14ED, 0x14ED}, {0x14EE, 0x14EE, 0x14EE}, {0x14EF, 0x14EF, 0x14EF}, {0x14F0, 0x14F0, 0x14F0}, {0x14F1, 0x14F1, 0x14F1}, {0x14F2, 0x14F2, 0x14F2}, {0x14F3, 0x14F3, 0x14F3}, {0x14F4, 0x14F4, 0x14F4}, {0x14F5, 0x14F5, 0x14F5}, {0x14F6, 0x14F6, 0x14F6}, {0x14F7, 0x14F7, 0x14F7}, {0x14F8, 0x14F8, 0x14F8}, {0x14F9, 0x14F9, 0x14F9}, {0x14FA, 0x14FA, 0x14FA}, {0x14FB, 0x14FB, 0x14FB}, {0x14FC, 0x14FC, 0x14FC}, {0x14FD, 0x14FD, 0x14FD}, {0x14FE, 0x14FE, 0x14FE}, {0x14FF, 0x14FF, 0x14FF}, {0x1500, 0x1500, 0x1500}, {0x1501, 0x1501, 0x1501}, {0x1502, 0x1502, 0x1502}, {0x1503, 0x1503, 0x1503}, {0x1504, 0x1504, 0x1504}, {0x1505, 0x1505, 0x1505}, {0x1506, 0x1506, 0x1506}, {0x1507, 0x1507, 0x1507}, {0x1508, 0x1508, 0x1508}, {0x1509, 0x1509, 0x1509}, {0x150A, 0x150A, 0x150A}, {0x150B, 0x150B, 0x150B}, {0x150C, 0x150C, 0x150C}, {0x150D, 0x150D, 0x150D}, {0x150E, 0x150E, 0x150E}, {0x150F, 0x150F, 0x150F}, {0x1510, 0x1510, 0x1510}, {0x1511, 0x1511, 0x1511}, {0x1512, 0x1512, 0x1512}, {0x1513, 0x1513, 0x1513}, {0x1514, 0x1514, 0x1514}, {0x1515, 0x1515, 0x1515}, {0x1516, 0x1516, 0x1516}, {0x1517, 0x1517, 0x1517}, {0x1518, 0x1518, 0x1518}, {0x1519, 0x1519, 0x1519}, {0x151A, 0x151A, 0x151A}, {0x151B, 0x151B, 0x151B}, {0x151C, 0x151C, 0x151C}, {0x151D, 0x151D, 0x151D}, {0x151E, 0x151E, 0x151E}, {0x151F, 0x151F, 0x151F}, {0x1520, 0x1520, 0x1520}, {0x1521, 0x1521, 0x1521}, {0x1522, 0x1522, 0x1522}, {0x1523, 0x1523, 0x1523}, {0x1524, 0x1524, 0x1524}, {0x1525, 0x1525, 0x1525}, {0x1526, 0x1526, 0x1526}, {0x1527, 0x1527, 0x1527}, {0x1528, 0x1528, 0x1528}, {0x1529, 0x1529, 0x1529}, {0x152A, 0x152A, 0x152A}, {0x152B, 0x152B, 0x152B}, {0x152C, 0x152C, 0x152C}, {0x152D, 0x152D, 0x152D}, {0x152E, 0x152E, 0x152E}, {0x152F, 0x152F, 0x152F}, {0x1530, 0x1530, 0x1530}, {0x1531, 0x1531, 0x1531}, {0x1532, 0x1532, 0x1532}, {0x1533, 0x1533, 0x1533}, {0x1534, 0x1534, 0x1534}, {0x1535, 0x1535, 0x1535}, {0x1536, 0x1536, 0x1536}, {0x1537, 0x1537, 0x1537}, {0x1538, 0x1538, 0x1538}, {0x1539, 0x1539, 0x1539}, {0x153A, 0x153A, 0x153A}, {0x153B, 0x153B, 0x153B}, {0x153C, 0x153C, 0x153C}, {0x153D, 0x153D, 0x153D}, {0x153E, 0x153E, 0x153E}, {0x153F, 0x153F, 0x153F}, {0x1540, 0x1540, 0x1540}, {0x1541, 0x1541, 0x1541}, {0x1542, 0x1542, 0x1542}, {0x1543, 0x1543, 0x1543}, {0x1544, 0x1544, 0x1544}, {0x1545, 0x1545, 0x1545}, {0x1546, 0x1546, 0x1546}, {0x1547, 0x1547, 0x1547}, {0x1548, 0x1548, 0x1548}, {0x1549, 0x1549, 0x1549}, {0x154A, 0x154A, 0x154A}, {0x154B, 0x154B, 0x154B}, {0x154C, 0x154C, 0x154C}, {0x154D, 0x154D, 0x154D}, {0x154E, 0x154E, 0x154E}, {0x154F, 0x154F, 0x154F}, {0x1550, 0x1550, 0x1550}, {0x1551, 0x1551, 0x1551}, {0x1552, 0x1552, 0x1552}, {0x1553, 0x1553, 0x1553}, {0x1554, 0x1554, 0x1554}, {0x1555, 0x1555, 0x1555}, {0x1556, 0x1556, 0x1556}, {0x1557, 0x1557, 0x1557}, {0x1558, 0x1558, 0x1558}, {0x1559, 0x1559, 0x1559}, {0x155A, 0x155A, 0x155A}, {0x155B, 0x155B, 0x155B}, {0x155C, 0x155C, 0x155C}, {0x155D, 0x155D, 0x155D}, {0x155E, 0x155E, 0x155E}, {0x155F, 0x155F, 0x155F}, {0x1560, 0x1560, 0x1560}, {0x1561, 0x1561, 0x1561}, {0x1562, 0x1562, 0x1562}, {0x1563, 0x1563, 0x1563}, {0x1564, 0x1564, 0x1564}, {0x1565, 0x1565, 0x1565}, {0x1566, 0x1566, 0x1566}, {0x1567, 0x1567, 0x1567}, {0x1568, 0x1568, 0x1568}, {0x1569, 0x1569, 0x1569}, {0x156A, 0x156A, 0x156A}, {0x156B, 0x156B, 0x156B}, {0x156C, 0x156C, 0x156C}, {0x156D, 0x156D, 0x156D}, {0x156E, 0x156E, 0x156E}, {0x156F, 0x156F, 0x156F}, {0x1570, 0x1570, 0x1570}, {0x1571, 0x1571, 0x1571}, {0x1572, 0x1572, 0x1572}, {0x1573, 0x1573, 0x1573}, {0x1574, 0x1574, 0x1574}, {0x1575, 0x1575, 0x1575}, {0x1576, 0x1576, 0x1576}, {0x1577, 0x1577, 0x1577}, {0x1578, 0x1578, 0x1578}, {0x1579, 0x1579, 0x1579}, {0x157A, 0x157A, 0x157A}, {0x157B, 0x157B, 0x157B}, {0x157C, 0x157C, 0x157C}, {0x157D, 0x157D, 0x157D}, {0x157E, 0x157E, 0x157E}, {0x157F, 0x157F, 0x157F}, {0x1580, 0x1580, 0x1580}, {0x1581, 0x1581, 0x1581}, {0x1582, 0x1582, 0x1582}, {0x1583, 0x1583, 0x1583}, {0x1584, 0x1584, 0x1584}, {0x1585, 0x1585, 0x1585}, {0x1586, 0x1586, 0x1586}, {0x1587, 0x1587, 0x1587}, {0x1588, 0x1588, 0x1588}, {0x1589, 0x1589, 0x1589}, {0x158A, 0x158A, 0x158A}, {0x158B, 0x158B, 0x158B}, {0x158C, 0x158C, 0x158C}, {0x158D, 0x158D, 0x158D}, {0x158E, 0x158E, 0x158E}, {0x158F, 0x158F, 0x158F}, {0x1590, 0x1590, 0x1590}, {0x1591, 0x1591, 0x1591}, {0x1592, 0x1592, 0x1592}, {0x1593, 0x1593, 0x1593}, {0x1594, 0x1594, 0x1594}, {0x1595, 0x1595, 0x1595}, {0x1596, 0x1596, 0x1596}, {0x1597, 0x1597, 0x1597}, {0x1598, 0x1598, 0x1598}, {0x1599, 0x1599, 0x1599}, {0x159A, 0x159A, 0x159A}, {0x159B, 0x159B, 0x159B}, {0x159C, 0x159C, 0x159C}, {0x159D, 0x159D, 0x159D}, {0x159E, 0x159E, 0x159E}, {0x159F, 0x159F, 0x159F}, {0x15A0, 0x15A0, 0x15A0}, {0x15A1, 0x15A1, 0x15A1}, {0x15A2, 0x15A2, 0x15A2}, {0x15A3, 0x15A3, 0x15A3}, {0x15A4, 0x15A4, 0x15A4}, {0x15A5, 0x15A5, 0x15A5}, {0x15A6, 0x15A6, 0x15A6}, {0x15A7, 0x15A7, 0x15A7}, {0x15A8, 0x15A8, 0x15A8}, {0x15A9, 0x15A9, 0x15A9}, {0x15AA, 0x15AA, 0x15AA}, {0x15AB, 0x15AB, 0x15AB}, {0x15AC, 0x15AC, 0x15AC}, {0x15AD, 0x15AD, 0x15AD}, {0x15AE, 0x15AE, 0x15AE}, {0x15AF, 0x15AF, 0x15AF}, {0x15B0, 0x15B0, 0x15B0}, {0x15B1, 0x15B1, 0x15B1}, {0x15B2, 0x15B2, 0x15B2}, {0x15B3, 0x15B3, 0x15B3}, {0x15B4, 0x15B4, 0x15B4}, {0x15B5, 0x15B5, 0x15B5}, {0x15B6, 0x15B6, 0x15B6}, {0x15B7, 0x15B7, 0x15B7}, {0x15B8, 0x15B8, 0x15B8}, {0x15B9, 0x15B9, 0x15B9}, {0x15BA, 0x15BA, 0x15BA}, {0x15BB, 0x15BB, 0x15BB}, {0x15BC, 0x15BC, 0x15BC}, {0x15BD, 0x15BD, 0x15BD}, {0x15BE, 0x15BE, 0x15BE}, {0x15BF, 0x15BF, 0x15BF}, {0x15C0, 0x15C0, 0x15C0}, {0x15C1, 0x15C1, 0x15C1}, {0x15C2, 0x15C2, 0x15C2}, {0x15C3, 0x15C3, 0x15C3}, {0x15C4, 0x15C4, 0x15C4}, {0x15C5, 0x15C5, 0x15C5}, {0x15C6, 0x15C6, 0x15C6}, {0x15C7, 0x15C7, 0x15C7}, {0x15C8, 0x15C8, 0x15C8}, {0x15C9, 0x15C9, 0x15C9}, {0x15CA, 0x15CA, 0x15CA}, {0x15CB, 0x15CB, 0x15CB}, {0x15CC, 0x15CC, 0x15CC}, {0x15CD, 0x15CD, 0x15CD}, {0x15CE, 0x15CE, 0x15CE}, {0x15CF, 0x15CF, 0x15CF}, {0x15D0, 0x15D0, 0x15D0}, {0x15D1, 0x15D1, 0x15D1}, {0x15D2, 0x15D2, 0x15D2}, {0x15D3, 0x15D3, 0x15D3}, {0x15D4, 0x15D4, 0x15D4}, {0x15D5, 0x15D5, 0x15D5}, {0x15D6, 0x15D6, 0x15D6}, {0x15D7, 0x15D7, 0x15D7}, {0x15D8, 0x15D8, 0x15D8}, {0x15D9, 0x15D9, 0x15D9}, {0x15DA, 0x15DA, 0x15DA}, {0x15DB, 0x15DB, 0x15DB}, {0x15DC, 0x15DC, 0x15DC}, {0x15DD, 0x15DD, 0x15DD}, {0x15DE, 0x15DE, 0x15DE}, {0x15DF, 0x15DF, 0x15DF}, {0x15E0, 0x15E0, 0x15E0}, {0x15E1, 0x15E1, 0x15E1}, {0x15E2, 0x15E2, 0x15E2}, {0x15E3, 0x15E3, 0x15E3}, {0x15E4, 0x15E4, 0x15E4}, {0x15E5, 0x15E5, 0x15E5}, {0x15E6, 0x15E6, 0x15E6}, {0x15E7, 0x15E7, 0x15E7}, {0x15E8, 0x15E8, 0x15E8}, {0x15E9, 0x15E9, 0x15E9}, {0x15EA, 0x15EA, 0x15EA}, {0x15EB, 0x15EB, 0x15EB}, {0x15EC, 0x15EC, 0x15EC}, {0x15ED, 0x15ED, 0x15ED}, {0x15EE, 0x15EE, 0x15EE}, {0x15EF, 0x15EF, 0x15EF}, {0x15F0, 0x15F0, 0x15F0}, {0x15F1, 0x15F1, 0x15F1}, {0x15F2, 0x15F2, 0x15F2}, {0x15F3, 0x15F3, 0x15F3}, {0x15F4, 0x15F4, 0x15F4}, {0x15F5, 0x15F5, 0x15F5}, {0x15F6, 0x15F6, 0x15F6}, {0x15F7, 0x15F7, 0x15F7}, {0x15F8, 0x15F8, 0x15F8}, {0x15F9, 0x15F9, 0x15F9}, {0x15FA, 0x15FA, 0x15FA}, {0x15FB, 0x15FB, 0x15FB}, {0x15FC, 0x15FC, 0x15FC}, {0x15FD, 0x15FD, 0x15FD}, {0x15FE, 0x15FE, 0x15FE}, {0x15FF, 0x15FF, 0x15FF}, {0x1600, 0x1600, 0x1600}, {0x1601, 0x1601, 0x1601}, {0x1602, 0x1602, 0x1602}, {0x1603, 0x1603, 0x1603}, {0x1604, 0x1604, 0x1604}, {0x1605, 0x1605, 0x1605}, {0x1606, 0x1606, 0x1606}, {0x1607, 0x1607, 0x1607}, {0x1608, 0x1608, 0x1608}, {0x1609, 0x1609, 0x1609}, {0x160A, 0x160A, 0x160A}, {0x160B, 0x160B, 0x160B}, {0x160C, 0x160C, 0x160C}, {0x160D, 0x160D, 0x160D}, {0x160E, 0x160E, 0x160E}, {0x160F, 0x160F, 0x160F}, {0x1610, 0x1610, 0x1610}, {0x1611, 0x1611, 0x1611}, {0x1612, 0x1612, 0x1612}, {0x1613, 0x1613, 0x1613}, {0x1614, 0x1614, 0x1614}, {0x1615, 0x1615, 0x1615}, {0x1616, 0x1616, 0x1616}, {0x1617, 0x1617, 0x1617}, {0x1618, 0x1618, 0x1618}, {0x1619, 0x1619, 0x1619}, {0x161A, 0x161A, 0x161A}, {0x161B, 0x161B, 0x161B}, {0x161C, 0x161C, 0x161C}, {0x161D, 0x161D, 0x161D}, {0x161E, 0x161E, 0x161E}, {0x161F, 0x161F, 0x161F}, {0x1620, 0x1620, 0x1620}, {0x1621, 0x1621, 0x1621}, {0x1622, 0x1622, 0x1622}, {0x1623, 0x1623, 0x1623}, {0x1624, 0x1624, 0x1624}, {0x1625, 0x1625, 0x1625}, {0x1626, 0x1626, 0x1626}, {0x1627, 0x1627, 0x1627}, {0x1628, 0x1628, 0x1628}, {0x1629, 0x1629, 0x1629}, {0x162A, 0x162A, 0x162A}, {0x162B, 0x162B, 0x162B}, {0x162C, 0x162C, 0x162C}, {0x162D, 0x162D, 0x162D}, {0x162E, 0x162E, 0x162E}, {0x162F, 0x162F, 0x162F}, {0x1630, 0x1630, 0x1630}, {0x1631, 0x1631, 0x1631}, {0x1632, 0x1632, 0x1632}, {0x1633, 0x1633, 0x1633}, {0x1634, 0x1634, 0x1634}, {0x1635, 0x1635, 0x1635}, {0x1636, 0x1636, 0x1636}, {0x1637, 0x1637, 0x1637}, {0x1638, 0x1638, 0x1638}, {0x1639, 0x1639, 0x1639}, {0x163A, 0x163A, 0x163A}, {0x163B, 0x163B, 0x163B}, {0x163C, 0x163C, 0x163C}, {0x163D, 0x163D, 0x163D}, {0x163E, 0x163E, 0x163E}, {0x163F, 0x163F, 0x163F}, {0x1640, 0x1640, 0x1640}, {0x1641, 0x1641, 0x1641}, {0x1642, 0x1642, 0x1642}, {0x1643, 0x1643, 0x1643}, {0x1644, 0x1644, 0x1644}, {0x1645, 0x1645, 0x1645}, {0x1646, 0x1646, 0x1646}, {0x1647, 0x1647, 0x1647}, {0x1648, 0x1648, 0x1648}, {0x1649, 0x1649, 0x1649}, {0x164A, 0x164A, 0x164A}, {0x164B, 0x164B, 0x164B}, {0x164C, 0x164C, 0x164C}, {0x164D, 0x164D, 0x164D}, {0x164E, 0x164E, 0x164E}, {0x164F, 0x164F, 0x164F}, {0x1650, 0x1650, 0x1650}, {0x1651, 0x1651, 0x1651}, {0x1652, 0x1652, 0x1652}, {0x1653, 0x1653, 0x1653}, {0x1654, 0x1654, 0x1654}, {0x1655, 0x1655, 0x1655}, {0x1656, 0x1656, 0x1656}, {0x1657, 0x1657, 0x1657}, {0x1658, 0x1658, 0x1658}, {0x1659, 0x1659, 0x1659}, {0x165A, 0x165A, 0x165A}, {0x165B, 0x165B, 0x165B}, {0x165C, 0x165C, 0x165C}, {0x165D, 0x165D, 0x165D}, {0x165E, 0x165E, 0x165E}, {0x165F, 0x165F, 0x165F}, {0x1660, 0x1660, 0x1660}, {0x1661, 0x1661, 0x1661}, {0x1662, 0x1662, 0x1662}, {0x1663, 0x1663, 0x1663}, {0x1664, 0x1664, 0x1664}, {0x1665, 0x1665, 0x1665}, {0x1666, 0x1666, 0x1666}, {0x1667, 0x1667, 0x1667}, {0x1668, 0x1668, 0x1668}, {0x1669, 0x1669, 0x1669}, {0x166A, 0x166A, 0x166A}, {0x166B, 0x166B, 0x166B}, {0x166C, 0x166C, 0x166C}, {0x166F, 0x166F, 0x166F}, {0x1670, 0x1670, 0x1670}, {0x1671, 0x1671, 0x1671}, {0x1672, 0x1672, 0x1672}, {0x1673, 0x1673, 0x1673}, {0x1674, 0x1674, 0x1674}, {0x1675, 0x1675, 0x1675}, {0x1676, 0x1676, 0x1676}, {0x1681, 0x1681, 0x1681}, {0x1682, 0x1682, 0x1682}, {0x1683, 0x1683, 0x1683}, {0x1684, 0x1684, 0x1684}, {0x1685, 0x1685, 0x1685}, {0x1686, 0x1686, 0x1686}, {0x1687, 0x1687, 0x1687}, {0x1688, 0x1688, 0x1688}, {0x1689, 0x1689, 0x1689}, {0x168A, 0x168A, 0x168A}, {0x168B, 0x168B, 0x168B}, {0x168C, 0x168C, 0x168C}, {0x168D, 0x168D, 0x168D}, {0x168E, 0x168E, 0x168E}, {0x168F, 0x168F, 0x168F}, {0x1690, 0x1690, 0x1690}, {0x1691, 0x1691, 0x1691}, {0x1692, 0x1692, 0x1692}, {0x1693, 0x1693, 0x1693}, {0x1694, 0x1694, 0x1694}, {0x1695, 0x1695, 0x1695}, {0x1696, 0x1696, 0x1696}, {0x1697, 0x1697, 0x1697}, {0x1698, 0x1698, 0x1698}, {0x1699, 0x1699, 0x1699}, {0x169A, 0x169A, 0x169A}, {0x16A0, 0x16A0, 0x16A0}, {0x16A1, 0x16A1, 0x16A1}, {0x16A2, 0x16A2, 0x16A2}, {0x16A3, 0x16A3, 0x16A3}, {0x16A4, 0x16A4, 0x16A4}, {0x16A5, 0x16A5, 0x16A5}, {0x16A6, 0x16A6, 0x16A6}, {0x16A7, 0x16A7, 0x16A7}, {0x16A8, 0x16A8, 0x16A8}, {0x16A9, 0x16A9, 0x16A9}, {0x16AA, 0x16AA, 0x16AA}, {0x16AB, 0x16AB, 0x16AB}, {0x16AC, 0x16AC, 0x16AC}, {0x16AD, 0x16AD, 0x16AD}, {0x16AE, 0x16AE, 0x16AE}, {0x16AF, 0x16AF, 0x16AF}, {0x16B0, 0x16B0, 0x16B0}, {0x16B1, 0x16B1, 0x16B1}, {0x16B2, 0x16B2, 0x16B2}, {0x16B3, 0x16B3, 0x16B3}, {0x16B4, 0x16B4, 0x16B4}, {0x16B5, 0x16B5, 0x16B5}, {0x16B6, 0x16B6, 0x16B6}, {0x16B7, 0x16B7, 0x16B7}, {0x16B8, 0x16B8, 0x16B8}, {0x16B9, 0x16B9, 0x16B9}, {0x16BA, 0x16BA, 0x16BA}, {0x16BB, 0x16BB, 0x16BB}, {0x16BC, 0x16BC, 0x16BC}, {0x16BD, 0x16BD, 0x16BD}, {0x16BE, 0x16BE, 0x16BE}, {0x16BF, 0x16BF, 0x16BF}, {0x16C0, 0x16C0, 0x16C0}, {0x16C1, 0x16C1, 0x16C1}, {0x16C2, 0x16C2, 0x16C2}, {0x16C3, 0x16C3, 0x16C3}, {0x16C4, 0x16C4, 0x16C4}, {0x16C5, 0x16C5, 0x16C5}, {0x16C6, 0x16C6, 0x16C6}, {0x16C7, 0x16C7, 0x16C7}, {0x16C8, 0x16C8, 0x16C8}, {0x16C9, 0x16C9, 0x16C9}, {0x16CA, 0x16CA, 0x16CA}, {0x16CB, 0x16CB, 0x16CB}, {0x16CC, 0x16CC, 0x16CC}, {0x16CD, 0x16CD, 0x16CD}, {0x16CE, 0x16CE, 0x16CE}, {0x16CF, 0x16CF, 0x16CF}, {0x16D0, 0x16D0, 0x16D0}, {0x16D1, 0x16D1, 0x16D1}, {0x16D2, 0x16D2, 0x16D2}, {0x16D3, 0x16D3, 0x16D3}, {0x16D4, 0x16D4, 0x16D4}, {0x16D5, 0x16D5, 0x16D5}, {0x16D6, 0x16D6, 0x16D6}, {0x16D7, 0x16D7, 0x16D7}, {0x16D8, 0x16D8, 0x16D8}, {0x16D9, 0x16D9, 0x16D9}, {0x16DA, 0x16DA, 0x16DA}, {0x16DB, 0x16DB, 0x16DB}, {0x16DC, 0x16DC, 0x16DC}, {0x16DD, 0x16DD, 0x16DD}, {0x16DE, 0x16DE, 0x16DE}, {0x16DF, 0x16DF, 0x16DF}, {0x16E0, 0x16E0, 0x16E0}, {0x16E1, 0x16E1, 0x16E1}, {0x16E2, 0x16E2, 0x16E2}, {0x16E3, 0x16E3, 0x16E3}, {0x16E4, 0x16E4, 0x16E4}, {0x16E5, 0x16E5, 0x16E5}, {0x16E6, 0x16E6, 0x16E6}, {0x16E7, 0x16E7, 0x16E7}, {0x16E8, 0x16E8, 0x16E8}, {0x16E9, 0x16E9, 0x16E9}, {0x16EA, 0x16EA, 0x16EA}, {0x1700, 0x1700, 0x1700}, {0x1701, 0x1701, 0x1701}, {0x1702, 0x1702, 0x1702}, {0x1703, 0x1703, 0x1703}, {0x1704, 0x1704, 0x1704}, {0x1705, 0x1705, 0x1705}, {0x1706, 0x1706, 0x1706}, {0x1707, 0x1707, 0x1707}, {0x1708, 0x1708, 0x1708}, {0x1709, 0x1709, 0x1709}, {0x170A, 0x170A, 0x170A}, {0x170B, 0x170B, 0x170B}, {0x170C, 0x170C, 0x170C}, {0x170E, 0x170E, 0x170E}, {0x170F, 0x170F, 0x170F}, {0x1710, 0x1710, 0x1710}, {0x1711, 0x1711, 0x1711}, {0x1712, 0x1712, 0x1712}, {0x1713, 0x1713, 0x1713}, {0x1714, 0x1714, 0x1714}, {0x1720, 0x1720, 0x1720}, {0x1721, 0x1721, 0x1721}, {0x1722, 0x1722, 0x1722}, {0x1723, 0x1723, 0x1723}, {0x1724, 0x1724, 0x1724}, {0x1725, 0x1725, 0x1725}, {0x1726, 0x1726, 0x1726}, {0x1727, 0x1727, 0x1727}, {0x1728, 0x1728, 0x1728}, {0x1729, 0x1729, 0x1729}, {0x172A, 0x172A, 0x172A}, {0x172B, 0x172B, 0x172B}, {0x172C, 0x172C, 0x172C}, {0x172D, 0x172D, 0x172D}, {0x172E, 0x172E, 0x172E}, {0x172F, 0x172F, 0x172F}, {0x1730, 0x1730, 0x1730}, {0x1731, 0x1731, 0x1731}, {0x1732, 0x1732, 0x1732}, {0x1733, 0x1733, 0x1733}, {0x1734, 0x1734, 0x1734}, {0x1740, 0x1740, 0x1740}, {0x1741, 0x1741, 0x1741}, {0x1742, 0x1742, 0x1742}, {0x1743, 0x1743, 0x1743}, {0x1744, 0x1744, 0x1744}, {0x1745, 0x1745, 0x1745}, {0x1746, 0x1746, 0x1746}, {0x1747, 0x1747, 0x1747}, {0x1748, 0x1748, 0x1748}, {0x1749, 0x1749, 0x1749}, {0x174A, 0x174A, 0x174A}, {0x174B, 0x174B, 0x174B}, {0x174C, 0x174C, 0x174C}, {0x174D, 0x174D, 0x174D}, {0x174E, 0x174E, 0x174E}, {0x174F, 0x174F, 0x174F}, {0x1750, 0x1750, 0x1750}, {0x1751, 0x1751, 0x1751}, {0x1752, 0x1752, 0x1752}, {0x1753, 0x1753, 0x1753}, {0x1760, 0x1760, 0x1760}, {0x1761, 0x1761, 0x1761}, {0x1762, 0x1762, 0x1762}, {0x1763, 0x1763, 0x1763}, {0x1764, 0x1764, 0x1764}, {0x1765, 0x1765, 0x1765}, {0x1766, 0x1766, 0x1766}, {0x1767, 0x1767, 0x1767}, {0x1768, 0x1768, 0x1768}, {0x1769, 0x1769, 0x1769}, {0x176A, 0x176A, 0x176A}, {0x176B, 0x176B, 0x176B}, {0x176C, 0x176C, 0x176C}, {0x176E, 0x176E, 0x176E}, {0x176F, 0x176F, 0x176F}, {0x1770, 0x1770, 0x1770}, {0x1772, 0x1772, 0x1772}, {0x1773, 0x1773, 0x1773}, {0x1780, 0x1780, 0x1780}, {0x1781, 0x1781, 0x1781}, {0x1782, 0x1782, 0x1782}, {0x1783, 0x1783, 0x1783}, {0x1784, 0x1784, 0x1784}, {0x1785, 0x1785, 0x1785}, {0x1786, 0x1786, 0x1786}, {0x1787, 0x1787, 0x1787}, {0x1788, 0x1788, 0x1788}, {0x1789, 0x1789, 0x1789}, {0x178A, 0x178A, 0x178A}, {0x178B, 0x178B, 0x178B}, {0x178C, 0x178C, 0x178C}, {0x178D, 0x178D, 0x178D}, {0x178E, 0x178E, 0x178E}, {0x178F, 0x178F, 0x178F}, {0x1790, 0x1790, 0x1790}, {0x1791, 0x1791, 0x1791}, {0x1792, 0x1792, 0x1792}, {0x1793, 0x1793, 0x1793}, {0x1794, 0x1794, 0x1794}, {0x1795, 0x1795, 0x1795}, {0x1796, 0x1796, 0x1796}, {0x1797, 0x1797, 0x1797}, {0x1798, 0x1798, 0x1798}, {0x1799, 0x1799, 0x1799}, {0x179A, 0x179A, 0x179A}, {0x179B, 0x179B, 0x179B}, {0x179C, 0x179C, 0x179C}, {0x179D, 0x179D, 0x179D}, {0x179E, 0x179E, 0x179E}, {0x179F, 0x179F, 0x179F}, {0x17A0, 0x17A0, 0x17A0}, {0x17A1, 0x17A1, 0x17A1}, {0x17A2, 0x17A2, 0x17A2}, {0x17A3, 0x17A3, 0x17A3}, {0x17A4, 0x17A4, 0x17A4}, {0x17A5, 0x17A5, 0x17A5}, {0x17A6, 0x17A6, 0x17A6}, {0x17A7, 0x17A7, 0x17A7}, {0x17A8, 0x17A8, 0x17A8}, {0x17A9, 0x17A9, 0x17A9}, {0x17AA, 0x17AA, 0x17AA}, {0x17AB, 0x17AB, 0x17AB}, {0x17AC, 0x17AC, 0x17AC}, {0x17AD, 0x17AD, 0x17AD}, {0x17AE, 0x17AE, 0x17AE}, {0x17AF, 0x17AF, 0x17AF}, {0x17B0, 0x17B0, 0x17B0}, {0x17B1, 0x17B1, 0x17B1}, {0x17B2, 0x17B2, 0x17B2}, {0x17B3, 0x17B3, 0x17B3}, {0x17B7, 0x17B7, 0x17B7}, {0x17B8, 0x17B8, 0x17B8}, {0x17B9, 0x17B9, 0x17B9}, {0x17BA, 0x17BA, 0x17BA}, {0x17BB, 0x17BB, 0x17BB}, {0x17BC, 0x17BC, 0x17BC}, {0x17BD, 0x17BD, 0x17BD}, {0x17C6, 0x17C6, 0x17C6}, {0x17C9, 0x17C9, 0x17C9}, {0x17CA, 0x17CA, 0x17CA}, {0x17CB, 0x17CB, 0x17CB}, {0x17CC, 0x17CC, 0x17CC}, {0x17CD, 0x17CD, 0x17CD}, {0x17CE, 0x17CE, 0x17CE}, {0x17CF, 0x17CF, 0x17CF}, {0x17D0, 0x17D0, 0x17D0}, {0x17D1, 0x17D1, 0x17D1}, {0x17D2, 0x17D2, 0x17D2}, {0x17D3, 0x17D3, 0x17D3}, {0x17D7, 0x17D7, 0x17D7}, {0x17DC, 0x17DC, 0x17DC}, {0x17DD, 0x17DD, 0x17DD}, {0x180B, 0x180B, 0x180B}, {0x180C, 0x180C, 0x180C}, {0x180D, 0x180D, 0x180D}, {0x1820, 0x1820, 0x1820}, {0x1821, 0x1821, 0x1821}, {0x1822, 0x1822, 0x1822}, {0x1823, 0x1823, 0x1823}, {0x1824, 0x1824, 0x1824}, {0x1825, 0x1825, 0x1825}, {0x1826, 0x1826, 0x1826}, {0x1827, 0x1827, 0x1827}, {0x1828, 0x1828, 0x1828}, {0x1829, 0x1829, 0x1829}, {0x182A, 0x182A, 0x182A}, {0x182B, 0x182B, 0x182B}, {0x182C, 0x182C, 0x182C}, {0x182D, 0x182D, 0x182D}, {0x182E, 0x182E, 0x182E}, {0x182F, 0x182F, 0x182F}, {0x1830, 0x1830, 0x1830}, {0x1831, 0x1831, 0x1831}, {0x1832, 0x1832, 0x1832}, {0x1833, 0x1833, 0x1833}, {0x1834, 0x1834, 0x1834}, {0x1835, 0x1835, 0x1835}, {0x1836, 0x1836, 0x1836}, {0x1837, 0x1837, 0x1837}, {0x1838, 0x1838, 0x1838}, {0x1839, 0x1839, 0x1839}, {0x183A, 0x183A, 0x183A}, {0x183B, 0x183B, 0x183B}, {0x183C, 0x183C, 0x183C}, {0x183D, 0x183D, 0x183D}, {0x183E, 0x183E, 0x183E}, {0x183F, 0x183F, 0x183F}, {0x1840, 0x1840, 0x1840}, {0x1841, 0x1841, 0x1841}, {0x1842, 0x1842, 0x1842}, {0x1843, 0x1843, 0x1843}, {0x1844, 0x1844, 0x1844}, {0x1845, 0x1845, 0x1845}, {0x1846, 0x1846, 0x1846}, {0x1847, 0x1847, 0x1847}, {0x1848, 0x1848, 0x1848}, {0x1849, 0x1849, 0x1849}, {0x184A, 0x184A, 0x184A}, {0x184B, 0x184B, 0x184B}, {0x184C, 0x184C, 0x184C}, {0x184D, 0x184D, 0x184D}, {0x184E, 0x184E, 0x184E}, {0x184F, 0x184F, 0x184F}, {0x1850, 0x1850, 0x1850}, {0x1851, 0x1851, 0x1851}, {0x1852, 0x1852, 0x1852}, {0x1853, 0x1853, 0x1853}, {0x1854, 0x1854, 0x1854}, {0x1855, 0x1855, 0x1855}, {0x1856, 0x1856, 0x1856}, {0x1857, 0x1857, 0x1857}, {0x1858, 0x1858, 0x1858}, {0x1859, 0x1859, 0x1859}, {0x185A, 0x185A, 0x185A}, {0x185B, 0x185B, 0x185B}, {0x185C, 0x185C, 0x185C}, {0x185D, 0x185D, 0x185D}, {0x185E, 0x185E, 0x185E}, {0x185F, 0x185F, 0x185F}, {0x1860, 0x1860, 0x1860}, {0x1861, 0x1861, 0x1861}, {0x1862, 0x1862, 0x1862}, {0x1863, 0x1863, 0x1863}, {0x1864, 0x1864, 0x1864}, {0x1865, 0x1865, 0x1865}, {0x1866, 0x1866, 0x1866}, {0x1867, 0x1867, 0x1867}, {0x1868, 0x1868, 0x1868}, {0x1869, 0x1869, 0x1869}, {0x186A, 0x186A, 0x186A}, {0x186B, 0x186B, 0x186B}, {0x186C, 0x186C, 0x186C}, {0x186D, 0x186D, 0x186D}, {0x186E, 0x186E, 0x186E}, {0x186F, 0x186F, 0x186F}, {0x1870, 0x1870, 0x1870}, {0x1871, 0x1871, 0x1871}, {0x1872, 0x1872, 0x1872}, {0x1873, 0x1873, 0x1873}, {0x1874, 0x1874, 0x1874}, {0x1875, 0x1875, 0x1875}, {0x1876, 0x1876, 0x1876}, {0x1877, 0x1877, 0x1877}, {0x1880, 0x1880, 0x1880}, {0x1881, 0x1881, 0x1881}, {0x1882, 0x1882, 0x1882}, {0x1883, 0x1883, 0x1883}, {0x1884, 0x1884, 0x1884}, {0x1885, 0x1885, 0x1885}, {0x1886, 0x1886, 0x1886}, {0x1887, 0x1887, 0x1887}, {0x1888, 0x1888, 0x1888}, {0x1889, 0x1889, 0x1889}, {0x188A, 0x188A, 0x188A}, {0x188B, 0x188B, 0x188B}, {0x188C, 0x188C, 0x188C}, {0x188D, 0x188D, 0x188D}, {0x188E, 0x188E, 0x188E}, {0x188F, 0x188F, 0x188F}, {0x1890, 0x1890, 0x1890}, {0x1891, 0x1891, 0x1891}, {0x1892, 0x1892, 0x1892}, {0x1893, 0x1893, 0x1893}, {0x1894, 0x1894, 0x1894}, {0x1895, 0x1895, 0x1895}, {0x1896, 0x1896, 0x1896}, {0x1897, 0x1897, 0x1897}, {0x1898, 0x1898, 0x1898}, {0x1899, 0x1899, 0x1899}, {0x189A, 0x189A, 0x189A}, {0x189B, 0x189B, 0x189B}, {0x189C, 0x189C, 0x189C}, {0x189D, 0x189D, 0x189D}, {0x189E, 0x189E, 0x189E}, {0x189F, 0x189F, 0x189F}, {0x18A0, 0x18A0, 0x18A0}, {0x18A1, 0x18A1, 0x18A1}, {0x18A2, 0x18A2, 0x18A2}, {0x18A3, 0x18A3, 0x18A3}, {0x18A4, 0x18A4, 0x18A4}, {0x18A5, 0x18A5, 0x18A5}, {0x18A6, 0x18A6, 0x18A6}, {0x18A7, 0x18A7, 0x18A7}, {0x18A8, 0x18A8, 0x18A8}, {0x18A9, 0x18A9, 0x18A9}, {0x1900, 0x1900, 0x1900}, {0x1901, 0x1901, 0x1901}, {0x1902, 0x1902, 0x1902}, {0x1903, 0x1903, 0x1903}, {0x1904, 0x1904, 0x1904}, {0x1905, 0x1905, 0x1905}, {0x1906, 0x1906, 0x1906}, {0x1907, 0x1907, 0x1907}, {0x1908, 0x1908, 0x1908}, {0x1909, 0x1909, 0x1909}, {0x190A, 0x190A, 0x190A}, {0x190B, 0x190B, 0x190B}, {0x190C, 0x190C, 0x190C}, {0x190D, 0x190D, 0x190D}, {0x190E, 0x190E, 0x190E}, {0x190F, 0x190F, 0x190F}, {0x1910, 0x1910, 0x1910}, {0x1911, 0x1911, 0x1911}, {0x1912, 0x1912, 0x1912}, {0x1913, 0x1913, 0x1913}, {0x1914, 0x1914, 0x1914}, {0x1915, 0x1915, 0x1915}, {0x1916, 0x1916, 0x1916}, {0x1917, 0x1917, 0x1917}, {0x1918, 0x1918, 0x1918}, {0x1919, 0x1919, 0x1919}, {0x191A, 0x191A, 0x191A}, {0x191B, 0x191B, 0x191B}, {0x191C, 0x191C, 0x191C}, {0x1920, 0x1920, 0x1920}, {0x1921, 0x1921, 0x1921}, {0x1922, 0x1922, 0x1922}, {0x1927, 0x1927, 0x1927}, {0x1928, 0x1928, 0x1928}, {0x1932, 0x1932, 0x1932}, {0x1939, 0x1939, 0x1939}, {0x193A, 0x193A, 0x193A}, {0x193B, 0x193B, 0x193B}, {0x1950, 0x1950, 0x1950}, {0x1951, 0x1951, 0x1951}, {0x1952, 0x1952, 0x1952}, {0x1953, 0x1953, 0x1953}, {0x1954, 0x1954, 0x1954}, {0x1955, 0x1955, 0x1955}, {0x1956, 0x1956, 0x1956}, {0x1957, 0x1957, 0x1957}, {0x1958, 0x1958, 0x1958}, {0x1959, 0x1959, 0x1959}, {0x195A, 0x195A, 0x195A}, {0x195B, 0x195B, 0x195B}, {0x195C, 0x195C, 0x195C}, {0x195D, 0x195D, 0x195D}, {0x195E, 0x195E, 0x195E}, {0x195F, 0x195F, 0x195F}, {0x1960, 0x1960, 0x1960}, {0x1961, 0x1961, 0x1961}, {0x1962, 0x1962, 0x1962}, {0x1963, 0x1963, 0x1963}, {0x1964, 0x1964, 0x1964}, {0x1965, 0x1965, 0x1965}, {0x1966, 0x1966, 0x1966}, {0x1967, 0x1967, 0x1967}, {0x1968, 0x1968, 0x1968}, {0x1969, 0x1969, 0x1969}, {0x196A, 0x196A, 0x196A}, {0x196B, 0x196B, 0x196B}, {0x196C, 0x196C, 0x196C}, {0x196D, 0x196D, 0x196D}, {0x1970, 0x1970, 0x1970}, {0x1971, 0x1971, 0x1971}, {0x1972, 0x1972, 0x1972}, {0x1973, 0x1973, 0x1973}, {0x1974, 0x1974, 0x1974}, {0x1980, 0x1980, 0x1980}, {0x1981, 0x1981, 0x1981}, {0x1982, 0x1982, 0x1982}, {0x1983, 0x1983, 0x1983}, {0x1984, 0x1984, 0x1984}, {0x1985, 0x1985, 0x1985}, {0x1986, 0x1986, 0x1986}, {0x1987, 0x1987, 0x1987}, {0x1988, 0x1988, 0x1988}, {0x1989, 0x1989, 0x1989}, {0x198A, 0x198A, 0x198A}, {0x198B, 0x198B, 0x198B}, {0x198C, 0x198C, 0x198C}, {0x198D, 0x198D, 0x198D}, {0x198E, 0x198E, 0x198E}, {0x198F, 0x198F, 0x198F}, {0x1990, 0x1990, 0x1990}, {0x1991, 0x1991, 0x1991}, {0x1992, 0x1992, 0x1992}, {0x1993, 0x1993, 0x1993}, {0x1994, 0x1994, 0x1994}, {0x1995, 0x1995, 0x1995}, {0x1996, 0x1996, 0x1996}, {0x1997, 0x1997, 0x1997}, {0x1998, 0x1998, 0x1998}, {0x1999, 0x1999, 0x1999}, {0x199A, 0x199A, 0x199A}, {0x199B, 0x199B, 0x199B}, {0x199C, 0x199C, 0x199C}, {0x199D, 0x199D, 0x199D}, {0x199E, 0x199E, 0x199E}, {0x199F, 0x199F, 0x199F}, {0x19A0, 0x19A0, 0x19A0}, {0x19A1, 0x19A1, 0x19A1}, {0x19A2, 0x19A2, 0x19A2}, {0x19A3, 0x19A3, 0x19A3}, {0x19A4, 0x19A4, 0x19A4}, {0x19A5, 0x19A5, 0x19A5}, {0x19A6, 0x19A6, 0x19A6}, {0x19A7, 0x19A7, 0x19A7}, {0x19A8, 0x19A8, 0x19A8}, {0x19A9, 0x19A9, 0x19A9}, {0x19C1, 0x19C1, 0x19C1}, {0x19C2, 0x19C2, 0x19C2}, {0x19C3, 0x19C3, 0x19C3}, {0x19C4, 0x19C4, 0x19C4}, {0x19C5, 0x19C5, 0x19C5}, {0x19C6, 0x19C6, 0x19C6}, {0x19C7, 0x19C7, 0x19C7}, {0x1A00, 0x1A00, 0x1A00}, {0x1A01, 0x1A01, 0x1A01}, {0x1A02, 0x1A02, 0x1A02}, {0x1A03, 0x1A03, 0x1A03}, {0x1A04, 0x1A04, 0x1A04}, {0x1A05, 0x1A05, 0x1A05}, {0x1A06, 0x1A06, 0x1A06}, {0x1A07, 0x1A07, 0x1A07}, {0x1A08, 0x1A08, 0x1A08}, {0x1A09, 0x1A09, 0x1A09}, {0x1A0A, 0x1A0A, 0x1A0A}, {0x1A0B, 0x1A0B, 0x1A0B}, {0x1A0C, 0x1A0C, 0x1A0C}, {0x1A0D, 0x1A0D, 0x1A0D}, {0x1A0E, 0x1A0E, 0x1A0E}, {0x1A0F, 0x1A0F, 0x1A0F}, {0x1A10, 0x1A10, 0x1A10}, {0x1A11, 0x1A11, 0x1A11}, {0x1A12, 0x1A12, 0x1A12}, {0x1A13, 0x1A13, 0x1A13}, {0x1A14, 0x1A14, 0x1A14}, {0x1A15, 0x1A15, 0x1A15}, {0x1A16, 0x1A16, 0x1A16}, {0x1A17, 0x1A17, 0x1A17}, {0x1A18, 0x1A18, 0x1A18}, {0x1D00, 0x1D00, 0x1D00}, {0x1D01, 0x1D01, 0x1D01}, {0x1D02, 0x1D02, 0x1D02}, {0x1D03, 0x1D03, 0x1D03}, {0x1D04, 0x1D04, 0x1D04}, {0x1D05, 0x1D05, 0x1D05}, {0x1D06, 0x1D06, 0x1D06}, {0x1D07, 0x1D07, 0x1D07}, {0x1D08, 0x1D08, 0x1D08}, {0x1D09, 0x1D09, 0x1D09}, {0x1D0A, 0x1D0A, 0x1D0A}, {0x1D0B, 0x1D0B, 0x1D0B}, {0x1D0C, 0x1D0C, 0x1D0C}, {0x1D0D, 0x1D0D, 0x1D0D}, {0x1D0E, 0x1D0E, 0x1D0E}, {0x1D0F, 0x1D0F, 0x1D0F}, {0x1D10, 0x1D10, 0x1D10}, {0x1D11, 0x1D11, 0x1D11}, {0x1D12, 0x1D12, 0x1D12}, {0x1D13, 0x1D13, 0x1D13}, {0x1D14, 0x1D14, 0x1D14}, {0x1D15, 0x1D15, 0x1D15}, {0x1D16, 0x1D16, 0x1D16}, {0x1D17, 0x1D17, 0x1D17}, {0x1D18, 0x1D18, 0x1D18}, {0x1D19, 0x1D19, 0x1D19}, {0x1D1A, 0x1D1A, 0x1D1A}, {0x1D1B, 0x1D1B, 0x1D1B}, {0x1D1C, 0x1D1C, 0x1D1C}, {0x1D1D, 0x1D1D, 0x1D1D}, {0x1D1E, 0x1D1E, 0x1D1E}, {0x1D1F, 0x1D1F, 0x1D1F}, {0x1D20, 0x1D20, 0x1D20}, {0x1D21, 0x1D21, 0x1D21}, {0x1D22, 0x1D22, 0x1D22}, {0x1D23, 0x1D23, 0x1D23}, {0x1D24, 0x1D24, 0x1D24}, {0x1D25, 0x1D25, 0x1D25}, {0x1D26, 0x1D26, 0x1D26}, {0x1D27, 0x1D27, 0x1D27}, {0x1D28, 0x1D28, 0x1D28}, {0x1D29, 0x1D29, 0x1D29}, {0x1D2A, 0x1D2A, 0x1D2A}, {0x1D2B, 0x1D2B, 0x1D2B}, {0x1D2C, 0x1D2C, 0x1D2C}, {0x1D2D, 0x1D2D, 0x1D2D}, {0x1D2E, 0x1D2E, 0x1D2E}, {0x1D2F, 0x1D2F, 0x1D2F}, {0x1D30, 0x1D30, 0x1D30}, {0x1D31, 0x1D31, 0x1D31}, {0x1D32, 0x1D32, 0x1D32}, {0x1D33, 0x1D33, 0x1D33}, {0x1D34, 0x1D34, 0x1D34}, {0x1D35, 0x1D35, 0x1D35}, {0x1D36, 0x1D36, 0x1D36}, {0x1D37, 0x1D37, 0x1D37}, {0x1D38, 0x1D38, 0x1D38}, {0x1D39, 0x1D39, 0x1D39}, {0x1D3A, 0x1D3A, 0x1D3A}, {0x1D3B, 0x1D3B, 0x1D3B}, {0x1D3C, 0x1D3C, 0x1D3C}, {0x1D3D, 0x1D3D, 0x1D3D}, {0x1D3E, 0x1D3E, 0x1D3E}, {0x1D3F, 0x1D3F, 0x1D3F}, {0x1D40, 0x1D40, 0x1D40}, {0x1D41, 0x1D41, 0x1D41}, {0x1D42, 0x1D42, 0x1D42}, {0x1D43, 0x1D43, 0x1D43}, {0x1D44, 0x1D44, 0x1D44}, {0x1D45, 0x1D45, 0x1D45}, {0x1D46, 0x1D46, 0x1D46}, {0x1D47, 0x1D47, 0x1D47}, {0x1D48, 0x1D48, 0x1D48}, {0x1D49, 0x1D49, 0x1D49}, {0x1D4A, 0x1D4A, 0x1D4A}, {0x1D4B, 0x1D4B, 0x1D4B}, {0x1D4C, 0x1D4C, 0x1D4C}, {0x1D4D, 0x1D4D, 0x1D4D}, {0x1D4E, 0x1D4E, 0x1D4E}, {0x1D4F, 0x1D4F, 0x1D4F}, {0x1D50, 0x1D50, 0x1D50}, {0x1D51, 0x1D51, 0x1D51}, {0x1D52, 0x1D52, 0x1D52}, {0x1D53, 0x1D53, 0x1D53}, {0x1D54, 0x1D54, 0x1D54}, {0x1D55, 0x1D55, 0x1D55}, {0x1D56, 0x1D56, 0x1D56}, {0x1D57, 0x1D57, 0x1D57}, {0x1D58, 0x1D58, 0x1D58}, {0x1D59, 0x1D59, 0x1D59}, {0x1D5A, 0x1D5A, 0x1D5A}, {0x1D5B, 0x1D5B, 0x1D5B}, {0x1D5C, 0x1D5C, 0x1D5C}, {0x1D5D, 0x1D5D, 0x1D5D}, {0x1D5E, 0x1D5E, 0x1D5E}, {0x1D5F, 0x1D5F, 0x1D5F}, {0x1D60, 0x1D60, 0x1D60}, {0x1D61, 0x1D61, 0x1D61}, {0x1D62, 0x1D62, 0x1D62}, {0x1D63, 0x1D63, 0x1D63}, {0x1D64, 0x1D64, 0x1D64}, {0x1D65, 0x1D65, 0x1D65}, {0x1D66, 0x1D66, 0x1D66}, {0x1D67, 0x1D67, 0x1D67}, {0x1D68, 0x1D68, 0x1D68}, {0x1D69, 0x1D69, 0x1D69}, {0x1D6A, 0x1D6A, 0x1D6A}, {0x1D6B, 0x1D6B, 0x1D6B}, {0x1D6C, 0x1D6C, 0x1D6C}, {0x1D6D, 0x1D6D, 0x1D6D}, {0x1D6E, 0x1D6E, 0x1D6E}, {0x1D6F, 0x1D6F, 0x1D6F}, {0x1D70, 0x1D70, 0x1D70}, {0x1D71, 0x1D71, 0x1D71}, {0x1D72, 0x1D72, 0x1D72}, {0x1D73, 0x1D73, 0x1D73}, {0x1D74, 0x1D74, 0x1D74}, {0x1D75, 0x1D75, 0x1D75}, {0x1D76, 0x1D76, 0x1D76}, {0x1D77, 0x1D77, 0x1D77}, {0x1D78, 0x1D78, 0x1D78}, {0x1D79, 0x1D79, 0x1D79}, {0x1D7A, 0x1D7A, 0x1D7A}, {0x1D7B, 0x1D7B, 0x1D7B}, {0x1D7C, 0x1D7C, 0x1D7C}, {0x1D7D, 0x1D7D, 0x1D7D}, {0x1D7E, 0x1D7E, 0x1D7E}, {0x1D7F, 0x1D7F, 0x1D7F}, {0x1D80, 0x1D80, 0x1D80}, {0x1D81, 0x1D81, 0x1D81}, {0x1D82, 0x1D82, 0x1D82}, {0x1D83, 0x1D83, 0x1D83}, {0x1D84, 0x1D84, 0x1D84}, {0x1D85, 0x1D85, 0x1D85}, {0x1D86, 0x1D86, 0x1D86}, {0x1D87, 0x1D87, 0x1D87}, {0x1D88, 0x1D88, 0x1D88}, {0x1D89, 0x1D89, 0x1D89}, {0x1D8A, 0x1D8A, 0x1D8A}, {0x1D8B, 0x1D8B, 0x1D8B}, {0x1D8C, 0x1D8C, 0x1D8C}, {0x1D8D, 0x1D8D, 0x1D8D}, {0x1D8E, 0x1D8E, 0x1D8E}, {0x1D8F, 0x1D8F, 0x1D8F}, {0x1D90, 0x1D90, 0x1D90}, {0x1D91, 0x1D91, 0x1D91}, {0x1D92, 0x1D92, 0x1D92}, {0x1D93, 0x1D93, 0x1D93}, {0x1D94, 0x1D94, 0x1D94}, {0x1D95, 0x1D95, 0x1D95}, {0x1D96, 0x1D96, 0x1D96}, {0x1D97, 0x1D97, 0x1D97}, {0x1D98, 0x1D98, 0x1D98}, {0x1D99, 0x1D99, 0x1D99}, {0x1D9A, 0x1D9A, 0x1D9A}, {0x1D9B, 0x1D9B, 0x1D9B}, {0x1D9C, 0x1D9C, 0x1D9C}, {0x1D9D, 0x1D9D, 0x1D9D}, {0x1D9E, 0x1D9E, 0x1D9E}, {0x1D9F, 0x1D9F, 0x1D9F}, {0x1DA0, 0x1DA0, 0x1DA0}, {0x1DA1, 0x1DA1, 0x1DA1}, {0x1DA2, 0x1DA2, 0x1DA2}, {0x1DA3, 0x1DA3, 0x1DA3}, {0x1DA4, 0x1DA4, 0x1DA4}, {0x1DA5, 0x1DA5, 0x1DA5}, {0x1DA6, 0x1DA6, 0x1DA6}, {0x1DA7, 0x1DA7, 0x1DA7}, {0x1DA8, 0x1DA8, 0x1DA8}, {0x1DA9, 0x1DA9, 0x1DA9}, {0x1DAA, 0x1DAA, 0x1DAA}, {0x1DAB, 0x1DAB, 0x1DAB}, {0x1DAC, 0x1DAC, 0x1DAC}, {0x1DAD, 0x1DAD, 0x1DAD}, {0x1DAE, 0x1DAE, 0x1DAE}, {0x1DAF, 0x1DAF, 0x1DAF}, {0x1DB0, 0x1DB0, 0x1DB0}, {0x1DB1, 0x1DB1, 0x1DB1}, {0x1DB2, 0x1DB2, 0x1DB2}, {0x1DB3, 0x1DB3, 0x1DB3}, {0x1DB4, 0x1DB4, 0x1DB4}, {0x1DB5, 0x1DB5, 0x1DB5}, {0x1DB6, 0x1DB6, 0x1DB6}, {0x1DB7, 0x1DB7, 0x1DB7}, {0x1DB8, 0x1DB8, 0x1DB8}, {0x1DB9, 0x1DB9, 0x1DB9}, {0x1DBA, 0x1DBA, 0x1DBA}, {0x1DBB, 0x1DBB, 0x1DBB}, {0x1DBC, 0x1DBC, 0x1DBC}, {0x1DBD, 0x1DBD, 0x1DBD}, {0x1DBE, 0x1DBE, 0x1DBE}, {0x1DBF, 0x1DBF, 0x1DBF}, {0x1DC0, 0x1DC0, 0x1DC0}, {0x1DC1, 0x1DC1, 0x1DC1}, {0x1DC2, 0x1DC2, 0x1DC2}, {0x1DC3, 0x1DC3, 0x1DC3}, {0x1E00, 0x1E00, 0x1E01}, {0x1E01, 0x1E00, 0x1E01}, {0x1E02, 0x1E02, 0x1E03}, {0x1E03, 0x1E02, 0x1E03}, {0x1E04, 0x1E04, 0x1E05}, {0x1E05, 0x1E04, 0x1E05}, {0x1E06, 0x1E06, 0x1E07}, {0x1E07, 0x1E06, 0x1E07}, {0x1E08, 0x1E08, 0x1E09}, {0x1E09, 0x1E08, 0x1E09}, {0x1E0A, 0x1E0A, 0x1E0B}, {0x1E0B, 0x1E0A, 0x1E0B}, {0x1E0C, 0x1E0C, 0x1E0D}, {0x1E0D, 0x1E0C, 0x1E0D}, {0x1E0E, 0x1E0E, 0x1E0F}, {0x1E0F, 0x1E0E, 0x1E0F}, {0x1E10, 0x1E10, 0x1E11}, {0x1E11, 0x1E10, 0x1E11}, {0x1E12, 0x1E12, 0x1E13}, {0x1E13, 0x1E12, 0x1E13}, {0x1E14, 0x1E14, 0x1E15}, {0x1E15, 0x1E14, 0x1E15}, {0x1E16, 0x1E16, 0x1E17}, {0x1E17, 0x1E16, 0x1E17}, {0x1E18, 0x1E18, 0x1E19}, {0x1E19, 0x1E18, 0x1E19}, {0x1E1A, 0x1E1A, 0x1E1B}, {0x1E1B, 0x1E1A, 0x1E1B}, {0x1E1C, 0x1E1C, 0x1E1D}, {0x1E1D, 0x1E1C, 0x1E1D}, {0x1E1E, 0x1E1E, 0x1E1F}, {0x1E1F, 0x1E1E, 0x1E1F}, {0x1E20, 0x1E20, 0x1E21}, {0x1E21, 0x1E20, 0x1E21}, {0x1E22, 0x1E22, 0x1E23}, {0x1E23, 0x1E22, 0x1E23}, {0x1E24, 0x1E24, 0x1E25}, {0x1E25, 0x1E24, 0x1E25}, {0x1E26, 0x1E26, 0x1E27}, {0x1E27, 0x1E26, 0x1E27}, {0x1E28, 0x1E28, 0x1E29}, {0x1E29, 0x1E28, 0x1E29}, {0x1E2A, 0x1E2A, 0x1E2B}, {0x1E2B, 0x1E2A, 0x1E2B}, {0x1E2C, 0x1E2C, 0x1E2D}, {0x1E2D, 0x1E2C, 0x1E2D}, {0x1E2E, 0x1E2E, 0x1E2F}, {0x1E2F, 0x1E2E, 0x1E2F}, {0x1E30, 0x1E30, 0x1E31}, {0x1E31, 0x1E30, 0x1E31}, {0x1E32, 0x1E32, 0x1E33}, {0x1E33, 0x1E32, 0x1E33}, {0x1E34, 0x1E34, 0x1E35}, {0x1E35, 0x1E34, 0x1E35}, {0x1E36, 0x1E36, 0x1E37}, {0x1E37, 0x1E36, 0x1E37}, {0x1E38, 0x1E38, 0x1E39}, {0x1E39, 0x1E38, 0x1E39}, {0x1E3A, 0x1E3A, 0x1E3B}, {0x1E3B, 0x1E3A, 0x1E3B}, {0x1E3C, 0x1E3C, 0x1E3D}, {0x1E3D, 0x1E3C, 0x1E3D}, {0x1E3E, 0x1E3E, 0x1E3F}, {0x1E3F, 0x1E3E, 0x1E3F}, {0x1E40, 0x1E40, 0x1E41}, {0x1E41, 0x1E40, 0x1E41}, {0x1E42, 0x1E42, 0x1E43}, {0x1E43, 0x1E42, 0x1E43}, {0x1E44, 0x1E44, 0x1E45}, {0x1E45, 0x1E44, 0x1E45}, {0x1E46, 0x1E46, 0x1E47}, {0x1E47, 0x1E46, 0x1E47}, {0x1E48, 0x1E48, 0x1E49}, {0x1E49, 0x1E48, 0x1E49}, {0x1E4A, 0x1E4A, 0x1E4B}, {0x1E4B, 0x1E4A, 0x1E4B}, {0x1E4C, 0x1E4C, 0x1E4D}, {0x1E4D, 0x1E4C, 0x1E4D}, {0x1E4E, 0x1E4E, 0x1E4F}, {0x1E4F, 0x1E4E, 0x1E4F}, {0x1E50, 0x1E50, 0x1E51}, {0x1E51, 0x1E50, 0x1E51}, {0x1E52, 0x1E52, 0x1E53}, {0x1E53, 0x1E52, 0x1E53}, {0x1E54, 0x1E54, 0x1E55}, {0x1E55, 0x1E54, 0x1E55}, {0x1E56, 0x1E56, 0x1E57}, {0x1E57, 0x1E56, 0x1E57}, {0x1E58, 0x1E58, 0x1E59}, {0x1E59, 0x1E58, 0x1E59}, {0x1E5A, 0x1E5A, 0x1E5B}, {0x1E5B, 0x1E5A, 0x1E5B}, {0x1E5C, 0x1E5C, 0x1E5D}, {0x1E5D, 0x1E5C, 0x1E5D}, {0x1E5E, 0x1E5E, 0x1E5F}, {0x1E5F, 0x1E5E, 0x1E5F}, {0x1E60, 0x1E60, 0x1E61}, {0x1E61, 0x1E60, 0x1E61}, {0x1E62, 0x1E62, 0x1E63}, {0x1E63, 0x1E62, 0x1E63}, {0x1E64, 0x1E64, 0x1E65}, {0x1E65, 0x1E64, 0x1E65}, {0x1E66, 0x1E66, 0x1E67}, {0x1E67, 0x1E66, 0x1E67}, {0x1E68, 0x1E68, 0x1E69}, {0x1E69, 0x1E68, 0x1E69}, {0x1E6A, 0x1E6A, 0x1E6B}, {0x1E6B, 0x1E6A, 0x1E6B}, {0x1E6C, 0x1E6C, 0x1E6D}, {0x1E6D, 0x1E6C, 0x1E6D}, {0x1E6E, 0x1E6E, 0x1E6F}, {0x1E6F, 0x1E6E, 0x1E6F}, {0x1E70, 0x1E70, 0x1E71}, {0x1E71, 0x1E70, 0x1E71}, {0x1E72, 0x1E72, 0x1E73}, {0x1E73, 0x1E72, 0x1E73}, {0x1E74, 0x1E74, 0x1E75}, {0x1E75, 0x1E74, 0x1E75}, {0x1E76, 0x1E76, 0x1E77}, {0x1E77, 0x1E76, 0x1E77}, {0x1E78, 0x1E78, 0x1E79}, {0x1E79, 0x1E78, 0x1E79}, {0x1E7A, 0x1E7A, 0x1E7B}, {0x1E7B, 0x1E7A, 0x1E7B}, {0x1E7C, 0x1E7C, 0x1E7D}, {0x1E7D, 0x1E7C, 0x1E7D}, {0x1E7E, 0x1E7E, 0x1E7F}, {0x1E7F, 0x1E7E, 0x1E7F}, {0x1E80, 0x1E80, 0x1E81}, {0x1E81, 0x1E80, 0x1E81}, {0x1E82, 0x1E82, 0x1E83}, {0x1E83, 0x1E82, 0x1E83}, {0x1E84, 0x1E84, 0x1E85}, {0x1E85, 0x1E84, 0x1E85}, {0x1E86, 0x1E86, 0x1E87}, {0x1E87, 0x1E86, 0x1E87}, {0x1E88, 0x1E88, 0x1E89}, {0x1E89, 0x1E88, 0x1E89}, {0x1E8A, 0x1E8A, 0x1E8B}, {0x1E8B, 0x1E8A, 0x1E8B}, {0x1E8C, 0x1E8C, 0x1E8D}, {0x1E8D, 0x1E8C, 0x1E8D}, {0x1E8E, 0x1E8E, 0x1E8F}, {0x1E8F, 0x1E8E, 0x1E8F}, {0x1E90, 0x1E90, 0x1E91}, {0x1E91, 0x1E90, 0x1E91}, {0x1E92, 0x1E92, 0x1E93}, {0x1E93, 0x1E92, 0x1E93}, {0x1E94, 0x1E94, 0x1E95}, {0x1E95, 0x1E94, 0x1E95}, {0x1E96, 0x1E96, 0x1E96}, {0x1E97, 0x1E97, 0x1E97}, {0x1E98, 0x1E98, 0x1E98}, {0x1E99, 0x1E99, 0x1E99}, {0x1E9A, 0x1E9A, 0x1E9A}, {0x1E9B, 0x1E60, 0x1E9B}, {0x1EA0, 0x1EA0, 0x1EA1}, {0x1EA1, 0x1EA0, 0x1EA1}, {0x1EA2, 0x1EA2, 0x1EA3}, {0x1EA3, 0x1EA2, 0x1EA3}, {0x1EA4, 0x1EA4, 0x1EA5}, {0x1EA5, 0x1EA4, 0x1EA5}, {0x1EA6, 0x1EA6, 0x1EA7}, {0x1EA7, 0x1EA6, 0x1EA7}, {0x1EA8, 0x1EA8, 0x1EA9}, {0x1EA9, 0x1EA8, 0x1EA9}, {0x1EAA, 0x1EAA, 0x1EAB}, {0x1EAB, 0x1EAA, 0x1EAB}, {0x1EAC, 0x1EAC, 0x1EAD}, {0x1EAD, 0x1EAC, 0x1EAD}, {0x1EAE, 0x1EAE, 0x1EAF}, {0x1EAF, 0x1EAE, 0x1EAF}, {0x1EB0, 0x1EB0, 0x1EB1}, {0x1EB1, 0x1EB0, 0x1EB1}, {0x1EB2, 0x1EB2, 0x1EB3}, {0x1EB3, 0x1EB2, 0x1EB3}, {0x1EB4, 0x1EB4, 0x1EB5}, {0x1EB5, 0x1EB4, 0x1EB5}, {0x1EB6, 0x1EB6, 0x1EB7}, {0x1EB7, 0x1EB6, 0x1EB7}, {0x1EB8, 0x1EB8, 0x1EB9}, {0x1EB9, 0x1EB8, 0x1EB9}, {0x1EBA, 0x1EBA, 0x1EBB}, {0x1EBB, 0x1EBA, 0x1EBB}, {0x1EBC, 0x1EBC, 0x1EBD}, {0x1EBD, 0x1EBC, 0x1EBD}, {0x1EBE, 0x1EBE, 0x1EBF}, {0x1EBF, 0x1EBE, 0x1EBF}, {0x1EC0, 0x1EC0, 0x1EC1}, {0x1EC1, 0x1EC0, 0x1EC1}, {0x1EC2, 0x1EC2, 0x1EC3}, {0x1EC3, 0x1EC2, 0x1EC3}, {0x1EC4, 0x1EC4, 0x1EC5}, {0x1EC5, 0x1EC4, 0x1EC5}, {0x1EC6, 0x1EC6, 0x1EC7}, {0x1EC7, 0x1EC6, 0x1EC7}, {0x1EC8, 0x1EC8, 0x1EC9}, {0x1EC9, 0x1EC8, 0x1EC9}, {0x1ECA, 0x1ECA, 0x1ECB}, {0x1ECB, 0x1ECA, 0x1ECB}, {0x1ECC, 0x1ECC, 0x1ECD}, {0x1ECD, 0x1ECC, 0x1ECD}, {0x1ECE, 0x1ECE, 0x1ECF}, {0x1ECF, 0x1ECE, 0x1ECF}, {0x1ED0, 0x1ED0, 0x1ED1}, {0x1ED1, 0x1ED0, 0x1ED1}, {0x1ED2, 0x1ED2, 0x1ED3}, {0x1ED3, 0x1ED2, 0x1ED3}, {0x1ED4, 0x1ED4, 0x1ED5}, {0x1ED5, 0x1ED4, 0x1ED5}, {0x1ED6, 0x1ED6, 0x1ED7}, {0x1ED7, 0x1ED6, 0x1ED7}, {0x1ED8, 0x1ED8, 0x1ED9}, {0x1ED9, 0x1ED8, 0x1ED9}, {0x1EDA, 0x1EDA, 0x1EDB}, {0x1EDB, 0x1EDA, 0x1EDB}, {0x1EDC, 0x1EDC, 0x1EDD}, {0x1EDD, 0x1EDC, 0x1EDD}, {0x1EDE, 0x1EDE, 0x1EDF}, {0x1EDF, 0x1EDE, 0x1EDF}, {0x1EE0, 0x1EE0, 0x1EE1}, {0x1EE1, 0x1EE0, 0x1EE1}, {0x1EE2, 0x1EE2, 0x1EE3}, {0x1EE3, 0x1EE2, 0x1EE3}, {0x1EE4, 0x1EE4, 0x1EE5}, {0x1EE5, 0x1EE4, 0x1EE5}, {0x1EE6, 0x1EE6, 0x1EE7}, {0x1EE7, 0x1EE6, 0x1EE7}, {0x1EE8, 0x1EE8, 0x1EE9}, {0x1EE9, 0x1EE8, 0x1EE9}, {0x1EEA, 0x1EEA, 0x1EEB}, {0x1EEB, 0x1EEA, 0x1EEB}, {0x1EEC, 0x1EEC, 0x1EED}, {0x1EED, 0x1EEC, 0x1EED}, {0x1EEE, 0x1EEE, 0x1EEF}, {0x1EEF, 0x1EEE, 0x1EEF}, {0x1EF0, 0x1EF0, 0x1EF1}, {0x1EF1, 0x1EF0, 0x1EF1}, {0x1EF2, 0x1EF2, 0x1EF3}, {0x1EF3, 0x1EF2, 0x1EF3}, {0x1EF4, 0x1EF4, 0x1EF5}, {0x1EF5, 0x1EF4, 0x1EF5}, {0x1EF6, 0x1EF6, 0x1EF7}, {0x1EF7, 0x1EF6, 0x1EF7}, {0x1EF8, 0x1EF8, 0x1EF9}, {0x1EF9, 0x1EF8, 0x1EF9}, {0x1F00, 0x1F08, 0x1F00}, {0x1F01, 0x1F09, 0x1F01}, {0x1F02, 0x1F0A, 0x1F02}, {0x1F03, 0x1F0B, 0x1F03}, {0x1F04, 0x1F0C, 0x1F04}, {0x1F05, 0x1F0D, 0x1F05}, {0x1F06, 0x1F0E, 0x1F06}, {0x1F07, 0x1F0F, 0x1F07}, {0x1F08, 0x1F08, 0x1F00}, {0x1F09, 0x1F09, 0x1F01}, {0x1F0A, 0x1F0A, 0x1F02}, {0x1F0B, 0x1F0B, 0x1F03}, {0x1F0C, 0x1F0C, 0x1F04}, {0x1F0D, 0x1F0D, 0x1F05}, {0x1F0E, 0x1F0E, 0x1F06}, {0x1F0F, 0x1F0F, 0x1F07}, {0x1F10, 0x1F18, 0x1F10}, {0x1F11, 0x1F19, 0x1F11}, {0x1F12, 0x1F1A, 0x1F12}, {0x1F13, 0x1F1B, 0x1F13}, {0x1F14, 0x1F1C, 0x1F14}, {0x1F15, 0x1F1D, 0x1F15}, {0x1F18, 0x1F18, 0x1F10}, {0x1F19, 0x1F19, 0x1F11}, {0x1F1A, 0x1F1A, 0x1F12}, {0x1F1B, 0x1F1B, 0x1F13}, {0x1F1C, 0x1F1C, 0x1F14}, {0x1F1D, 0x1F1D, 0x1F15}, {0x1F20, 0x1F28, 0x1F20}, {0x1F21, 0x1F29, 0x1F21}, {0x1F22, 0x1F2A, 0x1F22}, {0x1F23, 0x1F2B, 0x1F23}, {0x1F24, 0x1F2C, 0x1F24}, {0x1F25, 0x1F2D, 0x1F25}, {0x1F26, 0x1F2E, 0x1F26}, {0x1F27, 0x1F2F, 0x1F27}, {0x1F28, 0x1F28, 0x1F20}, {0x1F29, 0x1F29, 0x1F21}, {0x1F2A, 0x1F2A, 0x1F22}, {0x1F2B, 0x1F2B, 0x1F23}, {0x1F2C, 0x1F2C, 0x1F24}, {0x1F2D, 0x1F2D, 0x1F25}, {0x1F2E, 0x1F2E, 0x1F26}, {0x1F2F, 0x1F2F, 0x1F27}, {0x1F30, 0x1F38, 0x1F30}, {0x1F31, 0x1F39, 0x1F31}, {0x1F32, 0x1F3A, 0x1F32}, {0x1F33, 0x1F3B, 0x1F33}, {0x1F34, 0x1F3C, 0x1F34}, {0x1F35, 0x1F3D, 0x1F35}, {0x1F36, 0x1F3E, 0x1F36}, {0x1F37, 0x1F3F, 0x1F37}, {0x1F38, 0x1F38, 0x1F30}, {0x1F39, 0x1F39, 0x1F31}, {0x1F3A, 0x1F3A, 0x1F32}, {0x1F3B, 0x1F3B, 0x1F33}, {0x1F3C, 0x1F3C, 0x1F34}, {0x1F3D, 0x1F3D, 0x1F35}, {0x1F3E, 0x1F3E, 0x1F36}, {0x1F3F, 0x1F3F, 0x1F37}, {0x1F40, 0x1F48, 0x1F40}, {0x1F41, 0x1F49, 0x1F41}, {0x1F42, 0x1F4A, 0x1F42}, {0x1F43, 0x1F4B, 0x1F43}, {0x1F44, 0x1F4C, 0x1F44}, {0x1F45, 0x1F4D, 0x1F45}, {0x1F48, 0x1F48, 0x1F40}, {0x1F49, 0x1F49, 0x1F41}, {0x1F4A, 0x1F4A, 0x1F42}, {0x1F4B, 0x1F4B, 0x1F43}, {0x1F4C, 0x1F4C, 0x1F44}, {0x1F4D, 0x1F4D, 0x1F45}, {0x1F50, 0x1F50, 0x1F50}, {0x1F51, 0x1F59, 0x1F51}, {0x1F52, 0x1F52, 0x1F52}, {0x1F53, 0x1F5B, 0x1F53}, {0x1F54, 0x1F54, 0x1F54}, {0x1F55, 0x1F5D, 0x1F55}, {0x1F56, 0x1F56, 0x1F56}, {0x1F57, 0x1F5F, 0x1F57}, {0x1F59, 0x1F59, 0x1F51}, {0x1F5B, 0x1F5B, 0x1F53}, {0x1F5D, 0x1F5D, 0x1F55}, {0x1F5F, 0x1F5F, 0x1F57}, {0x1F60, 0x1F68, 0x1F60}, {0x1F61, 0x1F69, 0x1F61}, {0x1F62, 0x1F6A, 0x1F62}, {0x1F63, 0x1F6B, 0x1F63}, {0x1F64, 0x1F6C, 0x1F64}, {0x1F65, 0x1F6D, 0x1F65}, {0x1F66, 0x1F6E, 0x1F66}, {0x1F67, 0x1F6F, 0x1F67}, {0x1F68, 0x1F68, 0x1F60}, {0x1F69, 0x1F69, 0x1F61}, {0x1F6A, 0x1F6A, 0x1F62}, {0x1F6B, 0x1F6B, 0x1F63}, {0x1F6C, 0x1F6C, 0x1F64}, {0x1F6D, 0x1F6D, 0x1F65}, {0x1F6E, 0x1F6E, 0x1F66}, {0x1F6F, 0x1F6F, 0x1F67}, {0x1F70, 0x1FBA, 0x1F70}, {0x1F71, 0x1FBB, 0x1F71}, {0x1F72, 0x1FC8, 0x1F72}, {0x1F73, 0x1FC9, 0x1F73}, {0x1F74, 0x1FCA, 0x1F74}, {0x1F75, 0x1FCB, 0x1F75}, {0x1F76, 0x1FDA, 0x1F76}, {0x1F77, 0x1FDB, 0x1F77}, {0x1F78, 0x1FF8, 0x1F78}, {0x1F79, 0x1FF9, 0x1F79}, {0x1F7A, 0x1FEA, 0x1F7A}, {0x1F7B, 0x1FEB, 0x1F7B}, {0x1F7C, 0x1FFA, 0x1F7C}, {0x1F7D, 0x1FFB, 0x1F7D}, {0x1F80, 0x1F88, 0x1F80}, {0x1F81, 0x1F89, 0x1F81}, {0x1F82, 0x1F8A, 0x1F82}, {0x1F83, 0x1F8B, 0x1F83}, {0x1F84, 0x1F8C, 0x1F84}, {0x1F85, 0x1F8D, 0x1F85}, {0x1F86, 0x1F8E, 0x1F86}, {0x1F87, 0x1F8F, 0x1F87}, {0x1F88, 0x1F88, 0x1F80}, {0x1F89, 0x1F89, 0x1F81}, {0x1F8A, 0x1F8A, 0x1F82}, {0x1F8B, 0x1F8B, 0x1F83}, {0x1F8C, 0x1F8C, 0x1F84}, {0x1F8D, 0x1F8D, 0x1F85}, {0x1F8E, 0x1F8E, 0x1F86}, {0x1F8F, 0x1F8F, 0x1F87}, {0x1F90, 0x1F98, 0x1F90}, {0x1F91, 0x1F99, 0x1F91}, {0x1F92, 0x1F9A, 0x1F92}, {0x1F93, 0x1F9B, 0x1F93}, {0x1F94, 0x1F9C, 0x1F94}, {0x1F95, 0x1F9D, 0x1F95}, {0x1F96, 0x1F9E, 0x1F96}, {0x1F97, 0x1F9F, 0x1F97}, {0x1F98, 0x1F98, 0x1F90}, {0x1F99, 0x1F99, 0x1F91}, {0x1F9A, 0x1F9A, 0x1F92}, {0x1F9B, 0x1F9B, 0x1F93}, {0x1F9C, 0x1F9C, 0x1F94}, {0x1F9D, 0x1F9D, 0x1F95}, {0x1F9E, 0x1F9E, 0x1F96}, {0x1F9F, 0x1F9F, 0x1F97}, {0x1FA0, 0x1FA8, 0x1FA0}, {0x1FA1, 0x1FA9, 0x1FA1}, {0x1FA2, 0x1FAA, 0x1FA2}, {0x1FA3, 0x1FAB, 0x1FA3}, {0x1FA4, 0x1FAC, 0x1FA4}, {0x1FA5, 0x1FAD, 0x1FA5}, {0x1FA6, 0x1FAE, 0x1FA6}, {0x1FA7, 0x1FAF, 0x1FA7}, {0x1FA8, 0x1FA8, 0x1FA0}, {0x1FA9, 0x1FA9, 0x1FA1}, {0x1FAA, 0x1FAA, 0x1FA2}, {0x1FAB, 0x1FAB, 0x1FA3}, {0x1FAC, 0x1FAC, 0x1FA4}, {0x1FAD, 0x1FAD, 0x1FA5}, {0x1FAE, 0x1FAE, 0x1FA6}, {0x1FAF, 0x1FAF, 0x1FA7}, {0x1FB0, 0x1FB8, 0x1FB0}, {0x1FB1, 0x1FB9, 0x1FB1}, {0x1FB2, 0x1FB2, 0x1FB2}, {0x1FB3, 0x1FBC, 0x1FB3}, {0x1FB4, 0x1FB4, 0x1FB4}, {0x1FB6, 0x1FB6, 0x1FB6}, {0x1FB7, 0x1FB7, 0x1FB7}, {0x1FB8, 0x1FB8, 0x1FB0}, {0x1FB9, 0x1FB9, 0x1FB1}, {0x1FBA, 0x1FBA, 0x1F70}, {0x1FBB, 0x1FBB, 0x1F71}, {0x1FBC, 0x1FBC, 0x1FB3}, {0x1FBE, 0x0399, 0x1FBE}, {0x1FC2, 0x1FC2, 0x1FC2}, {0x1FC3, 0x1FCC, 0x1FC3}, {0x1FC4, 0x1FC4, 0x1FC4}, {0x1FC6, 0x1FC6, 0x1FC6}, {0x1FC7, 0x1FC7, 0x1FC7}, {0x1FC8, 0x1FC8, 0x1F72}, {0x1FC9, 0x1FC9, 0x1F73}, {0x1FCA, 0x1FCA, 0x1F74}, {0x1FCB, 0x1FCB, 0x1F75}, {0x1FCC, 0x1FCC, 0x1FC3}, {0x1FD0, 0x1FD8, 0x1FD0}, {0x1FD1, 0x1FD9, 0x1FD1}, {0x1FD2, 0x1FD2, 0x1FD2}, {0x1FD3, 0x1FD3, 0x1FD3}, {0x1FD6, 0x1FD6, 0x1FD6}, {0x1FD7, 0x1FD7, 0x1FD7}, {0x1FD8, 0x1FD8, 0x1FD0}, {0x1FD9, 0x1FD9, 0x1FD1}, {0x1FDA, 0x1FDA, 0x1F76}, {0x1FDB, 0x1FDB, 0x1F77}, {0x1FE0, 0x1FE8, 0x1FE0}, {0x1FE1, 0x1FE9, 0x1FE1}, {0x1FE2, 0x1FE2, 0x1FE2}, {0x1FE3, 0x1FE3, 0x1FE3}, {0x1FE4, 0x1FE4, 0x1FE4}, {0x1FE5, 0x1FEC, 0x1FE5}, {0x1FE6, 0x1FE6, 0x1FE6}, {0x1FE7, 0x1FE7, 0x1FE7}, {0x1FE8, 0x1FE8, 0x1FE0}, {0x1FE9, 0x1FE9, 0x1FE1}, {0x1FEA, 0x1FEA, 0x1F7A}, {0x1FEB, 0x1FEB, 0x1F7B}, {0x1FEC, 0x1FEC, 0x1FE5}, {0x1FF2, 0x1FF2, 0x1FF2}, {0x1FF3, 0x1FFC, 0x1FF3}, {0x1FF4, 0x1FF4, 0x1FF4}, {0x1FF6, 0x1FF6, 0x1FF6}, {0x1FF7, 0x1FF7, 0x1FF7}, {0x1FF8, 0x1FF8, 0x1F78}, {0x1FF9, 0x1FF9, 0x1F79}, {0x1FFA, 0x1FFA, 0x1F7C}, {0x1FFB, 0x1FFB, 0x1F7D}, {0x1FFC, 0x1FFC, 0x1FF3}, {0x2071, 0x2071, 0x2071}, {0x207F, 0x207F, 0x207F}, {0x2090, 0x2090, 0x2090}, {0x2091, 0x2091, 0x2091}, {0x2092, 0x2092, 0x2092}, {0x2093, 0x2093, 0x2093}, {0x2094, 0x2094, 0x2094}, {0x20D0, 0x20D0, 0x20D0}, {0x20D1, 0x20D1, 0x20D1}, {0x20D2, 0x20D2, 0x20D2}, {0x20D3, 0x20D3, 0x20D3}, {0x20D4, 0x20D4, 0x20D4}, {0x20D5, 0x20D5, 0x20D5}, {0x20D6, 0x20D6, 0x20D6}, {0x20D7, 0x20D7, 0x20D7}, {0x20D8, 0x20D8, 0x20D8}, {0x20D9, 0x20D9, 0x20D9}, {0x20DA, 0x20DA, 0x20DA}, {0x20DB, 0x20DB, 0x20DB}, {0x20DC, 0x20DC, 0x20DC}, {0x20E1, 0x20E1, 0x20E1}, {0x20E5, 0x20E5, 0x20E5}, {0x20E6, 0x20E6, 0x20E6}, {0x20E7, 0x20E7, 0x20E7}, {0x20E8, 0x20E8, 0x20E8}, {0x20E9, 0x20E9, 0x20E9}, {0x20EA, 0x20EA, 0x20EA}, {0x20EB, 0x20EB, 0x20EB}, {0x2102, 0x2102, 0x2102}, {0x2107, 0x2107, 0x2107}, {0x210A, 0x210A, 0x210A}, {0x210B, 0x210B, 0x210B}, {0x210C, 0x210C, 0x210C}, {0x210D, 0x210D, 0x210D}, {0x210E, 0x210E, 0x210E}, {0x210F, 0x210F, 0x210F}, {0x2110, 0x2110, 0x2110}, {0x2111, 0x2111, 0x2111}, {0x2112, 0x2112, 0x2112}, {0x2113, 0x2113, 0x2113}, {0x2115, 0x2115, 0x2115}, {0x2119, 0x2119, 0x2119}, {0x211A, 0x211A, 0x211A}, {0x211B, 0x211B, 0x211B}, {0x211C, 0x211C, 0x211C}, {0x211D, 0x211D, 0x211D}, {0x2124, 0x2124, 0x2124}, {0x2126, 0x2126, 0x03C9}, {0x2128, 0x2128, 0x2128}, {0x212A, 0x212A, 0x006B}, {0x212B, 0x212B, 0x00E5}, {0x212C, 0x212C, 0x212C}, {0x212D, 0x212D, 0x212D}, {0x212F, 0x212F, 0x212F}, {0x2130, 0x2130, 0x2130}, {0x2131, 0x2131, 0x2131}, {0x2133, 0x2133, 0x2133}, {0x2134, 0x2134, 0x2134}, {0x2135, 0x2135, 0x2135}, {0x2136, 0x2136, 0x2136}, {0x2137, 0x2137, 0x2137}, {0x2138, 0x2138, 0x2138}, {0x2139, 0x2139, 0x2139}, {0x213C, 0x213C, 0x213C}, {0x213D, 0x213D, 0x213D}, {0x213E, 0x213E, 0x213E}, {0x213F, 0x213F, 0x213F}, {0x2145, 0x2145, 0x2145}, {0x2146, 0x2146, 0x2146}, {0x2147, 0x2147, 0x2147}, {0x2148, 0x2148, 0x2148}, {0x2149, 0x2149, 0x2149}, {0x2C00, 0x2C00, 0x2C30}, {0x2C01, 0x2C01, 0x2C31}, {0x2C02, 0x2C02, 0x2C32}, {0x2C03, 0x2C03, 0x2C33}, {0x2C04, 0x2C04, 0x2C34}, {0x2C05, 0x2C05, 0x2C35}, {0x2C06, 0x2C06, 0x2C36}, {0x2C07, 0x2C07, 0x2C37}, {0x2C08, 0x2C08, 0x2C38}, {0x2C09, 0x2C09, 0x2C39}, {0x2C0A, 0x2C0A, 0x2C3A}, {0x2C0B, 0x2C0B, 0x2C3B}, {0x2C0C, 0x2C0C, 0x2C3C}, {0x2C0D, 0x2C0D, 0x2C3D}, {0x2C0E, 0x2C0E, 0x2C3E}, {0x2C0F, 0x2C0F, 0x2C3F}, {0x2C10, 0x2C10, 0x2C40}, {0x2C11, 0x2C11, 0x2C41}, {0x2C12, 0x2C12, 0x2C42}, {0x2C13, 0x2C13, 0x2C43}, {0x2C14, 0x2C14, 0x2C44}, {0x2C15, 0x2C15, 0x2C45}, {0x2C16, 0x2C16, 0x2C46}, {0x2C17, 0x2C17, 0x2C47}, {0x2C18, 0x2C18, 0x2C48}, {0x2C19, 0x2C19, 0x2C49}, {0x2C1A, 0x2C1A, 0x2C4A}, {0x2C1B, 0x2C1B, 0x2C4B}, {0x2C1C, 0x2C1C, 0x2C4C}, {0x2C1D, 0x2C1D, 0x2C4D}, {0x2C1E, 0x2C1E, 0x2C4E}, {0x2C1F, 0x2C1F, 0x2C4F}, {0x2C20, 0x2C20, 0x2C50}, {0x2C21, 0x2C21, 0x2C51}, {0x2C22, 0x2C22, 0x2C52}, {0x2C23, 0x2C23, 0x2C53}, {0x2C24, 0x2C24, 0x2C54}, {0x2C25, 0x2C25, 0x2C55}, {0x2C26, 0x2C26, 0x2C56}, {0x2C27, 0x2C27, 0x2C57}, {0x2C28, 0x2C28, 0x2C58}, {0x2C29, 0x2C29, 0x2C59}, {0x2C2A, 0x2C2A, 0x2C5A}, {0x2C2B, 0x2C2B, 0x2C5B}, {0x2C2C, 0x2C2C, 0x2C5C}, {0x2C2D, 0x2C2D, 0x2C5D}, {0x2C2E, 0x2C2E, 0x2C5E}, {0x2C30, 0x2C00, 0x2C30}, {0x2C31, 0x2C01, 0x2C31}, {0x2C32, 0x2C02, 0x2C32}, {0x2C33, 0x2C03, 0x2C33}, {0x2C34, 0x2C04, 0x2C34}, {0x2C35, 0x2C05, 0x2C35}, {0x2C36, 0x2C06, 0x2C36}, {0x2C37, 0x2C07, 0x2C37}, {0x2C38, 0x2C08, 0x2C38}, {0x2C39, 0x2C09, 0x2C39}, {0x2C3A, 0x2C0A, 0x2C3A}, {0x2C3B, 0x2C0B, 0x2C3B}, {0x2C3C, 0x2C0C, 0x2C3C}, {0x2C3D, 0x2C0D, 0x2C3D}, {0x2C3E, 0x2C0E, 0x2C3E}, {0x2C3F, 0x2C0F, 0x2C3F}, {0x2C40, 0x2C10, 0x2C40}, {0x2C41, 0x2C11, 0x2C41}, {0x2C42, 0x2C12, 0x2C42}, {0x2C43, 0x2C13, 0x2C43}, {0x2C44, 0x2C14, 0x2C44}, {0x2C45, 0x2C15, 0x2C45}, {0x2C46, 0x2C16, 0x2C46}, {0x2C47, 0x2C17, 0x2C47}, {0x2C48, 0x2C18, 0x2C48}, {0x2C49, 0x2C19, 0x2C49}, {0x2C4A, 0x2C1A, 0x2C4A}, {0x2C4B, 0x2C1B, 0x2C4B}, {0x2C4C, 0x2C1C, 0x2C4C}, {0x2C4D, 0x2C1D, 0x2C4D}, {0x2C4E, 0x2C1E, 0x2C4E}, {0x2C4F, 0x2C1F, 0x2C4F}, {0x2C50, 0x2C20, 0x2C50}, {0x2C51, 0x2C21, 0x2C51}, {0x2C52, 0x2C22, 0x2C52}, {0x2C53, 0x2C23, 0x2C53}, {0x2C54, 0x2C24, 0x2C54}, {0x2C55, 0x2C25, 0x2C55}, {0x2C56, 0x2C26, 0x2C56}, {0x2C57, 0x2C27, 0x2C57}, {0x2C58, 0x2C28, 0x2C58}, {0x2C59, 0x2C29, 0x2C59}, {0x2C5A, 0x2C2A, 0x2C5A}, {0x2C5B, 0x2C2B, 0x2C5B}, {0x2C5C, 0x2C2C, 0x2C5C}, {0x2C5D, 0x2C2D, 0x2C5D}, {0x2C5E, 0x2C2E, 0x2C5E}, {0x2C80, 0x2C80, 0x2C81}, {0x2C81, 0x2C80, 0x2C81}, {0x2C82, 0x2C82, 0x2C83}, {0x2C83, 0x2C82, 0x2C83}, {0x2C84, 0x2C84, 0x2C85}, {0x2C85, 0x2C84, 0x2C85}, {0x2C86, 0x2C86, 0x2C87}, {0x2C87, 0x2C86, 0x2C87}, {0x2C88, 0x2C88, 0x2C89}, {0x2C89, 0x2C88, 0x2C89}, {0x2C8A, 0x2C8A, 0x2C8B}, {0x2C8B, 0x2C8A, 0x2C8B}, {0x2C8C, 0x2C8C, 0x2C8D}, {0x2C8D, 0x2C8C, 0x2C8D}, {0x2C8E, 0x2C8E, 0x2C8F}, {0x2C8F, 0x2C8E, 0x2C8F}, {0x2C90, 0x2C90, 0x2C91}, {0x2C91, 0x2C90, 0x2C91}, {0x2C92, 0x2C92, 0x2C93}, {0x2C93, 0x2C92, 0x2C93}, {0x2C94, 0x2C94, 0x2C95}, {0x2C95, 0x2C94, 0x2C95}, {0x2C96, 0x2C96, 0x2C97}, {0x2C97, 0x2C96, 0x2C97}, {0x2C98, 0x2C98, 0x2C99}, {0x2C99, 0x2C98, 0x2C99}, {0x2C9A, 0x2C9A, 0x2C9B}, {0x2C9B, 0x2C9A, 0x2C9B}, {0x2C9C, 0x2C9C, 0x2C9D}, {0x2C9D, 0x2C9C, 0x2C9D}, {0x2C9E, 0x2C9E, 0x2C9F}, {0x2C9F, 0x2C9E, 0x2C9F}, {0x2CA0, 0x2CA0, 0x2CA1}, {0x2CA1, 0x2CA0, 0x2CA1}, {0x2CA2, 0x2CA2, 0x2CA3}, {0x2CA3, 0x2CA2, 0x2CA3}, {0x2CA4, 0x2CA4, 0x2CA5}, {0x2CA5, 0x2CA4, 0x2CA5}, {0x2CA6, 0x2CA6, 0x2CA7}, {0x2CA7, 0x2CA6, 0x2CA7}, {0x2CA8, 0x2CA8, 0x2CA9}, {0x2CA9, 0x2CA8, 0x2CA9}, {0x2CAA, 0x2CAA, 0x2CAB}, {0x2CAB, 0x2CAA, 0x2CAB}, {0x2CAC, 0x2CAC, 0x2CAD}, {0x2CAD, 0x2CAC, 0x2CAD}, {0x2CAE, 0x2CAE, 0x2CAF}, {0x2CAF, 0x2CAE, 0x2CAF}, {0x2CB0, 0x2CB0, 0x2CB1}, {0x2CB1, 0x2CB0, 0x2CB1}, {0x2CB2, 0x2CB2, 0x2CB3}, {0x2CB3, 0x2CB2, 0x2CB3}, {0x2CB4, 0x2CB4, 0x2CB5}, {0x2CB5, 0x2CB4, 0x2CB5}, {0x2CB6, 0x2CB6, 0x2CB7}, {0x2CB7, 0x2CB6, 0x2CB7}, {0x2CB8, 0x2CB8, 0x2CB9}, {0x2CB9, 0x2CB8, 0x2CB9}, {0x2CBA, 0x2CBA, 0x2CBB}, {0x2CBB, 0x2CBA, 0x2CBB}, {0x2CBC, 0x2CBC, 0x2CBD}, {0x2CBD, 0x2CBC, 0x2CBD}, {0x2CBE, 0x2CBE, 0x2CBF}, {0x2CBF, 0x2CBE, 0x2CBF}, {0x2CC0, 0x2CC0, 0x2CC1}, {0x2CC1, 0x2CC0, 0x2CC1}, {0x2CC2, 0x2CC2, 0x2CC3}, {0x2CC3, 0x2CC2, 0x2CC3}, {0x2CC4, 0x2CC4, 0x2CC5}, {0x2CC5, 0x2CC4, 0x2CC5}, {0x2CC6, 0x2CC6, 0x2CC7}, {0x2CC7, 0x2CC6, 0x2CC7}, {0x2CC8, 0x2CC8, 0x2CC9}, {0x2CC9, 0x2CC8, 0x2CC9}, {0x2CCA, 0x2CCA, 0x2CCB}, {0x2CCB, 0x2CCA, 0x2CCB}, {0x2CCC, 0x2CCC, 0x2CCD}, {0x2CCD, 0x2CCC, 0x2CCD}, {0x2CCE, 0x2CCE, 0x2CCF}, {0x2CCF, 0x2CCE, 0x2CCF}, {0x2CD0, 0x2CD0, 0x2CD1}, {0x2CD1, 0x2CD0, 0x2CD1}, {0x2CD2, 0x2CD2, 0x2CD3}, {0x2CD3, 0x2CD2, 0x2CD3}, {0x2CD4, 0x2CD4, 0x2CD5}, {0x2CD5, 0x2CD4, 0x2CD5}, {0x2CD6, 0x2CD6, 0x2CD7}, {0x2CD7, 0x2CD6, 0x2CD7}, {0x2CD8, 0x2CD8, 0x2CD9}, {0x2CD9, 0x2CD8, 0x2CD9}, {0x2CDA, 0x2CDA, 0x2CDB}, {0x2CDB, 0x2CDA, 0x2CDB}, {0x2CDC, 0x2CDC, 0x2CDD}, {0x2CDD, 0x2CDC, 0x2CDD}, {0x2CDE, 0x2CDE, 0x2CDF}, {0x2CDF, 0x2CDE, 0x2CDF}, {0x2CE0, 0x2CE0, 0x2CE1}, {0x2CE1, 0x2CE0, 0x2CE1}, {0x2CE2, 0x2CE2, 0x2CE3}, {0x2CE3, 0x2CE2, 0x2CE3}, {0x2CE4, 0x2CE4, 0x2CE4}, {0x2D00, 0x10A0, 0x2D00}, {0x2D01, 0x10A1, 0x2D01}, {0x2D02, 0x10A2, 0x2D02}, {0x2D03, 0x10A3, 0x2D03}, {0x2D04, 0x10A4, 0x2D04}, {0x2D05, 0x10A5, 0x2D05}, {0x2D06, 0x10A6, 0x2D06}, {0x2D07, 0x10A7, 0x2D07}, {0x2D08, 0x10A8, 0x2D08}, {0x2D09, 0x10A9, 0x2D09}, {0x2D0A, 0x10AA, 0x2D0A}, {0x2D0B, 0x10AB, 0x2D0B}, {0x2D0C, 0x10AC, 0x2D0C}, {0x2D0D, 0x10AD, 0x2D0D}, {0x2D0E, 0x10AE, 0x2D0E}, {0x2D0F, 0x10AF, 0x2D0F}, {0x2D10, 0x10B0, 0x2D10}, {0x2D11, 0x10B1, 0x2D11}, {0x2D12, 0x10B2, 0x2D12}, {0x2D13, 0x10B3, 0x2D13}, {0x2D14, 0x10B4, 0x2D14}, {0x2D15, 0x10B5, 0x2D15}, {0x2D16, 0x10B6, 0x2D16}, {0x2D17, 0x10B7, 0x2D17}, {0x2D18, 0x10B8, 0x2D18}, {0x2D19, 0x10B9, 0x2D19}, {0x2D1A, 0x10BA, 0x2D1A}, {0x2D1B, 0x10BB, 0x2D1B}, {0x2D1C, 0x10BC, 0x2D1C}, {0x2D1D, 0x10BD, 0x2D1D}, {0x2D1E, 0x10BE, 0x2D1E}, {0x2D1F, 0x10BF, 0x2D1F}, {0x2D20, 0x10C0, 0x2D20}, {0x2D21, 0x10C1, 0x2D21}, {0x2D22, 0x10C2, 0x2D22}, {0x2D23, 0x10C3, 0x2D23}, {0x2D24, 0x10C4, 0x2D24}, {0x2D25, 0x10C5, 0x2D25}, {0x2D30, 0x2D30, 0x2D30}, {0x2D31, 0x2D31, 0x2D31}, {0x2D32, 0x2D32, 0x2D32}, {0x2D33, 0x2D33, 0x2D33}, {0x2D34, 0x2D34, 0x2D34}, {0x2D35, 0x2D35, 0x2D35}, {0x2D36, 0x2D36, 0x2D36}, {0x2D37, 0x2D37, 0x2D37}, {0x2D38, 0x2D38, 0x2D38}, {0x2D39, 0x2D39, 0x2D39}, {0x2D3A, 0x2D3A, 0x2D3A}, {0x2D3B, 0x2D3B, 0x2D3B}, {0x2D3C, 0x2D3C, 0x2D3C}, {0x2D3D, 0x2D3D, 0x2D3D}, {0x2D3E, 0x2D3E, 0x2D3E}, {0x2D3F, 0x2D3F, 0x2D3F}, {0x2D40, 0x2D40, 0x2D40}, {0x2D41, 0x2D41, 0x2D41}, {0x2D42, 0x2D42, 0x2D42}, {0x2D43, 0x2D43, 0x2D43}, {0x2D44, 0x2D44, 0x2D44}, {0x2D45, 0x2D45, 0x2D45}, {0x2D46, 0x2D46, 0x2D46}, {0x2D47, 0x2D47, 0x2D47}, {0x2D48, 0x2D48, 0x2D48}, {0x2D49, 0x2D49, 0x2D49}, {0x2D4A, 0x2D4A, 0x2D4A}, {0x2D4B, 0x2D4B, 0x2D4B}, {0x2D4C, 0x2D4C, 0x2D4C}, {0x2D4D, 0x2D4D, 0x2D4D}, {0x2D4E, 0x2D4E, 0x2D4E}, {0x2D4F, 0x2D4F, 0x2D4F}, {0x2D50, 0x2D50, 0x2D50}, {0x2D51, 0x2D51, 0x2D51}, {0x2D52, 0x2D52, 0x2D52}, {0x2D53, 0x2D53, 0x2D53}, {0x2D54, 0x2D54, 0x2D54}, {0x2D55, 0x2D55, 0x2D55}, {0x2D56, 0x2D56, 0x2D56}, {0x2D57, 0x2D57, 0x2D57}, {0x2D58, 0x2D58, 0x2D58}, {0x2D59, 0x2D59, 0x2D59}, {0x2D5A, 0x2D5A, 0x2D5A}, {0x2D5B, 0x2D5B, 0x2D5B}, {0x2D5C, 0x2D5C, 0x2D5C}, {0x2D5D, 0x2D5D, 0x2D5D}, {0x2D5E, 0x2D5E, 0x2D5E}, {0x2D5F, 0x2D5F, 0x2D5F}, {0x2D60, 0x2D60, 0x2D60}, {0x2D61, 0x2D61, 0x2D61}, {0x2D62, 0x2D62, 0x2D62}, {0x2D63, 0x2D63, 0x2D63}, {0x2D64, 0x2D64, 0x2D64}, {0x2D65, 0x2D65, 0x2D65}, {0x2D6F, 0x2D6F, 0x2D6F}, {0x2D80, 0x2D80, 0x2D80}, {0x2D81, 0x2D81, 0x2D81}, {0x2D82, 0x2D82, 0x2D82}, {0x2D83, 0x2D83, 0x2D83}, {0x2D84, 0x2D84, 0x2D84}, {0x2D85, 0x2D85, 0x2D85}, {0x2D86, 0x2D86, 0x2D86}, {0x2D87, 0x2D87, 0x2D87}, {0x2D88, 0x2D88, 0x2D88}, {0x2D89, 0x2D89, 0x2D89}, {0x2D8A, 0x2D8A, 0x2D8A}, {0x2D8B, 0x2D8B, 0x2D8B}, {0x2D8C, 0x2D8C, 0x2D8C}, {0x2D8D, 0x2D8D, 0x2D8D}, {0x2D8E, 0x2D8E, 0x2D8E}, {0x2D8F, 0x2D8F, 0x2D8F}, {0x2D90, 0x2D90, 0x2D90}, {0x2D91, 0x2D91, 0x2D91}, {0x2D92, 0x2D92, 0x2D92}, {0x2D93, 0x2D93, 0x2D93}, {0x2D94, 0x2D94, 0x2D94}, {0x2D95, 0x2D95, 0x2D95}, {0x2D96, 0x2D96, 0x2D96}, {0x2DA0, 0x2DA0, 0x2DA0}, {0x2DA1, 0x2DA1, 0x2DA1}, {0x2DA2, 0x2DA2, 0x2DA2}, {0x2DA3, 0x2DA3, 0x2DA3}, {0x2DA4, 0x2DA4, 0x2DA4}, {0x2DA5, 0x2DA5, 0x2DA5}, {0x2DA6, 0x2DA6, 0x2DA6}, {0x2DA8, 0x2DA8, 0x2DA8}, {0x2DA9, 0x2DA9, 0x2DA9}, {0x2DAA, 0x2DAA, 0x2DAA}, {0x2DAB, 0x2DAB, 0x2DAB}, {0x2DAC, 0x2DAC, 0x2DAC}, {0x2DAD, 0x2DAD, 0x2DAD}, {0x2DAE, 0x2DAE, 0x2DAE}, {0x2DB0, 0x2DB0, 0x2DB0}, {0x2DB1, 0x2DB1, 0x2DB1}, {0x2DB2, 0x2DB2, 0x2DB2}, {0x2DB3, 0x2DB3, 0x2DB3}, {0x2DB4, 0x2DB4, 0x2DB4}, {0x2DB5, 0x2DB5, 0x2DB5}, {0x2DB6, 0x2DB6, 0x2DB6}, {0x2DB8, 0x2DB8, 0x2DB8}, {0x2DB9, 0x2DB9, 0x2DB9}, {0x2DBA, 0x2DBA, 0x2DBA}, {0x2DBB, 0x2DBB, 0x2DBB}, {0x2DBC, 0x2DBC, 0x2DBC}, {0x2DBD, 0x2DBD, 0x2DBD}, {0x2DBE, 0x2DBE, 0x2DBE}, {0x2DC0, 0x2DC0, 0x2DC0}, {0x2DC1, 0x2DC1, 0x2DC1}, {0x2DC2, 0x2DC2, 0x2DC2}, {0x2DC3, 0x2DC3, 0x2DC3}, {0x2DC4, 0x2DC4, 0x2DC4}, {0x2DC5, 0x2DC5, 0x2DC5}, {0x2DC6, 0x2DC6, 0x2DC6}, {0x2DC8, 0x2DC8, 0x2DC8}, {0x2DC9, 0x2DC9, 0x2DC9}, {0x2DCA, 0x2DCA, 0x2DCA}, {0x2DCB, 0x2DCB, 0x2DCB}, {0x2DCC, 0x2DCC, 0x2DCC}, {0x2DCD, 0x2DCD, 0x2DCD}, {0x2DCE, 0x2DCE, 0x2DCE}, {0x2DD0, 0x2DD0, 0x2DD0}, {0x2DD1, 0x2DD1, 0x2DD1}, {0x2DD2, 0x2DD2, 0x2DD2}, {0x2DD3, 0x2DD3, 0x2DD3}, {0x2DD4, 0x2DD4, 0x2DD4}, {0x2DD5, 0x2DD5, 0x2DD5}, {0x2DD6, 0x2DD6, 0x2DD6}, {0x2DD8, 0x2DD8, 0x2DD8}, {0x2DD9, 0x2DD9, 0x2DD9}, {0x2DDA, 0x2DDA, 0x2DDA}, {0x2DDB, 0x2DDB, 0x2DDB}, {0x2DDC, 0x2DDC, 0x2DDC}, {0x2DDD, 0x2DDD, 0x2DDD}, {0x2DDE, 0x2DDE, 0x2DDE}, {0x3005, 0x3005, 0x3005}, {0x3006, 0x3006, 0x3006}, {0x302A, 0x302A, 0x302A}, {0x302B, 0x302B, 0x302B}, {0x302C, 0x302C, 0x302C}, {0x302D, 0x302D, 0x302D}, {0x302E, 0x302E, 0x302E}, {0x302F, 0x302F, 0x302F}, {0x3031, 0x3031, 0x3031}, {0x3032, 0x3032, 0x3032}, {0x3033, 0x3033, 0x3033}, {0x3034, 0x3034, 0x3034}, {0x3035, 0x3035, 0x3035}, {0x303B, 0x303B, 0x303B}, {0x303C, 0x303C, 0x303C}, {0x3041, 0x3041, 0x3041}, {0x3042, 0x3042, 0x3042}, {0x3043, 0x3043, 0x3043}, {0x3044, 0x3044, 0x3044}, {0x3045, 0x3045, 0x3045}, {0x3046, 0x3046, 0x3046}, {0x3047, 0x3047, 0x3047}, {0x3048, 0x3048, 0x3048}, {0x3049, 0x3049, 0x3049}, {0x304A, 0x304A, 0x304A}, {0x304B, 0x304B, 0x304B}, {0x304C, 0x304C, 0x304C}, {0x304D, 0x304D, 0x304D}, {0x304E, 0x304E, 0x304E}, {0x304F, 0x304F, 0x304F}, {0x3050, 0x3050, 0x3050}, {0x3051, 0x3051, 0x3051}, {0x3052, 0x3052, 0x3052}, {0x3053, 0x3053, 0x3053}, {0x3054, 0x3054, 0x3054}, {0x3055, 0x3055, 0x3055}, {0x3056, 0x3056, 0x3056}, {0x3057, 0x3057, 0x3057}, {0x3058, 0x3058, 0x3058}, {0x3059, 0x3059, 0x3059}, {0x305A, 0x305A, 0x305A}, {0x305B, 0x305B, 0x305B}, {0x305C, 0x305C, 0x305C}, {0x305D, 0x305D, 0x305D}, {0x305E, 0x305E, 0x305E}, {0x305F, 0x305F, 0x305F}, {0x3060, 0x3060, 0x3060}, {0x3061, 0x3061, 0x3061}, {0x3062, 0x3062, 0x3062}, {0x3063, 0x3063, 0x3063}, {0x3064, 0x3064, 0x3064}, {0x3065, 0x3065, 0x3065}, {0x3066, 0x3066, 0x3066}, {0x3067, 0x3067, 0x3067}, {0x3068, 0x3068, 0x3068}, {0x3069, 0x3069, 0x3069}, {0x306A, 0x306A, 0x306A}, {0x306B, 0x306B, 0x306B}, {0x306C, 0x306C, 0x306C}, {0x306D, 0x306D, 0x306D}, {0x306E, 0x306E, 0x306E}, {0x306F, 0x306F, 0x306F}, {0x3070, 0x3070, 0x3070}, {0x3071, 0x3071, 0x3071}, {0x3072, 0x3072, 0x3072}, {0x3073, 0x3073, 0x3073}, {0x3074, 0x3074, 0x3074}, {0x3075, 0x3075, 0x3075}, {0x3076, 0x3076, 0x3076}, {0x3077, 0x3077, 0x3077}, {0x3078, 0x3078, 0x3078}, {0x3079, 0x3079, 0x3079}, {0x307A, 0x307A, 0x307A}, {0x307B, 0x307B, 0x307B}, {0x307C, 0x307C, 0x307C}, {0x307D, 0x307D, 0x307D}, {0x307E, 0x307E, 0x307E}, {0x307F, 0x307F, 0x307F}, {0x3080, 0x3080, 0x3080}, {0x3081, 0x3081, 0x3081}, {0x3082, 0x3082, 0x3082}, {0x3083, 0x3083, 0x3083}, {0x3084, 0x3084, 0x3084}, {0x3085, 0x3085, 0x3085}, {0x3086, 0x3086, 0x3086}, {0x3087, 0x3087, 0x3087}, {0x3088, 0x3088, 0x3088}, {0x3089, 0x3089, 0x3089}, {0x308A, 0x308A, 0x308A}, {0x308B, 0x308B, 0x308B}, {0x308C, 0x308C, 0x308C}, {0x308D, 0x308D, 0x308D}, {0x308E, 0x308E, 0x308E}, {0x308F, 0x308F, 0x308F}, {0x3090, 0x3090, 0x3090}, {0x3091, 0x3091, 0x3091}, {0x3092, 0x3092, 0x3092}, {0x3093, 0x3093, 0x3093}, {0x3094, 0x3094, 0x3094}, {0x3095, 0x3095, 0x3095}, {0x3096, 0x3096, 0x3096}, {0x3099, 0x3099, 0x3099}, {0x309A, 0x309A, 0x309A}, {0x309D, 0x309D, 0x309D}, {0x309E, 0x309E, 0x309E}, {0x309F, 0x309F, 0x309F}, {0x30A1, 0x30A1, 0x30A1}, {0x30A2, 0x30A2, 0x30A2}, {0x30A3, 0x30A3, 0x30A3}, {0x30A4, 0x30A4, 0x30A4}, {0x30A5, 0x30A5, 0x30A5}, {0x30A6, 0x30A6, 0x30A6}, {0x30A7, 0x30A7, 0x30A7}, {0x30A8, 0x30A8, 0x30A8}, {0x30A9, 0x30A9, 0x30A9}, {0x30AA, 0x30AA, 0x30AA}, {0x30AB, 0x30AB, 0x30AB}, {0x30AC, 0x30AC, 0x30AC}, {0x30AD, 0x30AD, 0x30AD}, {0x30AE, 0x30AE, 0x30AE}, {0x30AF, 0x30AF, 0x30AF}, {0x30B0, 0x30B0, 0x30B0}, {0x30B1, 0x30B1, 0x30B1}, {0x30B2, 0x30B2, 0x30B2}, {0x30B3, 0x30B3, 0x30B3}, {0x30B4, 0x30B4, 0x30B4}, {0x30B5, 0x30B5, 0x30B5}, {0x30B6, 0x30B6, 0x30B6}, {0x30B7, 0x30B7, 0x30B7}, {0x30B8, 0x30B8, 0x30B8}, {0x30B9, 0x30B9, 0x30B9}, {0x30BA, 0x30BA, 0x30BA}, {0x30BB, 0x30BB, 0x30BB}, {0x30BC, 0x30BC, 0x30BC}, {0x30BD, 0x30BD, 0x30BD}, {0x30BE, 0x30BE, 0x30BE}, {0x30BF, 0x30BF, 0x30BF}, {0x30C0, 0x30C0, 0x30C0}, {0x30C1, 0x30C1, 0x30C1}, {0x30C2, 0x30C2, 0x30C2}, {0x30C3, 0x30C3, 0x30C3}, {0x30C4, 0x30C4, 0x30C4}, {0x30C5, 0x30C5, 0x30C5}, {0x30C6, 0x30C6, 0x30C6}, {0x30C7, 0x30C7, 0x30C7}, {0x30C8, 0x30C8, 0x30C8}, {0x30C9, 0x30C9, 0x30C9}, {0x30CA, 0x30CA, 0x30CA}, {0x30CB, 0x30CB, 0x30CB}, {0x30CC, 0x30CC, 0x30CC}, {0x30CD, 0x30CD, 0x30CD}, {0x30CE, 0x30CE, 0x30CE}, {0x30CF, 0x30CF, 0x30CF}, {0x30D0, 0x30D0, 0x30D0}, {0x30D1, 0x30D1, 0x30D1}, {0x30D2, 0x30D2, 0x30D2}, {0x30D3, 0x30D3, 0x30D3}, {0x30D4, 0x30D4, 0x30D4}, {0x30D5, 0x30D5, 0x30D5}, {0x30D6, 0x30D6, 0x30D6}, {0x30D7, 0x30D7, 0x30D7}, {0x30D8, 0x30D8, 0x30D8}, {0x30D9, 0x30D9, 0x30D9}, {0x30DA, 0x30DA, 0x30DA}, {0x30DB, 0x30DB, 0x30DB}, {0x30DC, 0x30DC, 0x30DC}, {0x30DD, 0x30DD, 0x30DD}, {0x30DE, 0x30DE, 0x30DE}, {0x30DF, 0x30DF, 0x30DF}, {0x30E0, 0x30E0, 0x30E0}, {0x30E1, 0x30E1, 0x30E1}, {0x30E2, 0x30E2, 0x30E2}, {0x30E3, 0x30E3, 0x30E3}, {0x30E4, 0x30E4, 0x30E4}, {0x30E5, 0x30E5, 0x30E5}, {0x30E6, 0x30E6, 0x30E6}, {0x30E7, 0x30E7, 0x30E7}, {0x30E8, 0x30E8, 0x30E8}, {0x30E9, 0x30E9, 0x30E9}, {0x30EA, 0x30EA, 0x30EA}, {0x30EB, 0x30EB, 0x30EB}, {0x30EC, 0x30EC, 0x30EC}, {0x30ED, 0x30ED, 0x30ED}, {0x30EE, 0x30EE, 0x30EE}, {0x30EF, 0x30EF, 0x30EF}, {0x30F0, 0x30F0, 0x30F0}, {0x30F1, 0x30F1, 0x30F1}, {0x30F2, 0x30F2, 0x30F2}, {0x30F3, 0x30F3, 0x30F3}, {0x30F4, 0x30F4, 0x30F4}, {0x30F5, 0x30F5, 0x30F5}, {0x30F6, 0x30F6, 0x30F6}, {0x30F7, 0x30F7, 0x30F7}, {0x30F8, 0x30F8, 0x30F8}, {0x30F9, 0x30F9, 0x30F9}, {0x30FA, 0x30FA, 0x30FA}, {0x30FC, 0x30FC, 0x30FC}, {0x30FD, 0x30FD, 0x30FD}, {0x30FE, 0x30FE, 0x30FE}, {0x30FF, 0x30FF, 0x30FF}, {0x3105, 0x3105, 0x3105}, {0x3106, 0x3106, 0x3106}, {0x3107, 0x3107, 0x3107}, {0x3108, 0x3108, 0x3108}, {0x3109, 0x3109, 0x3109}, {0x310A, 0x310A, 0x310A}, {0x310B, 0x310B, 0x310B}, {0x310C, 0x310C, 0x310C}, {0x310D, 0x310D, 0x310D}, {0x310E, 0x310E, 0x310E}, {0x310F, 0x310F, 0x310F}, {0x3110, 0x3110, 0x3110}, {0x3111, 0x3111, 0x3111}, {0x3112, 0x3112, 0x3112}, {0x3113, 0x3113, 0x3113}, {0x3114, 0x3114, 0x3114}, {0x3115, 0x3115, 0x3115}, {0x3116, 0x3116, 0x3116}, {0x3117, 0x3117, 0x3117}, {0x3118, 0x3118, 0x3118}, {0x3119, 0x3119, 0x3119}, {0x311A, 0x311A, 0x311A}, {0x311B, 0x311B, 0x311B}, {0x311C, 0x311C, 0x311C}, {0x311D, 0x311D, 0x311D}, {0x311E, 0x311E, 0x311E}, {0x311F, 0x311F, 0x311F}, {0x3120, 0x3120, 0x3120}, {0x3121, 0x3121, 0x3121}, {0x3122, 0x3122, 0x3122}, {0x3123, 0x3123, 0x3123}, {0x3124, 0x3124, 0x3124}, {0x3125, 0x3125, 0x3125}, {0x3126, 0x3126, 0x3126}, {0x3127, 0x3127, 0x3127}, {0x3128, 0x3128, 0x3128}, {0x3129, 0x3129, 0x3129}, {0x312A, 0x312A, 0x312A}, {0x312B, 0x312B, 0x312B}, {0x312C, 0x312C, 0x312C}, {0x3131, 0x3131, 0x3131}, {0x3132, 0x3132, 0x3132}, {0x3133, 0x3133, 0x3133}, {0x3134, 0x3134, 0x3134}, {0x3135, 0x3135, 0x3135}, {0x3136, 0x3136, 0x3136}, {0x3137, 0x3137, 0x3137}, {0x3138, 0x3138, 0x3138}, {0x3139, 0x3139, 0x3139}, {0x313A, 0x313A, 0x313A}, {0x313B, 0x313B, 0x313B}, {0x313C, 0x313C, 0x313C}, {0x313D, 0x313D, 0x313D}, {0x313E, 0x313E, 0x313E}, {0x313F, 0x313F, 0x313F}, {0x3140, 0x3140, 0x3140}, {0x3141, 0x3141, 0x3141}, {0x3142, 0x3142, 0x3142}, {0x3143, 0x3143, 0x3143}, {0x3144, 0x3144, 0x3144}, {0x3145, 0x3145, 0x3145}, {0x3146, 0x3146, 0x3146}, {0x3147, 0x3147, 0x3147}, {0x3148, 0x3148, 0x3148}, {0x3149, 0x3149, 0x3149}, {0x314A, 0x314A, 0x314A}, {0x314B, 0x314B, 0x314B}, {0x314C, 0x314C, 0x314C}, {0x314D, 0x314D, 0x314D}, {0x314E, 0x314E, 0x314E}, {0x314F, 0x314F, 0x314F}, {0x3150, 0x3150, 0x3150}, {0x3151, 0x3151, 0x3151}, {0x3152, 0x3152, 0x3152}, {0x3153, 0x3153, 0x3153}, {0x3154, 0x3154, 0x3154}, {0x3155, 0x3155, 0x3155}, {0x3156, 0x3156, 0x3156}, {0x3157, 0x3157, 0x3157}, {0x3158, 0x3158, 0x3158}, {0x3159, 0x3159, 0x3159}, {0x315A, 0x315A, 0x315A}, {0x315B, 0x315B, 0x315B}, {0x315C, 0x315C, 0x315C}, {0x315D, 0x315D, 0x315D}, {0x315E, 0x315E, 0x315E}, {0x315F, 0x315F, 0x315F}, {0x3160, 0x3160, 0x3160}, {0x3161, 0x3161, 0x3161}, {0x3162, 0x3162, 0x3162}, {0x3163, 0x3163, 0x3163}, {0x3164, 0x3164, 0x3164}, {0x3165, 0x3165, 0x3165}, {0x3166, 0x3166, 0x3166}, {0x3167, 0x3167, 0x3167}, {0x3168, 0x3168, 0x3168}, {0x3169, 0x3169, 0x3169}, {0x316A, 0x316A, 0x316A}, {0x316B, 0x316B, 0x316B}, {0x316C, 0x316C, 0x316C}, {0x316D, 0x316D, 0x316D}, {0x316E, 0x316E, 0x316E}, {0x316F, 0x316F, 0x316F}, {0x3170, 0x3170, 0x3170}, {0x3171, 0x3171, 0x3171}, {0x3172, 0x3172, 0x3172}, {0x3173, 0x3173, 0x3173}, {0x3174, 0x3174, 0x3174}, {0x3175, 0x3175, 0x3175}, {0x3176, 0x3176, 0x3176}, {0x3177, 0x3177, 0x3177}, {0x3178, 0x3178, 0x3178}, {0x3179, 0x3179, 0x3179}, {0x317A, 0x317A, 0x317A}, {0x317B, 0x317B, 0x317B}, {0x317C, 0x317C, 0x317C}, {0x317D, 0x317D, 0x317D}, {0x317E, 0x317E, 0x317E}, {0x317F, 0x317F, 0x317F}, {0x3180, 0x3180, 0x3180}, {0x3181, 0x3181, 0x3181}, {0x3182, 0x3182, 0x3182}, {0x3183, 0x3183, 0x3183}, {0x3184, 0x3184, 0x3184}, {0x3185, 0x3185, 0x3185}, {0x3186, 0x3186, 0x3186}, {0x3187, 0x3187, 0x3187}, {0x3188, 0x3188, 0x3188}, {0x3189, 0x3189, 0x3189}, {0x318A, 0x318A, 0x318A}, {0x318B, 0x318B, 0x318B}, {0x318C, 0x318C, 0x318C}, {0x318D, 0x318D, 0x318D}, {0x318E, 0x318E, 0x318E}, {0x31A0, 0x31A0, 0x31A0}, {0x31A1, 0x31A1, 0x31A1}, {0x31A2, 0x31A2, 0x31A2}, {0x31A3, 0x31A3, 0x31A3}, {0x31A4, 0x31A4, 0x31A4}, {0x31A5, 0x31A5, 0x31A5}, {0x31A6, 0x31A6, 0x31A6}, {0x31A7, 0x31A7, 0x31A7}, {0x31A8, 0x31A8, 0x31A8}, {0x31A9, 0x31A9, 0x31A9}, {0x31AA, 0x31AA, 0x31AA}, {0x31AB, 0x31AB, 0x31AB}, {0x31AC, 0x31AC, 0x31AC}, {0x31AD, 0x31AD, 0x31AD}, {0x31AE, 0x31AE, 0x31AE}, {0x31AF, 0x31AF, 0x31AF}, {0x31B0, 0x31B0, 0x31B0}, {0x31B1, 0x31B1, 0x31B1}, {0x31B2, 0x31B2, 0x31B2}, {0x31B3, 0x31B3, 0x31B3}, {0x31B4, 0x31B4, 0x31B4}, {0x31B5, 0x31B5, 0x31B5}, {0x31B6, 0x31B6, 0x31B6}, {0x31B7, 0x31B7, 0x31B7}, {0x31F0, 0x31F0, 0x31F0}, {0x31F1, 0x31F1, 0x31F1}, {0x31F2, 0x31F2, 0x31F2}, {0x31F3, 0x31F3, 0x31F3}, {0x31F4, 0x31F4, 0x31F4}, {0x31F5, 0x31F5, 0x31F5}, {0x31F6, 0x31F6, 0x31F6}, {0x31F7, 0x31F7, 0x31F7}, {0x31F8, 0x31F8, 0x31F8}, {0x31F9, 0x31F9, 0x31F9}, {0x31FA, 0x31FA, 0x31FA}, {0x31FB, 0x31FB, 0x31FB}, {0x31FC, 0x31FC, 0x31FC}, {0x31FD, 0x31FD, 0x31FD}, {0x31FE, 0x31FE, 0x31FE}, {0x31FF, 0x31FF, 0x31FF}, {0x3400, 0x3400, 0x3400}, {0x4DB5, 0x4DB5, 0x4DB5}, {0x4E00, 0x4E00, 0x4E00}, {0x9FBB, 0x9FBB, 0x9FBB}, {0xA000, 0xA000, 0xA000}, {0xA001, 0xA001, 0xA001}, {0xA002, 0xA002, 0xA002}, {0xA003, 0xA003, 0xA003}, {0xA004, 0xA004, 0xA004}, {0xA005, 0xA005, 0xA005}, {0xA006, 0xA006, 0xA006}, {0xA007, 0xA007, 0xA007}, {0xA008, 0xA008, 0xA008}, {0xA009, 0xA009, 0xA009}, {0xA00A, 0xA00A, 0xA00A}, {0xA00B, 0xA00B, 0xA00B}, {0xA00C, 0xA00C, 0xA00C}, {0xA00D, 0xA00D, 0xA00D}, {0xA00E, 0xA00E, 0xA00E}, {0xA00F, 0xA00F, 0xA00F}, {0xA010, 0xA010, 0xA010}, {0xA011, 0xA011, 0xA011}, {0xA012, 0xA012, 0xA012}, {0xA013, 0xA013, 0xA013}, {0xA014, 0xA014, 0xA014}, {0xA015, 0xA015, 0xA015}, {0xA016, 0xA016, 0xA016}, {0xA017, 0xA017, 0xA017}, {0xA018, 0xA018, 0xA018}, {0xA019, 0xA019, 0xA019}, {0xA01A, 0xA01A, 0xA01A}, {0xA01B, 0xA01B, 0xA01B}, {0xA01C, 0xA01C, 0xA01C}, {0xA01D, 0xA01D, 0xA01D}, {0xA01E, 0xA01E, 0xA01E}, {0xA01F, 0xA01F, 0xA01F}, {0xA020, 0xA020, 0xA020}, {0xA021, 0xA021, 0xA021}, {0xA022, 0xA022, 0xA022}, {0xA023, 0xA023, 0xA023}, {0xA024, 0xA024, 0xA024}, {0xA025, 0xA025, 0xA025}, {0xA026, 0xA026, 0xA026}, {0xA027, 0xA027, 0xA027}, {0xA028, 0xA028, 0xA028}, {0xA029, 0xA029, 0xA029}, {0xA02A, 0xA02A, 0xA02A}, {0xA02B, 0xA02B, 0xA02B}, {0xA02C, 0xA02C, 0xA02C}, {0xA02D, 0xA02D, 0xA02D}, {0xA02E, 0xA02E, 0xA02E}, {0xA02F, 0xA02F, 0xA02F}, {0xA030, 0xA030, 0xA030}, {0xA031, 0xA031, 0xA031}, {0xA032, 0xA032, 0xA032}, {0xA033, 0xA033, 0xA033}, {0xA034, 0xA034, 0xA034}, {0xA035, 0xA035, 0xA035}, {0xA036, 0xA036, 0xA036}, {0xA037, 0xA037, 0xA037}, {0xA038, 0xA038, 0xA038}, {0xA039, 0xA039, 0xA039}, {0xA03A, 0xA03A, 0xA03A}, {0xA03B, 0xA03B, 0xA03B}, {0xA03C, 0xA03C, 0xA03C}, {0xA03D, 0xA03D, 0xA03D}, {0xA03E, 0xA03E, 0xA03E}, {0xA03F, 0xA03F, 0xA03F}, {0xA040, 0xA040, 0xA040}, {0xA041, 0xA041, 0xA041}, {0xA042, 0xA042, 0xA042}, {0xA043, 0xA043, 0xA043}, {0xA044, 0xA044, 0xA044}, {0xA045, 0xA045, 0xA045}, {0xA046, 0xA046, 0xA046}, {0xA047, 0xA047, 0xA047}, {0xA048, 0xA048, 0xA048}, {0xA049, 0xA049, 0xA049}, {0xA04A, 0xA04A, 0xA04A}, {0xA04B, 0xA04B, 0xA04B}, {0xA04C, 0xA04C, 0xA04C}, {0xA04D, 0xA04D, 0xA04D}, {0xA04E, 0xA04E, 0xA04E}, {0xA04F, 0xA04F, 0xA04F}, {0xA050, 0xA050, 0xA050}, {0xA051, 0xA051, 0xA051}, {0xA052, 0xA052, 0xA052}, {0xA053, 0xA053, 0xA053}, {0xA054, 0xA054, 0xA054}, {0xA055, 0xA055, 0xA055}, {0xA056, 0xA056, 0xA056}, {0xA057, 0xA057, 0xA057}, {0xA058, 0xA058, 0xA058}, {0xA059, 0xA059, 0xA059}, {0xA05A, 0xA05A, 0xA05A}, {0xA05B, 0xA05B, 0xA05B}, {0xA05C, 0xA05C, 0xA05C}, {0xA05D, 0xA05D, 0xA05D}, {0xA05E, 0xA05E, 0xA05E}, {0xA05F, 0xA05F, 0xA05F}, {0xA060, 0xA060, 0xA060}, {0xA061, 0xA061, 0xA061}, {0xA062, 0xA062, 0xA062}, {0xA063, 0xA063, 0xA063}, {0xA064, 0xA064, 0xA064}, {0xA065, 0xA065, 0xA065}, {0xA066, 0xA066, 0xA066}, {0xA067, 0xA067, 0xA067}, {0xA068, 0xA068, 0xA068}, {0xA069, 0xA069, 0xA069}, {0xA06A, 0xA06A, 0xA06A}, {0xA06B, 0xA06B, 0xA06B}, {0xA06C, 0xA06C, 0xA06C}, {0xA06D, 0xA06D, 0xA06D}, {0xA06E, 0xA06E, 0xA06E}, {0xA06F, 0xA06F, 0xA06F}, {0xA070, 0xA070, 0xA070}, {0xA071, 0xA071, 0xA071}, {0xA072, 0xA072, 0xA072}, {0xA073, 0xA073, 0xA073}, {0xA074, 0xA074, 0xA074}, {0xA075, 0xA075, 0xA075}, {0xA076, 0xA076, 0xA076}, {0xA077, 0xA077, 0xA077}, {0xA078, 0xA078, 0xA078}, {0xA079, 0xA079, 0xA079}, {0xA07A, 0xA07A, 0xA07A}, {0xA07B, 0xA07B, 0xA07B}, {0xA07C, 0xA07C, 0xA07C}, {0xA07D, 0xA07D, 0xA07D}, {0xA07E, 0xA07E, 0xA07E}, {0xA07F, 0xA07F, 0xA07F}, {0xA080, 0xA080, 0xA080}, {0xA081, 0xA081, 0xA081}, {0xA082, 0xA082, 0xA082}, {0xA083, 0xA083, 0xA083}, {0xA084, 0xA084, 0xA084}, {0xA085, 0xA085, 0xA085}, {0xA086, 0xA086, 0xA086}, {0xA087, 0xA087, 0xA087}, {0xA088, 0xA088, 0xA088}, {0xA089, 0xA089, 0xA089}, {0xA08A, 0xA08A, 0xA08A}, {0xA08B, 0xA08B, 0xA08B}, {0xA08C, 0xA08C, 0xA08C}, {0xA08D, 0xA08D, 0xA08D}, {0xA08E, 0xA08E, 0xA08E}, {0xA08F, 0xA08F, 0xA08F}, {0xA090, 0xA090, 0xA090}, {0xA091, 0xA091, 0xA091}, {0xA092, 0xA092, 0xA092}, {0xA093, 0xA093, 0xA093}, {0xA094, 0xA094, 0xA094}, {0xA095, 0xA095, 0xA095}, {0xA096, 0xA096, 0xA096}, {0xA097, 0xA097, 0xA097}, {0xA098, 0xA098, 0xA098}, {0xA099, 0xA099, 0xA099}, {0xA09A, 0xA09A, 0xA09A}, {0xA09B, 0xA09B, 0xA09B}, {0xA09C, 0xA09C, 0xA09C}, {0xA09D, 0xA09D, 0xA09D}, {0xA09E, 0xA09E, 0xA09E}, {0xA09F, 0xA09F, 0xA09F}, {0xA0A0, 0xA0A0, 0xA0A0}, {0xA0A1, 0xA0A1, 0xA0A1}, {0xA0A2, 0xA0A2, 0xA0A2}, {0xA0A3, 0xA0A3, 0xA0A3}, {0xA0A4, 0xA0A4, 0xA0A4}, {0xA0A5, 0xA0A5, 0xA0A5}, {0xA0A6, 0xA0A6, 0xA0A6}, {0xA0A7, 0xA0A7, 0xA0A7}, {0xA0A8, 0xA0A8, 0xA0A8}, {0xA0A9, 0xA0A9, 0xA0A9}, {0xA0AA, 0xA0AA, 0xA0AA}, {0xA0AB, 0xA0AB, 0xA0AB}, {0xA0AC, 0xA0AC, 0xA0AC}, {0xA0AD, 0xA0AD, 0xA0AD}, {0xA0AE, 0xA0AE, 0xA0AE}, {0xA0AF, 0xA0AF, 0xA0AF}, {0xA0B0, 0xA0B0, 0xA0B0}, {0xA0B1, 0xA0B1, 0xA0B1}, {0xA0B2, 0xA0B2, 0xA0B2}, {0xA0B3, 0xA0B3, 0xA0B3}, {0xA0B4, 0xA0B4, 0xA0B4}, {0xA0B5, 0xA0B5, 0xA0B5}, {0xA0B6, 0xA0B6, 0xA0B6}, {0xA0B7, 0xA0B7, 0xA0B7}, {0xA0B8, 0xA0B8, 0xA0B8}, {0xA0B9, 0xA0B9, 0xA0B9}, {0xA0BA, 0xA0BA, 0xA0BA}, {0xA0BB, 0xA0BB, 0xA0BB}, {0xA0BC, 0xA0BC, 0xA0BC}, {0xA0BD, 0xA0BD, 0xA0BD}, {0xA0BE, 0xA0BE, 0xA0BE}, {0xA0BF, 0xA0BF, 0xA0BF}, {0xA0C0, 0xA0C0, 0xA0C0}, {0xA0C1, 0xA0C1, 0xA0C1}, {0xA0C2, 0xA0C2, 0xA0C2}, {0xA0C3, 0xA0C3, 0xA0C3}, {0xA0C4, 0xA0C4, 0xA0C4}, {0xA0C5, 0xA0C5, 0xA0C5}, {0xA0C6, 0xA0C6, 0xA0C6}, {0xA0C7, 0xA0C7, 0xA0C7}, {0xA0C8, 0xA0C8, 0xA0C8}, {0xA0C9, 0xA0C9, 0xA0C9}, {0xA0CA, 0xA0CA, 0xA0CA}, {0xA0CB, 0xA0CB, 0xA0CB}, {0xA0CC, 0xA0CC, 0xA0CC}, {0xA0CD, 0xA0CD, 0xA0CD}, {0xA0CE, 0xA0CE, 0xA0CE}, {0xA0CF, 0xA0CF, 0xA0CF}, {0xA0D0, 0xA0D0, 0xA0D0}, {0xA0D1, 0xA0D1, 0xA0D1}, {0xA0D2, 0xA0D2, 0xA0D2}, {0xA0D3, 0xA0D3, 0xA0D3}, {0xA0D4, 0xA0D4, 0xA0D4}, {0xA0D5, 0xA0D5, 0xA0D5}, {0xA0D6, 0xA0D6, 0xA0D6}, {0xA0D7, 0xA0D7, 0xA0D7}, {0xA0D8, 0xA0D8, 0xA0D8}, {0xA0D9, 0xA0D9, 0xA0D9}, {0xA0DA, 0xA0DA, 0xA0DA}, {0xA0DB, 0xA0DB, 0xA0DB}, {0xA0DC, 0xA0DC, 0xA0DC}, {0xA0DD, 0xA0DD, 0xA0DD}, {0xA0DE, 0xA0DE, 0xA0DE}, {0xA0DF, 0xA0DF, 0xA0DF}, {0xA0E0, 0xA0E0, 0xA0E0}, {0xA0E1, 0xA0E1, 0xA0E1}, {0xA0E2, 0xA0E2, 0xA0E2}, {0xA0E3, 0xA0E3, 0xA0E3}, {0xA0E4, 0xA0E4, 0xA0E4}, {0xA0E5, 0xA0E5, 0xA0E5}, {0xA0E6, 0xA0E6, 0xA0E6}, {0xA0E7, 0xA0E7, 0xA0E7}, {0xA0E8, 0xA0E8, 0xA0E8}, {0xA0E9, 0xA0E9, 0xA0E9}, {0xA0EA, 0xA0EA, 0xA0EA}, {0xA0EB, 0xA0EB, 0xA0EB}, {0xA0EC, 0xA0EC, 0xA0EC}, {0xA0ED, 0xA0ED, 0xA0ED}, {0xA0EE, 0xA0EE, 0xA0EE}, {0xA0EF, 0xA0EF, 0xA0EF}, {0xA0F0, 0xA0F0, 0xA0F0}, {0xA0F1, 0xA0F1, 0xA0F1}, {0xA0F2, 0xA0F2, 0xA0F2}, {0xA0F3, 0xA0F3, 0xA0F3}, {0xA0F4, 0xA0F4, 0xA0F4}, {0xA0F5, 0xA0F5, 0xA0F5}, {0xA0F6, 0xA0F6, 0xA0F6}, {0xA0F7, 0xA0F7, 0xA0F7}, {0xA0F8, 0xA0F8, 0xA0F8}, {0xA0F9, 0xA0F9, 0xA0F9}, {0xA0FA, 0xA0FA, 0xA0FA}, {0xA0FB, 0xA0FB, 0xA0FB}, {0xA0FC, 0xA0FC, 0xA0FC}, {0xA0FD, 0xA0FD, 0xA0FD}, {0xA0FE, 0xA0FE, 0xA0FE}, {0xA0FF, 0xA0FF, 0xA0FF}, {0xA100, 0xA100, 0xA100}, {0xA101, 0xA101, 0xA101}, {0xA102, 0xA102, 0xA102}, {0xA103, 0xA103, 0xA103}, {0xA104, 0xA104, 0xA104}, {0xA105, 0xA105, 0xA105}, {0xA106, 0xA106, 0xA106}, {0xA107, 0xA107, 0xA107}, {0xA108, 0xA108, 0xA108}, {0xA109, 0xA109, 0xA109}, {0xA10A, 0xA10A, 0xA10A}, {0xA10B, 0xA10B, 0xA10B}, {0xA10C, 0xA10C, 0xA10C}, {0xA10D, 0xA10D, 0xA10D}, {0xA10E, 0xA10E, 0xA10E}, {0xA10F, 0xA10F, 0xA10F}, {0xA110, 0xA110, 0xA110}, {0xA111, 0xA111, 0xA111}, {0xA112, 0xA112, 0xA112}, {0xA113, 0xA113, 0xA113}, {0xA114, 0xA114, 0xA114}, {0xA115, 0xA115, 0xA115}, {0xA116, 0xA116, 0xA116}, {0xA117, 0xA117, 0xA117}, {0xA118, 0xA118, 0xA118}, {0xA119, 0xA119, 0xA119}, {0xA11A, 0xA11A, 0xA11A}, {0xA11B, 0xA11B, 0xA11B}, {0xA11C, 0xA11C, 0xA11C}, {0xA11D, 0xA11D, 0xA11D}, {0xA11E, 0xA11E, 0xA11E}, {0xA11F, 0xA11F, 0xA11F}, {0xA120, 0xA120, 0xA120}, {0xA121, 0xA121, 0xA121}, {0xA122, 0xA122, 0xA122}, {0xA123, 0xA123, 0xA123}, {0xA124, 0xA124, 0xA124}, {0xA125, 0xA125, 0xA125}, {0xA126, 0xA126, 0xA126}, {0xA127, 0xA127, 0xA127}, {0xA128, 0xA128, 0xA128}, {0xA129, 0xA129, 0xA129}, {0xA12A, 0xA12A, 0xA12A}, {0xA12B, 0xA12B, 0xA12B}, {0xA12C, 0xA12C, 0xA12C}, {0xA12D, 0xA12D, 0xA12D}, {0xA12E, 0xA12E, 0xA12E}, {0xA12F, 0xA12F, 0xA12F}, {0xA130, 0xA130, 0xA130}, {0xA131, 0xA131, 0xA131}, {0xA132, 0xA132, 0xA132}, {0xA133, 0xA133, 0xA133}, {0xA134, 0xA134, 0xA134}, {0xA135, 0xA135, 0xA135}, {0xA136, 0xA136, 0xA136}, {0xA137, 0xA137, 0xA137}, {0xA138, 0xA138, 0xA138}, {0xA139, 0xA139, 0xA139}, {0xA13A, 0xA13A, 0xA13A}, {0xA13B, 0xA13B, 0xA13B}, {0xA13C, 0xA13C, 0xA13C}, {0xA13D, 0xA13D, 0xA13D}, {0xA13E, 0xA13E, 0xA13E}, {0xA13F, 0xA13F, 0xA13F}, {0xA140, 0xA140, 0xA140}, {0xA141, 0xA141, 0xA141}, {0xA142, 0xA142, 0xA142}, {0xA143, 0xA143, 0xA143}, {0xA144, 0xA144, 0xA144}, {0xA145, 0xA145, 0xA145}, {0xA146, 0xA146, 0xA146}, {0xA147, 0xA147, 0xA147}, {0xA148, 0xA148, 0xA148}, {0xA149, 0xA149, 0xA149}, {0xA14A, 0xA14A, 0xA14A}, {0xA14B, 0xA14B, 0xA14B}, {0xA14C, 0xA14C, 0xA14C}, {0xA14D, 0xA14D, 0xA14D}, {0xA14E, 0xA14E, 0xA14E}, {0xA14F, 0xA14F, 0xA14F}, {0xA150, 0xA150, 0xA150}, {0xA151, 0xA151, 0xA151}, {0xA152, 0xA152, 0xA152}, {0xA153, 0xA153, 0xA153}, {0xA154, 0xA154, 0xA154}, {0xA155, 0xA155, 0xA155}, {0xA156, 0xA156, 0xA156}, {0xA157, 0xA157, 0xA157}, {0xA158, 0xA158, 0xA158}, {0xA159, 0xA159, 0xA159}, {0xA15A, 0xA15A, 0xA15A}, {0xA15B, 0xA15B, 0xA15B}, {0xA15C, 0xA15C, 0xA15C}, {0xA15D, 0xA15D, 0xA15D}, {0xA15E, 0xA15E, 0xA15E}, {0xA15F, 0xA15F, 0xA15F}, {0xA160, 0xA160, 0xA160}, {0xA161, 0xA161, 0xA161}, {0xA162, 0xA162, 0xA162}, {0xA163, 0xA163, 0xA163}, {0xA164, 0xA164, 0xA164}, {0xA165, 0xA165, 0xA165}, {0xA166, 0xA166, 0xA166}, {0xA167, 0xA167, 0xA167}, {0xA168, 0xA168, 0xA168}, {0xA169, 0xA169, 0xA169}, {0xA16A, 0xA16A, 0xA16A}, {0xA16B, 0xA16B, 0xA16B}, {0xA16C, 0xA16C, 0xA16C}, {0xA16D, 0xA16D, 0xA16D}, {0xA16E, 0xA16E, 0xA16E}, {0xA16F, 0xA16F, 0xA16F}, {0xA170, 0xA170, 0xA170}, {0xA171, 0xA171, 0xA171}, {0xA172, 0xA172, 0xA172}, {0xA173, 0xA173, 0xA173}, {0xA174, 0xA174, 0xA174}, {0xA175, 0xA175, 0xA175}, {0xA176, 0xA176, 0xA176}, {0xA177, 0xA177, 0xA177}, {0xA178, 0xA178, 0xA178}, {0xA179, 0xA179, 0xA179}, {0xA17A, 0xA17A, 0xA17A}, {0xA17B, 0xA17B, 0xA17B}, {0xA17C, 0xA17C, 0xA17C}, {0xA17D, 0xA17D, 0xA17D}, {0xA17E, 0xA17E, 0xA17E}, {0xA17F, 0xA17F, 0xA17F}, {0xA180, 0xA180, 0xA180}, {0xA181, 0xA181, 0xA181}, {0xA182, 0xA182, 0xA182}, {0xA183, 0xA183, 0xA183}, {0xA184, 0xA184, 0xA184}, {0xA185, 0xA185, 0xA185}, {0xA186, 0xA186, 0xA186}, {0xA187, 0xA187, 0xA187}, {0xA188, 0xA188, 0xA188}, {0xA189, 0xA189, 0xA189}, {0xA18A, 0xA18A, 0xA18A}, {0xA18B, 0xA18B, 0xA18B}, {0xA18C, 0xA18C, 0xA18C}, {0xA18D, 0xA18D, 0xA18D}, {0xA18E, 0xA18E, 0xA18E}, {0xA18F, 0xA18F, 0xA18F}, {0xA190, 0xA190, 0xA190}, {0xA191, 0xA191, 0xA191}, {0xA192, 0xA192, 0xA192}, {0xA193, 0xA193, 0xA193}, {0xA194, 0xA194, 0xA194}, {0xA195, 0xA195, 0xA195}, {0xA196, 0xA196, 0xA196}, {0xA197, 0xA197, 0xA197}, {0xA198, 0xA198, 0xA198}, {0xA199, 0xA199, 0xA199}, {0xA19A, 0xA19A, 0xA19A}, {0xA19B, 0xA19B, 0xA19B}, {0xA19C, 0xA19C, 0xA19C}, {0xA19D, 0xA19D, 0xA19D}, {0xA19E, 0xA19E, 0xA19E}, {0xA19F, 0xA19F, 0xA19F}, {0xA1A0, 0xA1A0, 0xA1A0}, {0xA1A1, 0xA1A1, 0xA1A1}, {0xA1A2, 0xA1A2, 0xA1A2}, {0xA1A3, 0xA1A3, 0xA1A3}, {0xA1A4, 0xA1A4, 0xA1A4}, {0xA1A5, 0xA1A5, 0xA1A5}, {0xA1A6, 0xA1A6, 0xA1A6}, {0xA1A7, 0xA1A7, 0xA1A7}, {0xA1A8, 0xA1A8, 0xA1A8}, {0xA1A9, 0xA1A9, 0xA1A9}, {0xA1AA, 0xA1AA, 0xA1AA}, {0xA1AB, 0xA1AB, 0xA1AB}, {0xA1AC, 0xA1AC, 0xA1AC}, {0xA1AD, 0xA1AD, 0xA1AD}, {0xA1AE, 0xA1AE, 0xA1AE}, {0xA1AF, 0xA1AF, 0xA1AF}, {0xA1B0, 0xA1B0, 0xA1B0}, {0xA1B1, 0xA1B1, 0xA1B1}, {0xA1B2, 0xA1B2, 0xA1B2}, {0xA1B3, 0xA1B3, 0xA1B3}, {0xA1B4, 0xA1B4, 0xA1B4}, {0xA1B5, 0xA1B5, 0xA1B5}, {0xA1B6, 0xA1B6, 0xA1B6}, {0xA1B7, 0xA1B7, 0xA1B7}, {0xA1B8, 0xA1B8, 0xA1B8}, {0xA1B9, 0xA1B9, 0xA1B9}, {0xA1BA, 0xA1BA, 0xA1BA}, {0xA1BB, 0xA1BB, 0xA1BB}, {0xA1BC, 0xA1BC, 0xA1BC}, {0xA1BD, 0xA1BD, 0xA1BD}, {0xA1BE, 0xA1BE, 0xA1BE}, {0xA1BF, 0xA1BF, 0xA1BF}, {0xA1C0, 0xA1C0, 0xA1C0}, {0xA1C1, 0xA1C1, 0xA1C1}, {0xA1C2, 0xA1C2, 0xA1C2}, {0xA1C3, 0xA1C3, 0xA1C3}, {0xA1C4, 0xA1C4, 0xA1C4}, {0xA1C5, 0xA1C5, 0xA1C5}, {0xA1C6, 0xA1C6, 0xA1C6}, {0xA1C7, 0xA1C7, 0xA1C7}, {0xA1C8, 0xA1C8, 0xA1C8}, {0xA1C9, 0xA1C9, 0xA1C9}, {0xA1CA, 0xA1CA, 0xA1CA}, {0xA1CB, 0xA1CB, 0xA1CB}, {0xA1CC, 0xA1CC, 0xA1CC}, {0xA1CD, 0xA1CD, 0xA1CD}, {0xA1CE, 0xA1CE, 0xA1CE}, {0xA1CF, 0xA1CF, 0xA1CF}, {0xA1D0, 0xA1D0, 0xA1D0}, {0xA1D1, 0xA1D1, 0xA1D1}, {0xA1D2, 0xA1D2, 0xA1D2}, {0xA1D3, 0xA1D3, 0xA1D3}, {0xA1D4, 0xA1D4, 0xA1D4}, {0xA1D5, 0xA1D5, 0xA1D5}, {0xA1D6, 0xA1D6, 0xA1D6}, {0xA1D7, 0xA1D7, 0xA1D7}, {0xA1D8, 0xA1D8, 0xA1D8}, {0xA1D9, 0xA1D9, 0xA1D9}, {0xA1DA, 0xA1DA, 0xA1DA}, {0xA1DB, 0xA1DB, 0xA1DB}, {0xA1DC, 0xA1DC, 0xA1DC}, {0xA1DD, 0xA1DD, 0xA1DD}, {0xA1DE, 0xA1DE, 0xA1DE}, {0xA1DF, 0xA1DF, 0xA1DF}, {0xA1E0, 0xA1E0, 0xA1E0}, {0xA1E1, 0xA1E1, 0xA1E1}, {0xA1E2, 0xA1E2, 0xA1E2}, {0xA1E3, 0xA1E3, 0xA1E3}, {0xA1E4, 0xA1E4, 0xA1E4}, {0xA1E5, 0xA1E5, 0xA1E5}, {0xA1E6, 0xA1E6, 0xA1E6}, {0xA1E7, 0xA1E7, 0xA1E7}, {0xA1E8, 0xA1E8, 0xA1E8}, {0xA1E9, 0xA1E9, 0xA1E9}, {0xA1EA, 0xA1EA, 0xA1EA}, {0xA1EB, 0xA1EB, 0xA1EB}, {0xA1EC, 0xA1EC, 0xA1EC}, {0xA1ED, 0xA1ED, 0xA1ED}, {0xA1EE, 0xA1EE, 0xA1EE}, {0xA1EF, 0xA1EF, 0xA1EF}, {0xA1F0, 0xA1F0, 0xA1F0}, {0xA1F1, 0xA1F1, 0xA1F1}, {0xA1F2, 0xA1F2, 0xA1F2}, {0xA1F3, 0xA1F3, 0xA1F3}, {0xA1F4, 0xA1F4, 0xA1F4}, {0xA1F5, 0xA1F5, 0xA1F5}, {0xA1F6, 0xA1F6, 0xA1F6}, {0xA1F7, 0xA1F7, 0xA1F7}, {0xA1F8, 0xA1F8, 0xA1F8}, {0xA1F9, 0xA1F9, 0xA1F9}, {0xA1FA, 0xA1FA, 0xA1FA}, {0xA1FB, 0xA1FB, 0xA1FB}, {0xA1FC, 0xA1FC, 0xA1FC}, {0xA1FD, 0xA1FD, 0xA1FD}, {0xA1FE, 0xA1FE, 0xA1FE}, {0xA1FF, 0xA1FF, 0xA1FF}, {0xA200, 0xA200, 0xA200}, {0xA201, 0xA201, 0xA201}, {0xA202, 0xA202, 0xA202}, {0xA203, 0xA203, 0xA203}, {0xA204, 0xA204, 0xA204}, {0xA205, 0xA205, 0xA205}, {0xA206, 0xA206, 0xA206}, {0xA207, 0xA207, 0xA207}, {0xA208, 0xA208, 0xA208}, {0xA209, 0xA209, 0xA209}, {0xA20A, 0xA20A, 0xA20A}, {0xA20B, 0xA20B, 0xA20B}, {0xA20C, 0xA20C, 0xA20C}, {0xA20D, 0xA20D, 0xA20D}, {0xA20E, 0xA20E, 0xA20E}, {0xA20F, 0xA20F, 0xA20F}, {0xA210, 0xA210, 0xA210}, {0xA211, 0xA211, 0xA211}, {0xA212, 0xA212, 0xA212}, {0xA213, 0xA213, 0xA213}, {0xA214, 0xA214, 0xA214}, {0xA215, 0xA215, 0xA215}, {0xA216, 0xA216, 0xA216}, {0xA217, 0xA217, 0xA217}, {0xA218, 0xA218, 0xA218}, {0xA219, 0xA219, 0xA219}, {0xA21A, 0xA21A, 0xA21A}, {0xA21B, 0xA21B, 0xA21B}, {0xA21C, 0xA21C, 0xA21C}, {0xA21D, 0xA21D, 0xA21D}, {0xA21E, 0xA21E, 0xA21E}, {0xA21F, 0xA21F, 0xA21F}, {0xA220, 0xA220, 0xA220}, {0xA221, 0xA221, 0xA221}, {0xA222, 0xA222, 0xA222}, {0xA223, 0xA223, 0xA223}, {0xA224, 0xA224, 0xA224}, {0xA225, 0xA225, 0xA225}, {0xA226, 0xA226, 0xA226}, {0xA227, 0xA227, 0xA227}, {0xA228, 0xA228, 0xA228}, {0xA229, 0xA229, 0xA229}, {0xA22A, 0xA22A, 0xA22A}, {0xA22B, 0xA22B, 0xA22B}, {0xA22C, 0xA22C, 0xA22C}, {0xA22D, 0xA22D, 0xA22D}, {0xA22E, 0xA22E, 0xA22E}, {0xA22F, 0xA22F, 0xA22F}, {0xA230, 0xA230, 0xA230}, {0xA231, 0xA231, 0xA231}, {0xA232, 0xA232, 0xA232}, {0xA233, 0xA233, 0xA233}, {0xA234, 0xA234, 0xA234}, {0xA235, 0xA235, 0xA235}, {0xA236, 0xA236, 0xA236}, {0xA237, 0xA237, 0xA237}, {0xA238, 0xA238, 0xA238}, {0xA239, 0xA239, 0xA239}, {0xA23A, 0xA23A, 0xA23A}, {0xA23B, 0xA23B, 0xA23B}, {0xA23C, 0xA23C, 0xA23C}, {0xA23D, 0xA23D, 0xA23D}, {0xA23E, 0xA23E, 0xA23E}, {0xA23F, 0xA23F, 0xA23F}, {0xA240, 0xA240, 0xA240}, {0xA241, 0xA241, 0xA241}, {0xA242, 0xA242, 0xA242}, {0xA243, 0xA243, 0xA243}, {0xA244, 0xA244, 0xA244}, {0xA245, 0xA245, 0xA245}, {0xA246, 0xA246, 0xA246}, {0xA247, 0xA247, 0xA247}, {0xA248, 0xA248, 0xA248}, {0xA249, 0xA249, 0xA249}, {0xA24A, 0xA24A, 0xA24A}, {0xA24B, 0xA24B, 0xA24B}, {0xA24C, 0xA24C, 0xA24C}, {0xA24D, 0xA24D, 0xA24D}, {0xA24E, 0xA24E, 0xA24E}, {0xA24F, 0xA24F, 0xA24F}, {0xA250, 0xA250, 0xA250}, {0xA251, 0xA251, 0xA251}, {0xA252, 0xA252, 0xA252}, {0xA253, 0xA253, 0xA253}, {0xA254, 0xA254, 0xA254}, {0xA255, 0xA255, 0xA255}, {0xA256, 0xA256, 0xA256}, {0xA257, 0xA257, 0xA257}, {0xA258, 0xA258, 0xA258}, {0xA259, 0xA259, 0xA259}, {0xA25A, 0xA25A, 0xA25A}, {0xA25B, 0xA25B, 0xA25B}, {0xA25C, 0xA25C, 0xA25C}, {0xA25D, 0xA25D, 0xA25D}, {0xA25E, 0xA25E, 0xA25E}, {0xA25F, 0xA25F, 0xA25F}, {0xA260, 0xA260, 0xA260}, {0xA261, 0xA261, 0xA261}, {0xA262, 0xA262, 0xA262}, {0xA263, 0xA263, 0xA263}, {0xA264, 0xA264, 0xA264}, {0xA265, 0xA265, 0xA265}, {0xA266, 0xA266, 0xA266}, {0xA267, 0xA267, 0xA267}, {0xA268, 0xA268, 0xA268}, {0xA269, 0xA269, 0xA269}, {0xA26A, 0xA26A, 0xA26A}, {0xA26B, 0xA26B, 0xA26B}, {0xA26C, 0xA26C, 0xA26C}, {0xA26D, 0xA26D, 0xA26D}, {0xA26E, 0xA26E, 0xA26E}, {0xA26F, 0xA26F, 0xA26F}, {0xA270, 0xA270, 0xA270}, {0xA271, 0xA271, 0xA271}, {0xA272, 0xA272, 0xA272}, {0xA273, 0xA273, 0xA273}, {0xA274, 0xA274, 0xA274}, {0xA275, 0xA275, 0xA275}, {0xA276, 0xA276, 0xA276}, {0xA277, 0xA277, 0xA277}, {0xA278, 0xA278, 0xA278}, {0xA279, 0xA279, 0xA279}, {0xA27A, 0xA27A, 0xA27A}, {0xA27B, 0xA27B, 0xA27B}, {0xA27C, 0xA27C, 0xA27C}, {0xA27D, 0xA27D, 0xA27D}, {0xA27E, 0xA27E, 0xA27E}, {0xA27F, 0xA27F, 0xA27F}, {0xA280, 0xA280, 0xA280}, {0xA281, 0xA281, 0xA281}, {0xA282, 0xA282, 0xA282}, {0xA283, 0xA283, 0xA283}, {0xA284, 0xA284, 0xA284}, {0xA285, 0xA285, 0xA285}, {0xA286, 0xA286, 0xA286}, {0xA287, 0xA287, 0xA287}, {0xA288, 0xA288, 0xA288}, {0xA289, 0xA289, 0xA289}, {0xA28A, 0xA28A, 0xA28A}, {0xA28B, 0xA28B, 0xA28B}, {0xA28C, 0xA28C, 0xA28C}, {0xA28D, 0xA28D, 0xA28D}, {0xA28E, 0xA28E, 0xA28E}, {0xA28F, 0xA28F, 0xA28F}, {0xA290, 0xA290, 0xA290}, {0xA291, 0xA291, 0xA291}, {0xA292, 0xA292, 0xA292}, {0xA293, 0xA293, 0xA293}, {0xA294, 0xA294, 0xA294}, {0xA295, 0xA295, 0xA295}, {0xA296, 0xA296, 0xA296}, {0xA297, 0xA297, 0xA297}, {0xA298, 0xA298, 0xA298}, {0xA299, 0xA299, 0xA299}, {0xA29A, 0xA29A, 0xA29A}, {0xA29B, 0xA29B, 0xA29B}, {0xA29C, 0xA29C, 0xA29C}, {0xA29D, 0xA29D, 0xA29D}, {0xA29E, 0xA29E, 0xA29E}, {0xA29F, 0xA29F, 0xA29F}, {0xA2A0, 0xA2A0, 0xA2A0}, {0xA2A1, 0xA2A1, 0xA2A1}, {0xA2A2, 0xA2A2, 0xA2A2}, {0xA2A3, 0xA2A3, 0xA2A3}, {0xA2A4, 0xA2A4, 0xA2A4}, {0xA2A5, 0xA2A5, 0xA2A5}, {0xA2A6, 0xA2A6, 0xA2A6}, {0xA2A7, 0xA2A7, 0xA2A7}, {0xA2A8, 0xA2A8, 0xA2A8}, {0xA2A9, 0xA2A9, 0xA2A9}, {0xA2AA, 0xA2AA, 0xA2AA}, {0xA2AB, 0xA2AB, 0xA2AB}, {0xA2AC, 0xA2AC, 0xA2AC}, {0xA2AD, 0xA2AD, 0xA2AD}, {0xA2AE, 0xA2AE, 0xA2AE}, {0xA2AF, 0xA2AF, 0xA2AF}, {0xA2B0, 0xA2B0, 0xA2B0}, {0xA2B1, 0xA2B1, 0xA2B1}, {0xA2B2, 0xA2B2, 0xA2B2}, {0xA2B3, 0xA2B3, 0xA2B3}, {0xA2B4, 0xA2B4, 0xA2B4}, {0xA2B5, 0xA2B5, 0xA2B5}, {0xA2B6, 0xA2B6, 0xA2B6}, {0xA2B7, 0xA2B7, 0xA2B7}, {0xA2B8, 0xA2B8, 0xA2B8}, {0xA2B9, 0xA2B9, 0xA2B9}, {0xA2BA, 0xA2BA, 0xA2BA}, {0xA2BB, 0xA2BB, 0xA2BB}, {0xA2BC, 0xA2BC, 0xA2BC}, {0xA2BD, 0xA2BD, 0xA2BD}, {0xA2BE, 0xA2BE, 0xA2BE}, {0xA2BF, 0xA2BF, 0xA2BF}, {0xA2C0, 0xA2C0, 0xA2C0}, {0xA2C1, 0xA2C1, 0xA2C1}, {0xA2C2, 0xA2C2, 0xA2C2}, {0xA2C3, 0xA2C3, 0xA2C3}, {0xA2C4, 0xA2C4, 0xA2C4}, {0xA2C5, 0xA2C5, 0xA2C5}, {0xA2C6, 0xA2C6, 0xA2C6}, {0xA2C7, 0xA2C7, 0xA2C7}, {0xA2C8, 0xA2C8, 0xA2C8}, {0xA2C9, 0xA2C9, 0xA2C9}, {0xA2CA, 0xA2CA, 0xA2CA}, {0xA2CB, 0xA2CB, 0xA2CB}, {0xA2CC, 0xA2CC, 0xA2CC}, {0xA2CD, 0xA2CD, 0xA2CD}, {0xA2CE, 0xA2CE, 0xA2CE}, {0xA2CF, 0xA2CF, 0xA2CF}, {0xA2D0, 0xA2D0, 0xA2D0}, {0xA2D1, 0xA2D1, 0xA2D1}, {0xA2D2, 0xA2D2, 0xA2D2}, {0xA2D3, 0xA2D3, 0xA2D3}, {0xA2D4, 0xA2D4, 0xA2D4}, {0xA2D5, 0xA2D5, 0xA2D5}, {0xA2D6, 0xA2D6, 0xA2D6}, {0xA2D7, 0xA2D7, 0xA2D7}, {0xA2D8, 0xA2D8, 0xA2D8}, {0xA2D9, 0xA2D9, 0xA2D9}, {0xA2DA, 0xA2DA, 0xA2DA}, {0xA2DB, 0xA2DB, 0xA2DB}, {0xA2DC, 0xA2DC, 0xA2DC}, {0xA2DD, 0xA2DD, 0xA2DD}, {0xA2DE, 0xA2DE, 0xA2DE}, {0xA2DF, 0xA2DF, 0xA2DF}, {0xA2E0, 0xA2E0, 0xA2E0}, {0xA2E1, 0xA2E1, 0xA2E1}, {0xA2E2, 0xA2E2, 0xA2E2}, {0xA2E3, 0xA2E3, 0xA2E3}, {0xA2E4, 0xA2E4, 0xA2E4}, {0xA2E5, 0xA2E5, 0xA2E5}, {0xA2E6, 0xA2E6, 0xA2E6}, {0xA2E7, 0xA2E7, 0xA2E7}, {0xA2E8, 0xA2E8, 0xA2E8}, {0xA2E9, 0xA2E9, 0xA2E9}, {0xA2EA, 0xA2EA, 0xA2EA}, {0xA2EB, 0xA2EB, 0xA2EB}, {0xA2EC, 0xA2EC, 0xA2EC}, {0xA2ED, 0xA2ED, 0xA2ED}, {0xA2EE, 0xA2EE, 0xA2EE}, {0xA2EF, 0xA2EF, 0xA2EF}, {0xA2F0, 0xA2F0, 0xA2F0}, {0xA2F1, 0xA2F1, 0xA2F1}, {0xA2F2, 0xA2F2, 0xA2F2}, {0xA2F3, 0xA2F3, 0xA2F3}, {0xA2F4, 0xA2F4, 0xA2F4}, {0xA2F5, 0xA2F5, 0xA2F5}, {0xA2F6, 0xA2F6, 0xA2F6}, {0xA2F7, 0xA2F7, 0xA2F7}, {0xA2F8, 0xA2F8, 0xA2F8}, {0xA2F9, 0xA2F9, 0xA2F9}, {0xA2FA, 0xA2FA, 0xA2FA}, {0xA2FB, 0xA2FB, 0xA2FB}, {0xA2FC, 0xA2FC, 0xA2FC}, {0xA2FD, 0xA2FD, 0xA2FD}, {0xA2FE, 0xA2FE, 0xA2FE}, {0xA2FF, 0xA2FF, 0xA2FF}, {0xA300, 0xA300, 0xA300}, {0xA301, 0xA301, 0xA301}, {0xA302, 0xA302, 0xA302}, {0xA303, 0xA303, 0xA303}, {0xA304, 0xA304, 0xA304}, {0xA305, 0xA305, 0xA305}, {0xA306, 0xA306, 0xA306}, {0xA307, 0xA307, 0xA307}, {0xA308, 0xA308, 0xA308}, {0xA309, 0xA309, 0xA309}, {0xA30A, 0xA30A, 0xA30A}, {0xA30B, 0xA30B, 0xA30B}, {0xA30C, 0xA30C, 0xA30C}, {0xA30D, 0xA30D, 0xA30D}, {0xA30E, 0xA30E, 0xA30E}, {0xA30F, 0xA30F, 0xA30F}, {0xA310, 0xA310, 0xA310}, {0xA311, 0xA311, 0xA311}, {0xA312, 0xA312, 0xA312}, {0xA313, 0xA313, 0xA313}, {0xA314, 0xA314, 0xA314}, {0xA315, 0xA315, 0xA315}, {0xA316, 0xA316, 0xA316}, {0xA317, 0xA317, 0xA317}, {0xA318, 0xA318, 0xA318}, {0xA319, 0xA319, 0xA319}, {0xA31A, 0xA31A, 0xA31A}, {0xA31B, 0xA31B, 0xA31B}, {0xA31C, 0xA31C, 0xA31C}, {0xA31D, 0xA31D, 0xA31D}, {0xA31E, 0xA31E, 0xA31E}, {0xA31F, 0xA31F, 0xA31F}, {0xA320, 0xA320, 0xA320}, {0xA321, 0xA321, 0xA321}, {0xA322, 0xA322, 0xA322}, {0xA323, 0xA323, 0xA323}, {0xA324, 0xA324, 0xA324}, {0xA325, 0xA325, 0xA325}, {0xA326, 0xA326, 0xA326}, {0xA327, 0xA327, 0xA327}, {0xA328, 0xA328, 0xA328}, {0xA329, 0xA329, 0xA329}, {0xA32A, 0xA32A, 0xA32A}, {0xA32B, 0xA32B, 0xA32B}, {0xA32C, 0xA32C, 0xA32C}, {0xA32D, 0xA32D, 0xA32D}, {0xA32E, 0xA32E, 0xA32E}, {0xA32F, 0xA32F, 0xA32F}, {0xA330, 0xA330, 0xA330}, {0xA331, 0xA331, 0xA331}, {0xA332, 0xA332, 0xA332}, {0xA333, 0xA333, 0xA333}, {0xA334, 0xA334, 0xA334}, {0xA335, 0xA335, 0xA335}, {0xA336, 0xA336, 0xA336}, {0xA337, 0xA337, 0xA337}, {0xA338, 0xA338, 0xA338}, {0xA339, 0xA339, 0xA339}, {0xA33A, 0xA33A, 0xA33A}, {0xA33B, 0xA33B, 0xA33B}, {0xA33C, 0xA33C, 0xA33C}, {0xA33D, 0xA33D, 0xA33D}, {0xA33E, 0xA33E, 0xA33E}, {0xA33F, 0xA33F, 0xA33F}, {0xA340, 0xA340, 0xA340}, {0xA341, 0xA341, 0xA341}, {0xA342, 0xA342, 0xA342}, {0xA343, 0xA343, 0xA343}, {0xA344, 0xA344, 0xA344}, {0xA345, 0xA345, 0xA345}, {0xA346, 0xA346, 0xA346}, {0xA347, 0xA347, 0xA347}, {0xA348, 0xA348, 0xA348}, {0xA349, 0xA349, 0xA349}, {0xA34A, 0xA34A, 0xA34A}, {0xA34B, 0xA34B, 0xA34B}, {0xA34C, 0xA34C, 0xA34C}, {0xA34D, 0xA34D, 0xA34D}, {0xA34E, 0xA34E, 0xA34E}, {0xA34F, 0xA34F, 0xA34F}, {0xA350, 0xA350, 0xA350}, {0xA351, 0xA351, 0xA351}, {0xA352, 0xA352, 0xA352}, {0xA353, 0xA353, 0xA353}, {0xA354, 0xA354, 0xA354}, {0xA355, 0xA355, 0xA355}, {0xA356, 0xA356, 0xA356}, {0xA357, 0xA357, 0xA357}, {0xA358, 0xA358, 0xA358}, {0xA359, 0xA359, 0xA359}, {0xA35A, 0xA35A, 0xA35A}, {0xA35B, 0xA35B, 0xA35B}, {0xA35C, 0xA35C, 0xA35C}, {0xA35D, 0xA35D, 0xA35D}, {0xA35E, 0xA35E, 0xA35E}, {0xA35F, 0xA35F, 0xA35F}, {0xA360, 0xA360, 0xA360}, {0xA361, 0xA361, 0xA361}, {0xA362, 0xA362, 0xA362}, {0xA363, 0xA363, 0xA363}, {0xA364, 0xA364, 0xA364}, {0xA365, 0xA365, 0xA365}, {0xA366, 0xA366, 0xA366}, {0xA367, 0xA367, 0xA367}, {0xA368, 0xA368, 0xA368}, {0xA369, 0xA369, 0xA369}, {0xA36A, 0xA36A, 0xA36A}, {0xA36B, 0xA36B, 0xA36B}, {0xA36C, 0xA36C, 0xA36C}, {0xA36D, 0xA36D, 0xA36D}, {0xA36E, 0xA36E, 0xA36E}, {0xA36F, 0xA36F, 0xA36F}, {0xA370, 0xA370, 0xA370}, {0xA371, 0xA371, 0xA371}, {0xA372, 0xA372, 0xA372}, {0xA373, 0xA373, 0xA373}, {0xA374, 0xA374, 0xA374}, {0xA375, 0xA375, 0xA375}, {0xA376, 0xA376, 0xA376}, {0xA377, 0xA377, 0xA377}, {0xA378, 0xA378, 0xA378}, {0xA379, 0xA379, 0xA379}, {0xA37A, 0xA37A, 0xA37A}, {0xA37B, 0xA37B, 0xA37B}, {0xA37C, 0xA37C, 0xA37C}, {0xA37D, 0xA37D, 0xA37D}, {0xA37E, 0xA37E, 0xA37E}, {0xA37F, 0xA37F, 0xA37F}, {0xA380, 0xA380, 0xA380}, {0xA381, 0xA381, 0xA381}, {0xA382, 0xA382, 0xA382}, {0xA383, 0xA383, 0xA383}, {0xA384, 0xA384, 0xA384}, {0xA385, 0xA385, 0xA385}, {0xA386, 0xA386, 0xA386}, {0xA387, 0xA387, 0xA387}, {0xA388, 0xA388, 0xA388}, {0xA389, 0xA389, 0xA389}, {0xA38A, 0xA38A, 0xA38A}, {0xA38B, 0xA38B, 0xA38B}, {0xA38C, 0xA38C, 0xA38C}, {0xA38D, 0xA38D, 0xA38D}, {0xA38E, 0xA38E, 0xA38E}, {0xA38F, 0xA38F, 0xA38F}, {0xA390, 0xA390, 0xA390}, {0xA391, 0xA391, 0xA391}, {0xA392, 0xA392, 0xA392}, {0xA393, 0xA393, 0xA393}, {0xA394, 0xA394, 0xA394}, {0xA395, 0xA395, 0xA395}, {0xA396, 0xA396, 0xA396}, {0xA397, 0xA397, 0xA397}, {0xA398, 0xA398, 0xA398}, {0xA399, 0xA399, 0xA399}, {0xA39A, 0xA39A, 0xA39A}, {0xA39B, 0xA39B, 0xA39B}, {0xA39C, 0xA39C, 0xA39C}, {0xA39D, 0xA39D, 0xA39D}, {0xA39E, 0xA39E, 0xA39E}, {0xA39F, 0xA39F, 0xA39F}, {0xA3A0, 0xA3A0, 0xA3A0}, {0xA3A1, 0xA3A1, 0xA3A1}, {0xA3A2, 0xA3A2, 0xA3A2}, {0xA3A3, 0xA3A3, 0xA3A3}, {0xA3A4, 0xA3A4, 0xA3A4}, {0xA3A5, 0xA3A5, 0xA3A5}, {0xA3A6, 0xA3A6, 0xA3A6}, {0xA3A7, 0xA3A7, 0xA3A7}, {0xA3A8, 0xA3A8, 0xA3A8}, {0xA3A9, 0xA3A9, 0xA3A9}, {0xA3AA, 0xA3AA, 0xA3AA}, {0xA3AB, 0xA3AB, 0xA3AB}, {0xA3AC, 0xA3AC, 0xA3AC}, {0xA3AD, 0xA3AD, 0xA3AD}, {0xA3AE, 0xA3AE, 0xA3AE}, {0xA3AF, 0xA3AF, 0xA3AF}, {0xA3B0, 0xA3B0, 0xA3B0}, {0xA3B1, 0xA3B1, 0xA3B1}, {0xA3B2, 0xA3B2, 0xA3B2}, {0xA3B3, 0xA3B3, 0xA3B3}, {0xA3B4, 0xA3B4, 0xA3B4}, {0xA3B5, 0xA3B5, 0xA3B5}, {0xA3B6, 0xA3B6, 0xA3B6}, {0xA3B7, 0xA3B7, 0xA3B7}, {0xA3B8, 0xA3B8, 0xA3B8}, {0xA3B9, 0xA3B9, 0xA3B9}, {0xA3BA, 0xA3BA, 0xA3BA}, {0xA3BB, 0xA3BB, 0xA3BB}, {0xA3BC, 0xA3BC, 0xA3BC}, {0xA3BD, 0xA3BD, 0xA3BD}, {0xA3BE, 0xA3BE, 0xA3BE}, {0xA3BF, 0xA3BF, 0xA3BF}, {0xA3C0, 0xA3C0, 0xA3C0}, {0xA3C1, 0xA3C1, 0xA3C1}, {0xA3C2, 0xA3C2, 0xA3C2}, {0xA3C3, 0xA3C3, 0xA3C3}, {0xA3C4, 0xA3C4, 0xA3C4}, {0xA3C5, 0xA3C5, 0xA3C5}, {0xA3C6, 0xA3C6, 0xA3C6}, {0xA3C7, 0xA3C7, 0xA3C7}, {0xA3C8, 0xA3C8, 0xA3C8}, {0xA3C9, 0xA3C9, 0xA3C9}, {0xA3CA, 0xA3CA, 0xA3CA}, {0xA3CB, 0xA3CB, 0xA3CB}, {0xA3CC, 0xA3CC, 0xA3CC}, {0xA3CD, 0xA3CD, 0xA3CD}, {0xA3CE, 0xA3CE, 0xA3CE}, {0xA3CF, 0xA3CF, 0xA3CF}, {0xA3D0, 0xA3D0, 0xA3D0}, {0xA3D1, 0xA3D1, 0xA3D1}, {0xA3D2, 0xA3D2, 0xA3D2}, {0xA3D3, 0xA3D3, 0xA3D3}, {0xA3D4, 0xA3D4, 0xA3D4}, {0xA3D5, 0xA3D5, 0xA3D5}, {0xA3D6, 0xA3D6, 0xA3D6}, {0xA3D7, 0xA3D7, 0xA3D7}, {0xA3D8, 0xA3D8, 0xA3D8}, {0xA3D9, 0xA3D9, 0xA3D9}, {0xA3DA, 0xA3DA, 0xA3DA}, {0xA3DB, 0xA3DB, 0xA3DB}, {0xA3DC, 0xA3DC, 0xA3DC}, {0xA3DD, 0xA3DD, 0xA3DD}, {0xA3DE, 0xA3DE, 0xA3DE}, {0xA3DF, 0xA3DF, 0xA3DF}, {0xA3E0, 0xA3E0, 0xA3E0}, {0xA3E1, 0xA3E1, 0xA3E1}, {0xA3E2, 0xA3E2, 0xA3E2}, {0xA3E3, 0xA3E3, 0xA3E3}, {0xA3E4, 0xA3E4, 0xA3E4}, {0xA3E5, 0xA3E5, 0xA3E5}, {0xA3E6, 0xA3E6, 0xA3E6}, {0xA3E7, 0xA3E7, 0xA3E7}, {0xA3E8, 0xA3E8, 0xA3E8}, {0xA3E9, 0xA3E9, 0xA3E9}, {0xA3EA, 0xA3EA, 0xA3EA}, {0xA3EB, 0xA3EB, 0xA3EB}, {0xA3EC, 0xA3EC, 0xA3EC}, {0xA3ED, 0xA3ED, 0xA3ED}, {0xA3EE, 0xA3EE, 0xA3EE}, {0xA3EF, 0xA3EF, 0xA3EF}, {0xA3F0, 0xA3F0, 0xA3F0}, {0xA3F1, 0xA3F1, 0xA3F1}, {0xA3F2, 0xA3F2, 0xA3F2}, {0xA3F3, 0xA3F3, 0xA3F3}, {0xA3F4, 0xA3F4, 0xA3F4}, {0xA3F5, 0xA3F5, 0xA3F5}, {0xA3F6, 0xA3F6, 0xA3F6}, {0xA3F7, 0xA3F7, 0xA3F7}, {0xA3F8, 0xA3F8, 0xA3F8}, {0xA3F9, 0xA3F9, 0xA3F9}, {0xA3FA, 0xA3FA, 0xA3FA}, {0xA3FB, 0xA3FB, 0xA3FB}, {0xA3FC, 0xA3FC, 0xA3FC}, {0xA3FD, 0xA3FD, 0xA3FD}, {0xA3FE, 0xA3FE, 0xA3FE}, {0xA3FF, 0xA3FF, 0xA3FF}, {0xA400, 0xA400, 0xA400}, {0xA401, 0xA401, 0xA401}, {0xA402, 0xA402, 0xA402}, {0xA403, 0xA403, 0xA403}, {0xA404, 0xA404, 0xA404}, {0xA405, 0xA405, 0xA405}, {0xA406, 0xA406, 0xA406}, {0xA407, 0xA407, 0xA407}, {0xA408, 0xA408, 0xA408}, {0xA409, 0xA409, 0xA409}, {0xA40A, 0xA40A, 0xA40A}, {0xA40B, 0xA40B, 0xA40B}, {0xA40C, 0xA40C, 0xA40C}, {0xA40D, 0xA40D, 0xA40D}, {0xA40E, 0xA40E, 0xA40E}, {0xA40F, 0xA40F, 0xA40F}, {0xA410, 0xA410, 0xA410}, {0xA411, 0xA411, 0xA411}, {0xA412, 0xA412, 0xA412}, {0xA413, 0xA413, 0xA413}, {0xA414, 0xA414, 0xA414}, {0xA415, 0xA415, 0xA415}, {0xA416, 0xA416, 0xA416}, {0xA417, 0xA417, 0xA417}, {0xA418, 0xA418, 0xA418}, {0xA419, 0xA419, 0xA419}, {0xA41A, 0xA41A, 0xA41A}, {0xA41B, 0xA41B, 0xA41B}, {0xA41C, 0xA41C, 0xA41C}, {0xA41D, 0xA41D, 0xA41D}, {0xA41E, 0xA41E, 0xA41E}, {0xA41F, 0xA41F, 0xA41F}, {0xA420, 0xA420, 0xA420}, {0xA421, 0xA421, 0xA421}, {0xA422, 0xA422, 0xA422}, {0xA423, 0xA423, 0xA423}, {0xA424, 0xA424, 0xA424}, {0xA425, 0xA425, 0xA425}, {0xA426, 0xA426, 0xA426}, {0xA427, 0xA427, 0xA427}, {0xA428, 0xA428, 0xA428}, {0xA429, 0xA429, 0xA429}, {0xA42A, 0xA42A, 0xA42A}, {0xA42B, 0xA42B, 0xA42B}, {0xA42C, 0xA42C, 0xA42C}, {0xA42D, 0xA42D, 0xA42D}, {0xA42E, 0xA42E, 0xA42E}, {0xA42F, 0xA42F, 0xA42F}, {0xA430, 0xA430, 0xA430}, {0xA431, 0xA431, 0xA431}, {0xA432, 0xA432, 0xA432}, {0xA433, 0xA433, 0xA433}, {0xA434, 0xA434, 0xA434}, {0xA435, 0xA435, 0xA435}, {0xA436, 0xA436, 0xA436}, {0xA437, 0xA437, 0xA437}, {0xA438, 0xA438, 0xA438}, {0xA439, 0xA439, 0xA439}, {0xA43A, 0xA43A, 0xA43A}, {0xA43B, 0xA43B, 0xA43B}, {0xA43C, 0xA43C, 0xA43C}, {0xA43D, 0xA43D, 0xA43D}, {0xA43E, 0xA43E, 0xA43E}, {0xA43F, 0xA43F, 0xA43F}, {0xA440, 0xA440, 0xA440}, {0xA441, 0xA441, 0xA441}, {0xA442, 0xA442, 0xA442}, {0xA443, 0xA443, 0xA443}, {0xA444, 0xA444, 0xA444}, {0xA445, 0xA445, 0xA445}, {0xA446, 0xA446, 0xA446}, {0xA447, 0xA447, 0xA447}, {0xA448, 0xA448, 0xA448}, {0xA449, 0xA449, 0xA449}, {0xA44A, 0xA44A, 0xA44A}, {0xA44B, 0xA44B, 0xA44B}, {0xA44C, 0xA44C, 0xA44C}, {0xA44D, 0xA44D, 0xA44D}, {0xA44E, 0xA44E, 0xA44E}, {0xA44F, 0xA44F, 0xA44F}, {0xA450, 0xA450, 0xA450}, {0xA451, 0xA451, 0xA451}, {0xA452, 0xA452, 0xA452}, {0xA453, 0xA453, 0xA453}, {0xA454, 0xA454, 0xA454}, {0xA455, 0xA455, 0xA455}, {0xA456, 0xA456, 0xA456}, {0xA457, 0xA457, 0xA457}, {0xA458, 0xA458, 0xA458}, {0xA459, 0xA459, 0xA459}, {0xA45A, 0xA45A, 0xA45A}, {0xA45B, 0xA45B, 0xA45B}, {0xA45C, 0xA45C, 0xA45C}, {0xA45D, 0xA45D, 0xA45D}, {0xA45E, 0xA45E, 0xA45E}, {0xA45F, 0xA45F, 0xA45F}, {0xA460, 0xA460, 0xA460}, {0xA461, 0xA461, 0xA461}, {0xA462, 0xA462, 0xA462}, {0xA463, 0xA463, 0xA463}, {0xA464, 0xA464, 0xA464}, {0xA465, 0xA465, 0xA465}, {0xA466, 0xA466, 0xA466}, {0xA467, 0xA467, 0xA467}, {0xA468, 0xA468, 0xA468}, {0xA469, 0xA469, 0xA469}, {0xA46A, 0xA46A, 0xA46A}, {0xA46B, 0xA46B, 0xA46B}, {0xA46C, 0xA46C, 0xA46C}, {0xA46D, 0xA46D, 0xA46D}, {0xA46E, 0xA46E, 0xA46E}, {0xA46F, 0xA46F, 0xA46F}, {0xA470, 0xA470, 0xA470}, {0xA471, 0xA471, 0xA471}, {0xA472, 0xA472, 0xA472}, {0xA473, 0xA473, 0xA473}, {0xA474, 0xA474, 0xA474}, {0xA475, 0xA475, 0xA475}, {0xA476, 0xA476, 0xA476}, {0xA477, 0xA477, 0xA477}, {0xA478, 0xA478, 0xA478}, {0xA479, 0xA479, 0xA479}, {0xA47A, 0xA47A, 0xA47A}, {0xA47B, 0xA47B, 0xA47B}, {0xA47C, 0xA47C, 0xA47C}, {0xA47D, 0xA47D, 0xA47D}, {0xA47E, 0xA47E, 0xA47E}, {0xA47F, 0xA47F, 0xA47F}, {0xA480, 0xA480, 0xA480}, {0xA481, 0xA481, 0xA481}, {0xA482, 0xA482, 0xA482}, {0xA483, 0xA483, 0xA483}, {0xA484, 0xA484, 0xA484}, {0xA485, 0xA485, 0xA485}, {0xA486, 0xA486, 0xA486}, {0xA487, 0xA487, 0xA487}, {0xA488, 0xA488, 0xA488}, {0xA489, 0xA489, 0xA489}, {0xA48A, 0xA48A, 0xA48A}, {0xA48B, 0xA48B, 0xA48B}, {0xA48C, 0xA48C, 0xA48C}, {0xA800, 0xA800, 0xA800}, {0xA801, 0xA801, 0xA801}, {0xA803, 0xA803, 0xA803}, {0xA804, 0xA804, 0xA804}, {0xA805, 0xA805, 0xA805}, {0xA806, 0xA806, 0xA806}, {0xA807, 0xA807, 0xA807}, {0xA808, 0xA808, 0xA808}, {0xA809, 0xA809, 0xA809}, {0xA80A, 0xA80A, 0xA80A}, {0xA80B, 0xA80B, 0xA80B}, {0xA80C, 0xA80C, 0xA80C}, {0xA80D, 0xA80D, 0xA80D}, {0xA80E, 0xA80E, 0xA80E}, {0xA80F, 0xA80F, 0xA80F}, {0xA810, 0xA810, 0xA810}, {0xA811, 0xA811, 0xA811}, {0xA812, 0xA812, 0xA812}, {0xA813, 0xA813, 0xA813}, {0xA814, 0xA814, 0xA814}, {0xA815, 0xA815, 0xA815}, {0xA816, 0xA816, 0xA816}, {0xA817, 0xA817, 0xA817}, {0xA818, 0xA818, 0xA818}, {0xA819, 0xA819, 0xA819}, {0xA81A, 0xA81A, 0xA81A}, {0xA81B, 0xA81B, 0xA81B}, {0xA81C, 0xA81C, 0xA81C}, {0xA81D, 0xA81D, 0xA81D}, {0xA81E, 0xA81E, 0xA81E}, {0xA81F, 0xA81F, 0xA81F}, {0xA820, 0xA820, 0xA820}, {0xA821, 0xA821, 0xA821}, {0xA822, 0xA822, 0xA822}, {0xA825, 0xA825, 0xA825}, {0xA826, 0xA826, 0xA826}, {0xAC00, 0xAC00, 0xAC00}, {0xAC01, 0xAC01, 0xAC01}, {0xAC02, 0xAC02, 0xAC02}, {0xAC03, 0xAC03, 0xAC03}, {0xAC04, 0xAC04, 0xAC04}, {0xAC05, 0xAC05, 0xAC05}, {0xAC06, 0xAC06, 0xAC06}, {0xAC07, 0xAC07, 0xAC07}, {0xAC08, 0xAC08, 0xAC08}, {0xAC09, 0xAC09, 0xAC09}, {0xAC0A, 0xAC0A, 0xAC0A}, {0xAC0B, 0xAC0B, 0xAC0B}, {0xAC0C, 0xAC0C, 0xAC0C}, {0xAC0D, 0xAC0D, 0xAC0D}, {0xAC0E, 0xAC0E, 0xAC0E}, {0xAC0F, 0xAC0F, 0xAC0F}, {0xAC10, 0xAC10, 0xAC10}, {0xAC11, 0xAC11, 0xAC11}, {0xAC12, 0xAC12, 0xAC12}, {0xAC13, 0xAC13, 0xAC13}, {0xAC14, 0xAC14, 0xAC14}, {0xAC15, 0xAC15, 0xAC15}, {0xAC16, 0xAC16, 0xAC16}, {0xAC17, 0xAC17, 0xAC17}, {0xAC18, 0xAC18, 0xAC18}, {0xAC19, 0xAC19, 0xAC19}, {0xAC1A, 0xAC1A, 0xAC1A}, {0xAC1B, 0xAC1B, 0xAC1B}, {0xAC1C, 0xAC1C, 0xAC1C}, {0xAC1D, 0xAC1D, 0xAC1D}, {0xAC1E, 0xAC1E, 0xAC1E}, {0xAC1F, 0xAC1F, 0xAC1F}, {0xAC20, 0xAC20, 0xAC20}, {0xAC21, 0xAC21, 0xAC21}, {0xAC22, 0xAC22, 0xAC22}, {0xAC23, 0xAC23, 0xAC23}, {0xAC24, 0xAC24, 0xAC24}, {0xAC25, 0xAC25, 0xAC25}, {0xAC26, 0xAC26, 0xAC26}, {0xAC27, 0xAC27, 0xAC27}, {0xAC28, 0xAC28, 0xAC28}, {0xAC29, 0xAC29, 0xAC29}, {0xAC2A, 0xAC2A, 0xAC2A}, {0xAC2B, 0xAC2B, 0xAC2B}, {0xAC2C, 0xAC2C, 0xAC2C}, {0xAC2D, 0xAC2D, 0xAC2D}, {0xAC2E, 0xAC2E, 0xAC2E}, {0xAC2F, 0xAC2F, 0xAC2F}, {0xAC30, 0xAC30, 0xAC30}, {0xAC31, 0xAC31, 0xAC31}, {0xAC32, 0xAC32, 0xAC32}, {0xAC33, 0xAC33, 0xAC33}, {0xAC34, 0xAC34, 0xAC34}, {0xAC35, 0xAC35, 0xAC35}, {0xAC36, 0xAC36, 0xAC36}, {0xAC37, 0xAC37, 0xAC37}, {0xAC38, 0xAC38, 0xAC38}, {0xAC39, 0xAC39, 0xAC39}, {0xAC3A, 0xAC3A, 0xAC3A}, {0xAC3B, 0xAC3B, 0xAC3B}, {0xAC3C, 0xAC3C, 0xAC3C}, {0xAC3D, 0xAC3D, 0xAC3D}, {0xAC3E, 0xAC3E, 0xAC3E}, {0xAC3F, 0xAC3F, 0xAC3F}, {0xAC40, 0xAC40, 0xAC40}, {0xAC41, 0xAC41, 0xAC41}, {0xAC42, 0xAC42, 0xAC42}, {0xAC43, 0xAC43, 0xAC43}, {0xAC44, 0xAC44, 0xAC44}, {0xAC45, 0xAC45, 0xAC45}, {0xAC46, 0xAC46, 0xAC46}, {0xAC47, 0xAC47, 0xAC47}, {0xAC48, 0xAC48, 0xAC48}, {0xAC49, 0xAC49, 0xAC49}, {0xAC4A, 0xAC4A, 0xAC4A}, {0xAC4B, 0xAC4B, 0xAC4B}, {0xAC4C, 0xAC4C, 0xAC4C}, {0xAC4D, 0xAC4D, 0xAC4D}, {0xAC4E, 0xAC4E, 0xAC4E}, {0xAC4F, 0xAC4F, 0xAC4F}, {0xAC50, 0xAC50, 0xAC50}, {0xAC51, 0xAC51, 0xAC51}, {0xAC52, 0xAC52, 0xAC52}, {0xAC53, 0xAC53, 0xAC53}, {0xAC54, 0xAC54, 0xAC54}, {0xAC55, 0xAC55, 0xAC55}, {0xAC56, 0xAC56, 0xAC56}, {0xAC57, 0xAC57, 0xAC57}, {0xAC58, 0xAC58, 0xAC58}, {0xAC59, 0xAC59, 0xAC59}, {0xAC5A, 0xAC5A, 0xAC5A}, {0xAC5B, 0xAC5B, 0xAC5B}, {0xAC5C, 0xAC5C, 0xAC5C}, {0xAC5D, 0xAC5D, 0xAC5D}, {0xAC5E, 0xAC5E, 0xAC5E}, {0xAC5F, 0xAC5F, 0xAC5F}, {0xAC60, 0xAC60, 0xAC60}, {0xAC61, 0xAC61, 0xAC61}, {0xAC62, 0xAC62, 0xAC62}, {0xAC63, 0xAC63, 0xAC63}, {0xAC64, 0xAC64, 0xAC64}, {0xAC65, 0xAC65, 0xAC65}, {0xAC66, 0xAC66, 0xAC66}, {0xAC67, 0xAC67, 0xAC67}, {0xAC68, 0xAC68, 0xAC68}, {0xAC69, 0xAC69, 0xAC69}, {0xAC6A, 0xAC6A, 0xAC6A}, {0xAC6B, 0xAC6B, 0xAC6B}, {0xAC6C, 0xAC6C, 0xAC6C}, {0xAC6D, 0xAC6D, 0xAC6D}, {0xAC6E, 0xAC6E, 0xAC6E}, {0xAC6F, 0xAC6F, 0xAC6F}, {0xAC70, 0xAC70, 0xAC70}, {0xAC71, 0xAC71, 0xAC71}, {0xAC72, 0xAC72, 0xAC72}, {0xAC73, 0xAC73, 0xAC73}, {0xAC74, 0xAC74, 0xAC74}, {0xAC75, 0xAC75, 0xAC75}, {0xAC76, 0xAC76, 0xAC76}, {0xAC77, 0xAC77, 0xAC77}, {0xAC78, 0xAC78, 0xAC78}, {0xAC79, 0xAC79, 0xAC79}, {0xAC7A, 0xAC7A, 0xAC7A}, {0xAC7B, 0xAC7B, 0xAC7B}, {0xAC7C, 0xAC7C, 0xAC7C}, {0xAC7D, 0xAC7D, 0xAC7D}, {0xAC7E, 0xAC7E, 0xAC7E}, {0xAC7F, 0xAC7F, 0xAC7F}, {0xAC80, 0xAC80, 0xAC80}, {0xAC81, 0xAC81, 0xAC81}, {0xAC82, 0xAC82, 0xAC82}, {0xAC83, 0xAC83, 0xAC83}, {0xAC84, 0xAC84, 0xAC84}, {0xAC85, 0xAC85, 0xAC85}, {0xAC86, 0xAC86, 0xAC86}, {0xAC87, 0xAC87, 0xAC87}, {0xAC88, 0xAC88, 0xAC88}, {0xAC89, 0xAC89, 0xAC89}, {0xAC8A, 0xAC8A, 0xAC8A}, {0xAC8B, 0xAC8B, 0xAC8B}, {0xAC8C, 0xAC8C, 0xAC8C}, {0xAC8D, 0xAC8D, 0xAC8D}, {0xAC8E, 0xAC8E, 0xAC8E}, {0xAC8F, 0xAC8F, 0xAC8F}, {0xAC90, 0xAC90, 0xAC90}, {0xAC91, 0xAC91, 0xAC91}, {0xAC92, 0xAC92, 0xAC92}, {0xAC93, 0xAC93, 0xAC93}, {0xAC94, 0xAC94, 0xAC94}, {0xAC95, 0xAC95, 0xAC95}, {0xAC96, 0xAC96, 0xAC96}, {0xAC97, 0xAC97, 0xAC97}, {0xAC98, 0xAC98, 0xAC98}, {0xAC99, 0xAC99, 0xAC99}, {0xAC9A, 0xAC9A, 0xAC9A}, {0xAC9B, 0xAC9B, 0xAC9B}, {0xAC9C, 0xAC9C, 0xAC9C}, {0xAC9D, 0xAC9D, 0xAC9D}, {0xAC9E, 0xAC9E, 0xAC9E}, {0xAC9F, 0xAC9F, 0xAC9F}, {0xACA0, 0xACA0, 0xACA0}, {0xACA1, 0xACA1, 0xACA1}, {0xACA2, 0xACA2, 0xACA2}, {0xACA3, 0xACA3, 0xACA3}, {0xACA4, 0xACA4, 0xACA4}, {0xACA5, 0xACA5, 0xACA5}, {0xACA6, 0xACA6, 0xACA6}, {0xACA7, 0xACA7, 0xACA7}, {0xACA8, 0xACA8, 0xACA8}, {0xACA9, 0xACA9, 0xACA9}, {0xACAA, 0xACAA, 0xACAA}, {0xACAB, 0xACAB, 0xACAB}, {0xACAC, 0xACAC, 0xACAC}, {0xACAD, 0xACAD, 0xACAD}, {0xACAE, 0xACAE, 0xACAE}, {0xACAF, 0xACAF, 0xACAF}, {0xACB0, 0xACB0, 0xACB0}, {0xACB1, 0xACB1, 0xACB1}, {0xACB2, 0xACB2, 0xACB2}, {0xACB3, 0xACB3, 0xACB3}, {0xACB4, 0xACB4, 0xACB4}, {0xACB5, 0xACB5, 0xACB5}, {0xACB6, 0xACB6, 0xACB6}, {0xACB7, 0xACB7, 0xACB7}, {0xACB8, 0xACB8, 0xACB8}, {0xACB9, 0xACB9, 0xACB9}, {0xACBA, 0xACBA, 0xACBA}, {0xACBB, 0xACBB, 0xACBB}, {0xACBC, 0xACBC, 0xACBC}, {0xACBD, 0xACBD, 0xACBD}, {0xACBE, 0xACBE, 0xACBE}, {0xACBF, 0xACBF, 0xACBF}, {0xACC0, 0xACC0, 0xACC0}, {0xACC1, 0xACC1, 0xACC1}, {0xACC2, 0xACC2, 0xACC2}, {0xACC3, 0xACC3, 0xACC3}, {0xACC4, 0xACC4, 0xACC4}, {0xACC5, 0xACC5, 0xACC5}, {0xACC6, 0xACC6, 0xACC6}, {0xACC7, 0xACC7, 0xACC7}, {0xACC8, 0xACC8, 0xACC8}, {0xACC9, 0xACC9, 0xACC9}, {0xACCA, 0xACCA, 0xACCA}, {0xACCB, 0xACCB, 0xACCB}, {0xACCC, 0xACCC, 0xACCC}, {0xACCD, 0xACCD, 0xACCD}, {0xACCE, 0xACCE, 0xACCE}, {0xACCF, 0xACCF, 0xACCF}, {0xACD0, 0xACD0, 0xACD0}, {0xACD1, 0xACD1, 0xACD1}, {0xACD2, 0xACD2, 0xACD2}, {0xACD3, 0xACD3, 0xACD3}, {0xACD4, 0xACD4, 0xACD4}, {0xACD5, 0xACD5, 0xACD5}, {0xACD6, 0xACD6, 0xACD6}, {0xACD7, 0xACD7, 0xACD7}, {0xACD8, 0xACD8, 0xACD8}, {0xACD9, 0xACD9, 0xACD9}, {0xACDA, 0xACDA, 0xACDA}, {0xACDB, 0xACDB, 0xACDB}, {0xACDC, 0xACDC, 0xACDC}, {0xACDD, 0xACDD, 0xACDD}, {0xACDE, 0xACDE, 0xACDE}, {0xACDF, 0xACDF, 0xACDF}, {0xACE0, 0xACE0, 0xACE0}, {0xACE1, 0xACE1, 0xACE1}, {0xACE2, 0xACE2, 0xACE2}, {0xACE3, 0xACE3, 0xACE3}, {0xACE4, 0xACE4, 0xACE4}, {0xACE5, 0xACE5, 0xACE5}, {0xACE6, 0xACE6, 0xACE6}, {0xACE7, 0xACE7, 0xACE7}, {0xACE8, 0xACE8, 0xACE8}, {0xACE9, 0xACE9, 0xACE9}, {0xACEA, 0xACEA, 0xACEA}, {0xACEB, 0xACEB, 0xACEB}, {0xACEC, 0xACEC, 0xACEC}, {0xACED, 0xACED, 0xACED}, {0xACEE, 0xACEE, 0xACEE}, {0xACEF, 0xACEF, 0xACEF}, {0xACF0, 0xACF0, 0xACF0}, {0xACF1, 0xACF1, 0xACF1}, {0xACF2, 0xACF2, 0xACF2}, {0xACF3, 0xACF3, 0xACF3}, {0xACF4, 0xACF4, 0xACF4}, {0xACF5, 0xACF5, 0xACF5}, {0xACF6, 0xACF6, 0xACF6}, {0xACF7, 0xACF7, 0xACF7}, {0xACF8, 0xACF8, 0xACF8}, {0xACF9, 0xACF9, 0xACF9}, {0xACFA, 0xACFA, 0xACFA}, {0xACFB, 0xACFB, 0xACFB}, {0xACFC, 0xACFC, 0xACFC}, {0xACFD, 0xACFD, 0xACFD}, {0xACFE, 0xACFE, 0xACFE}, {0xACFF, 0xACFF, 0xACFF}, {0xAD00, 0xAD00, 0xAD00}, {0xAD01, 0xAD01, 0xAD01}, {0xAD02, 0xAD02, 0xAD02}, {0xAD03, 0xAD03, 0xAD03}, {0xAD04, 0xAD04, 0xAD04}, {0xAD05, 0xAD05, 0xAD05}, {0xAD06, 0xAD06, 0xAD06}, {0xAD07, 0xAD07, 0xAD07}, {0xAD08, 0xAD08, 0xAD08}, {0xAD09, 0xAD09, 0xAD09}, {0xAD0A, 0xAD0A, 0xAD0A}, {0xAD0B, 0xAD0B, 0xAD0B}, {0xAD0C, 0xAD0C, 0xAD0C}, {0xAD0D, 0xAD0D, 0xAD0D}, {0xAD0E, 0xAD0E, 0xAD0E}, {0xAD0F, 0xAD0F, 0xAD0F}, {0xAD10, 0xAD10, 0xAD10}, {0xAD11, 0xAD11, 0xAD11}, {0xAD12, 0xAD12, 0xAD12}, {0xAD13, 0xAD13, 0xAD13}, {0xAD14, 0xAD14, 0xAD14}, {0xAD15, 0xAD15, 0xAD15}, {0xAD16, 0xAD16, 0xAD16}, {0xAD17, 0xAD17, 0xAD17}, {0xAD18, 0xAD18, 0xAD18}, {0xAD19, 0xAD19, 0xAD19}, {0xAD1A, 0xAD1A, 0xAD1A}, {0xAD1B, 0xAD1B, 0xAD1B}, {0xAD1C, 0xAD1C, 0xAD1C}, {0xAD1D, 0xAD1D, 0xAD1D}, {0xAD1E, 0xAD1E, 0xAD1E}, {0xAD1F, 0xAD1F, 0xAD1F}, {0xAD20, 0xAD20, 0xAD20}, {0xAD21, 0xAD21, 0xAD21}, {0xAD22, 0xAD22, 0xAD22}, {0xAD23, 0xAD23, 0xAD23}, {0xAD24, 0xAD24, 0xAD24}, {0xAD25, 0xAD25, 0xAD25}, {0xAD26, 0xAD26, 0xAD26}, {0xAD27, 0xAD27, 0xAD27}, {0xAD28, 0xAD28, 0xAD28}, {0xAD29, 0xAD29, 0xAD29}, {0xAD2A, 0xAD2A, 0xAD2A}, {0xAD2B, 0xAD2B, 0xAD2B}, {0xAD2C, 0xAD2C, 0xAD2C}, {0xAD2D, 0xAD2D, 0xAD2D}, {0xAD2E, 0xAD2E, 0xAD2E}, {0xAD2F, 0xAD2F, 0xAD2F}, {0xAD30, 0xAD30, 0xAD30}, {0xAD31, 0xAD31, 0xAD31}, {0xAD32, 0xAD32, 0xAD32}, {0xAD33, 0xAD33, 0xAD33}, {0xAD34, 0xAD34, 0xAD34}, {0xAD35, 0xAD35, 0xAD35}, {0xAD36, 0xAD36, 0xAD36}, {0xAD37, 0xAD37, 0xAD37}, {0xAD38, 0xAD38, 0xAD38}, {0xAD39, 0xAD39, 0xAD39}, {0xAD3A, 0xAD3A, 0xAD3A}, {0xAD3B, 0xAD3B, 0xAD3B}, {0xAD3C, 0xAD3C, 0xAD3C}, {0xAD3D, 0xAD3D, 0xAD3D}, {0xAD3E, 0xAD3E, 0xAD3E}, {0xAD3F, 0xAD3F, 0xAD3F}, {0xAD40, 0xAD40, 0xAD40}, {0xAD41, 0xAD41, 0xAD41}, {0xAD42, 0xAD42, 0xAD42}, {0xAD43, 0xAD43, 0xAD43}, {0xAD44, 0xAD44, 0xAD44}, {0xAD45, 0xAD45, 0xAD45}, {0xAD46, 0xAD46, 0xAD46}, {0xAD47, 0xAD47, 0xAD47}, {0xAD48, 0xAD48, 0xAD48}, {0xAD49, 0xAD49, 0xAD49}, {0xAD4A, 0xAD4A, 0xAD4A}, {0xAD4B, 0xAD4B, 0xAD4B}, {0xAD4C, 0xAD4C, 0xAD4C}, {0xAD4D, 0xAD4D, 0xAD4D}, {0xAD4E, 0xAD4E, 0xAD4E}, {0xAD4F, 0xAD4F, 0xAD4F}, {0xAD50, 0xAD50, 0xAD50}, {0xAD51, 0xAD51, 0xAD51}, {0xAD52, 0xAD52, 0xAD52}, {0xAD53, 0xAD53, 0xAD53}, {0xAD54, 0xAD54, 0xAD54}, {0xAD55, 0xAD55, 0xAD55}, {0xAD56, 0xAD56, 0xAD56}, {0xAD57, 0xAD57, 0xAD57}, {0xAD58, 0xAD58, 0xAD58}, {0xAD59, 0xAD59, 0xAD59}, {0xAD5A, 0xAD5A, 0xAD5A}, {0xAD5B, 0xAD5B, 0xAD5B}, {0xAD5C, 0xAD5C, 0xAD5C}, {0xAD5D, 0xAD5D, 0xAD5D}, {0xAD5E, 0xAD5E, 0xAD5E}, {0xAD5F, 0xAD5F, 0xAD5F}, {0xAD60, 0xAD60, 0xAD60}, {0xAD61, 0xAD61, 0xAD61}, {0xAD62, 0xAD62, 0xAD62}, {0xAD63, 0xAD63, 0xAD63}, {0xAD64, 0xAD64, 0xAD64}, {0xAD65, 0xAD65, 0xAD65}, {0xAD66, 0xAD66, 0xAD66}, {0xAD67, 0xAD67, 0xAD67}, {0xAD68, 0xAD68, 0xAD68}, {0xAD69, 0xAD69, 0xAD69}, {0xAD6A, 0xAD6A, 0xAD6A}, {0xAD6B, 0xAD6B, 0xAD6B}, {0xAD6C, 0xAD6C, 0xAD6C}, {0xAD6D, 0xAD6D, 0xAD6D}, {0xAD6E, 0xAD6E, 0xAD6E}, {0xAD6F, 0xAD6F, 0xAD6F}, {0xAD70, 0xAD70, 0xAD70}, {0xAD71, 0xAD71, 0xAD71}, {0xAD72, 0xAD72, 0xAD72}, {0xAD73, 0xAD73, 0xAD73}, {0xAD74, 0xAD74, 0xAD74}, {0xAD75, 0xAD75, 0xAD75}, {0xAD76, 0xAD76, 0xAD76}, {0xAD77, 0xAD77, 0xAD77}, {0xAD78, 0xAD78, 0xAD78}, {0xAD79, 0xAD79, 0xAD79}, {0xAD7A, 0xAD7A, 0xAD7A}, {0xAD7B, 0xAD7B, 0xAD7B}, {0xAD7C, 0xAD7C, 0xAD7C}, {0xAD7D, 0xAD7D, 0xAD7D}, {0xAD7E, 0xAD7E, 0xAD7E}, {0xAD7F, 0xAD7F, 0xAD7F}, {0xAD80, 0xAD80, 0xAD80}, {0xAD81, 0xAD81, 0xAD81}, {0xAD82, 0xAD82, 0xAD82}, {0xAD83, 0xAD83, 0xAD83}, {0xAD84, 0xAD84, 0xAD84}, {0xAD85, 0xAD85, 0xAD85}, {0xAD86, 0xAD86, 0xAD86}, {0xAD87, 0xAD87, 0xAD87}, {0xAD88, 0xAD88, 0xAD88}, {0xAD89, 0xAD89, 0xAD89}, {0xAD8A, 0xAD8A, 0xAD8A}, {0xAD8B, 0xAD8B, 0xAD8B}, {0xAD8C, 0xAD8C, 0xAD8C}, {0xAD8D, 0xAD8D, 0xAD8D}, {0xAD8E, 0xAD8E, 0xAD8E}, {0xAD8F, 0xAD8F, 0xAD8F}, {0xAD90, 0xAD90, 0xAD90}, {0xAD91, 0xAD91, 0xAD91}, {0xAD92, 0xAD92, 0xAD92}, {0xAD93, 0xAD93, 0xAD93}, {0xAD94, 0xAD94, 0xAD94}, {0xAD95, 0xAD95, 0xAD95}, {0xAD96, 0xAD96, 0xAD96}, {0xAD97, 0xAD97, 0xAD97}, {0xAD98, 0xAD98, 0xAD98}, {0xAD99, 0xAD99, 0xAD99}, {0xAD9A, 0xAD9A, 0xAD9A}, {0xAD9B, 0xAD9B, 0xAD9B}, {0xAD9C, 0xAD9C, 0xAD9C}, {0xAD9D, 0xAD9D, 0xAD9D}, {0xAD9E, 0xAD9E, 0xAD9E}, {0xAD9F, 0xAD9F, 0xAD9F}, {0xADA0, 0xADA0, 0xADA0}, {0xADA1, 0xADA1, 0xADA1}, {0xADA2, 0xADA2, 0xADA2}, {0xADA3, 0xADA3, 0xADA3}, {0xADA4, 0xADA4, 0xADA4}, {0xADA5, 0xADA5, 0xADA5}, {0xADA6, 0xADA6, 0xADA6}, {0xADA7, 0xADA7, 0xADA7}, {0xADA8, 0xADA8, 0xADA8}, {0xADA9, 0xADA9, 0xADA9}, {0xADAA, 0xADAA, 0xADAA}, {0xADAB, 0xADAB, 0xADAB}, {0xADAC, 0xADAC, 0xADAC}, {0xADAD, 0xADAD, 0xADAD}, {0xADAE, 0xADAE, 0xADAE}, {0xADAF, 0xADAF, 0xADAF}, {0xADB0, 0xADB0, 0xADB0}, {0xADB1, 0xADB1, 0xADB1}, {0xADB2, 0xADB2, 0xADB2}, {0xADB3, 0xADB3, 0xADB3}, {0xADB4, 0xADB4, 0xADB4}, {0xADB5, 0xADB5, 0xADB5}, {0xADB6, 0xADB6, 0xADB6}, {0xADB7, 0xADB7, 0xADB7}, {0xADB8, 0xADB8, 0xADB8}, {0xADB9, 0xADB9, 0xADB9}, {0xADBA, 0xADBA, 0xADBA}, {0xADBB, 0xADBB, 0xADBB}, {0xADBC, 0xADBC, 0xADBC}, {0xADBD, 0xADBD, 0xADBD}, {0xADBE, 0xADBE, 0xADBE}, {0xADBF, 0xADBF, 0xADBF}, {0xADC0, 0xADC0, 0xADC0}, {0xADC1, 0xADC1, 0xADC1}, {0xADC2, 0xADC2, 0xADC2}, {0xADC3, 0xADC3, 0xADC3}, {0xADC4, 0xADC4, 0xADC4}, {0xADC5, 0xADC5, 0xADC5}, {0xADC6, 0xADC6, 0xADC6}, {0xADC7, 0xADC7, 0xADC7}, {0xADC8, 0xADC8, 0xADC8}, {0xADC9, 0xADC9, 0xADC9}, {0xADCA, 0xADCA, 0xADCA}, {0xADCB, 0xADCB, 0xADCB}, {0xADCC, 0xADCC, 0xADCC}, {0xADCD, 0xADCD, 0xADCD}, {0xADCE, 0xADCE, 0xADCE}, {0xADCF, 0xADCF, 0xADCF}, {0xADD0, 0xADD0, 0xADD0}, {0xADD1, 0xADD1, 0xADD1}, {0xADD2, 0xADD2, 0xADD2}, {0xADD3, 0xADD3, 0xADD3}, {0xADD4, 0xADD4, 0xADD4}, {0xADD5, 0xADD5, 0xADD5}, {0xADD6, 0xADD6, 0xADD6}, {0xADD7, 0xADD7, 0xADD7}, {0xADD8, 0xADD8, 0xADD8}, {0xADD9, 0xADD9, 0xADD9}, {0xADDA, 0xADDA, 0xADDA}, {0xADDB, 0xADDB, 0xADDB}, {0xADDC, 0xADDC, 0xADDC}, {0xADDD, 0xADDD, 0xADDD}, {0xADDE, 0xADDE, 0xADDE}, {0xADDF, 0xADDF, 0xADDF}, {0xADE0, 0xADE0, 0xADE0}, {0xADE1, 0xADE1, 0xADE1}, {0xADE2, 0xADE2, 0xADE2}, {0xADE3, 0xADE3, 0xADE3}, {0xADE4, 0xADE4, 0xADE4}, {0xADE5, 0xADE5, 0xADE5}, {0xADE6, 0xADE6, 0xADE6}, {0xADE7, 0xADE7, 0xADE7}, {0xADE8, 0xADE8, 0xADE8}, {0xADE9, 0xADE9, 0xADE9}, {0xADEA, 0xADEA, 0xADEA}, {0xADEB, 0xADEB, 0xADEB}, {0xADEC, 0xADEC, 0xADEC}, {0xADED, 0xADED, 0xADED}, {0xADEE, 0xADEE, 0xADEE}, {0xADEF, 0xADEF, 0xADEF}, {0xADF0, 0xADF0, 0xADF0}, {0xADF1, 0xADF1, 0xADF1}, {0xADF2, 0xADF2, 0xADF2}, {0xADF3, 0xADF3, 0xADF3}, {0xADF4, 0xADF4, 0xADF4}, {0xADF5, 0xADF5, 0xADF5}, {0xADF6, 0xADF6, 0xADF6}, {0xADF7, 0xADF7, 0xADF7}, {0xADF8, 0xADF8, 0xADF8}, {0xADF9, 0xADF9, 0xADF9}, {0xADFA, 0xADFA, 0xADFA}, {0xADFB, 0xADFB, 0xADFB}, {0xADFC, 0xADFC, 0xADFC}, {0xADFD, 0xADFD, 0xADFD}, {0xADFE, 0xADFE, 0xADFE}, {0xADFF, 0xADFF, 0xADFF}, {0xAE00, 0xAE00, 0xAE00}, {0xAE01, 0xAE01, 0xAE01}, {0xAE02, 0xAE02, 0xAE02}, {0xAE03, 0xAE03, 0xAE03}, {0xAE04, 0xAE04, 0xAE04}, {0xAE05, 0xAE05, 0xAE05}, {0xAE06, 0xAE06, 0xAE06}, {0xAE07, 0xAE07, 0xAE07}, {0xAE08, 0xAE08, 0xAE08}, {0xAE09, 0xAE09, 0xAE09}, {0xAE0A, 0xAE0A, 0xAE0A}, {0xAE0B, 0xAE0B, 0xAE0B}, {0xAE0C, 0xAE0C, 0xAE0C}, {0xAE0D, 0xAE0D, 0xAE0D}, {0xAE0E, 0xAE0E, 0xAE0E}, {0xAE0F, 0xAE0F, 0xAE0F}, {0xAE10, 0xAE10, 0xAE10}, {0xAE11, 0xAE11, 0xAE11}, {0xAE12, 0xAE12, 0xAE12}, {0xAE13, 0xAE13, 0xAE13}, {0xAE14, 0xAE14, 0xAE14}, {0xAE15, 0xAE15, 0xAE15}, {0xAE16, 0xAE16, 0xAE16}, {0xAE17, 0xAE17, 0xAE17}, {0xAE18, 0xAE18, 0xAE18}, {0xAE19, 0xAE19, 0xAE19}, {0xAE1A, 0xAE1A, 0xAE1A}, {0xAE1B, 0xAE1B, 0xAE1B}, {0xAE1C, 0xAE1C, 0xAE1C}, {0xAE1D, 0xAE1D, 0xAE1D}, {0xAE1E, 0xAE1E, 0xAE1E}, {0xAE1F, 0xAE1F, 0xAE1F}, {0xAE20, 0xAE20, 0xAE20}, {0xAE21, 0xAE21, 0xAE21}, {0xAE22, 0xAE22, 0xAE22}, {0xAE23, 0xAE23, 0xAE23}, {0xAE24, 0xAE24, 0xAE24}, {0xAE25, 0xAE25, 0xAE25}, {0xAE26, 0xAE26, 0xAE26}, {0xAE27, 0xAE27, 0xAE27}, {0xAE28, 0xAE28, 0xAE28}, {0xAE29, 0xAE29, 0xAE29}, {0xAE2A, 0xAE2A, 0xAE2A}, {0xAE2B, 0xAE2B, 0xAE2B}, {0xAE2C, 0xAE2C, 0xAE2C}, {0xAE2D, 0xAE2D, 0xAE2D}, {0xAE2E, 0xAE2E, 0xAE2E}, {0xAE2F, 0xAE2F, 0xAE2F}, {0xAE30, 0xAE30, 0xAE30}, {0xAE31, 0xAE31, 0xAE31}, {0xAE32, 0xAE32, 0xAE32}, {0xAE33, 0xAE33, 0xAE33}, {0xAE34, 0xAE34, 0xAE34}, {0xAE35, 0xAE35, 0xAE35}, {0xAE36, 0xAE36, 0xAE36}, {0xAE37, 0xAE37, 0xAE37}, {0xAE38, 0xAE38, 0xAE38}, {0xAE39, 0xAE39, 0xAE39}, {0xAE3A, 0xAE3A, 0xAE3A}, {0xAE3B, 0xAE3B, 0xAE3B}, {0xAE3C, 0xAE3C, 0xAE3C}, {0xAE3D, 0xAE3D, 0xAE3D}, {0xAE3E, 0xAE3E, 0xAE3E}, {0xAE3F, 0xAE3F, 0xAE3F}, {0xAE40, 0xAE40, 0xAE40}, {0xAE41, 0xAE41, 0xAE41}, {0xAE42, 0xAE42, 0xAE42}, {0xAE43, 0xAE43, 0xAE43}, {0xAE44, 0xAE44, 0xAE44}, {0xAE45, 0xAE45, 0xAE45}, {0xAE46, 0xAE46, 0xAE46}, {0xAE47, 0xAE47, 0xAE47}, {0xAE48, 0xAE48, 0xAE48}, {0xAE49, 0xAE49, 0xAE49}, {0xAE4A, 0xAE4A, 0xAE4A}, {0xAE4B, 0xAE4B, 0xAE4B}, {0xAE4C, 0xAE4C, 0xAE4C}, {0xAE4D, 0xAE4D, 0xAE4D}, {0xAE4E, 0xAE4E, 0xAE4E}, {0xAE4F, 0xAE4F, 0xAE4F}, {0xAE50, 0xAE50, 0xAE50}, {0xAE51, 0xAE51, 0xAE51}, {0xAE52, 0xAE52, 0xAE52}, {0xAE53, 0xAE53, 0xAE53}, {0xAE54, 0xAE54, 0xAE54}, {0xAE55, 0xAE55, 0xAE55}, {0xAE56, 0xAE56, 0xAE56}, {0xAE57, 0xAE57, 0xAE57}, {0xAE58, 0xAE58, 0xAE58}, {0xAE59, 0xAE59, 0xAE59}, {0xAE5A, 0xAE5A, 0xAE5A}, {0xAE5B, 0xAE5B, 0xAE5B}, {0xAE5C, 0xAE5C, 0xAE5C}, {0xAE5D, 0xAE5D, 0xAE5D}, {0xAE5E, 0xAE5E, 0xAE5E}, {0xAE5F, 0xAE5F, 0xAE5F}, {0xAE60, 0xAE60, 0xAE60}, {0xAE61, 0xAE61, 0xAE61}, {0xAE62, 0xAE62, 0xAE62}, {0xAE63, 0xAE63, 0xAE63}, {0xAE64, 0xAE64, 0xAE64}, {0xAE65, 0xAE65, 0xAE65}, {0xAE66, 0xAE66, 0xAE66}, {0xAE67, 0xAE67, 0xAE67}, {0xAE68, 0xAE68, 0xAE68}, {0xAE69, 0xAE69, 0xAE69}, {0xAE6A, 0xAE6A, 0xAE6A}, {0xAE6B, 0xAE6B, 0xAE6B}, {0xAE6C, 0xAE6C, 0xAE6C}, {0xAE6D, 0xAE6D, 0xAE6D}, {0xAE6E, 0xAE6E, 0xAE6E}, {0xAE6F, 0xAE6F, 0xAE6F}, {0xAE70, 0xAE70, 0xAE70}, {0xAE71, 0xAE71, 0xAE71}, {0xAE72, 0xAE72, 0xAE72}, {0xAE73, 0xAE73, 0xAE73}, {0xAE74, 0xAE74, 0xAE74}, {0xAE75, 0xAE75, 0xAE75}, {0xAE76, 0xAE76, 0xAE76}, {0xAE77, 0xAE77, 0xAE77}, {0xAE78, 0xAE78, 0xAE78}, {0xAE79, 0xAE79, 0xAE79}, {0xAE7A, 0xAE7A, 0xAE7A}, {0xAE7B, 0xAE7B, 0xAE7B}, {0xAE7C, 0xAE7C, 0xAE7C}, {0xAE7D, 0xAE7D, 0xAE7D}, {0xAE7E, 0xAE7E, 0xAE7E}, {0xAE7F, 0xAE7F, 0xAE7F}, {0xAE80, 0xAE80, 0xAE80}, {0xAE81, 0xAE81, 0xAE81}, {0xAE82, 0xAE82, 0xAE82}, {0xAE83, 0xAE83, 0xAE83}, {0xAE84, 0xAE84, 0xAE84}, {0xAE85, 0xAE85, 0xAE85}, {0xAE86, 0xAE86, 0xAE86}, {0xAE87, 0xAE87, 0xAE87}, {0xAE88, 0xAE88, 0xAE88}, {0xAE89, 0xAE89, 0xAE89}, {0xAE8A, 0xAE8A, 0xAE8A}, {0xAE8B, 0xAE8B, 0xAE8B}, {0xAE8C, 0xAE8C, 0xAE8C}, {0xAE8D, 0xAE8D, 0xAE8D}, {0xAE8E, 0xAE8E, 0xAE8E}, {0xAE8F, 0xAE8F, 0xAE8F}, {0xAE90, 0xAE90, 0xAE90}, {0xAE91, 0xAE91, 0xAE91}, {0xAE92, 0xAE92, 0xAE92}, {0xAE93, 0xAE93, 0xAE93}, {0xAE94, 0xAE94, 0xAE94}, {0xAE95, 0xAE95, 0xAE95}, {0xAE96, 0xAE96, 0xAE96}, {0xAE97, 0xAE97, 0xAE97}, {0xAE98, 0xAE98, 0xAE98}, {0xAE99, 0xAE99, 0xAE99}, {0xAE9A, 0xAE9A, 0xAE9A}, {0xAE9B, 0xAE9B, 0xAE9B}, {0xAE9C, 0xAE9C, 0xAE9C}, {0xAE9D, 0xAE9D, 0xAE9D}, {0xAE9E, 0xAE9E, 0xAE9E}, {0xAE9F, 0xAE9F, 0xAE9F}, {0xAEA0, 0xAEA0, 0xAEA0}, {0xAEA1, 0xAEA1, 0xAEA1}, {0xAEA2, 0xAEA2, 0xAEA2}, {0xAEA3, 0xAEA3, 0xAEA3}, {0xAEA4, 0xAEA4, 0xAEA4}, {0xAEA5, 0xAEA5, 0xAEA5}, {0xAEA6, 0xAEA6, 0xAEA6}, {0xAEA7, 0xAEA7, 0xAEA7}, {0xAEA8, 0xAEA8, 0xAEA8}, {0xAEA9, 0xAEA9, 0xAEA9}, {0xAEAA, 0xAEAA, 0xAEAA}, {0xAEAB, 0xAEAB, 0xAEAB}, {0xAEAC, 0xAEAC, 0xAEAC}, {0xAEAD, 0xAEAD, 0xAEAD}, {0xAEAE, 0xAEAE, 0xAEAE}, {0xAEAF, 0xAEAF, 0xAEAF}, {0xAEB0, 0xAEB0, 0xAEB0}, {0xAEB1, 0xAEB1, 0xAEB1}, {0xAEB2, 0xAEB2, 0xAEB2}, {0xAEB3, 0xAEB3, 0xAEB3}, {0xAEB4, 0xAEB4, 0xAEB4}, {0xAEB5, 0xAEB5, 0xAEB5}, {0xAEB6, 0xAEB6, 0xAEB6}, {0xAEB7, 0xAEB7, 0xAEB7}, {0xAEB8, 0xAEB8, 0xAEB8}, {0xAEB9, 0xAEB9, 0xAEB9}, {0xAEBA, 0xAEBA, 0xAEBA}, {0xAEBB, 0xAEBB, 0xAEBB}, {0xAEBC, 0xAEBC, 0xAEBC}, {0xAEBD, 0xAEBD, 0xAEBD}, {0xAEBE, 0xAEBE, 0xAEBE}, {0xAEBF, 0xAEBF, 0xAEBF}, {0xAEC0, 0xAEC0, 0xAEC0}, {0xAEC1, 0xAEC1, 0xAEC1}, {0xAEC2, 0xAEC2, 0xAEC2}, {0xAEC3, 0xAEC3, 0xAEC3}, {0xAEC4, 0xAEC4, 0xAEC4}, {0xAEC5, 0xAEC5, 0xAEC5}, {0xAEC6, 0xAEC6, 0xAEC6}, {0xAEC7, 0xAEC7, 0xAEC7}, {0xAEC8, 0xAEC8, 0xAEC8}, {0xAEC9, 0xAEC9, 0xAEC9}, {0xAECA, 0xAECA, 0xAECA}, {0xAECB, 0xAECB, 0xAECB}, {0xAECC, 0xAECC, 0xAECC}, {0xAECD, 0xAECD, 0xAECD}, {0xAECE, 0xAECE, 0xAECE}, {0xAECF, 0xAECF, 0xAECF}, {0xAED0, 0xAED0, 0xAED0}, {0xAED1, 0xAED1, 0xAED1}, {0xAED2, 0xAED2, 0xAED2}, {0xAED3, 0xAED3, 0xAED3}, {0xAED4, 0xAED4, 0xAED4}, {0xAED5, 0xAED5, 0xAED5}, {0xAED6, 0xAED6, 0xAED6}, {0xAED7, 0xAED7, 0xAED7}, {0xAED8, 0xAED8, 0xAED8}, {0xAED9, 0xAED9, 0xAED9}, {0xAEDA, 0xAEDA, 0xAEDA}, {0xAEDB, 0xAEDB, 0xAEDB}, {0xAEDC, 0xAEDC, 0xAEDC}, {0xAEDD, 0xAEDD, 0xAEDD}, {0xAEDE, 0xAEDE, 0xAEDE}, {0xAEDF, 0xAEDF, 0xAEDF}, {0xAEE0, 0xAEE0, 0xAEE0}, {0xAEE1, 0xAEE1, 0xAEE1}, {0xAEE2, 0xAEE2, 0xAEE2}, {0xAEE3, 0xAEE3, 0xAEE3}, {0xAEE4, 0xAEE4, 0xAEE4}, {0xAEE5, 0xAEE5, 0xAEE5}, {0xAEE6, 0xAEE6, 0xAEE6}, {0xAEE7, 0xAEE7, 0xAEE7}, {0xAEE8, 0xAEE8, 0xAEE8}, {0xAEE9, 0xAEE9, 0xAEE9}, {0xAEEA, 0xAEEA, 0xAEEA}, {0xAEEB, 0xAEEB, 0xAEEB}, {0xAEEC, 0xAEEC, 0xAEEC}, {0xAEED, 0xAEED, 0xAEED}, {0xAEEE, 0xAEEE, 0xAEEE}, {0xAEEF, 0xAEEF, 0xAEEF}, {0xAEF0, 0xAEF0, 0xAEF0}, {0xAEF1, 0xAEF1, 0xAEF1}, {0xAEF2, 0xAEF2, 0xAEF2}, {0xAEF3, 0xAEF3, 0xAEF3}, {0xAEF4, 0xAEF4, 0xAEF4}, {0xAEF5, 0xAEF5, 0xAEF5}, {0xAEF6, 0xAEF6, 0xAEF6}, {0xAEF7, 0xAEF7, 0xAEF7}, {0xAEF8, 0xAEF8, 0xAEF8}, {0xAEF9, 0xAEF9, 0xAEF9}, {0xAEFA, 0xAEFA, 0xAEFA}, {0xAEFB, 0xAEFB, 0xAEFB}, {0xAEFC, 0xAEFC, 0xAEFC}, {0xAEFD, 0xAEFD, 0xAEFD}, {0xAEFE, 0xAEFE, 0xAEFE}, {0xAEFF, 0xAEFF, 0xAEFF}, {0xAF00, 0xAF00, 0xAF00}, {0xAF01, 0xAF01, 0xAF01}, {0xAF02, 0xAF02, 0xAF02}, {0xAF03, 0xAF03, 0xAF03}, {0xAF04, 0xAF04, 0xAF04}, {0xAF05, 0xAF05, 0xAF05}, {0xAF06, 0xAF06, 0xAF06}, {0xAF07, 0xAF07, 0xAF07}, {0xAF08, 0xAF08, 0xAF08}, {0xAF09, 0xAF09, 0xAF09}, {0xAF0A, 0xAF0A, 0xAF0A}, {0xAF0B, 0xAF0B, 0xAF0B}, {0xAF0C, 0xAF0C, 0xAF0C}, {0xAF0D, 0xAF0D, 0xAF0D}, {0xAF0E, 0xAF0E, 0xAF0E}, {0xAF0F, 0xAF0F, 0xAF0F}, {0xAF10, 0xAF10, 0xAF10}, {0xAF11, 0xAF11, 0xAF11}, {0xAF12, 0xAF12, 0xAF12}, {0xAF13, 0xAF13, 0xAF13}, {0xAF14, 0xAF14, 0xAF14}, {0xAF15, 0xAF15, 0xAF15}, {0xAF16, 0xAF16, 0xAF16}, {0xAF17, 0xAF17, 0xAF17}, {0xAF18, 0xAF18, 0xAF18}, {0xAF19, 0xAF19, 0xAF19}, {0xAF1A, 0xAF1A, 0xAF1A}, {0xAF1B, 0xAF1B, 0xAF1B}, {0xAF1C, 0xAF1C, 0xAF1C}, {0xAF1D, 0xAF1D, 0xAF1D}, {0xAF1E, 0xAF1E, 0xAF1E}, {0xAF1F, 0xAF1F, 0xAF1F}, {0xAF20, 0xAF20, 0xAF20}, {0xAF21, 0xAF21, 0xAF21}, {0xAF22, 0xAF22, 0xAF22}, {0xAF23, 0xAF23, 0xAF23}, {0xAF24, 0xAF24, 0xAF24}, {0xAF25, 0xAF25, 0xAF25}, {0xAF26, 0xAF26, 0xAF26}, {0xAF27, 0xAF27, 0xAF27}, {0xAF28, 0xAF28, 0xAF28}, {0xAF29, 0xAF29, 0xAF29}, {0xAF2A, 0xAF2A, 0xAF2A}, {0xAF2B, 0xAF2B, 0xAF2B}, {0xAF2C, 0xAF2C, 0xAF2C}, {0xAF2D, 0xAF2D, 0xAF2D}, {0xAF2E, 0xAF2E, 0xAF2E}, {0xAF2F, 0xAF2F, 0xAF2F}, {0xAF30, 0xAF30, 0xAF30}, {0xAF31, 0xAF31, 0xAF31}, {0xAF32, 0xAF32, 0xAF32}, {0xAF33, 0xAF33, 0xAF33}, {0xAF34, 0xAF34, 0xAF34}, {0xAF35, 0xAF35, 0xAF35}, {0xAF36, 0xAF36, 0xAF36}, {0xAF37, 0xAF37, 0xAF37}, {0xAF38, 0xAF38, 0xAF38}, {0xAF39, 0xAF39, 0xAF39}, {0xAF3A, 0xAF3A, 0xAF3A}, {0xAF3B, 0xAF3B, 0xAF3B}, {0xAF3C, 0xAF3C, 0xAF3C}, {0xAF3D, 0xAF3D, 0xAF3D}, {0xAF3E, 0xAF3E, 0xAF3E}, {0xAF3F, 0xAF3F, 0xAF3F}, {0xAF40, 0xAF40, 0xAF40}, {0xAF41, 0xAF41, 0xAF41}, {0xAF42, 0xAF42, 0xAF42}, {0xAF43, 0xAF43, 0xAF43}, {0xAF44, 0xAF44, 0xAF44}, {0xAF45, 0xAF45, 0xAF45}, {0xAF46, 0xAF46, 0xAF46}, {0xAF47, 0xAF47, 0xAF47}, {0xAF48, 0xAF48, 0xAF48}, {0xAF49, 0xAF49, 0xAF49}, {0xAF4A, 0xAF4A, 0xAF4A}, {0xAF4B, 0xAF4B, 0xAF4B}, {0xAF4C, 0xAF4C, 0xAF4C}, {0xAF4D, 0xAF4D, 0xAF4D}, {0xAF4E, 0xAF4E, 0xAF4E}, {0xAF4F, 0xAF4F, 0xAF4F}, {0xAF50, 0xAF50, 0xAF50}, {0xAF51, 0xAF51, 0xAF51}, {0xAF52, 0xAF52, 0xAF52}, {0xAF53, 0xAF53, 0xAF53}, {0xAF54, 0xAF54, 0xAF54}, {0xAF55, 0xAF55, 0xAF55}, {0xAF56, 0xAF56, 0xAF56}, {0xAF57, 0xAF57, 0xAF57}, {0xAF58, 0xAF58, 0xAF58}, {0xAF59, 0xAF59, 0xAF59}, {0xAF5A, 0xAF5A, 0xAF5A}, {0xAF5B, 0xAF5B, 0xAF5B}, {0xAF5C, 0xAF5C, 0xAF5C}, {0xAF5D, 0xAF5D, 0xAF5D}, {0xAF5E, 0xAF5E, 0xAF5E}, {0xAF5F, 0xAF5F, 0xAF5F}, {0xAF60, 0xAF60, 0xAF60}, {0xAF61, 0xAF61, 0xAF61}, {0xAF62, 0xAF62, 0xAF62}, {0xAF63, 0xAF63, 0xAF63}, {0xAF64, 0xAF64, 0xAF64}, {0xAF65, 0xAF65, 0xAF65}, {0xAF66, 0xAF66, 0xAF66}, {0xAF67, 0xAF67, 0xAF67}, {0xAF68, 0xAF68, 0xAF68}, {0xAF69, 0xAF69, 0xAF69}, {0xAF6A, 0xAF6A, 0xAF6A}, {0xAF6B, 0xAF6B, 0xAF6B}, {0xAF6C, 0xAF6C, 0xAF6C}, {0xAF6D, 0xAF6D, 0xAF6D}, {0xAF6E, 0xAF6E, 0xAF6E}, {0xAF6F, 0xAF6F, 0xAF6F}, {0xAF70, 0xAF70, 0xAF70}, {0xAF71, 0xAF71, 0xAF71}, {0xAF72, 0xAF72, 0xAF72}, {0xAF73, 0xAF73, 0xAF73}, {0xAF74, 0xAF74, 0xAF74}, {0xAF75, 0xAF75, 0xAF75}, {0xAF76, 0xAF76, 0xAF76}, {0xAF77, 0xAF77, 0xAF77}, {0xAF78, 0xAF78, 0xAF78}, {0xAF79, 0xAF79, 0xAF79}, {0xAF7A, 0xAF7A, 0xAF7A}, {0xAF7B, 0xAF7B, 0xAF7B}, {0xAF7C, 0xAF7C, 0xAF7C}, {0xAF7D, 0xAF7D, 0xAF7D}, {0xAF7E, 0xAF7E, 0xAF7E}, {0xAF7F, 0xAF7F, 0xAF7F}, {0xAF80, 0xAF80, 0xAF80}, {0xAF81, 0xAF81, 0xAF81}, {0xAF82, 0xAF82, 0xAF82}, {0xAF83, 0xAF83, 0xAF83}, {0xAF84, 0xAF84, 0xAF84}, {0xAF85, 0xAF85, 0xAF85}, {0xAF86, 0xAF86, 0xAF86}, {0xAF87, 0xAF87, 0xAF87}, {0xAF88, 0xAF88, 0xAF88}, {0xAF89, 0xAF89, 0xAF89}, {0xAF8A, 0xAF8A, 0xAF8A}, {0xAF8B, 0xAF8B, 0xAF8B}, {0xAF8C, 0xAF8C, 0xAF8C}, {0xAF8D, 0xAF8D, 0xAF8D}, {0xAF8E, 0xAF8E, 0xAF8E}, {0xAF8F, 0xAF8F, 0xAF8F}, {0xAF90, 0xAF90, 0xAF90}, {0xAF91, 0xAF91, 0xAF91}, {0xAF92, 0xAF92, 0xAF92}, {0xAF93, 0xAF93, 0xAF93}, {0xAF94, 0xAF94, 0xAF94}, {0xAF95, 0xAF95, 0xAF95}, {0xAF96, 0xAF96, 0xAF96}, {0xAF97, 0xAF97, 0xAF97}, {0xAF98, 0xAF98, 0xAF98}, {0xAF99, 0xAF99, 0xAF99}, {0xAF9A, 0xAF9A, 0xAF9A}, {0xAF9B, 0xAF9B, 0xAF9B}, {0xAF9C, 0xAF9C, 0xAF9C}, {0xAF9D, 0xAF9D, 0xAF9D}, {0xAF9E, 0xAF9E, 0xAF9E}, {0xAF9F, 0xAF9F, 0xAF9F}, {0xAFA0, 0xAFA0, 0xAFA0}, {0xAFA1, 0xAFA1, 0xAFA1}, {0xAFA2, 0xAFA2, 0xAFA2}, {0xAFA3, 0xAFA3, 0xAFA3}, {0xAFA4, 0xAFA4, 0xAFA4}, {0xAFA5, 0xAFA5, 0xAFA5}, {0xAFA6, 0xAFA6, 0xAFA6}, {0xAFA7, 0xAFA7, 0xAFA7}, {0xAFA8, 0xAFA8, 0xAFA8}, {0xAFA9, 0xAFA9, 0xAFA9}, {0xAFAA, 0xAFAA, 0xAFAA}, {0xAFAB, 0xAFAB, 0xAFAB}, {0xAFAC, 0xAFAC, 0xAFAC}, {0xAFAD, 0xAFAD, 0xAFAD}, {0xAFAE, 0xAFAE, 0xAFAE}, {0xAFAF, 0xAFAF, 0xAFAF}, {0xAFB0, 0xAFB0, 0xAFB0}, {0xAFB1, 0xAFB1, 0xAFB1}, {0xAFB2, 0xAFB2, 0xAFB2}, {0xAFB3, 0xAFB3, 0xAFB3}, {0xAFB4, 0xAFB4, 0xAFB4}, {0xAFB5, 0xAFB5, 0xAFB5}, {0xAFB6, 0xAFB6, 0xAFB6}, {0xAFB7, 0xAFB7, 0xAFB7}, {0xAFB8, 0xAFB8, 0xAFB8}, {0xAFB9, 0xAFB9, 0xAFB9}, {0xAFBA, 0xAFBA, 0xAFBA}, {0xAFBB, 0xAFBB, 0xAFBB}, {0xAFBC, 0xAFBC, 0xAFBC}, {0xAFBD, 0xAFBD, 0xAFBD}, {0xAFBE, 0xAFBE, 0xAFBE}, {0xAFBF, 0xAFBF, 0xAFBF}, {0xAFC0, 0xAFC0, 0xAFC0}, {0xAFC1, 0xAFC1, 0xAFC1}, {0xAFC2, 0xAFC2, 0xAFC2}, {0xAFC3, 0xAFC3, 0xAFC3}, {0xAFC4, 0xAFC4, 0xAFC4}, {0xAFC5, 0xAFC5, 0xAFC5}, {0xAFC6, 0xAFC6, 0xAFC6}, {0xAFC7, 0xAFC7, 0xAFC7}, {0xAFC8, 0xAFC8, 0xAFC8}, {0xAFC9, 0xAFC9, 0xAFC9}, {0xAFCA, 0xAFCA, 0xAFCA}, {0xAFCB, 0xAFCB, 0xAFCB}, {0xAFCC, 0xAFCC, 0xAFCC}, {0xAFCD, 0xAFCD, 0xAFCD}, {0xAFCE, 0xAFCE, 0xAFCE}, {0xAFCF, 0xAFCF, 0xAFCF}, {0xAFD0, 0xAFD0, 0xAFD0}, {0xAFD1, 0xAFD1, 0xAFD1}, {0xAFD2, 0xAFD2, 0xAFD2}, {0xAFD3, 0xAFD3, 0xAFD3}, {0xAFD4, 0xAFD4, 0xAFD4}, {0xAFD5, 0xAFD5, 0xAFD5}, {0xAFD6, 0xAFD6, 0xAFD6}, {0xAFD7, 0xAFD7, 0xAFD7}, {0xAFD8, 0xAFD8, 0xAFD8}, {0xAFD9, 0xAFD9, 0xAFD9}, {0xAFDA, 0xAFDA, 0xAFDA}, {0xAFDB, 0xAFDB, 0xAFDB}, {0xAFDC, 0xAFDC, 0xAFDC}, {0xAFDD, 0xAFDD, 0xAFDD}, {0xAFDE, 0xAFDE, 0xAFDE}, {0xAFDF, 0xAFDF, 0xAFDF}, {0xAFE0, 0xAFE0, 0xAFE0}, {0xAFE1, 0xAFE1, 0xAFE1}, {0xAFE2, 0xAFE2, 0xAFE2}, {0xAFE3, 0xAFE3, 0xAFE3}, {0xAFE4, 0xAFE4, 0xAFE4}, {0xAFE5, 0xAFE5, 0xAFE5}, {0xAFE6, 0xAFE6, 0xAFE6}, {0xAFE7, 0xAFE7, 0xAFE7}, {0xAFE8, 0xAFE8, 0xAFE8}, {0xAFE9, 0xAFE9, 0xAFE9}, {0xAFEA, 0xAFEA, 0xAFEA}, {0xAFEB, 0xAFEB, 0xAFEB}, {0xAFEC, 0xAFEC, 0xAFEC}, {0xAFED, 0xAFED, 0xAFED}, {0xAFEE, 0xAFEE, 0xAFEE}, {0xAFEF, 0xAFEF, 0xAFEF}, {0xAFF0, 0xAFF0, 0xAFF0}, {0xAFF1, 0xAFF1, 0xAFF1}, {0xAFF2, 0xAFF2, 0xAFF2}, {0xAFF3, 0xAFF3, 0xAFF3}, {0xAFF4, 0xAFF4, 0xAFF4}, {0xAFF5, 0xAFF5, 0xAFF5}, {0xAFF6, 0xAFF6, 0xAFF6}, {0xAFF7, 0xAFF7, 0xAFF7}, {0xAFF8, 0xAFF8, 0xAFF8}, {0xAFF9, 0xAFF9, 0xAFF9}, {0xAFFA, 0xAFFA, 0xAFFA}, {0xAFFB, 0xAFFB, 0xAFFB}, {0xAFFC, 0xAFFC, 0xAFFC}, {0xAFFD, 0xAFFD, 0xAFFD}, {0xAFFE, 0xAFFE, 0xAFFE}, {0xAFFF, 0xAFFF, 0xAFFF}, {0xB000, 0xB000, 0xB000}, {0xB001, 0xB001, 0xB001}, {0xB002, 0xB002, 0xB002}, {0xB003, 0xB003, 0xB003}, {0xB004, 0xB004, 0xB004}, {0xB005, 0xB005, 0xB005}, {0xB006, 0xB006, 0xB006}, {0xB007, 0xB007, 0xB007}, {0xB008, 0xB008, 0xB008}, {0xB009, 0xB009, 0xB009}, {0xB00A, 0xB00A, 0xB00A}, {0xB00B, 0xB00B, 0xB00B}, {0xB00C, 0xB00C, 0xB00C}, {0xB00D, 0xB00D, 0xB00D}, {0xB00E, 0xB00E, 0xB00E}, {0xB00F, 0xB00F, 0xB00F}, {0xB010, 0xB010, 0xB010}, {0xB011, 0xB011, 0xB011}, {0xB012, 0xB012, 0xB012}, {0xB013, 0xB013, 0xB013}, {0xB014, 0xB014, 0xB014}, {0xB015, 0xB015, 0xB015}, {0xB016, 0xB016, 0xB016}, {0xB017, 0xB017, 0xB017}, {0xB018, 0xB018, 0xB018}, {0xB019, 0xB019, 0xB019}, {0xB01A, 0xB01A, 0xB01A}, {0xB01B, 0xB01B, 0xB01B}, {0xB01C, 0xB01C, 0xB01C}, {0xB01D, 0xB01D, 0xB01D}, {0xB01E, 0xB01E, 0xB01E}, {0xB01F, 0xB01F, 0xB01F}, {0xB020, 0xB020, 0xB020}, {0xB021, 0xB021, 0xB021}, {0xB022, 0xB022, 0xB022}, {0xB023, 0xB023, 0xB023}, {0xB024, 0xB024, 0xB024}, {0xB025, 0xB025, 0xB025}, {0xB026, 0xB026, 0xB026}, {0xB027, 0xB027, 0xB027}, {0xB028, 0xB028, 0xB028}, {0xB029, 0xB029, 0xB029}, {0xB02A, 0xB02A, 0xB02A}, {0xB02B, 0xB02B, 0xB02B}, {0xB02C, 0xB02C, 0xB02C}, {0xB02D, 0xB02D, 0xB02D}, {0xB02E, 0xB02E, 0xB02E}, {0xB02F, 0xB02F, 0xB02F}, {0xB030, 0xB030, 0xB030}, {0xB031, 0xB031, 0xB031}, {0xB032, 0xB032, 0xB032}, {0xB033, 0xB033, 0xB033}, {0xB034, 0xB034, 0xB034}, {0xB035, 0xB035, 0xB035}, {0xB036, 0xB036, 0xB036}, {0xB037, 0xB037, 0xB037}, {0xB038, 0xB038, 0xB038}, {0xB039, 0xB039, 0xB039}, {0xB03A, 0xB03A, 0xB03A}, {0xB03B, 0xB03B, 0xB03B}, {0xB03C, 0xB03C, 0xB03C}, {0xB03D, 0xB03D, 0xB03D}, {0xB03E, 0xB03E, 0xB03E}, {0xB03F, 0xB03F, 0xB03F}, {0xB040, 0xB040, 0xB040}, {0xB041, 0xB041, 0xB041}, {0xB042, 0xB042, 0xB042}, {0xB043, 0xB043, 0xB043}, {0xB044, 0xB044, 0xB044}, {0xB045, 0xB045, 0xB045}, {0xB046, 0xB046, 0xB046}, {0xB047, 0xB047, 0xB047}, {0xB048, 0xB048, 0xB048}, {0xB049, 0xB049, 0xB049}, {0xB04A, 0xB04A, 0xB04A}, {0xB04B, 0xB04B, 0xB04B}, {0xB04C, 0xB04C, 0xB04C}, {0xB04D, 0xB04D, 0xB04D}, {0xB04E, 0xB04E, 0xB04E}, {0xB04F, 0xB04F, 0xB04F}, {0xB050, 0xB050, 0xB050}, {0xB051, 0xB051, 0xB051}, {0xB052, 0xB052, 0xB052}, {0xB053, 0xB053, 0xB053}, {0xB054, 0xB054, 0xB054}, {0xB055, 0xB055, 0xB055}, {0xB056, 0xB056, 0xB056}, {0xB057, 0xB057, 0xB057}, {0xB058, 0xB058, 0xB058}, {0xB059, 0xB059, 0xB059}, {0xB05A, 0xB05A, 0xB05A}, {0xB05B, 0xB05B, 0xB05B}, {0xB05C, 0xB05C, 0xB05C}, {0xB05D, 0xB05D, 0xB05D}, {0xB05E, 0xB05E, 0xB05E}, {0xB05F, 0xB05F, 0xB05F}, {0xB060, 0xB060, 0xB060}, {0xB061, 0xB061, 0xB061}, {0xB062, 0xB062, 0xB062}, {0xB063, 0xB063, 0xB063}, {0xB064, 0xB064, 0xB064}, {0xB065, 0xB065, 0xB065}, {0xB066, 0xB066, 0xB066}, {0xB067, 0xB067, 0xB067}, {0xB068, 0xB068, 0xB068}, {0xB069, 0xB069, 0xB069}, {0xB06A, 0xB06A, 0xB06A}, {0xB06B, 0xB06B, 0xB06B}, {0xB06C, 0xB06C, 0xB06C}, {0xB06D, 0xB06D, 0xB06D}, {0xB06E, 0xB06E, 0xB06E}, {0xB06F, 0xB06F, 0xB06F}, {0xB070, 0xB070, 0xB070}, {0xB071, 0xB071, 0xB071}, {0xB072, 0xB072, 0xB072}, {0xB073, 0xB073, 0xB073}, {0xB074, 0xB074, 0xB074}, {0xB075, 0xB075, 0xB075}, {0xB076, 0xB076, 0xB076}, {0xB077, 0xB077, 0xB077}, {0xB078, 0xB078, 0xB078}, {0xB079, 0xB079, 0xB079}, {0xB07A, 0xB07A, 0xB07A}, {0xB07B, 0xB07B, 0xB07B}, {0xB07C, 0xB07C, 0xB07C}, {0xB07D, 0xB07D, 0xB07D}, {0xB07E, 0xB07E, 0xB07E}, {0xB07F, 0xB07F, 0xB07F}, {0xB080, 0xB080, 0xB080}, {0xB081, 0xB081, 0xB081}, {0xB082, 0xB082, 0xB082}, {0xB083, 0xB083, 0xB083}, {0xB084, 0xB084, 0xB084}, {0xB085, 0xB085, 0xB085}, {0xB086, 0xB086, 0xB086}, {0xB087, 0xB087, 0xB087}, {0xB088, 0xB088, 0xB088}, {0xB089, 0xB089, 0xB089}, {0xB08A, 0xB08A, 0xB08A}, {0xB08B, 0xB08B, 0xB08B}, {0xB08C, 0xB08C, 0xB08C}, {0xB08D, 0xB08D, 0xB08D}, {0xB08E, 0xB08E, 0xB08E}, {0xB08F, 0xB08F, 0xB08F}, {0xB090, 0xB090, 0xB090}, {0xB091, 0xB091, 0xB091}, {0xB092, 0xB092, 0xB092}, {0xB093, 0xB093, 0xB093}, {0xB094, 0xB094, 0xB094}, {0xB095, 0xB095, 0xB095}, {0xB096, 0xB096, 0xB096}, {0xB097, 0xB097, 0xB097}, {0xB098, 0xB098, 0xB098}, {0xB099, 0xB099, 0xB099}, {0xB09A, 0xB09A, 0xB09A}, {0xB09B, 0xB09B, 0xB09B}, {0xB09C, 0xB09C, 0xB09C}, {0xB09D, 0xB09D, 0xB09D}, {0xB09E, 0xB09E, 0xB09E}, {0xB09F, 0xB09F, 0xB09F}, {0xB0A0, 0xB0A0, 0xB0A0}, {0xB0A1, 0xB0A1, 0xB0A1}, {0xB0A2, 0xB0A2, 0xB0A2}, {0xB0A3, 0xB0A3, 0xB0A3}, {0xB0A4, 0xB0A4, 0xB0A4}, {0xB0A5, 0xB0A5, 0xB0A5}, {0xB0A6, 0xB0A6, 0xB0A6}, {0xB0A7, 0xB0A7, 0xB0A7}, {0xB0A8, 0xB0A8, 0xB0A8}, {0xB0A9, 0xB0A9, 0xB0A9}, {0xB0AA, 0xB0AA, 0xB0AA}, {0xB0AB, 0xB0AB, 0xB0AB}, {0xB0AC, 0xB0AC, 0xB0AC}, {0xB0AD, 0xB0AD, 0xB0AD}, {0xB0AE, 0xB0AE, 0xB0AE}, {0xB0AF, 0xB0AF, 0xB0AF}, {0xB0B0, 0xB0B0, 0xB0B0}, {0xB0B1, 0xB0B1, 0xB0B1}, {0xB0B2, 0xB0B2, 0xB0B2}, {0xB0B3, 0xB0B3, 0xB0B3}, {0xB0B4, 0xB0B4, 0xB0B4}, {0xB0B5, 0xB0B5, 0xB0B5}, {0xB0B6, 0xB0B6, 0xB0B6}, {0xB0B7, 0xB0B7, 0xB0B7}, {0xB0B8, 0xB0B8, 0xB0B8}, {0xB0B9, 0xB0B9, 0xB0B9}, {0xB0BA, 0xB0BA, 0xB0BA}, {0xB0BB, 0xB0BB, 0xB0BB}, {0xB0BC, 0xB0BC, 0xB0BC}, {0xB0BD, 0xB0BD, 0xB0BD}, {0xB0BE, 0xB0BE, 0xB0BE}, {0xB0BF, 0xB0BF, 0xB0BF}, {0xB0C0, 0xB0C0, 0xB0C0}, {0xB0C1, 0xB0C1, 0xB0C1}, {0xB0C2, 0xB0C2, 0xB0C2}, {0xB0C3, 0xB0C3, 0xB0C3}, {0xB0C4, 0xB0C4, 0xB0C4}, {0xB0C5, 0xB0C5, 0xB0C5}, {0xB0C6, 0xB0C6, 0xB0C6}, {0xB0C7, 0xB0C7, 0xB0C7}, {0xB0C8, 0xB0C8, 0xB0C8}, {0xB0C9, 0xB0C9, 0xB0C9}, {0xB0CA, 0xB0CA, 0xB0CA}, {0xB0CB, 0xB0CB, 0xB0CB}, {0xB0CC, 0xB0CC, 0xB0CC}, {0xB0CD, 0xB0CD, 0xB0CD}, {0xB0CE, 0xB0CE, 0xB0CE}, {0xB0CF, 0xB0CF, 0xB0CF}, {0xB0D0, 0xB0D0, 0xB0D0}, {0xB0D1, 0xB0D1, 0xB0D1}, {0xB0D2, 0xB0D2, 0xB0D2}, {0xB0D3, 0xB0D3, 0xB0D3}, {0xB0D4, 0xB0D4, 0xB0D4}, {0xB0D5, 0xB0D5, 0xB0D5}, {0xB0D6, 0xB0D6, 0xB0D6}, {0xB0D7, 0xB0D7, 0xB0D7}, {0xB0D8, 0xB0D8, 0xB0D8}, {0xB0D9, 0xB0D9, 0xB0D9}, {0xB0DA, 0xB0DA, 0xB0DA}, {0xB0DB, 0xB0DB, 0xB0DB}, {0xB0DC, 0xB0DC, 0xB0DC}, {0xB0DD, 0xB0DD, 0xB0DD}, {0xB0DE, 0xB0DE, 0xB0DE}, {0xB0DF, 0xB0DF, 0xB0DF}, {0xB0E0, 0xB0E0, 0xB0E0}, {0xB0E1, 0xB0E1, 0xB0E1}, {0xB0E2, 0xB0E2, 0xB0E2}, {0xB0E3, 0xB0E3, 0xB0E3}, {0xB0E4, 0xB0E4, 0xB0E4}, {0xB0E5, 0xB0E5, 0xB0E5}, {0xB0E6, 0xB0E6, 0xB0E6}, {0xB0E7, 0xB0E7, 0xB0E7}, {0xB0E8, 0xB0E8, 0xB0E8}, {0xB0E9, 0xB0E9, 0xB0E9}, {0xB0EA, 0xB0EA, 0xB0EA}, {0xB0EB, 0xB0EB, 0xB0EB}, {0xB0EC, 0xB0EC, 0xB0EC}, {0xB0ED, 0xB0ED, 0xB0ED}, {0xB0EE, 0xB0EE, 0xB0EE}, {0xB0EF, 0xB0EF, 0xB0EF}, {0xB0F0, 0xB0F0, 0xB0F0}, {0xB0F1, 0xB0F1, 0xB0F1}, {0xB0F2, 0xB0F2, 0xB0F2}, {0xB0F3, 0xB0F3, 0xB0F3}, {0xB0F4, 0xB0F4, 0xB0F4}, {0xB0F5, 0xB0F5, 0xB0F5}, {0xB0F6, 0xB0F6, 0xB0F6}, {0xB0F7, 0xB0F7, 0xB0F7}, {0xB0F8, 0xB0F8, 0xB0F8}, {0xB0F9, 0xB0F9, 0xB0F9}, {0xB0FA, 0xB0FA, 0xB0FA}, {0xB0FB, 0xB0FB, 0xB0FB}, {0xB0FC, 0xB0FC, 0xB0FC}, {0xB0FD, 0xB0FD, 0xB0FD}, {0xB0FE, 0xB0FE, 0xB0FE}, {0xB0FF, 0xB0FF, 0xB0FF}, {0xB100, 0xB100, 0xB100}, {0xB101, 0xB101, 0xB101}, {0xB102, 0xB102, 0xB102}, {0xB103, 0xB103, 0xB103}, {0xB104, 0xB104, 0xB104}, {0xB105, 0xB105, 0xB105}, {0xB106, 0xB106, 0xB106}, {0xB107, 0xB107, 0xB107}, {0xB108, 0xB108, 0xB108}, {0xB109, 0xB109, 0xB109}, {0xB10A, 0xB10A, 0xB10A}, {0xB10B, 0xB10B, 0xB10B}, {0xB10C, 0xB10C, 0xB10C}, {0xB10D, 0xB10D, 0xB10D}, {0xB10E, 0xB10E, 0xB10E}, {0xB10F, 0xB10F, 0xB10F}, {0xB110, 0xB110, 0xB110}, {0xB111, 0xB111, 0xB111}, {0xB112, 0xB112, 0xB112}, {0xB113, 0xB113, 0xB113}, {0xB114, 0xB114, 0xB114}, {0xB115, 0xB115, 0xB115}, {0xB116, 0xB116, 0xB116}, {0xB117, 0xB117, 0xB117}, {0xB118, 0xB118, 0xB118}, {0xB119, 0xB119, 0xB119}, {0xB11A, 0xB11A, 0xB11A}, {0xB11B, 0xB11B, 0xB11B}, {0xB11C, 0xB11C, 0xB11C}, {0xB11D, 0xB11D, 0xB11D}, {0xB11E, 0xB11E, 0xB11E}, {0xB11F, 0xB11F, 0xB11F}, {0xB120, 0xB120, 0xB120}, {0xB121, 0xB121, 0xB121}, {0xB122, 0xB122, 0xB122}, {0xB123, 0xB123, 0xB123}, {0xB124, 0xB124, 0xB124}, {0xB125, 0xB125, 0xB125}, {0xB126, 0xB126, 0xB126}, {0xB127, 0xB127, 0xB127}, {0xB128, 0xB128, 0xB128}, {0xB129, 0xB129, 0xB129}, {0xB12A, 0xB12A, 0xB12A}, {0xB12B, 0xB12B, 0xB12B}, {0xB12C, 0xB12C, 0xB12C}, {0xB12D, 0xB12D, 0xB12D}, {0xB12E, 0xB12E, 0xB12E}, {0xB12F, 0xB12F, 0xB12F}, {0xB130, 0xB130, 0xB130}, {0xB131, 0xB131, 0xB131}, {0xB132, 0xB132, 0xB132}, {0xB133, 0xB133, 0xB133}, {0xB134, 0xB134, 0xB134}, {0xB135, 0xB135, 0xB135}, {0xB136, 0xB136, 0xB136}, {0xB137, 0xB137, 0xB137}, {0xB138, 0xB138, 0xB138}, {0xB139, 0xB139, 0xB139}, {0xB13A, 0xB13A, 0xB13A}, {0xB13B, 0xB13B, 0xB13B}, {0xB13C, 0xB13C, 0xB13C}, {0xB13D, 0xB13D, 0xB13D}, {0xB13E, 0xB13E, 0xB13E}, {0xB13F, 0xB13F, 0xB13F}, {0xB140, 0xB140, 0xB140}, {0xB141, 0xB141, 0xB141}, {0xB142, 0xB142, 0xB142}, {0xB143, 0xB143, 0xB143}, {0xB144, 0xB144, 0xB144}, {0xB145, 0xB145, 0xB145}, {0xB146, 0xB146, 0xB146}, {0xB147, 0xB147, 0xB147}, {0xB148, 0xB148, 0xB148}, {0xB149, 0xB149, 0xB149}, {0xB14A, 0xB14A, 0xB14A}, {0xB14B, 0xB14B, 0xB14B}, {0xB14C, 0xB14C, 0xB14C}, {0xB14D, 0xB14D, 0xB14D}, {0xB14E, 0xB14E, 0xB14E}, {0xB14F, 0xB14F, 0xB14F}, {0xB150, 0xB150, 0xB150}, {0xB151, 0xB151, 0xB151}, {0xB152, 0xB152, 0xB152}, {0xB153, 0xB153, 0xB153}, {0xB154, 0xB154, 0xB154}, {0xB155, 0xB155, 0xB155}, {0xB156, 0xB156, 0xB156}, {0xB157, 0xB157, 0xB157}, {0xB158, 0xB158, 0xB158}, {0xB159, 0xB159, 0xB159}, {0xB15A, 0xB15A, 0xB15A}, {0xB15B, 0xB15B, 0xB15B}, {0xB15C, 0xB15C, 0xB15C}, {0xB15D, 0xB15D, 0xB15D}, {0xB15E, 0xB15E, 0xB15E}, {0xB15F, 0xB15F, 0xB15F}, {0xB160, 0xB160, 0xB160}, {0xB161, 0xB161, 0xB161}, {0xB162, 0xB162, 0xB162}, {0xB163, 0xB163, 0xB163}, {0xB164, 0xB164, 0xB164}, {0xB165, 0xB165, 0xB165}, {0xB166, 0xB166, 0xB166}, {0xB167, 0xB167, 0xB167}, {0xB168, 0xB168, 0xB168}, {0xB169, 0xB169, 0xB169}, {0xB16A, 0xB16A, 0xB16A}, {0xB16B, 0xB16B, 0xB16B}, {0xB16C, 0xB16C, 0xB16C}, {0xB16D, 0xB16D, 0xB16D}, {0xB16E, 0xB16E, 0xB16E}, {0xB16F, 0xB16F, 0xB16F}, {0xB170, 0xB170, 0xB170}, {0xB171, 0xB171, 0xB171}, {0xB172, 0xB172, 0xB172}, {0xB173, 0xB173, 0xB173}, {0xB174, 0xB174, 0xB174}, {0xB175, 0xB175, 0xB175}, {0xB176, 0xB176, 0xB176}, {0xB177, 0xB177, 0xB177}, {0xB178, 0xB178, 0xB178}, {0xB179, 0xB179, 0xB179}, {0xB17A, 0xB17A, 0xB17A}, {0xB17B, 0xB17B, 0xB17B}, {0xB17C, 0xB17C, 0xB17C}, {0xB17D, 0xB17D, 0xB17D}, {0xB17E, 0xB17E, 0xB17E}, {0xB17F, 0xB17F, 0xB17F}, {0xB180, 0xB180, 0xB180}, {0xB181, 0xB181, 0xB181}, {0xB182, 0xB182, 0xB182}, {0xB183, 0xB183, 0xB183}, {0xB184, 0xB184, 0xB184}, {0xB185, 0xB185, 0xB185}, {0xB186, 0xB186, 0xB186}, {0xB187, 0xB187, 0xB187}, {0xB188, 0xB188, 0xB188}, {0xB189, 0xB189, 0xB189}, {0xB18A, 0xB18A, 0xB18A}, {0xB18B, 0xB18B, 0xB18B}, {0xB18C, 0xB18C, 0xB18C}, {0xB18D, 0xB18D, 0xB18D}, {0xB18E, 0xB18E, 0xB18E}, {0xB18F, 0xB18F, 0xB18F}, {0xB190, 0xB190, 0xB190}, {0xB191, 0xB191, 0xB191}, {0xB192, 0xB192, 0xB192}, {0xB193, 0xB193, 0xB193}, {0xB194, 0xB194, 0xB194}, {0xB195, 0xB195, 0xB195}, {0xB196, 0xB196, 0xB196}, {0xB197, 0xB197, 0xB197}, {0xB198, 0xB198, 0xB198}, {0xB199, 0xB199, 0xB199}, {0xB19A, 0xB19A, 0xB19A}, {0xB19B, 0xB19B, 0xB19B}, {0xB19C, 0xB19C, 0xB19C}, {0xB19D, 0xB19D, 0xB19D}, {0xB19E, 0xB19E, 0xB19E}, {0xB19F, 0xB19F, 0xB19F}, {0xB1A0, 0xB1A0, 0xB1A0}, {0xB1A1, 0xB1A1, 0xB1A1}, {0xB1A2, 0xB1A2, 0xB1A2}, {0xB1A3, 0xB1A3, 0xB1A3}, {0xB1A4, 0xB1A4, 0xB1A4}, {0xB1A5, 0xB1A5, 0xB1A5}, {0xB1A6, 0xB1A6, 0xB1A6}, {0xB1A7, 0xB1A7, 0xB1A7}, {0xB1A8, 0xB1A8, 0xB1A8}, {0xB1A9, 0xB1A9, 0xB1A9}, {0xB1AA, 0xB1AA, 0xB1AA}, {0xB1AB, 0xB1AB, 0xB1AB}, {0xB1AC, 0xB1AC, 0xB1AC}, {0xB1AD, 0xB1AD, 0xB1AD}, {0xB1AE, 0xB1AE, 0xB1AE}, {0xB1AF, 0xB1AF, 0xB1AF}, {0xB1B0, 0xB1B0, 0xB1B0}, {0xB1B1, 0xB1B1, 0xB1B1}, {0xB1B2, 0xB1B2, 0xB1B2}, {0xB1B3, 0xB1B3, 0xB1B3}, {0xB1B4, 0xB1B4, 0xB1B4}, {0xB1B5, 0xB1B5, 0xB1B5}, {0xB1B6, 0xB1B6, 0xB1B6}, {0xB1B7, 0xB1B7, 0xB1B7}, {0xB1B8, 0xB1B8, 0xB1B8}, {0xB1B9, 0xB1B9, 0xB1B9}, {0xB1BA, 0xB1BA, 0xB1BA}, {0xB1BB, 0xB1BB, 0xB1BB}, {0xB1BC, 0xB1BC, 0xB1BC}, {0xB1BD, 0xB1BD, 0xB1BD}, {0xB1BE, 0xB1BE, 0xB1BE}, {0xB1BF, 0xB1BF, 0xB1BF}, {0xB1C0, 0xB1C0, 0xB1C0}, {0xB1C1, 0xB1C1, 0xB1C1}, {0xB1C2, 0xB1C2, 0xB1C2}, {0xB1C3, 0xB1C3, 0xB1C3}, {0xB1C4, 0xB1C4, 0xB1C4}, {0xB1C5, 0xB1C5, 0xB1C5}, {0xB1C6, 0xB1C6, 0xB1C6}, {0xB1C7, 0xB1C7, 0xB1C7}, {0xB1C8, 0xB1C8, 0xB1C8}, {0xB1C9, 0xB1C9, 0xB1C9}, {0xB1CA, 0xB1CA, 0xB1CA}, {0xB1CB, 0xB1CB, 0xB1CB}, {0xB1CC, 0xB1CC, 0xB1CC}, {0xB1CD, 0xB1CD, 0xB1CD}, {0xB1CE, 0xB1CE, 0xB1CE}, {0xB1CF, 0xB1CF, 0xB1CF}, {0xB1D0, 0xB1D0, 0xB1D0}, {0xB1D1, 0xB1D1, 0xB1D1}, {0xB1D2, 0xB1D2, 0xB1D2}, {0xB1D3, 0xB1D3, 0xB1D3}, {0xB1D4, 0xB1D4, 0xB1D4}, {0xB1D5, 0xB1D5, 0xB1D5}, {0xB1D6, 0xB1D6, 0xB1D6}, {0xB1D7, 0xB1D7, 0xB1D7}, {0xB1D8, 0xB1D8, 0xB1D8}, {0xB1D9, 0xB1D9, 0xB1D9}, {0xB1DA, 0xB1DA, 0xB1DA}, {0xB1DB, 0xB1DB, 0xB1DB}, {0xB1DC, 0xB1DC, 0xB1DC}, {0xB1DD, 0xB1DD, 0xB1DD}, {0xB1DE, 0xB1DE, 0xB1DE}, {0xB1DF, 0xB1DF, 0xB1DF}, {0xB1E0, 0xB1E0, 0xB1E0}, {0xB1E1, 0xB1E1, 0xB1E1}, {0xB1E2, 0xB1E2, 0xB1E2}, {0xB1E3, 0xB1E3, 0xB1E3}, {0xB1E4, 0xB1E4, 0xB1E4}, {0xB1E5, 0xB1E5, 0xB1E5}, {0xB1E6, 0xB1E6, 0xB1E6}, {0xB1E7, 0xB1E7, 0xB1E7}, {0xB1E8, 0xB1E8, 0xB1E8}, {0xB1E9, 0xB1E9, 0xB1E9}, {0xB1EA, 0xB1EA, 0xB1EA}, {0xB1EB, 0xB1EB, 0xB1EB}, {0xB1EC, 0xB1EC, 0xB1EC}, {0xB1ED, 0xB1ED, 0xB1ED}, {0xB1EE, 0xB1EE, 0xB1EE}, {0xB1EF, 0xB1EF, 0xB1EF}, {0xB1F0, 0xB1F0, 0xB1F0}, {0xB1F1, 0xB1F1, 0xB1F1}, {0xB1F2, 0xB1F2, 0xB1F2}, {0xB1F3, 0xB1F3, 0xB1F3}, {0xB1F4, 0xB1F4, 0xB1F4}, {0xB1F5, 0xB1F5, 0xB1F5}, {0xB1F6, 0xB1F6, 0xB1F6}, {0xB1F7, 0xB1F7, 0xB1F7}, {0xB1F8, 0xB1F8, 0xB1F8}, {0xB1F9, 0xB1F9, 0xB1F9}, {0xB1FA, 0xB1FA, 0xB1FA}, {0xB1FB, 0xB1FB, 0xB1FB}, {0xB1FC, 0xB1FC, 0xB1FC}, {0xB1FD, 0xB1FD, 0xB1FD}, {0xB1FE, 0xB1FE, 0xB1FE}, {0xB1FF, 0xB1FF, 0xB1FF}, {0xB200, 0xB200, 0xB200}, {0xB201, 0xB201, 0xB201}, {0xB202, 0xB202, 0xB202}, {0xB203, 0xB203, 0xB203}, {0xB204, 0xB204, 0xB204}, {0xB205, 0xB205, 0xB205}, {0xB206, 0xB206, 0xB206}, {0xB207, 0xB207, 0xB207}, {0xB208, 0xB208, 0xB208}, {0xB209, 0xB209, 0xB209}, {0xB20A, 0xB20A, 0xB20A}, {0xB20B, 0xB20B, 0xB20B}, {0xB20C, 0xB20C, 0xB20C}, {0xB20D, 0xB20D, 0xB20D}, {0xB20E, 0xB20E, 0xB20E}, {0xB20F, 0xB20F, 0xB20F}, {0xB210, 0xB210, 0xB210}, {0xB211, 0xB211, 0xB211}, {0xB212, 0xB212, 0xB212}, {0xB213, 0xB213, 0xB213}, {0xB214, 0xB214, 0xB214}, {0xB215, 0xB215, 0xB215}, {0xB216, 0xB216, 0xB216}, {0xB217, 0xB217, 0xB217}, {0xB218, 0xB218, 0xB218}, {0xB219, 0xB219, 0xB219}, {0xB21A, 0xB21A, 0xB21A}, {0xB21B, 0xB21B, 0xB21B}, {0xB21C, 0xB21C, 0xB21C}, {0xB21D, 0xB21D, 0xB21D}, {0xB21E, 0xB21E, 0xB21E}, {0xB21F, 0xB21F, 0xB21F}, {0xB220, 0xB220, 0xB220}, {0xB221, 0xB221, 0xB221}, {0xB222, 0xB222, 0xB222}, {0xB223, 0xB223, 0xB223}, {0xB224, 0xB224, 0xB224}, {0xB225, 0xB225, 0xB225}, {0xB226, 0xB226, 0xB226}, {0xB227, 0xB227, 0xB227}, {0xB228, 0xB228, 0xB228}, {0xB229, 0xB229, 0xB229}, {0xB22A, 0xB22A, 0xB22A}, {0xB22B, 0xB22B, 0xB22B}, {0xB22C, 0xB22C, 0xB22C}, {0xB22D, 0xB22D, 0xB22D}, {0xB22E, 0xB22E, 0xB22E}, {0xB22F, 0xB22F, 0xB22F}, {0xB230, 0xB230, 0xB230}, {0xB231, 0xB231, 0xB231}, {0xB232, 0xB232, 0xB232}, {0xB233, 0xB233, 0xB233}, {0xB234, 0xB234, 0xB234}, {0xB235, 0xB235, 0xB235}, {0xB236, 0xB236, 0xB236}, {0xB237, 0xB237, 0xB237}, {0xB238, 0xB238, 0xB238}, {0xB239, 0xB239, 0xB239}, {0xB23A, 0xB23A, 0xB23A}, {0xB23B, 0xB23B, 0xB23B}, {0xB23C, 0xB23C, 0xB23C}, {0xB23D, 0xB23D, 0xB23D}, {0xB23E, 0xB23E, 0xB23E}, {0xB23F, 0xB23F, 0xB23F}, {0xB240, 0xB240, 0xB240}, {0xB241, 0xB241, 0xB241}, {0xB242, 0xB242, 0xB242}, {0xB243, 0xB243, 0xB243}, {0xB244, 0xB244, 0xB244}, {0xB245, 0xB245, 0xB245}, {0xB246, 0xB246, 0xB246}, {0xB247, 0xB247, 0xB247}, {0xB248, 0xB248, 0xB248}, {0xB249, 0xB249, 0xB249}, {0xB24A, 0xB24A, 0xB24A}, {0xB24B, 0xB24B, 0xB24B}, {0xB24C, 0xB24C, 0xB24C}, {0xB24D, 0xB24D, 0xB24D}, {0xB24E, 0xB24E, 0xB24E}, {0xB24F, 0xB24F, 0xB24F}, {0xB250, 0xB250, 0xB250}, {0xB251, 0xB251, 0xB251}, {0xB252, 0xB252, 0xB252}, {0xB253, 0xB253, 0xB253}, {0xB254, 0xB254, 0xB254}, {0xB255, 0xB255, 0xB255}, {0xB256, 0xB256, 0xB256}, {0xB257, 0xB257, 0xB257}, {0xB258, 0xB258, 0xB258}, {0xB259, 0xB259, 0xB259}, {0xB25A, 0xB25A, 0xB25A}, {0xB25B, 0xB25B, 0xB25B}, {0xB25C, 0xB25C, 0xB25C}, {0xB25D, 0xB25D, 0xB25D}, {0xB25E, 0xB25E, 0xB25E}, {0xB25F, 0xB25F, 0xB25F}, {0xB260, 0xB260, 0xB260}, {0xB261, 0xB261, 0xB261}, {0xB262, 0xB262, 0xB262}, {0xB263, 0xB263, 0xB263}, {0xB264, 0xB264, 0xB264}, {0xB265, 0xB265, 0xB265}, {0xB266, 0xB266, 0xB266}, {0xB267, 0xB267, 0xB267}, {0xB268, 0xB268, 0xB268}, {0xB269, 0xB269, 0xB269}, {0xB26A, 0xB26A, 0xB26A}, {0xB26B, 0xB26B, 0xB26B}, {0xB26C, 0xB26C, 0xB26C}, {0xB26D, 0xB26D, 0xB26D}, {0xB26E, 0xB26E, 0xB26E}, {0xB26F, 0xB26F, 0xB26F}, {0xB270, 0xB270, 0xB270}, {0xB271, 0xB271, 0xB271}, {0xB272, 0xB272, 0xB272}, {0xB273, 0xB273, 0xB273}, {0xB274, 0xB274, 0xB274}, {0xB275, 0xB275, 0xB275}, {0xB276, 0xB276, 0xB276}, {0xB277, 0xB277, 0xB277}, {0xB278, 0xB278, 0xB278}, {0xB279, 0xB279, 0xB279}, {0xB27A, 0xB27A, 0xB27A}, {0xB27B, 0xB27B, 0xB27B}, {0xB27C, 0xB27C, 0xB27C}, {0xB27D, 0xB27D, 0xB27D}, {0xB27E, 0xB27E, 0xB27E}, {0xB27F, 0xB27F, 0xB27F}, {0xB280, 0xB280, 0xB280}, {0xB281, 0xB281, 0xB281}, {0xB282, 0xB282, 0xB282}, {0xB283, 0xB283, 0xB283}, {0xB284, 0xB284, 0xB284}, {0xB285, 0xB285, 0xB285}, {0xB286, 0xB286, 0xB286}, {0xB287, 0xB287, 0xB287}, {0xB288, 0xB288, 0xB288}, {0xB289, 0xB289, 0xB289}, {0xB28A, 0xB28A, 0xB28A}, {0xB28B, 0xB28B, 0xB28B}, {0xB28C, 0xB28C, 0xB28C}, {0xB28D, 0xB28D, 0xB28D}, {0xB28E, 0xB28E, 0xB28E}, {0xB28F, 0xB28F, 0xB28F}, {0xB290, 0xB290, 0xB290}, {0xB291, 0xB291, 0xB291}, {0xB292, 0xB292, 0xB292}, {0xB293, 0xB293, 0xB293}, {0xB294, 0xB294, 0xB294}, {0xB295, 0xB295, 0xB295}, {0xB296, 0xB296, 0xB296}, {0xB297, 0xB297, 0xB297}, {0xB298, 0xB298, 0xB298}, {0xB299, 0xB299, 0xB299}, {0xB29A, 0xB29A, 0xB29A}, {0xB29B, 0xB29B, 0xB29B}, {0xB29C, 0xB29C, 0xB29C}, {0xB29D, 0xB29D, 0xB29D}, {0xB29E, 0xB29E, 0xB29E}, {0xB29F, 0xB29F, 0xB29F}, {0xB2A0, 0xB2A0, 0xB2A0}, {0xB2A1, 0xB2A1, 0xB2A1}, {0xB2A2, 0xB2A2, 0xB2A2}, {0xB2A3, 0xB2A3, 0xB2A3}, {0xB2A4, 0xB2A4, 0xB2A4}, {0xB2A5, 0xB2A5, 0xB2A5}, {0xB2A6, 0xB2A6, 0xB2A6}, {0xB2A7, 0xB2A7, 0xB2A7}, {0xB2A8, 0xB2A8, 0xB2A8}, {0xB2A9, 0xB2A9, 0xB2A9}, {0xB2AA, 0xB2AA, 0xB2AA}, {0xB2AB, 0xB2AB, 0xB2AB}, {0xB2AC, 0xB2AC, 0xB2AC}, {0xB2AD, 0xB2AD, 0xB2AD}, {0xB2AE, 0xB2AE, 0xB2AE}, {0xB2AF, 0xB2AF, 0xB2AF}, {0xB2B0, 0xB2B0, 0xB2B0}, {0xB2B1, 0xB2B1, 0xB2B1}, {0xB2B2, 0xB2B2, 0xB2B2}, {0xB2B3, 0xB2B3, 0xB2B3}, {0xB2B4, 0xB2B4, 0xB2B4}, {0xB2B5, 0xB2B5, 0xB2B5}, {0xB2B6, 0xB2B6, 0xB2B6}, {0xB2B7, 0xB2B7, 0xB2B7}, {0xB2B8, 0xB2B8, 0xB2B8}, {0xB2B9, 0xB2B9, 0xB2B9}, {0xB2BA, 0xB2BA, 0xB2BA}, {0xB2BB, 0xB2BB, 0xB2BB}, {0xB2BC, 0xB2BC, 0xB2BC}, {0xB2BD, 0xB2BD, 0xB2BD}, {0xB2BE, 0xB2BE, 0xB2BE}, {0xB2BF, 0xB2BF, 0xB2BF}, {0xB2C0, 0xB2C0, 0xB2C0}, {0xB2C1, 0xB2C1, 0xB2C1}, {0xB2C2, 0xB2C2, 0xB2C2}, {0xB2C3, 0xB2C3, 0xB2C3}, {0xB2C4, 0xB2C4, 0xB2C4}, {0xB2C5, 0xB2C5, 0xB2C5}, {0xB2C6, 0xB2C6, 0xB2C6}, {0xB2C7, 0xB2C7, 0xB2C7}, {0xB2C8, 0xB2C8, 0xB2C8}, {0xB2C9, 0xB2C9, 0xB2C9}, {0xB2CA, 0xB2CA, 0xB2CA}, {0xB2CB, 0xB2CB, 0xB2CB}, {0xB2CC, 0xB2CC, 0xB2CC}, {0xB2CD, 0xB2CD, 0xB2CD}, {0xB2CE, 0xB2CE, 0xB2CE}, {0xB2CF, 0xB2CF, 0xB2CF}, {0xB2D0, 0xB2D0, 0xB2D0}, {0xB2D1, 0xB2D1, 0xB2D1}, {0xB2D2, 0xB2D2, 0xB2D2}, {0xB2D3, 0xB2D3, 0xB2D3}, {0xB2D4, 0xB2D4, 0xB2D4}, {0xB2D5, 0xB2D5, 0xB2D5}, {0xB2D6, 0xB2D6, 0xB2D6}, {0xB2D7, 0xB2D7, 0xB2D7}, {0xB2D8, 0xB2D8, 0xB2D8}, {0xB2D9, 0xB2D9, 0xB2D9}, {0xB2DA, 0xB2DA, 0xB2DA}, {0xB2DB, 0xB2DB, 0xB2DB}, {0xB2DC, 0xB2DC, 0xB2DC}, {0xB2DD, 0xB2DD, 0xB2DD}, {0xB2DE, 0xB2DE, 0xB2DE}, {0xB2DF, 0xB2DF, 0xB2DF}, {0xB2E0, 0xB2E0, 0xB2E0}, {0xB2E1, 0xB2E1, 0xB2E1}, {0xB2E2, 0xB2E2, 0xB2E2}, {0xB2E3, 0xB2E3, 0xB2E3}, {0xB2E4, 0xB2E4, 0xB2E4}, {0xB2E5, 0xB2E5, 0xB2E5}, {0xB2E6, 0xB2E6, 0xB2E6}, {0xB2E7, 0xB2E7, 0xB2E7}, {0xB2E8, 0xB2E8, 0xB2E8}, {0xB2E9, 0xB2E9, 0xB2E9}, {0xB2EA, 0xB2EA, 0xB2EA}, {0xB2EB, 0xB2EB, 0xB2EB}, {0xB2EC, 0xB2EC, 0xB2EC}, {0xB2ED, 0xB2ED, 0xB2ED}, {0xB2EE, 0xB2EE, 0xB2EE}, {0xB2EF, 0xB2EF, 0xB2EF}, {0xB2F0, 0xB2F0, 0xB2F0}, {0xB2F1, 0xB2F1, 0xB2F1}, {0xB2F2, 0xB2F2, 0xB2F2}, {0xB2F3, 0xB2F3, 0xB2F3}, {0xB2F4, 0xB2F4, 0xB2F4}, {0xB2F5, 0xB2F5, 0xB2F5}, {0xB2F6, 0xB2F6, 0xB2F6}, {0xB2F7, 0xB2F7, 0xB2F7}, {0xB2F8, 0xB2F8, 0xB2F8}, {0xB2F9, 0xB2F9, 0xB2F9}, {0xB2FA, 0xB2FA, 0xB2FA}, {0xB2FB, 0xB2FB, 0xB2FB}, {0xB2FC, 0xB2FC, 0xB2FC}, {0xB2FD, 0xB2FD, 0xB2FD}, {0xB2FE, 0xB2FE, 0xB2FE}, {0xB2FF, 0xB2FF, 0xB2FF}, {0xB300, 0xB300, 0xB300}, {0xB301, 0xB301, 0xB301}, {0xB302, 0xB302, 0xB302}, {0xB303, 0xB303, 0xB303}, {0xB304, 0xB304, 0xB304}, {0xB305, 0xB305, 0xB305}, {0xB306, 0xB306, 0xB306}, {0xB307, 0xB307, 0xB307}, {0xB308, 0xB308, 0xB308}, {0xB309, 0xB309, 0xB309}, {0xB30A, 0xB30A, 0xB30A}, {0xB30B, 0xB30B, 0xB30B}, {0xB30C, 0xB30C, 0xB30C}, {0xB30D, 0xB30D, 0xB30D}, {0xB30E, 0xB30E, 0xB30E}, {0xB30F, 0xB30F, 0xB30F}, {0xB310, 0xB310, 0xB310}, {0xB311, 0xB311, 0xB311}, {0xB312, 0xB312, 0xB312}, {0xB313, 0xB313, 0xB313}, {0xB314, 0xB314, 0xB314}, {0xB315, 0xB315, 0xB315}, {0xB316, 0xB316, 0xB316}, {0xB317, 0xB317, 0xB317}, {0xB318, 0xB318, 0xB318}, {0xB319, 0xB319, 0xB319}, {0xB31A, 0xB31A, 0xB31A}, {0xB31B, 0xB31B, 0xB31B}, {0xB31C, 0xB31C, 0xB31C}, {0xB31D, 0xB31D, 0xB31D}, {0xB31E, 0xB31E, 0xB31E}, {0xB31F, 0xB31F, 0xB31F}, {0xB320, 0xB320, 0xB320}, {0xB321, 0xB321, 0xB321}, {0xB322, 0xB322, 0xB322}, {0xB323, 0xB323, 0xB323}, {0xB324, 0xB324, 0xB324}, {0xB325, 0xB325, 0xB325}, {0xB326, 0xB326, 0xB326}, {0xB327, 0xB327, 0xB327}, {0xB328, 0xB328, 0xB328}, {0xB329, 0xB329, 0xB329}, {0xB32A, 0xB32A, 0xB32A}, {0xB32B, 0xB32B, 0xB32B}, {0xB32C, 0xB32C, 0xB32C}, {0xB32D, 0xB32D, 0xB32D}, {0xB32E, 0xB32E, 0xB32E}, {0xB32F, 0xB32F, 0xB32F}, {0xB330, 0xB330, 0xB330}, {0xB331, 0xB331, 0xB331}, {0xB332, 0xB332, 0xB332}, {0xB333, 0xB333, 0xB333}, {0xB334, 0xB334, 0xB334}, {0xB335, 0xB335, 0xB335}, {0xB336, 0xB336, 0xB336}, {0xB337, 0xB337, 0xB337}, {0xB338, 0xB338, 0xB338}, {0xB339, 0xB339, 0xB339}, {0xB33A, 0xB33A, 0xB33A}, {0xB33B, 0xB33B, 0xB33B}, {0xB33C, 0xB33C, 0xB33C}, {0xB33D, 0xB33D, 0xB33D}, {0xB33E, 0xB33E, 0xB33E}, {0xB33F, 0xB33F, 0xB33F}, {0xB340, 0xB340, 0xB340}, {0xB341, 0xB341, 0xB341}, {0xB342, 0xB342, 0xB342}, {0xB343, 0xB343, 0xB343}, {0xB344, 0xB344, 0xB344}, {0xB345, 0xB345, 0xB345}, {0xB346, 0xB346, 0xB346}, {0xB347, 0xB347, 0xB347}, {0xB348, 0xB348, 0xB348}, {0xB349, 0xB349, 0xB349}, {0xB34A, 0xB34A, 0xB34A}, {0xB34B, 0xB34B, 0xB34B}, {0xB34C, 0xB34C, 0xB34C}, {0xB34D, 0xB34D, 0xB34D}, {0xB34E, 0xB34E, 0xB34E}, {0xB34F, 0xB34F, 0xB34F}, {0xB350, 0xB350, 0xB350}, {0xB351, 0xB351, 0xB351}, {0xB352, 0xB352, 0xB352}, {0xB353, 0xB353, 0xB353}, {0xB354, 0xB354, 0xB354}, {0xB355, 0xB355, 0xB355}, {0xB356, 0xB356, 0xB356}, {0xB357, 0xB357, 0xB357}, {0xB358, 0xB358, 0xB358}, {0xB359, 0xB359, 0xB359}, {0xB35A, 0xB35A, 0xB35A}, {0xB35B, 0xB35B, 0xB35B}, {0xB35C, 0xB35C, 0xB35C}, {0xB35D, 0xB35D, 0xB35D}, {0xB35E, 0xB35E, 0xB35E}, {0xB35F, 0xB35F, 0xB35F}, {0xB360, 0xB360, 0xB360}, {0xB361, 0xB361, 0xB361}, {0xB362, 0xB362, 0xB362}, {0xB363, 0xB363, 0xB363}, {0xB364, 0xB364, 0xB364}, {0xB365, 0xB365, 0xB365}, {0xB366, 0xB366, 0xB366}, {0xB367, 0xB367, 0xB367}, {0xB368, 0xB368, 0xB368}, {0xB369, 0xB369, 0xB369}, {0xB36A, 0xB36A, 0xB36A}, {0xB36B, 0xB36B, 0xB36B}, {0xB36C, 0xB36C, 0xB36C}, {0xB36D, 0xB36D, 0xB36D}, {0xB36E, 0xB36E, 0xB36E}, {0xB36F, 0xB36F, 0xB36F}, {0xB370, 0xB370, 0xB370}, {0xB371, 0xB371, 0xB371}, {0xB372, 0xB372, 0xB372}, {0xB373, 0xB373, 0xB373}, {0xB374, 0xB374, 0xB374}, {0xB375, 0xB375, 0xB375}, {0xB376, 0xB376, 0xB376}, {0xB377, 0xB377, 0xB377}, {0xB378, 0xB378, 0xB378}, {0xB379, 0xB379, 0xB379}, {0xB37A, 0xB37A, 0xB37A}, {0xB37B, 0xB37B, 0xB37B}, {0xB37C, 0xB37C, 0xB37C}, {0xB37D, 0xB37D, 0xB37D}, {0xB37E, 0xB37E, 0xB37E}, {0xB37F, 0xB37F, 0xB37F}, {0xB380, 0xB380, 0xB380}, {0xB381, 0xB381, 0xB381}, {0xB382, 0xB382, 0xB382}, {0xB383, 0xB383, 0xB383}, {0xB384, 0xB384, 0xB384}, {0xB385, 0xB385, 0xB385}, {0xB386, 0xB386, 0xB386}, {0xB387, 0xB387, 0xB387}, {0xB388, 0xB388, 0xB388}, {0xB389, 0xB389, 0xB389}, {0xB38A, 0xB38A, 0xB38A}, {0xB38B, 0xB38B, 0xB38B}, {0xB38C, 0xB38C, 0xB38C}, {0xB38D, 0xB38D, 0xB38D}, {0xB38E, 0xB38E, 0xB38E}, {0xB38F, 0xB38F, 0xB38F}, {0xB390, 0xB390, 0xB390}, {0xB391, 0xB391, 0xB391}, {0xB392, 0xB392, 0xB392}, {0xB393, 0xB393, 0xB393}, {0xB394, 0xB394, 0xB394}, {0xB395, 0xB395, 0xB395}, {0xB396, 0xB396, 0xB396}, {0xB397, 0xB397, 0xB397}, {0xB398, 0xB398, 0xB398}, {0xB399, 0xB399, 0xB399}, {0xB39A, 0xB39A, 0xB39A}, {0xB39B, 0xB39B, 0xB39B}, {0xB39C, 0xB39C, 0xB39C}, {0xB39D, 0xB39D, 0xB39D}, {0xB39E, 0xB39E, 0xB39E}, {0xB39F, 0xB39F, 0xB39F}, {0xB3A0, 0xB3A0, 0xB3A0}, {0xB3A1, 0xB3A1, 0xB3A1}, {0xB3A2, 0xB3A2, 0xB3A2}, {0xB3A3, 0xB3A3, 0xB3A3}, {0xB3A4, 0xB3A4, 0xB3A4}, {0xB3A5, 0xB3A5, 0xB3A5}, {0xB3A6, 0xB3A6, 0xB3A6}, {0xB3A7, 0xB3A7, 0xB3A7}, {0xB3A8, 0xB3A8, 0xB3A8}, {0xB3A9, 0xB3A9, 0xB3A9}, {0xB3AA, 0xB3AA, 0xB3AA}, {0xB3AB, 0xB3AB, 0xB3AB}, {0xB3AC, 0xB3AC, 0xB3AC}, {0xB3AD, 0xB3AD, 0xB3AD}, {0xB3AE, 0xB3AE, 0xB3AE}, {0xB3AF, 0xB3AF, 0xB3AF}, {0xB3B0, 0xB3B0, 0xB3B0}, {0xB3B1, 0xB3B1, 0xB3B1}, {0xB3B2, 0xB3B2, 0xB3B2}, {0xB3B3, 0xB3B3, 0xB3B3}, {0xB3B4, 0xB3B4, 0xB3B4}, {0xB3B5, 0xB3B5, 0xB3B5}, {0xB3B6, 0xB3B6, 0xB3B6}, {0xB3B7, 0xB3B7, 0xB3B7}, {0xB3B8, 0xB3B8, 0xB3B8}, {0xB3B9, 0xB3B9, 0xB3B9}, {0xB3BA, 0xB3BA, 0xB3BA}, {0xB3BB, 0xB3BB, 0xB3BB}, {0xB3BC, 0xB3BC, 0xB3BC}, {0xB3BD, 0xB3BD, 0xB3BD}, {0xB3BE, 0xB3BE, 0xB3BE}, {0xB3BF, 0xB3BF, 0xB3BF}, {0xB3C0, 0xB3C0, 0xB3C0}, {0xB3C1, 0xB3C1, 0xB3C1}, {0xB3C2, 0xB3C2, 0xB3C2}, {0xB3C3, 0xB3C3, 0xB3C3}, {0xB3C4, 0xB3C4, 0xB3C4}, {0xB3C5, 0xB3C5, 0xB3C5}, {0xB3C6, 0xB3C6, 0xB3C6}, {0xB3C7, 0xB3C7, 0xB3C7}, {0xB3C8, 0xB3C8, 0xB3C8}, {0xB3C9, 0xB3C9, 0xB3C9}, {0xB3CA, 0xB3CA, 0xB3CA}, {0xB3CB, 0xB3CB, 0xB3CB}, {0xB3CC, 0xB3CC, 0xB3CC}, {0xB3CD, 0xB3CD, 0xB3CD}, {0xB3CE, 0xB3CE, 0xB3CE}, {0xB3CF, 0xB3CF, 0xB3CF}, {0xB3D0, 0xB3D0, 0xB3D0}, {0xB3D1, 0xB3D1, 0xB3D1}, {0xB3D2, 0xB3D2, 0xB3D2}, {0xB3D3, 0xB3D3, 0xB3D3}, {0xB3D4, 0xB3D4, 0xB3D4}, {0xB3D5, 0xB3D5, 0xB3D5}, {0xB3D6, 0xB3D6, 0xB3D6}, {0xB3D7, 0xB3D7, 0xB3D7}, {0xB3D8, 0xB3D8, 0xB3D8}, {0xB3D9, 0xB3D9, 0xB3D9}, {0xB3DA, 0xB3DA, 0xB3DA}, {0xB3DB, 0xB3DB, 0xB3DB}, {0xB3DC, 0xB3DC, 0xB3DC}, {0xB3DD, 0xB3DD, 0xB3DD}, {0xB3DE, 0xB3DE, 0xB3DE}, {0xB3DF, 0xB3DF, 0xB3DF}, {0xB3E0, 0xB3E0, 0xB3E0}, {0xB3E1, 0xB3E1, 0xB3E1}, {0xB3E2, 0xB3E2, 0xB3E2}, {0xB3E3, 0xB3E3, 0xB3E3}, {0xB3E4, 0xB3E4, 0xB3E4}, {0xB3E5, 0xB3E5, 0xB3E5}, {0xB3E6, 0xB3E6, 0xB3E6}, {0xB3E7, 0xB3E7, 0xB3E7}, {0xB3E8, 0xB3E8, 0xB3E8}, {0xB3E9, 0xB3E9, 0xB3E9}, {0xB3EA, 0xB3EA, 0xB3EA}, {0xB3EB, 0xB3EB, 0xB3EB}, {0xB3EC, 0xB3EC, 0xB3EC}, {0xB3ED, 0xB3ED, 0xB3ED}, {0xB3EE, 0xB3EE, 0xB3EE}, {0xB3EF, 0xB3EF, 0xB3EF}, {0xB3F0, 0xB3F0, 0xB3F0}, {0xB3F1, 0xB3F1, 0xB3F1}, {0xB3F2, 0xB3F2, 0xB3F2}, {0xB3F3, 0xB3F3, 0xB3F3}, {0xB3F4, 0xB3F4, 0xB3F4}, {0xB3F5, 0xB3F5, 0xB3F5}, {0xB3F6, 0xB3F6, 0xB3F6}, {0xB3F7, 0xB3F7, 0xB3F7}, {0xB3F8, 0xB3F8, 0xB3F8}, {0xB3F9, 0xB3F9, 0xB3F9}, {0xB3FA, 0xB3FA, 0xB3FA}, {0xB3FB, 0xB3FB, 0xB3FB}, {0xB3FC, 0xB3FC, 0xB3FC}, {0xB3FD, 0xB3FD, 0xB3FD}, {0xB3FE, 0xB3FE, 0xB3FE}, {0xB3FF, 0xB3FF, 0xB3FF}, {0xB400, 0xB400, 0xB400}, {0xB401, 0xB401, 0xB401}, {0xB402, 0xB402, 0xB402}, {0xB403, 0xB403, 0xB403}, {0xB404, 0xB404, 0xB404}, {0xB405, 0xB405, 0xB405}, {0xB406, 0xB406, 0xB406}, {0xB407, 0xB407, 0xB407}, {0xB408, 0xB408, 0xB408}, {0xB409, 0xB409, 0xB409}, {0xB40A, 0xB40A, 0xB40A}, {0xB40B, 0xB40B, 0xB40B}, {0xB40C, 0xB40C, 0xB40C}, {0xB40D, 0xB40D, 0xB40D}, {0xB40E, 0xB40E, 0xB40E}, {0xB40F, 0xB40F, 0xB40F}, {0xB410, 0xB410, 0xB410}, {0xB411, 0xB411, 0xB411}, {0xB412, 0xB412, 0xB412}, {0xB413, 0xB413, 0xB413}, {0xB414, 0xB414, 0xB414}, {0xB415, 0xB415, 0xB415}, {0xB416, 0xB416, 0xB416}, {0xB417, 0xB417, 0xB417}, {0xB418, 0xB418, 0xB418}, {0xB419, 0xB419, 0xB419}, {0xB41A, 0xB41A, 0xB41A}, {0xB41B, 0xB41B, 0xB41B}, {0xB41C, 0xB41C, 0xB41C}, {0xB41D, 0xB41D, 0xB41D}, {0xB41E, 0xB41E, 0xB41E}, {0xB41F, 0xB41F, 0xB41F}, {0xB420, 0xB420, 0xB420}, {0xB421, 0xB421, 0xB421}, {0xB422, 0xB422, 0xB422}, {0xB423, 0xB423, 0xB423}, {0xB424, 0xB424, 0xB424}, {0xB425, 0xB425, 0xB425}, {0xB426, 0xB426, 0xB426}, {0xB427, 0xB427, 0xB427}, {0xB428, 0xB428, 0xB428}, {0xB429, 0xB429, 0xB429}, {0xB42A, 0xB42A, 0xB42A}, {0xB42B, 0xB42B, 0xB42B}, {0xB42C, 0xB42C, 0xB42C}, {0xB42D, 0xB42D, 0xB42D}, {0xB42E, 0xB42E, 0xB42E}, {0xB42F, 0xB42F, 0xB42F}, {0xB430, 0xB430, 0xB430}, {0xB431, 0xB431, 0xB431}, {0xB432, 0xB432, 0xB432}, {0xB433, 0xB433, 0xB433}, {0xB434, 0xB434, 0xB434}, {0xB435, 0xB435, 0xB435}, {0xB436, 0xB436, 0xB436}, {0xB437, 0xB437, 0xB437}, {0xB438, 0xB438, 0xB438}, {0xB439, 0xB439, 0xB439}, {0xB43A, 0xB43A, 0xB43A}, {0xB43B, 0xB43B, 0xB43B}, {0xB43C, 0xB43C, 0xB43C}, {0xB43D, 0xB43D, 0xB43D}, {0xB43E, 0xB43E, 0xB43E}, {0xB43F, 0xB43F, 0xB43F}, {0xB440, 0xB440, 0xB440}, {0xB441, 0xB441, 0xB441}, {0xB442, 0xB442, 0xB442}, {0xB443, 0xB443, 0xB443}, {0xB444, 0xB444, 0xB444}, {0xB445, 0xB445, 0xB445}, {0xB446, 0xB446, 0xB446}, {0xB447, 0xB447, 0xB447}, {0xB448, 0xB448, 0xB448}, {0xB449, 0xB449, 0xB449}, {0xB44A, 0xB44A, 0xB44A}, {0xB44B, 0xB44B, 0xB44B}, {0xB44C, 0xB44C, 0xB44C}, {0xB44D, 0xB44D, 0xB44D}, {0xB44E, 0xB44E, 0xB44E}, {0xB44F, 0xB44F, 0xB44F}, {0xB450, 0xB450, 0xB450}, {0xB451, 0xB451, 0xB451}, {0xB452, 0xB452, 0xB452}, {0xB453, 0xB453, 0xB453}, {0xB454, 0xB454, 0xB454}, {0xB455, 0xB455, 0xB455}, {0xB456, 0xB456, 0xB456}, {0xB457, 0xB457, 0xB457}, {0xB458, 0xB458, 0xB458}, {0xB459, 0xB459, 0xB459}, {0xB45A, 0xB45A, 0xB45A}, {0xB45B, 0xB45B, 0xB45B}, {0xB45C, 0xB45C, 0xB45C}, {0xB45D, 0xB45D, 0xB45D}, {0xB45E, 0xB45E, 0xB45E}, {0xB45F, 0xB45F, 0xB45F}, {0xB460, 0xB460, 0xB460}, {0xB461, 0xB461, 0xB461}, {0xB462, 0xB462, 0xB462}, {0xB463, 0xB463, 0xB463}, {0xB464, 0xB464, 0xB464}, {0xB465, 0xB465, 0xB465}, {0xB466, 0xB466, 0xB466}, {0xB467, 0xB467, 0xB467}, {0xB468, 0xB468, 0xB468}, {0xB469, 0xB469, 0xB469}, {0xB46A, 0xB46A, 0xB46A}, {0xB46B, 0xB46B, 0xB46B}, {0xB46C, 0xB46C, 0xB46C}, {0xB46D, 0xB46D, 0xB46D}, {0xB46E, 0xB46E, 0xB46E}, {0xB46F, 0xB46F, 0xB46F}, {0xB470, 0xB470, 0xB470}, {0xB471, 0xB471, 0xB471}, {0xB472, 0xB472, 0xB472}, {0xB473, 0xB473, 0xB473}, {0xB474, 0xB474, 0xB474}, {0xB475, 0xB475, 0xB475}, {0xB476, 0xB476, 0xB476}, {0xB477, 0xB477, 0xB477}, {0xB478, 0xB478, 0xB478}, {0xB479, 0xB479, 0xB479}, {0xB47A, 0xB47A, 0xB47A}, {0xB47B, 0xB47B, 0xB47B}, {0xB47C, 0xB47C, 0xB47C}, {0xB47D, 0xB47D, 0xB47D}, {0xB47E, 0xB47E, 0xB47E}, {0xB47F, 0xB47F, 0xB47F}, {0xB480, 0xB480, 0xB480}, {0xB481, 0xB481, 0xB481}, {0xB482, 0xB482, 0xB482}, {0xB483, 0xB483, 0xB483}, {0xB484, 0xB484, 0xB484}, {0xB485, 0xB485, 0xB485}, {0xB486, 0xB486, 0xB486}, {0xB487, 0xB487, 0xB487}, {0xB488, 0xB488, 0xB488}, {0xB489, 0xB489, 0xB489}, {0xB48A, 0xB48A, 0xB48A}, {0xB48B, 0xB48B, 0xB48B}, {0xB48C, 0xB48C, 0xB48C}, {0xB48D, 0xB48D, 0xB48D}, {0xB48E, 0xB48E, 0xB48E}, {0xB48F, 0xB48F, 0xB48F}, {0xB490, 0xB490, 0xB490}, {0xB491, 0xB491, 0xB491}, {0xB492, 0xB492, 0xB492}, {0xB493, 0xB493, 0xB493}, {0xB494, 0xB494, 0xB494}, {0xB495, 0xB495, 0xB495}, {0xB496, 0xB496, 0xB496}, {0xB497, 0xB497, 0xB497}, {0xB498, 0xB498, 0xB498}, {0xB499, 0xB499, 0xB499}, {0xB49A, 0xB49A, 0xB49A}, {0xB49B, 0xB49B, 0xB49B}, {0xB49C, 0xB49C, 0xB49C}, {0xB49D, 0xB49D, 0xB49D}, {0xB49E, 0xB49E, 0xB49E}, {0xB49F, 0xB49F, 0xB49F}, {0xB4A0, 0xB4A0, 0xB4A0}, {0xB4A1, 0xB4A1, 0xB4A1}, {0xB4A2, 0xB4A2, 0xB4A2}, {0xB4A3, 0xB4A3, 0xB4A3}, {0xB4A4, 0xB4A4, 0xB4A4}, {0xB4A5, 0xB4A5, 0xB4A5}, {0xB4A6, 0xB4A6, 0xB4A6}, {0xB4A7, 0xB4A7, 0xB4A7}, {0xB4A8, 0xB4A8, 0xB4A8}, {0xB4A9, 0xB4A9, 0xB4A9}, {0xB4AA, 0xB4AA, 0xB4AA}, {0xB4AB, 0xB4AB, 0xB4AB}, {0xB4AC, 0xB4AC, 0xB4AC}, {0xB4AD, 0xB4AD, 0xB4AD}, {0xB4AE, 0xB4AE, 0xB4AE}, {0xB4AF, 0xB4AF, 0xB4AF}, {0xB4B0, 0xB4B0, 0xB4B0}, {0xB4B1, 0xB4B1, 0xB4B1}, {0xB4B2, 0xB4B2, 0xB4B2}, {0xB4B3, 0xB4B3, 0xB4B3}, {0xB4B4, 0xB4B4, 0xB4B4}, {0xB4B5, 0xB4B5, 0xB4B5}, {0xB4B6, 0xB4B6, 0xB4B6}, {0xB4B7, 0xB4B7, 0xB4B7}, {0xB4B8, 0xB4B8, 0xB4B8}, {0xB4B9, 0xB4B9, 0xB4B9}, {0xB4BA, 0xB4BA, 0xB4BA}, {0xB4BB, 0xB4BB, 0xB4BB}, {0xB4BC, 0xB4BC, 0xB4BC}, {0xB4BD, 0xB4BD, 0xB4BD}, {0xB4BE, 0xB4BE, 0xB4BE}, {0xB4BF, 0xB4BF, 0xB4BF}, {0xB4C0, 0xB4C0, 0xB4C0}, {0xB4C1, 0xB4C1, 0xB4C1}, {0xB4C2, 0xB4C2, 0xB4C2}, {0xB4C3, 0xB4C3, 0xB4C3}, {0xB4C4, 0xB4C4, 0xB4C4}, {0xB4C5, 0xB4C5, 0xB4C5}, {0xB4C6, 0xB4C6, 0xB4C6}, {0xB4C7, 0xB4C7, 0xB4C7}, {0xB4C8, 0xB4C8, 0xB4C8}, {0xB4C9, 0xB4C9, 0xB4C9}, {0xB4CA, 0xB4CA, 0xB4CA}, {0xB4CB, 0xB4CB, 0xB4CB}, {0xB4CC, 0xB4CC, 0xB4CC}, {0xB4CD, 0xB4CD, 0xB4CD}, {0xB4CE, 0xB4CE, 0xB4CE}, {0xB4CF, 0xB4CF, 0xB4CF}, {0xB4D0, 0xB4D0, 0xB4D0}, {0xB4D1, 0xB4D1, 0xB4D1}, {0xB4D2, 0xB4D2, 0xB4D2}, {0xB4D3, 0xB4D3, 0xB4D3}, {0xB4D4, 0xB4D4, 0xB4D4}, {0xB4D5, 0xB4D5, 0xB4D5}, {0xB4D6, 0xB4D6, 0xB4D6}, {0xB4D7, 0xB4D7, 0xB4D7}, {0xB4D8, 0xB4D8, 0xB4D8}, {0xB4D9, 0xB4D9, 0xB4D9}, {0xB4DA, 0xB4DA, 0xB4DA}, {0xB4DB, 0xB4DB, 0xB4DB}, {0xB4DC, 0xB4DC, 0xB4DC}, {0xB4DD, 0xB4DD, 0xB4DD}, {0xB4DE, 0xB4DE, 0xB4DE}, {0xB4DF, 0xB4DF, 0xB4DF}, {0xB4E0, 0xB4E0, 0xB4E0}, {0xB4E1, 0xB4E1, 0xB4E1}, {0xB4E2, 0xB4E2, 0xB4E2}, {0xB4E3, 0xB4E3, 0xB4E3}, {0xB4E4, 0xB4E4, 0xB4E4}, {0xB4E5, 0xB4E5, 0xB4E5}, {0xB4E6, 0xB4E6, 0xB4E6}, {0xB4E7, 0xB4E7, 0xB4E7}, {0xB4E8, 0xB4E8, 0xB4E8}, {0xB4E9, 0xB4E9, 0xB4E9}, {0xB4EA, 0xB4EA, 0xB4EA}, {0xB4EB, 0xB4EB, 0xB4EB}, {0xB4EC, 0xB4EC, 0xB4EC}, {0xB4ED, 0xB4ED, 0xB4ED}, {0xB4EE, 0xB4EE, 0xB4EE}, {0xB4EF, 0xB4EF, 0xB4EF}, {0xB4F0, 0xB4F0, 0xB4F0}, {0xB4F1, 0xB4F1, 0xB4F1}, {0xB4F2, 0xB4F2, 0xB4F2}, {0xB4F3, 0xB4F3, 0xB4F3}, {0xB4F4, 0xB4F4, 0xB4F4}, {0xB4F5, 0xB4F5, 0xB4F5}, {0xB4F6, 0xB4F6, 0xB4F6}, {0xB4F7, 0xB4F7, 0xB4F7}, {0xB4F8, 0xB4F8, 0xB4F8}, {0xB4F9, 0xB4F9, 0xB4F9}, {0xB4FA, 0xB4FA, 0xB4FA}, {0xB4FB, 0xB4FB, 0xB4FB}, {0xB4FC, 0xB4FC, 0xB4FC}, {0xB4FD, 0xB4FD, 0xB4FD}, {0xB4FE, 0xB4FE, 0xB4FE}, {0xB4FF, 0xB4FF, 0xB4FF}, {0xB500, 0xB500, 0xB500}, {0xB501, 0xB501, 0xB501}, {0xB502, 0xB502, 0xB502}, {0xB503, 0xB503, 0xB503}, {0xB504, 0xB504, 0xB504}, {0xB505, 0xB505, 0xB505}, {0xB506, 0xB506, 0xB506}, {0xB507, 0xB507, 0xB507}, {0xB508, 0xB508, 0xB508}, {0xB509, 0xB509, 0xB509}, {0xB50A, 0xB50A, 0xB50A}, {0xB50B, 0xB50B, 0xB50B}, {0xB50C, 0xB50C, 0xB50C}, {0xB50D, 0xB50D, 0xB50D}, {0xB50E, 0xB50E, 0xB50E}, {0xB50F, 0xB50F, 0xB50F}, {0xB510, 0xB510, 0xB510}, {0xB511, 0xB511, 0xB511}, {0xB512, 0xB512, 0xB512}, {0xB513, 0xB513, 0xB513}, {0xB514, 0xB514, 0xB514}, {0xB515, 0xB515, 0xB515}, {0xB516, 0xB516, 0xB516}, {0xB517, 0xB517, 0xB517}, {0xB518, 0xB518, 0xB518}, {0xB519, 0xB519, 0xB519}, {0xB51A, 0xB51A, 0xB51A}, {0xB51B, 0xB51B, 0xB51B}, {0xB51C, 0xB51C, 0xB51C}, {0xB51D, 0xB51D, 0xB51D}, {0xB51E, 0xB51E, 0xB51E}, {0xB51F, 0xB51F, 0xB51F}, {0xB520, 0xB520, 0xB520}, {0xB521, 0xB521, 0xB521}, {0xB522, 0xB522, 0xB522}, {0xB523, 0xB523, 0xB523}, {0xB524, 0xB524, 0xB524}, {0xB525, 0xB525, 0xB525}, {0xB526, 0xB526, 0xB526}, {0xB527, 0xB527, 0xB527}, {0xB528, 0xB528, 0xB528}, {0xB529, 0xB529, 0xB529}, {0xB52A, 0xB52A, 0xB52A}, {0xB52B, 0xB52B, 0xB52B}, {0xB52C, 0xB52C, 0xB52C}, {0xB52D, 0xB52D, 0xB52D}, {0xB52E, 0xB52E, 0xB52E}, {0xB52F, 0xB52F, 0xB52F}, {0xB530, 0xB530, 0xB530}, {0xB531, 0xB531, 0xB531}, {0xB532, 0xB532, 0xB532}, {0xB533, 0xB533, 0xB533}, {0xB534, 0xB534, 0xB534}, {0xB535, 0xB535, 0xB535}, {0xB536, 0xB536, 0xB536}, {0xB537, 0xB537, 0xB537}, {0xB538, 0xB538, 0xB538}, {0xB539, 0xB539, 0xB539}, {0xB53A, 0xB53A, 0xB53A}, {0xB53B, 0xB53B, 0xB53B}, {0xB53C, 0xB53C, 0xB53C}, {0xB53D, 0xB53D, 0xB53D}, {0xB53E, 0xB53E, 0xB53E}, {0xB53F, 0xB53F, 0xB53F}, {0xB540, 0xB540, 0xB540}, {0xB541, 0xB541, 0xB541}, {0xB542, 0xB542, 0xB542}, {0xB543, 0xB543, 0xB543}, {0xB544, 0xB544, 0xB544}, {0xB545, 0xB545, 0xB545}, {0xB546, 0xB546, 0xB546}, {0xB547, 0xB547, 0xB547}, {0xB548, 0xB548, 0xB548}, {0xB549, 0xB549, 0xB549}, {0xB54A, 0xB54A, 0xB54A}, {0xB54B, 0xB54B, 0xB54B}, {0xB54C, 0xB54C, 0xB54C}, {0xB54D, 0xB54D, 0xB54D}, {0xB54E, 0xB54E, 0xB54E}, {0xB54F, 0xB54F, 0xB54F}, {0xB550, 0xB550, 0xB550}, {0xB551, 0xB551, 0xB551}, {0xB552, 0xB552, 0xB552}, {0xB553, 0xB553, 0xB553}, {0xB554, 0xB554, 0xB554}, {0xB555, 0xB555, 0xB555}, {0xB556, 0xB556, 0xB556}, {0xB557, 0xB557, 0xB557}, {0xB558, 0xB558, 0xB558}, {0xB559, 0xB559, 0xB559}, {0xB55A, 0xB55A, 0xB55A}, {0xB55B, 0xB55B, 0xB55B}, {0xB55C, 0xB55C, 0xB55C}, {0xB55D, 0xB55D, 0xB55D}, {0xB55E, 0xB55E, 0xB55E}, {0xB55F, 0xB55F, 0xB55F}, {0xB560, 0xB560, 0xB560}, {0xB561, 0xB561, 0xB561}, {0xB562, 0xB562, 0xB562}, {0xB563, 0xB563, 0xB563}, {0xB564, 0xB564, 0xB564}, {0xB565, 0xB565, 0xB565}, {0xB566, 0xB566, 0xB566}, {0xB567, 0xB567, 0xB567}, {0xB568, 0xB568, 0xB568}, {0xB569, 0xB569, 0xB569}, {0xB56A, 0xB56A, 0xB56A}, {0xB56B, 0xB56B, 0xB56B}, {0xB56C, 0xB56C, 0xB56C}, {0xB56D, 0xB56D, 0xB56D}, {0xB56E, 0xB56E, 0xB56E}, {0xB56F, 0xB56F, 0xB56F}, {0xB570, 0xB570, 0xB570}, {0xB571, 0xB571, 0xB571}, {0xB572, 0xB572, 0xB572}, {0xB573, 0xB573, 0xB573}, {0xB574, 0xB574, 0xB574}, {0xB575, 0xB575, 0xB575}, {0xB576, 0xB576, 0xB576}, {0xB577, 0xB577, 0xB577}, {0xB578, 0xB578, 0xB578}, {0xB579, 0xB579, 0xB579}, {0xB57A, 0xB57A, 0xB57A}, {0xB57B, 0xB57B, 0xB57B}, {0xB57C, 0xB57C, 0xB57C}, {0xB57D, 0xB57D, 0xB57D}, {0xB57E, 0xB57E, 0xB57E}, {0xB57F, 0xB57F, 0xB57F}, {0xB580, 0xB580, 0xB580}, {0xB581, 0xB581, 0xB581}, {0xB582, 0xB582, 0xB582}, {0xB583, 0xB583, 0xB583}, {0xB584, 0xB584, 0xB584}, {0xB585, 0xB585, 0xB585}, {0xB586, 0xB586, 0xB586}, {0xB587, 0xB587, 0xB587}, {0xB588, 0xB588, 0xB588}, {0xB589, 0xB589, 0xB589}, {0xB58A, 0xB58A, 0xB58A}, {0xB58B, 0xB58B, 0xB58B}, {0xB58C, 0xB58C, 0xB58C}, {0xB58D, 0xB58D, 0xB58D}, {0xB58E, 0xB58E, 0xB58E}, {0xB58F, 0xB58F, 0xB58F}, {0xB590, 0xB590, 0xB590}, {0xB591, 0xB591, 0xB591}, {0xB592, 0xB592, 0xB592}, {0xB593, 0xB593, 0xB593}, {0xB594, 0xB594, 0xB594}, {0xB595, 0xB595, 0xB595}, {0xB596, 0xB596, 0xB596}, {0xB597, 0xB597, 0xB597}, {0xB598, 0xB598, 0xB598}, {0xB599, 0xB599, 0xB599}, {0xB59A, 0xB59A, 0xB59A}, {0xB59B, 0xB59B, 0xB59B}, {0xB59C, 0xB59C, 0xB59C}, {0xB59D, 0xB59D, 0xB59D}, {0xB59E, 0xB59E, 0xB59E}, {0xB59F, 0xB59F, 0xB59F}, {0xB5A0, 0xB5A0, 0xB5A0}, {0xB5A1, 0xB5A1, 0xB5A1}, {0xB5A2, 0xB5A2, 0xB5A2}, {0xB5A3, 0xB5A3, 0xB5A3}, {0xB5A4, 0xB5A4, 0xB5A4}, {0xB5A5, 0xB5A5, 0xB5A5}, {0xB5A6, 0xB5A6, 0xB5A6}, {0xB5A7, 0xB5A7, 0xB5A7}, {0xB5A8, 0xB5A8, 0xB5A8}, {0xB5A9, 0xB5A9, 0xB5A9}, {0xB5AA, 0xB5AA, 0xB5AA}, {0xB5AB, 0xB5AB, 0xB5AB}, {0xB5AC, 0xB5AC, 0xB5AC}, {0xB5AD, 0xB5AD, 0xB5AD}, {0xB5AE, 0xB5AE, 0xB5AE}, {0xB5AF, 0xB5AF, 0xB5AF}, {0xB5B0, 0xB5B0, 0xB5B0}, {0xB5B1, 0xB5B1, 0xB5B1}, {0xB5B2, 0xB5B2, 0xB5B2}, {0xB5B3, 0xB5B3, 0xB5B3}, {0xB5B4, 0xB5B4, 0xB5B4}, {0xB5B5, 0xB5B5, 0xB5B5}, {0xB5B6, 0xB5B6, 0xB5B6}, {0xB5B7, 0xB5B7, 0xB5B7}, {0xB5B8, 0xB5B8, 0xB5B8}, {0xB5B9, 0xB5B9, 0xB5B9}, {0xB5BA, 0xB5BA, 0xB5BA}, {0xB5BB, 0xB5BB, 0xB5BB}, {0xB5BC, 0xB5BC, 0xB5BC}, {0xB5BD, 0xB5BD, 0xB5BD}, {0xB5BE, 0xB5BE, 0xB5BE}, {0xB5BF, 0xB5BF, 0xB5BF}, {0xB5C0, 0xB5C0, 0xB5C0}, {0xB5C1, 0xB5C1, 0xB5C1}, {0xB5C2, 0xB5C2, 0xB5C2}, {0xB5C3, 0xB5C3, 0xB5C3}, {0xB5C4, 0xB5C4, 0xB5C4}, {0xB5C5, 0xB5C5, 0xB5C5}, {0xB5C6, 0xB5C6, 0xB5C6}, {0xB5C7, 0xB5C7, 0xB5C7}, {0xB5C8, 0xB5C8, 0xB5C8}, {0xB5C9, 0xB5C9, 0xB5C9}, {0xB5CA, 0xB5CA, 0xB5CA}, {0xB5CB, 0xB5CB, 0xB5CB}, {0xB5CC, 0xB5CC, 0xB5CC}, {0xB5CD, 0xB5CD, 0xB5CD}, {0xB5CE, 0xB5CE, 0xB5CE}, {0xB5CF, 0xB5CF, 0xB5CF}, {0xB5D0, 0xB5D0, 0xB5D0}, {0xB5D1, 0xB5D1, 0xB5D1}, {0xB5D2, 0xB5D2, 0xB5D2}, {0xB5D3, 0xB5D3, 0xB5D3}, {0xB5D4, 0xB5D4, 0xB5D4}, {0xB5D5, 0xB5D5, 0xB5D5}, {0xB5D6, 0xB5D6, 0xB5D6}, {0xB5D7, 0xB5D7, 0xB5D7}, {0xB5D8, 0xB5D8, 0xB5D8}, {0xB5D9, 0xB5D9, 0xB5D9}, {0xB5DA, 0xB5DA, 0xB5DA}, {0xB5DB, 0xB5DB, 0xB5DB}, {0xB5DC, 0xB5DC, 0xB5DC}, {0xB5DD, 0xB5DD, 0xB5DD}, {0xB5DE, 0xB5DE, 0xB5DE}, {0xB5DF, 0xB5DF, 0xB5DF}, {0xB5E0, 0xB5E0, 0xB5E0}, {0xB5E1, 0xB5E1, 0xB5E1}, {0xB5E2, 0xB5E2, 0xB5E2}, {0xB5E3, 0xB5E3, 0xB5E3}, {0xB5E4, 0xB5E4, 0xB5E4}, {0xB5E5, 0xB5E5, 0xB5E5}, {0xB5E6, 0xB5E6, 0xB5E6}, {0xB5E7, 0xB5E7, 0xB5E7}, {0xB5E8, 0xB5E8, 0xB5E8}, {0xB5E9, 0xB5E9, 0xB5E9}, {0xB5EA, 0xB5EA, 0xB5EA}, {0xB5EB, 0xB5EB, 0xB5EB}, {0xB5EC, 0xB5EC, 0xB5EC}, {0xB5ED, 0xB5ED, 0xB5ED}, {0xB5EE, 0xB5EE, 0xB5EE}, {0xB5EF, 0xB5EF, 0xB5EF}, {0xB5F0, 0xB5F0, 0xB5F0}, {0xB5F1, 0xB5F1, 0xB5F1}, {0xB5F2, 0xB5F2, 0xB5F2}, {0xB5F3, 0xB5F3, 0xB5F3}, {0xB5F4, 0xB5F4, 0xB5F4}, {0xB5F5, 0xB5F5, 0xB5F5}, {0xB5F6, 0xB5F6, 0xB5F6}, {0xB5F7, 0xB5F7, 0xB5F7}, {0xB5F8, 0xB5F8, 0xB5F8}, {0xB5F9, 0xB5F9, 0xB5F9}, {0xB5FA, 0xB5FA, 0xB5FA}, {0xB5FB, 0xB5FB, 0xB5FB}, {0xB5FC, 0xB5FC, 0xB5FC}, {0xB5FD, 0xB5FD, 0xB5FD}, {0xB5FE, 0xB5FE, 0xB5FE}, {0xB5FF, 0xB5FF, 0xB5FF}, {0xB600, 0xB600, 0xB600}, {0xB601, 0xB601, 0xB601}, {0xB602, 0xB602, 0xB602}, {0xB603, 0xB603, 0xB603}, {0xB604, 0xB604, 0xB604}, {0xB605, 0xB605, 0xB605}, {0xB606, 0xB606, 0xB606}, {0xB607, 0xB607, 0xB607}, {0xB608, 0xB608, 0xB608}, {0xB609, 0xB609, 0xB609}, {0xB60A, 0xB60A, 0xB60A}, {0xB60B, 0xB60B, 0xB60B}, {0xB60C, 0xB60C, 0xB60C}, {0xB60D, 0xB60D, 0xB60D}, {0xB60E, 0xB60E, 0xB60E}, {0xB60F, 0xB60F, 0xB60F}, {0xB610, 0xB610, 0xB610}, {0xB611, 0xB611, 0xB611}, {0xB612, 0xB612, 0xB612}, {0xB613, 0xB613, 0xB613}, {0xB614, 0xB614, 0xB614}, {0xB615, 0xB615, 0xB615}, {0xB616, 0xB616, 0xB616}, {0xB617, 0xB617, 0xB617}, {0xB618, 0xB618, 0xB618}, {0xB619, 0xB619, 0xB619}, {0xB61A, 0xB61A, 0xB61A}, {0xB61B, 0xB61B, 0xB61B}, {0xB61C, 0xB61C, 0xB61C}, {0xB61D, 0xB61D, 0xB61D}, {0xB61E, 0xB61E, 0xB61E}, {0xB61F, 0xB61F, 0xB61F}, {0xB620, 0xB620, 0xB620}, {0xB621, 0xB621, 0xB621}, {0xB622, 0xB622, 0xB622}, {0xB623, 0xB623, 0xB623}, {0xB624, 0xB624, 0xB624}, {0xB625, 0xB625, 0xB625}, {0xB626, 0xB626, 0xB626}, {0xB627, 0xB627, 0xB627}, {0xB628, 0xB628, 0xB628}, {0xB629, 0xB629, 0xB629}, {0xB62A, 0xB62A, 0xB62A}, {0xB62B, 0xB62B, 0xB62B}, {0xB62C, 0xB62C, 0xB62C}, {0xB62D, 0xB62D, 0xB62D}, {0xB62E, 0xB62E, 0xB62E}, {0xB62F, 0xB62F, 0xB62F}, {0xB630, 0xB630, 0xB630}, {0xB631, 0xB631, 0xB631}, {0xB632, 0xB632, 0xB632}, {0xB633, 0xB633, 0xB633}, {0xB634, 0xB634, 0xB634}, {0xB635, 0xB635, 0xB635}, {0xB636, 0xB636, 0xB636}, {0xB637, 0xB637, 0xB637}, {0xB638, 0xB638, 0xB638}, {0xB639, 0xB639, 0xB639}, {0xB63A, 0xB63A, 0xB63A}, {0xB63B, 0xB63B, 0xB63B}, {0xB63C, 0xB63C, 0xB63C}, {0xB63D, 0xB63D, 0xB63D}, {0xB63E, 0xB63E, 0xB63E}, {0xB63F, 0xB63F, 0xB63F}, {0xB640, 0xB640, 0xB640}, {0xB641, 0xB641, 0xB641}, {0xB642, 0xB642, 0xB642}, {0xB643, 0xB643, 0xB643}, {0xB644, 0xB644, 0xB644}, {0xB645, 0xB645, 0xB645}, {0xB646, 0xB646, 0xB646}, {0xB647, 0xB647, 0xB647}, {0xB648, 0xB648, 0xB648}, {0xB649, 0xB649, 0xB649}, {0xB64A, 0xB64A, 0xB64A}, {0xB64B, 0xB64B, 0xB64B}, {0xB64C, 0xB64C, 0xB64C}, {0xB64D, 0xB64D, 0xB64D}, {0xB64E, 0xB64E, 0xB64E}, {0xB64F, 0xB64F, 0xB64F}, {0xB650, 0xB650, 0xB650}, {0xB651, 0xB651, 0xB651}, {0xB652, 0xB652, 0xB652}, {0xB653, 0xB653, 0xB653}, {0xB654, 0xB654, 0xB654}, {0xB655, 0xB655, 0xB655}, {0xB656, 0xB656, 0xB656}, {0xB657, 0xB657, 0xB657}, {0xB658, 0xB658, 0xB658}, {0xB659, 0xB659, 0xB659}, {0xB65A, 0xB65A, 0xB65A}, {0xB65B, 0xB65B, 0xB65B}, {0xB65C, 0xB65C, 0xB65C}, {0xB65D, 0xB65D, 0xB65D}, {0xB65E, 0xB65E, 0xB65E}, {0xB65F, 0xB65F, 0xB65F}, {0xB660, 0xB660, 0xB660}, {0xB661, 0xB661, 0xB661}, {0xB662, 0xB662, 0xB662}, {0xB663, 0xB663, 0xB663}, {0xB664, 0xB664, 0xB664}, {0xB665, 0xB665, 0xB665}, {0xB666, 0xB666, 0xB666}, {0xB667, 0xB667, 0xB667}, {0xB668, 0xB668, 0xB668}, {0xB669, 0xB669, 0xB669}, {0xB66A, 0xB66A, 0xB66A}, {0xB66B, 0xB66B, 0xB66B}, {0xB66C, 0xB66C, 0xB66C}, {0xB66D, 0xB66D, 0xB66D}, {0xB66E, 0xB66E, 0xB66E}, {0xB66F, 0xB66F, 0xB66F}, {0xB670, 0xB670, 0xB670}, {0xB671, 0xB671, 0xB671}, {0xB672, 0xB672, 0xB672}, {0xB673, 0xB673, 0xB673}, {0xB674, 0xB674, 0xB674}, {0xB675, 0xB675, 0xB675}, {0xB676, 0xB676, 0xB676}, {0xB677, 0xB677, 0xB677}, {0xB678, 0xB678, 0xB678}, {0xB679, 0xB679, 0xB679}, {0xB67A, 0xB67A, 0xB67A}, {0xB67B, 0xB67B, 0xB67B}, {0xB67C, 0xB67C, 0xB67C}, {0xB67D, 0xB67D, 0xB67D}, {0xB67E, 0xB67E, 0xB67E}, {0xB67F, 0xB67F, 0xB67F}, {0xB680, 0xB680, 0xB680}, {0xB681, 0xB681, 0xB681}, {0xB682, 0xB682, 0xB682}, {0xB683, 0xB683, 0xB683}, {0xB684, 0xB684, 0xB684}, {0xB685, 0xB685, 0xB685}, {0xB686, 0xB686, 0xB686}, {0xB687, 0xB687, 0xB687}, {0xB688, 0xB688, 0xB688}, {0xB689, 0xB689, 0xB689}, {0xB68A, 0xB68A, 0xB68A}, {0xB68B, 0xB68B, 0xB68B}, {0xB68C, 0xB68C, 0xB68C}, {0xB68D, 0xB68D, 0xB68D}, {0xB68E, 0xB68E, 0xB68E}, {0xB68F, 0xB68F, 0xB68F}, {0xB690, 0xB690, 0xB690}, {0xB691, 0xB691, 0xB691}, {0xB692, 0xB692, 0xB692}, {0xB693, 0xB693, 0xB693}, {0xB694, 0xB694, 0xB694}, {0xB695, 0xB695, 0xB695}, {0xB696, 0xB696, 0xB696}, {0xB697, 0xB697, 0xB697}, {0xB698, 0xB698, 0xB698}, {0xB699, 0xB699, 0xB699}, {0xB69A, 0xB69A, 0xB69A}, {0xB69B, 0xB69B, 0xB69B}, {0xB69C, 0xB69C, 0xB69C}, {0xB69D, 0xB69D, 0xB69D}, {0xB69E, 0xB69E, 0xB69E}, {0xB69F, 0xB69F, 0xB69F}, {0xB6A0, 0xB6A0, 0xB6A0}, {0xB6A1, 0xB6A1, 0xB6A1}, {0xB6A2, 0xB6A2, 0xB6A2}, {0xB6A3, 0xB6A3, 0xB6A3}, {0xB6A4, 0xB6A4, 0xB6A4}, {0xB6A5, 0xB6A5, 0xB6A5}, {0xB6A6, 0xB6A6, 0xB6A6}, {0xB6A7, 0xB6A7, 0xB6A7}, {0xB6A8, 0xB6A8, 0xB6A8}, {0xB6A9, 0xB6A9, 0xB6A9}, {0xB6AA, 0xB6AA, 0xB6AA}, {0xB6AB, 0xB6AB, 0xB6AB}, {0xB6AC, 0xB6AC, 0xB6AC}, {0xB6AD, 0xB6AD, 0xB6AD}, {0xB6AE, 0xB6AE, 0xB6AE}, {0xB6AF, 0xB6AF, 0xB6AF}, {0xB6B0, 0xB6B0, 0xB6B0}, {0xB6B1, 0xB6B1, 0xB6B1}, {0xB6B2, 0xB6B2, 0xB6B2}, {0xB6B3, 0xB6B3, 0xB6B3}, {0xB6B4, 0xB6B4, 0xB6B4}, {0xB6B5, 0xB6B5, 0xB6B5}, {0xB6B6, 0xB6B6, 0xB6B6}, {0xB6B7, 0xB6B7, 0xB6B7}, {0xB6B8, 0xB6B8, 0xB6B8}, {0xB6B9, 0xB6B9, 0xB6B9}, {0xB6BA, 0xB6BA, 0xB6BA}, {0xB6BB, 0xB6BB, 0xB6BB}, {0xB6BC, 0xB6BC, 0xB6BC}, {0xB6BD, 0xB6BD, 0xB6BD}, {0xB6BE, 0xB6BE, 0xB6BE}, {0xB6BF, 0xB6BF, 0xB6BF}, {0xB6C0, 0xB6C0, 0xB6C0}, {0xB6C1, 0xB6C1, 0xB6C1}, {0xB6C2, 0xB6C2, 0xB6C2}, {0xB6C3, 0xB6C3, 0xB6C3}, {0xB6C4, 0xB6C4, 0xB6C4}, {0xB6C5, 0xB6C5, 0xB6C5}, {0xB6C6, 0xB6C6, 0xB6C6}, {0xB6C7, 0xB6C7, 0xB6C7}, {0xB6C8, 0xB6C8, 0xB6C8}, {0xB6C9, 0xB6C9, 0xB6C9}, {0xB6CA, 0xB6CA, 0xB6CA}, {0xB6CB, 0xB6CB, 0xB6CB}, {0xB6CC, 0xB6CC, 0xB6CC}, {0xB6CD, 0xB6CD, 0xB6CD}, {0xB6CE, 0xB6CE, 0xB6CE}, {0xB6CF, 0xB6CF, 0xB6CF}, {0xB6D0, 0xB6D0, 0xB6D0}, {0xB6D1, 0xB6D1, 0xB6D1}, {0xB6D2, 0xB6D2, 0xB6D2}, {0xB6D3, 0xB6D3, 0xB6D3}, {0xB6D4, 0xB6D4, 0xB6D4}, {0xB6D5, 0xB6D5, 0xB6D5}, {0xB6D6, 0xB6D6, 0xB6D6}, {0xB6D7, 0xB6D7, 0xB6D7}, {0xB6D8, 0xB6D8, 0xB6D8}, {0xB6D9, 0xB6D9, 0xB6D9}, {0xB6DA, 0xB6DA, 0xB6DA}, {0xB6DB, 0xB6DB, 0xB6DB}, {0xB6DC, 0xB6DC, 0xB6DC}, {0xB6DD, 0xB6DD, 0xB6DD}, {0xB6DE, 0xB6DE, 0xB6DE}, {0xB6DF, 0xB6DF, 0xB6DF}, {0xB6E0, 0xB6E0, 0xB6E0}, {0xB6E1, 0xB6E1, 0xB6E1}, {0xB6E2, 0xB6E2, 0xB6E2}, {0xB6E3, 0xB6E3, 0xB6E3}, {0xB6E4, 0xB6E4, 0xB6E4}, {0xB6E5, 0xB6E5, 0xB6E5}, {0xB6E6, 0xB6E6, 0xB6E6}, {0xB6E7, 0xB6E7, 0xB6E7}, {0xB6E8, 0xB6E8, 0xB6E8}, {0xB6E9, 0xB6E9, 0xB6E9}, {0xB6EA, 0xB6EA, 0xB6EA}, {0xB6EB, 0xB6EB, 0xB6EB}, {0xB6EC, 0xB6EC, 0xB6EC}, {0xB6ED, 0xB6ED, 0xB6ED}, {0xB6EE, 0xB6EE, 0xB6EE}, {0xB6EF, 0xB6EF, 0xB6EF}, {0xB6F0, 0xB6F0, 0xB6F0}, {0xB6F1, 0xB6F1, 0xB6F1}, {0xB6F2, 0xB6F2, 0xB6F2}, {0xB6F3, 0xB6F3, 0xB6F3}, {0xB6F4, 0xB6F4, 0xB6F4}, {0xB6F5, 0xB6F5, 0xB6F5}, {0xB6F6, 0xB6F6, 0xB6F6}, {0xB6F7, 0xB6F7, 0xB6F7}, {0xB6F8, 0xB6F8, 0xB6F8}, {0xB6F9, 0xB6F9, 0xB6F9}, {0xB6FA, 0xB6FA, 0xB6FA}, {0xB6FB, 0xB6FB, 0xB6FB}, {0xB6FC, 0xB6FC, 0xB6FC}, {0xB6FD, 0xB6FD, 0xB6FD}, {0xB6FE, 0xB6FE, 0xB6FE}, {0xB6FF, 0xB6FF, 0xB6FF}, {0xB700, 0xB700, 0xB700}, {0xB701, 0xB701, 0xB701}, {0xB702, 0xB702, 0xB702}, {0xB703, 0xB703, 0xB703}, {0xB704, 0xB704, 0xB704}, {0xB705, 0xB705, 0xB705}, {0xB706, 0xB706, 0xB706}, {0xB707, 0xB707, 0xB707}, {0xB708, 0xB708, 0xB708}, {0xB709, 0xB709, 0xB709}, {0xB70A, 0xB70A, 0xB70A}, {0xB70B, 0xB70B, 0xB70B}, {0xB70C, 0xB70C, 0xB70C}, {0xB70D, 0xB70D, 0xB70D}, {0xB70E, 0xB70E, 0xB70E}, {0xB70F, 0xB70F, 0xB70F}, {0xB710, 0xB710, 0xB710}, {0xB711, 0xB711, 0xB711}, {0xB712, 0xB712, 0xB712}, {0xB713, 0xB713, 0xB713}, {0xB714, 0xB714, 0xB714}, {0xB715, 0xB715, 0xB715}, {0xB716, 0xB716, 0xB716}, {0xB717, 0xB717, 0xB717}, {0xB718, 0xB718, 0xB718}, {0xB719, 0xB719, 0xB719}, {0xB71A, 0xB71A, 0xB71A}, {0xB71B, 0xB71B, 0xB71B}, {0xB71C, 0xB71C, 0xB71C}, {0xB71D, 0xB71D, 0xB71D}, {0xB71E, 0xB71E, 0xB71E}, {0xB71F, 0xB71F, 0xB71F}, {0xB720, 0xB720, 0xB720}, {0xB721, 0xB721, 0xB721}, {0xB722, 0xB722, 0xB722}, {0xB723, 0xB723, 0xB723}, {0xB724, 0xB724, 0xB724}, {0xB725, 0xB725, 0xB725}, {0xB726, 0xB726, 0xB726}, {0xB727, 0xB727, 0xB727}, {0xB728, 0xB728, 0xB728}, {0xB729, 0xB729, 0xB729}, {0xB72A, 0xB72A, 0xB72A}, {0xB72B, 0xB72B, 0xB72B}, {0xB72C, 0xB72C, 0xB72C}, {0xB72D, 0xB72D, 0xB72D}, {0xB72E, 0xB72E, 0xB72E}, {0xB72F, 0xB72F, 0xB72F}, {0xB730, 0xB730, 0xB730}, {0xB731, 0xB731, 0xB731}, {0xB732, 0xB732, 0xB732}, {0xB733, 0xB733, 0xB733}, {0xB734, 0xB734, 0xB734}, {0xB735, 0xB735, 0xB735}, {0xB736, 0xB736, 0xB736}, {0xB737, 0xB737, 0xB737}, {0xB738, 0xB738, 0xB738}, {0xB739, 0xB739, 0xB739}, {0xB73A, 0xB73A, 0xB73A}, {0xB73B, 0xB73B, 0xB73B}, {0xB73C, 0xB73C, 0xB73C}, {0xB73D, 0xB73D, 0xB73D}, {0xB73E, 0xB73E, 0xB73E}, {0xB73F, 0xB73F, 0xB73F}, {0xB740, 0xB740, 0xB740}, {0xB741, 0xB741, 0xB741}, {0xB742, 0xB742, 0xB742}, {0xB743, 0xB743, 0xB743}, {0xB744, 0xB744, 0xB744}, {0xB745, 0xB745, 0xB745}, {0xB746, 0xB746, 0xB746}, {0xB747, 0xB747, 0xB747}, {0xB748, 0xB748, 0xB748}, {0xB749, 0xB749, 0xB749}, {0xB74A, 0xB74A, 0xB74A}, {0xB74B, 0xB74B, 0xB74B}, {0xB74C, 0xB74C, 0xB74C}, {0xB74D, 0xB74D, 0xB74D}, {0xB74E, 0xB74E, 0xB74E}, {0xB74F, 0xB74F, 0xB74F}, {0xB750, 0xB750, 0xB750}, {0xB751, 0xB751, 0xB751}, {0xB752, 0xB752, 0xB752}, {0xB753, 0xB753, 0xB753}, {0xB754, 0xB754, 0xB754}, {0xB755, 0xB755, 0xB755}, {0xB756, 0xB756, 0xB756}, {0xB757, 0xB757, 0xB757}, {0xB758, 0xB758, 0xB758}, {0xB759, 0xB759, 0xB759}, {0xB75A, 0xB75A, 0xB75A}, {0xB75B, 0xB75B, 0xB75B}, {0xB75C, 0xB75C, 0xB75C}, {0xB75D, 0xB75D, 0xB75D}, {0xB75E, 0xB75E, 0xB75E}, {0xB75F, 0xB75F, 0xB75F}, {0xB760, 0xB760, 0xB760}, {0xB761, 0xB761, 0xB761}, {0xB762, 0xB762, 0xB762}, {0xB763, 0xB763, 0xB763}, {0xB764, 0xB764, 0xB764}, {0xB765, 0xB765, 0xB765}, {0xB766, 0xB766, 0xB766}, {0xB767, 0xB767, 0xB767}, {0xB768, 0xB768, 0xB768}, {0xB769, 0xB769, 0xB769}, {0xB76A, 0xB76A, 0xB76A}, {0xB76B, 0xB76B, 0xB76B}, {0xB76C, 0xB76C, 0xB76C}, {0xB76D, 0xB76D, 0xB76D}, {0xB76E, 0xB76E, 0xB76E}, {0xB76F, 0xB76F, 0xB76F}, {0xB770, 0xB770, 0xB770}, {0xB771, 0xB771, 0xB771}, {0xB772, 0xB772, 0xB772}, {0xB773, 0xB773, 0xB773}, {0xB774, 0xB774, 0xB774}, {0xB775, 0xB775, 0xB775}, {0xB776, 0xB776, 0xB776}, {0xB777, 0xB777, 0xB777}, {0xB778, 0xB778, 0xB778}, {0xB779, 0xB779, 0xB779}, {0xB77A, 0xB77A, 0xB77A}, {0xB77B, 0xB77B, 0xB77B}, {0xB77C, 0xB77C, 0xB77C}, {0xB77D, 0xB77D, 0xB77D}, {0xB77E, 0xB77E, 0xB77E}, {0xB77F, 0xB77F, 0xB77F}, {0xB780, 0xB780, 0xB780}, {0xB781, 0xB781, 0xB781}, {0xB782, 0xB782, 0xB782}, {0xB783, 0xB783, 0xB783}, {0xB784, 0xB784, 0xB784}, {0xB785, 0xB785, 0xB785}, {0xB786, 0xB786, 0xB786}, {0xB787, 0xB787, 0xB787}, {0xB788, 0xB788, 0xB788}, {0xB789, 0xB789, 0xB789}, {0xB78A, 0xB78A, 0xB78A}, {0xB78B, 0xB78B, 0xB78B}, {0xB78C, 0xB78C, 0xB78C}, {0xB78D, 0xB78D, 0xB78D}, {0xB78E, 0xB78E, 0xB78E}, {0xB78F, 0xB78F, 0xB78F}, {0xB790, 0xB790, 0xB790}, {0xB791, 0xB791, 0xB791}, {0xB792, 0xB792, 0xB792}, {0xB793, 0xB793, 0xB793}, {0xB794, 0xB794, 0xB794}, {0xB795, 0xB795, 0xB795}, {0xB796, 0xB796, 0xB796}, {0xB797, 0xB797, 0xB797}, {0xB798, 0xB798, 0xB798}, {0xB799, 0xB799, 0xB799}, {0xB79A, 0xB79A, 0xB79A}, {0xB79B, 0xB79B, 0xB79B}, {0xB79C, 0xB79C, 0xB79C}, {0xB79D, 0xB79D, 0xB79D}, {0xB79E, 0xB79E, 0xB79E}, {0xB79F, 0xB79F, 0xB79F}, {0xB7A0, 0xB7A0, 0xB7A0}, {0xB7A1, 0xB7A1, 0xB7A1}, {0xB7A2, 0xB7A2, 0xB7A2}, {0xB7A3, 0xB7A3, 0xB7A3}, {0xB7A4, 0xB7A4, 0xB7A4}, {0xB7A5, 0xB7A5, 0xB7A5}, {0xB7A6, 0xB7A6, 0xB7A6}, {0xB7A7, 0xB7A7, 0xB7A7}, {0xB7A8, 0xB7A8, 0xB7A8}, {0xB7A9, 0xB7A9, 0xB7A9}, {0xB7AA, 0xB7AA, 0xB7AA}, {0xB7AB, 0xB7AB, 0xB7AB}, {0xB7AC, 0xB7AC, 0xB7AC}, {0xB7AD, 0xB7AD, 0xB7AD}, {0xB7AE, 0xB7AE, 0xB7AE}, {0xB7AF, 0xB7AF, 0xB7AF}, {0xB7B0, 0xB7B0, 0xB7B0}, {0xB7B1, 0xB7B1, 0xB7B1}, {0xB7B2, 0xB7B2, 0xB7B2}, {0xB7B3, 0xB7B3, 0xB7B3}, {0xB7B4, 0xB7B4, 0xB7B4}, {0xB7B5, 0xB7B5, 0xB7B5}, {0xB7B6, 0xB7B6, 0xB7B6}, {0xB7B7, 0xB7B7, 0xB7B7}, {0xB7B8, 0xB7B8, 0xB7B8}, {0xB7B9, 0xB7B9, 0xB7B9}, {0xB7BA, 0xB7BA, 0xB7BA}, {0xB7BB, 0xB7BB, 0xB7BB}, {0xB7BC, 0xB7BC, 0xB7BC}, {0xB7BD, 0xB7BD, 0xB7BD}, {0xB7BE, 0xB7BE, 0xB7BE}, {0xB7BF, 0xB7BF, 0xB7BF}, {0xB7C0, 0xB7C0, 0xB7C0}, {0xB7C1, 0xB7C1, 0xB7C1}, {0xB7C2, 0xB7C2, 0xB7C2}, {0xB7C3, 0xB7C3, 0xB7C3}, {0xB7C4, 0xB7C4, 0xB7C4}, {0xB7C5, 0xB7C5, 0xB7C5}, {0xB7C6, 0xB7C6, 0xB7C6}, {0xB7C7, 0xB7C7, 0xB7C7}, {0xB7C8, 0xB7C8, 0xB7C8}, {0xB7C9, 0xB7C9, 0xB7C9}, {0xB7CA, 0xB7CA, 0xB7CA}, {0xB7CB, 0xB7CB, 0xB7CB}, {0xB7CC, 0xB7CC, 0xB7CC}, {0xB7CD, 0xB7CD, 0xB7CD}, {0xB7CE, 0xB7CE, 0xB7CE}, {0xB7CF, 0xB7CF, 0xB7CF}, {0xB7D0, 0xB7D0, 0xB7D0}, {0xB7D1, 0xB7D1, 0xB7D1}, {0xB7D2, 0xB7D2, 0xB7D2}, {0xB7D3, 0xB7D3, 0xB7D3}, {0xB7D4, 0xB7D4, 0xB7D4}, {0xB7D5, 0xB7D5, 0xB7D5}, {0xB7D6, 0xB7D6, 0xB7D6}, {0xB7D7, 0xB7D7, 0xB7D7}, {0xB7D8, 0xB7D8, 0xB7D8}, {0xB7D9, 0xB7D9, 0xB7D9}, {0xB7DA, 0xB7DA, 0xB7DA}, {0xB7DB, 0xB7DB, 0xB7DB}, {0xB7DC, 0xB7DC, 0xB7DC}, {0xB7DD, 0xB7DD, 0xB7DD}, {0xB7DE, 0xB7DE, 0xB7DE}, {0xB7DF, 0xB7DF, 0xB7DF}, {0xB7E0, 0xB7E0, 0xB7E0}, {0xB7E1, 0xB7E1, 0xB7E1}, {0xB7E2, 0xB7E2, 0xB7E2}, {0xB7E3, 0xB7E3, 0xB7E3}, {0xB7E4, 0xB7E4, 0xB7E4}, {0xB7E5, 0xB7E5, 0xB7E5}, {0xB7E6, 0xB7E6, 0xB7E6}, {0xB7E7, 0xB7E7, 0xB7E7}, {0xB7E8, 0xB7E8, 0xB7E8}, {0xB7E9, 0xB7E9, 0xB7E9}, {0xB7EA, 0xB7EA, 0xB7EA}, {0xB7EB, 0xB7EB, 0xB7EB}, {0xB7EC, 0xB7EC, 0xB7EC}, {0xB7ED, 0xB7ED, 0xB7ED}, {0xB7EE, 0xB7EE, 0xB7EE}, {0xB7EF, 0xB7EF, 0xB7EF}, {0xB7F0, 0xB7F0, 0xB7F0}, {0xB7F1, 0xB7F1, 0xB7F1}, {0xB7F2, 0xB7F2, 0xB7F2}, {0xB7F3, 0xB7F3, 0xB7F3}, {0xB7F4, 0xB7F4, 0xB7F4}, {0xB7F5, 0xB7F5, 0xB7F5}, {0xB7F6, 0xB7F6, 0xB7F6}, {0xB7F7, 0xB7F7, 0xB7F7}, {0xB7F8, 0xB7F8, 0xB7F8}, {0xB7F9, 0xB7F9, 0xB7F9}, {0xB7FA, 0xB7FA, 0xB7FA}, {0xB7FB, 0xB7FB, 0xB7FB}, {0xB7FC, 0xB7FC, 0xB7FC}, {0xB7FD, 0xB7FD, 0xB7FD}, {0xB7FE, 0xB7FE, 0xB7FE}, {0xB7FF, 0xB7FF, 0xB7FF}, {0xB800, 0xB800, 0xB800}, {0xB801, 0xB801, 0xB801}, {0xB802, 0xB802, 0xB802}, {0xB803, 0xB803, 0xB803}, {0xB804, 0xB804, 0xB804}, {0xB805, 0xB805, 0xB805}, {0xB806, 0xB806, 0xB806}, {0xB807, 0xB807, 0xB807}, {0xB808, 0xB808, 0xB808}, {0xB809, 0xB809, 0xB809}, {0xB80A, 0xB80A, 0xB80A}, {0xB80B, 0xB80B, 0xB80B}, {0xB80C, 0xB80C, 0xB80C}, {0xB80D, 0xB80D, 0xB80D}, {0xB80E, 0xB80E, 0xB80E}, {0xB80F, 0xB80F, 0xB80F}, {0xB810, 0xB810, 0xB810}, {0xB811, 0xB811, 0xB811}, {0xB812, 0xB812, 0xB812}, {0xB813, 0xB813, 0xB813}, {0xB814, 0xB814, 0xB814}, {0xB815, 0xB815, 0xB815}, {0xB816, 0xB816, 0xB816}, {0xB817, 0xB817, 0xB817}, {0xB818, 0xB818, 0xB818}, {0xB819, 0xB819, 0xB819}, {0xB81A, 0xB81A, 0xB81A}, {0xB81B, 0xB81B, 0xB81B}, {0xB81C, 0xB81C, 0xB81C}, {0xB81D, 0xB81D, 0xB81D}, {0xB81E, 0xB81E, 0xB81E}, {0xB81F, 0xB81F, 0xB81F}, {0xB820, 0xB820, 0xB820}, {0xB821, 0xB821, 0xB821}, {0xB822, 0xB822, 0xB822}, {0xB823, 0xB823, 0xB823}, {0xB824, 0xB824, 0xB824}, {0xB825, 0xB825, 0xB825}, {0xB826, 0xB826, 0xB826}, {0xB827, 0xB827, 0xB827}, {0xB828, 0xB828, 0xB828}, {0xB829, 0xB829, 0xB829}, {0xB82A, 0xB82A, 0xB82A}, {0xB82B, 0xB82B, 0xB82B}, {0xB82C, 0xB82C, 0xB82C}, {0xB82D, 0xB82D, 0xB82D}, {0xB82E, 0xB82E, 0xB82E}, {0xB82F, 0xB82F, 0xB82F}, {0xB830, 0xB830, 0xB830}, {0xB831, 0xB831, 0xB831}, {0xB832, 0xB832, 0xB832}, {0xB833, 0xB833, 0xB833}, {0xB834, 0xB834, 0xB834}, {0xB835, 0xB835, 0xB835}, {0xB836, 0xB836, 0xB836}, {0xB837, 0xB837, 0xB837}, {0xB838, 0xB838, 0xB838}, {0xB839, 0xB839, 0xB839}, {0xB83A, 0xB83A, 0xB83A}, {0xB83B, 0xB83B, 0xB83B}, {0xB83C, 0xB83C, 0xB83C}, {0xB83D, 0xB83D, 0xB83D}, {0xB83E, 0xB83E, 0xB83E}, {0xB83F, 0xB83F, 0xB83F}, {0xB840, 0xB840, 0xB840}, {0xB841, 0xB841, 0xB841}, {0xB842, 0xB842, 0xB842}, {0xB843, 0xB843, 0xB843}, {0xB844, 0xB844, 0xB844}, {0xB845, 0xB845, 0xB845}, {0xB846, 0xB846, 0xB846}, {0xB847, 0xB847, 0xB847}, {0xB848, 0xB848, 0xB848}, {0xB849, 0xB849, 0xB849}, {0xB84A, 0xB84A, 0xB84A}, {0xB84B, 0xB84B, 0xB84B}, {0xB84C, 0xB84C, 0xB84C}, {0xB84D, 0xB84D, 0xB84D}, {0xB84E, 0xB84E, 0xB84E}, {0xB84F, 0xB84F, 0xB84F}, {0xB850, 0xB850, 0xB850}, {0xB851, 0xB851, 0xB851}, {0xB852, 0xB852, 0xB852}, {0xB853, 0xB853, 0xB853}, {0xB854, 0xB854, 0xB854}, {0xB855, 0xB855, 0xB855}, {0xB856, 0xB856, 0xB856}, {0xB857, 0xB857, 0xB857}, {0xB858, 0xB858, 0xB858}, {0xB859, 0xB859, 0xB859}, {0xB85A, 0xB85A, 0xB85A}, {0xB85B, 0xB85B, 0xB85B}, {0xB85C, 0xB85C, 0xB85C}, {0xB85D, 0xB85D, 0xB85D}, {0xB85E, 0xB85E, 0xB85E}, {0xB85F, 0xB85F, 0xB85F}, {0xB860, 0xB860, 0xB860}, {0xB861, 0xB861, 0xB861}, {0xB862, 0xB862, 0xB862}, {0xB863, 0xB863, 0xB863}, {0xB864, 0xB864, 0xB864}, {0xB865, 0xB865, 0xB865}, {0xB866, 0xB866, 0xB866}, {0xB867, 0xB867, 0xB867}, {0xB868, 0xB868, 0xB868}, {0xB869, 0xB869, 0xB869}, {0xB86A, 0xB86A, 0xB86A}, {0xB86B, 0xB86B, 0xB86B}, {0xB86C, 0xB86C, 0xB86C}, {0xB86D, 0xB86D, 0xB86D}, {0xB86E, 0xB86E, 0xB86E}, {0xB86F, 0xB86F, 0xB86F}, {0xB870, 0xB870, 0xB870}, {0xB871, 0xB871, 0xB871}, {0xB872, 0xB872, 0xB872}, {0xB873, 0xB873, 0xB873}, {0xB874, 0xB874, 0xB874}, {0xB875, 0xB875, 0xB875}, {0xB876, 0xB876, 0xB876}, {0xB877, 0xB877, 0xB877}, {0xB878, 0xB878, 0xB878}, {0xB879, 0xB879, 0xB879}, {0xB87A, 0xB87A, 0xB87A}, {0xB87B, 0xB87B, 0xB87B}, {0xB87C, 0xB87C, 0xB87C}, {0xB87D, 0xB87D, 0xB87D}, {0xB87E, 0xB87E, 0xB87E}, {0xB87F, 0xB87F, 0xB87F}, {0xB880, 0xB880, 0xB880}, {0xB881, 0xB881, 0xB881}, {0xB882, 0xB882, 0xB882}, {0xB883, 0xB883, 0xB883}, {0xB884, 0xB884, 0xB884}, {0xB885, 0xB885, 0xB885}, {0xB886, 0xB886, 0xB886}, {0xB887, 0xB887, 0xB887}, {0xB888, 0xB888, 0xB888}, {0xB889, 0xB889, 0xB889}, {0xB88A, 0xB88A, 0xB88A}, {0xB88B, 0xB88B, 0xB88B}, {0xB88C, 0xB88C, 0xB88C}, {0xB88D, 0xB88D, 0xB88D}, {0xB88E, 0xB88E, 0xB88E}, {0xB88F, 0xB88F, 0xB88F}, {0xB890, 0xB890, 0xB890}, {0xB891, 0xB891, 0xB891}, {0xB892, 0xB892, 0xB892}, {0xB893, 0xB893, 0xB893}, {0xB894, 0xB894, 0xB894}, {0xB895, 0xB895, 0xB895}, {0xB896, 0xB896, 0xB896}, {0xB897, 0xB897, 0xB897}, {0xB898, 0xB898, 0xB898}, {0xB899, 0xB899, 0xB899}, {0xB89A, 0xB89A, 0xB89A}, {0xB89B, 0xB89B, 0xB89B}, {0xB89C, 0xB89C, 0xB89C}, {0xB89D, 0xB89D, 0xB89D}, {0xB89E, 0xB89E, 0xB89E}, {0xB89F, 0xB89F, 0xB89F}, {0xB8A0, 0xB8A0, 0xB8A0}, {0xB8A1, 0xB8A1, 0xB8A1}, {0xB8A2, 0xB8A2, 0xB8A2}, {0xB8A3, 0xB8A3, 0xB8A3}, {0xB8A4, 0xB8A4, 0xB8A4}, {0xB8A5, 0xB8A5, 0xB8A5}, {0xB8A6, 0xB8A6, 0xB8A6}, {0xB8A7, 0xB8A7, 0xB8A7}, {0xB8A8, 0xB8A8, 0xB8A8}, {0xB8A9, 0xB8A9, 0xB8A9}, {0xB8AA, 0xB8AA, 0xB8AA}, {0xB8AB, 0xB8AB, 0xB8AB}, {0xB8AC, 0xB8AC, 0xB8AC}, {0xB8AD, 0xB8AD, 0xB8AD}, {0xB8AE, 0xB8AE, 0xB8AE}, {0xB8AF, 0xB8AF, 0xB8AF}, {0xB8B0, 0xB8B0, 0xB8B0}, {0xB8B1, 0xB8B1, 0xB8B1}, {0xB8B2, 0xB8B2, 0xB8B2}, {0xB8B3, 0xB8B3, 0xB8B3}, {0xB8B4, 0xB8B4, 0xB8B4}, {0xB8B5, 0xB8B5, 0xB8B5}, {0xB8B6, 0xB8B6, 0xB8B6}, {0xB8B7, 0xB8B7, 0xB8B7}, {0xB8B8, 0xB8B8, 0xB8B8}, {0xB8B9, 0xB8B9, 0xB8B9}, {0xB8BA, 0xB8BA, 0xB8BA}, {0xB8BB, 0xB8BB, 0xB8BB}, {0xB8BC, 0xB8BC, 0xB8BC}, {0xB8BD, 0xB8BD, 0xB8BD}, {0xB8BE, 0xB8BE, 0xB8BE}, {0xB8BF, 0xB8BF, 0xB8BF}, {0xB8C0, 0xB8C0, 0xB8C0}, {0xB8C1, 0xB8C1, 0xB8C1}, {0xB8C2, 0xB8C2, 0xB8C2}, {0xB8C3, 0xB8C3, 0xB8C3}, {0xB8C4, 0xB8C4, 0xB8C4}, {0xB8C5, 0xB8C5, 0xB8C5}, {0xB8C6, 0xB8C6, 0xB8C6}, {0xB8C7, 0xB8C7, 0xB8C7}, {0xB8C8, 0xB8C8, 0xB8C8}, {0xB8C9, 0xB8C9, 0xB8C9}, {0xB8CA, 0xB8CA, 0xB8CA}, {0xB8CB, 0xB8CB, 0xB8CB}, {0xB8CC, 0xB8CC, 0xB8CC}, {0xB8CD, 0xB8CD, 0xB8CD}, {0xB8CE, 0xB8CE, 0xB8CE}, {0xB8CF, 0xB8CF, 0xB8CF}, {0xB8D0, 0xB8D0, 0xB8D0}, {0xB8D1, 0xB8D1, 0xB8D1}, {0xB8D2, 0xB8D2, 0xB8D2}, {0xB8D3, 0xB8D3, 0xB8D3}, {0xB8D4, 0xB8D4, 0xB8D4}, {0xB8D5, 0xB8D5, 0xB8D5}, {0xB8D6, 0xB8D6, 0xB8D6}, {0xB8D7, 0xB8D7, 0xB8D7}, {0xB8D8, 0xB8D8, 0xB8D8}, {0xB8D9, 0xB8D9, 0xB8D9}, {0xB8DA, 0xB8DA, 0xB8DA}, {0xB8DB, 0xB8DB, 0xB8DB}, {0xB8DC, 0xB8DC, 0xB8DC}, {0xB8DD, 0xB8DD, 0xB8DD}, {0xB8DE, 0xB8DE, 0xB8DE}, {0xB8DF, 0xB8DF, 0xB8DF}, {0xB8E0, 0xB8E0, 0xB8E0}, {0xB8E1, 0xB8E1, 0xB8E1}, {0xB8E2, 0xB8E2, 0xB8E2}, {0xB8E3, 0xB8E3, 0xB8E3}, {0xB8E4, 0xB8E4, 0xB8E4}, {0xB8E5, 0xB8E5, 0xB8E5}, {0xB8E6, 0xB8E6, 0xB8E6}, {0xB8E7, 0xB8E7, 0xB8E7}, {0xB8E8, 0xB8E8, 0xB8E8}, {0xB8E9, 0xB8E9, 0xB8E9}, {0xB8EA, 0xB8EA, 0xB8EA}, {0xB8EB, 0xB8EB, 0xB8EB}, {0xB8EC, 0xB8EC, 0xB8EC}, {0xB8ED, 0xB8ED, 0xB8ED}, {0xB8EE, 0xB8EE, 0xB8EE}, {0xB8EF, 0xB8EF, 0xB8EF}, {0xB8F0, 0xB8F0, 0xB8F0}, {0xB8F1, 0xB8F1, 0xB8F1}, {0xB8F2, 0xB8F2, 0xB8F2}, {0xB8F3, 0xB8F3, 0xB8F3}, {0xB8F4, 0xB8F4, 0xB8F4}, {0xB8F5, 0xB8F5, 0xB8F5}, {0xB8F6, 0xB8F6, 0xB8F6}, {0xB8F7, 0xB8F7, 0xB8F7}, {0xB8F8, 0xB8F8, 0xB8F8}, {0xB8F9, 0xB8F9, 0xB8F9}, {0xB8FA, 0xB8FA, 0xB8FA}, {0xB8FB, 0xB8FB, 0xB8FB}, {0xB8FC, 0xB8FC, 0xB8FC}, {0xB8FD, 0xB8FD, 0xB8FD}, {0xB8FE, 0xB8FE, 0xB8FE}, {0xB8FF, 0xB8FF, 0xB8FF}, {0xB900, 0xB900, 0xB900}, {0xB901, 0xB901, 0xB901}, {0xB902, 0xB902, 0xB902}, {0xB903, 0xB903, 0xB903}, {0xB904, 0xB904, 0xB904}, {0xB905, 0xB905, 0xB905}, {0xB906, 0xB906, 0xB906}, {0xB907, 0xB907, 0xB907}, {0xB908, 0xB908, 0xB908}, {0xB909, 0xB909, 0xB909}, {0xB90A, 0xB90A, 0xB90A}, {0xB90B, 0xB90B, 0xB90B}, {0xB90C, 0xB90C, 0xB90C}, {0xB90D, 0xB90D, 0xB90D}, {0xB90E, 0xB90E, 0xB90E}, {0xB90F, 0xB90F, 0xB90F}, {0xB910, 0xB910, 0xB910}, {0xB911, 0xB911, 0xB911}, {0xB912, 0xB912, 0xB912}, {0xB913, 0xB913, 0xB913}, {0xB914, 0xB914, 0xB914}, {0xB915, 0xB915, 0xB915}, {0xB916, 0xB916, 0xB916}, {0xB917, 0xB917, 0xB917}, {0xB918, 0xB918, 0xB918}, {0xB919, 0xB919, 0xB919}, {0xB91A, 0xB91A, 0xB91A}, {0xB91B, 0xB91B, 0xB91B}, {0xB91C, 0xB91C, 0xB91C}, {0xB91D, 0xB91D, 0xB91D}, {0xB91E, 0xB91E, 0xB91E}, {0xB91F, 0xB91F, 0xB91F}, {0xB920, 0xB920, 0xB920}, {0xB921, 0xB921, 0xB921}, {0xB922, 0xB922, 0xB922}, {0xB923, 0xB923, 0xB923}, {0xB924, 0xB924, 0xB924}, {0xB925, 0xB925, 0xB925}, {0xB926, 0xB926, 0xB926}, {0xB927, 0xB927, 0xB927}, {0xB928, 0xB928, 0xB928}, {0xB929, 0xB929, 0xB929}, {0xB92A, 0xB92A, 0xB92A}, {0xB92B, 0xB92B, 0xB92B}, {0xB92C, 0xB92C, 0xB92C}, {0xB92D, 0xB92D, 0xB92D}, {0xB92E, 0xB92E, 0xB92E}, {0xB92F, 0xB92F, 0xB92F}, {0xB930, 0xB930, 0xB930}, {0xB931, 0xB931, 0xB931}, {0xB932, 0xB932, 0xB932}, {0xB933, 0xB933, 0xB933}, {0xB934, 0xB934, 0xB934}, {0xB935, 0xB935, 0xB935}, {0xB936, 0xB936, 0xB936}, {0xB937, 0xB937, 0xB937}, {0xB938, 0xB938, 0xB938}, {0xB939, 0xB939, 0xB939}, {0xB93A, 0xB93A, 0xB93A}, {0xB93B, 0xB93B, 0xB93B}, {0xB93C, 0xB93C, 0xB93C}, {0xB93D, 0xB93D, 0xB93D}, {0xB93E, 0xB93E, 0xB93E}, {0xB93F, 0xB93F, 0xB93F}, {0xB940, 0xB940, 0xB940}, {0xB941, 0xB941, 0xB941}, {0xB942, 0xB942, 0xB942}, {0xB943, 0xB943, 0xB943}, {0xB944, 0xB944, 0xB944}, {0xB945, 0xB945, 0xB945}, {0xB946, 0xB946, 0xB946}, {0xB947, 0xB947, 0xB947}, {0xB948, 0xB948, 0xB948}, {0xB949, 0xB949, 0xB949}, {0xB94A, 0xB94A, 0xB94A}, {0xB94B, 0xB94B, 0xB94B}, {0xB94C, 0xB94C, 0xB94C}, {0xB94D, 0xB94D, 0xB94D}, {0xB94E, 0xB94E, 0xB94E}, {0xB94F, 0xB94F, 0xB94F}, {0xB950, 0xB950, 0xB950}, {0xB951, 0xB951, 0xB951}, {0xB952, 0xB952, 0xB952}, {0xB953, 0xB953, 0xB953}, {0xB954, 0xB954, 0xB954}, {0xB955, 0xB955, 0xB955}, {0xB956, 0xB956, 0xB956}, {0xB957, 0xB957, 0xB957}, {0xB958, 0xB958, 0xB958}, {0xB959, 0xB959, 0xB959}, {0xB95A, 0xB95A, 0xB95A}, {0xB95B, 0xB95B, 0xB95B}, {0xB95C, 0xB95C, 0xB95C}, {0xB95D, 0xB95D, 0xB95D}, {0xB95E, 0xB95E, 0xB95E}, {0xB95F, 0xB95F, 0xB95F}, {0xB960, 0xB960, 0xB960}, {0xB961, 0xB961, 0xB961}, {0xB962, 0xB962, 0xB962}, {0xB963, 0xB963, 0xB963}, {0xB964, 0xB964, 0xB964}, {0xB965, 0xB965, 0xB965}, {0xB966, 0xB966, 0xB966}, {0xB967, 0xB967, 0xB967}, {0xB968, 0xB968, 0xB968}, {0xB969, 0xB969, 0xB969}, {0xB96A, 0xB96A, 0xB96A}, {0xB96B, 0xB96B, 0xB96B}, {0xB96C, 0xB96C, 0xB96C}, {0xB96D, 0xB96D, 0xB96D}, {0xB96E, 0xB96E, 0xB96E}, {0xB96F, 0xB96F, 0xB96F}, {0xB970, 0xB970, 0xB970}, {0xB971, 0xB971, 0xB971}, {0xB972, 0xB972, 0xB972}, {0xB973, 0xB973, 0xB973}, {0xB974, 0xB974, 0xB974}, {0xB975, 0xB975, 0xB975}, {0xB976, 0xB976, 0xB976}, {0xB977, 0xB977, 0xB977}, {0xB978, 0xB978, 0xB978}, {0xB979, 0xB979, 0xB979}, {0xB97A, 0xB97A, 0xB97A}, {0xB97B, 0xB97B, 0xB97B}, {0xB97C, 0xB97C, 0xB97C}, {0xB97D, 0xB97D, 0xB97D}, {0xB97E, 0xB97E, 0xB97E}, {0xB97F, 0xB97F, 0xB97F}, {0xB980, 0xB980, 0xB980}, {0xB981, 0xB981, 0xB981}, {0xB982, 0xB982, 0xB982}, {0xB983, 0xB983, 0xB983}, {0xB984, 0xB984, 0xB984}, {0xB985, 0xB985, 0xB985}, {0xB986, 0xB986, 0xB986}, {0xB987, 0xB987, 0xB987}, {0xB988, 0xB988, 0xB988}, {0xB989, 0xB989, 0xB989}, {0xB98A, 0xB98A, 0xB98A}, {0xB98B, 0xB98B, 0xB98B}, {0xB98C, 0xB98C, 0xB98C}, {0xB98D, 0xB98D, 0xB98D}, {0xB98E, 0xB98E, 0xB98E}, {0xB98F, 0xB98F, 0xB98F}, {0xB990, 0xB990, 0xB990}, {0xB991, 0xB991, 0xB991}, {0xB992, 0xB992, 0xB992}, {0xB993, 0xB993, 0xB993}, {0xB994, 0xB994, 0xB994}, {0xB995, 0xB995, 0xB995}, {0xB996, 0xB996, 0xB996}, {0xB997, 0xB997, 0xB997}, {0xB998, 0xB998, 0xB998}, {0xB999, 0xB999, 0xB999}, {0xB99A, 0xB99A, 0xB99A}, {0xB99B, 0xB99B, 0xB99B}, {0xB99C, 0xB99C, 0xB99C}, {0xB99D, 0xB99D, 0xB99D}, {0xB99E, 0xB99E, 0xB99E}, {0xB99F, 0xB99F, 0xB99F}, {0xB9A0, 0xB9A0, 0xB9A0}, {0xB9A1, 0xB9A1, 0xB9A1}, {0xB9A2, 0xB9A2, 0xB9A2}, {0xB9A3, 0xB9A3, 0xB9A3}, {0xB9A4, 0xB9A4, 0xB9A4}, {0xB9A5, 0xB9A5, 0xB9A5}, {0xB9A6, 0xB9A6, 0xB9A6}, {0xB9A7, 0xB9A7, 0xB9A7}, {0xB9A8, 0xB9A8, 0xB9A8}, {0xB9A9, 0xB9A9, 0xB9A9}, {0xB9AA, 0xB9AA, 0xB9AA}, {0xB9AB, 0xB9AB, 0xB9AB}, {0xB9AC, 0xB9AC, 0xB9AC}, {0xB9AD, 0xB9AD, 0xB9AD}, {0xB9AE, 0xB9AE, 0xB9AE}, {0xB9AF, 0xB9AF, 0xB9AF}, {0xB9B0, 0xB9B0, 0xB9B0}, {0xB9B1, 0xB9B1, 0xB9B1}, {0xB9B2, 0xB9B2, 0xB9B2}, {0xB9B3, 0xB9B3, 0xB9B3}, {0xB9B4, 0xB9B4, 0xB9B4}, {0xB9B5, 0xB9B5, 0xB9B5}, {0xB9B6, 0xB9B6, 0xB9B6}, {0xB9B7, 0xB9B7, 0xB9B7}, {0xB9B8, 0xB9B8, 0xB9B8}, {0xB9B9, 0xB9B9, 0xB9B9}, {0xB9BA, 0xB9BA, 0xB9BA}, {0xB9BB, 0xB9BB, 0xB9BB}, {0xB9BC, 0xB9BC, 0xB9BC}, {0xB9BD, 0xB9BD, 0xB9BD}, {0xB9BE, 0xB9BE, 0xB9BE}, {0xB9BF, 0xB9BF, 0xB9BF}, {0xB9C0, 0xB9C0, 0xB9C0}, {0xB9C1, 0xB9C1, 0xB9C1}, {0xB9C2, 0xB9C2, 0xB9C2}, {0xB9C3, 0xB9C3, 0xB9C3}, {0xB9C4, 0xB9C4, 0xB9C4}, {0xB9C5, 0xB9C5, 0xB9C5}, {0xB9C6, 0xB9C6, 0xB9C6}, {0xB9C7, 0xB9C7, 0xB9C7}, {0xB9C8, 0xB9C8, 0xB9C8}, {0xB9C9, 0xB9C9, 0xB9C9}, {0xB9CA, 0xB9CA, 0xB9CA}, {0xB9CB, 0xB9CB, 0xB9CB}, {0xB9CC, 0xB9CC, 0xB9CC}, {0xB9CD, 0xB9CD, 0xB9CD}, {0xB9CE, 0xB9CE, 0xB9CE}, {0xB9CF, 0xB9CF, 0xB9CF}, {0xB9D0, 0xB9D0, 0xB9D0}, {0xB9D1, 0xB9D1, 0xB9D1}, {0xB9D2, 0xB9D2, 0xB9D2}, {0xB9D3, 0xB9D3, 0xB9D3}, {0xB9D4, 0xB9D4, 0xB9D4}, {0xB9D5, 0xB9D5, 0xB9D5}, {0xB9D6, 0xB9D6, 0xB9D6}, {0xB9D7, 0xB9D7, 0xB9D7}, {0xB9D8, 0xB9D8, 0xB9D8}, {0xB9D9, 0xB9D9, 0xB9D9}, {0xB9DA, 0xB9DA, 0xB9DA}, {0xB9DB, 0xB9DB, 0xB9DB}, {0xB9DC, 0xB9DC, 0xB9DC}, {0xB9DD, 0xB9DD, 0xB9DD}, {0xB9DE, 0xB9DE, 0xB9DE}, {0xB9DF, 0xB9DF, 0xB9DF}, {0xB9E0, 0xB9E0, 0xB9E0}, {0xB9E1, 0xB9E1, 0xB9E1}, {0xB9E2, 0xB9E2, 0xB9E2}, {0xB9E3, 0xB9E3, 0xB9E3}, {0xB9E4, 0xB9E4, 0xB9E4}, {0xB9E5, 0xB9E5, 0xB9E5}, {0xB9E6, 0xB9E6, 0xB9E6}, {0xB9E7, 0xB9E7, 0xB9E7}, {0xB9E8, 0xB9E8, 0xB9E8}, {0xB9E9, 0xB9E9, 0xB9E9}, {0xB9EA, 0xB9EA, 0xB9EA}, {0xB9EB, 0xB9EB, 0xB9EB}, {0xB9EC, 0xB9EC, 0xB9EC}, {0xB9ED, 0xB9ED, 0xB9ED}, {0xB9EE, 0xB9EE, 0xB9EE}, {0xB9EF, 0xB9EF, 0xB9EF}, {0xB9F0, 0xB9F0, 0xB9F0}, {0xB9F1, 0xB9F1, 0xB9F1}, {0xB9F2, 0xB9F2, 0xB9F2}, {0xB9F3, 0xB9F3, 0xB9F3}, {0xB9F4, 0xB9F4, 0xB9F4}, {0xB9F5, 0xB9F5, 0xB9F5}, {0xB9F6, 0xB9F6, 0xB9F6}, {0xB9F7, 0xB9F7, 0xB9F7}, {0xB9F8, 0xB9F8, 0xB9F8}, {0xB9F9, 0xB9F9, 0xB9F9}, {0xB9FA, 0xB9FA, 0xB9FA}, {0xB9FB, 0xB9FB, 0xB9FB}, {0xB9FC, 0xB9FC, 0xB9FC}, {0xB9FD, 0xB9FD, 0xB9FD}, {0xB9FE, 0xB9FE, 0xB9FE}, {0xB9FF, 0xB9FF, 0xB9FF}, {0xBA00, 0xBA00, 0xBA00}, {0xBA01, 0xBA01, 0xBA01}, {0xBA02, 0xBA02, 0xBA02}, {0xBA03, 0xBA03, 0xBA03}, {0xBA04, 0xBA04, 0xBA04}, {0xBA05, 0xBA05, 0xBA05}, {0xBA06, 0xBA06, 0xBA06}, {0xBA07, 0xBA07, 0xBA07}, {0xBA08, 0xBA08, 0xBA08}, {0xBA09, 0xBA09, 0xBA09}, {0xBA0A, 0xBA0A, 0xBA0A}, {0xBA0B, 0xBA0B, 0xBA0B}, {0xBA0C, 0xBA0C, 0xBA0C}, {0xBA0D, 0xBA0D, 0xBA0D}, {0xBA0E, 0xBA0E, 0xBA0E}, {0xBA0F, 0xBA0F, 0xBA0F}, {0xBA10, 0xBA10, 0xBA10}, {0xBA11, 0xBA11, 0xBA11}, {0xBA12, 0xBA12, 0xBA12}, {0xBA13, 0xBA13, 0xBA13}, {0xBA14, 0xBA14, 0xBA14}, {0xBA15, 0xBA15, 0xBA15}, {0xBA16, 0xBA16, 0xBA16}, {0xBA17, 0xBA17, 0xBA17}, {0xBA18, 0xBA18, 0xBA18}, {0xBA19, 0xBA19, 0xBA19}, {0xBA1A, 0xBA1A, 0xBA1A}, {0xBA1B, 0xBA1B, 0xBA1B}, {0xBA1C, 0xBA1C, 0xBA1C}, {0xBA1D, 0xBA1D, 0xBA1D}, {0xBA1E, 0xBA1E, 0xBA1E}, {0xBA1F, 0xBA1F, 0xBA1F}, {0xBA20, 0xBA20, 0xBA20}, {0xBA21, 0xBA21, 0xBA21}, {0xBA22, 0xBA22, 0xBA22}, {0xBA23, 0xBA23, 0xBA23}, {0xBA24, 0xBA24, 0xBA24}, {0xBA25, 0xBA25, 0xBA25}, {0xBA26, 0xBA26, 0xBA26}, {0xBA27, 0xBA27, 0xBA27}, {0xBA28, 0xBA28, 0xBA28}, {0xBA29, 0xBA29, 0xBA29}, {0xBA2A, 0xBA2A, 0xBA2A}, {0xBA2B, 0xBA2B, 0xBA2B}, {0xBA2C, 0xBA2C, 0xBA2C}, {0xBA2D, 0xBA2D, 0xBA2D}, {0xBA2E, 0xBA2E, 0xBA2E}, {0xBA2F, 0xBA2F, 0xBA2F}, {0xBA30, 0xBA30, 0xBA30}, {0xBA31, 0xBA31, 0xBA31}, {0xBA32, 0xBA32, 0xBA32}, {0xBA33, 0xBA33, 0xBA33}, {0xBA34, 0xBA34, 0xBA34}, {0xBA35, 0xBA35, 0xBA35}, {0xBA36, 0xBA36, 0xBA36}, {0xBA37, 0xBA37, 0xBA37}, {0xBA38, 0xBA38, 0xBA38}, {0xBA39, 0xBA39, 0xBA39}, {0xBA3A, 0xBA3A, 0xBA3A}, {0xBA3B, 0xBA3B, 0xBA3B}, {0xBA3C, 0xBA3C, 0xBA3C}, {0xBA3D, 0xBA3D, 0xBA3D}, {0xBA3E, 0xBA3E, 0xBA3E}, {0xBA3F, 0xBA3F, 0xBA3F}, {0xBA40, 0xBA40, 0xBA40}, {0xBA41, 0xBA41, 0xBA41}, {0xBA42, 0xBA42, 0xBA42}, {0xBA43, 0xBA43, 0xBA43}, {0xBA44, 0xBA44, 0xBA44}, {0xBA45, 0xBA45, 0xBA45}, {0xBA46, 0xBA46, 0xBA46}, {0xBA47, 0xBA47, 0xBA47}, {0xBA48, 0xBA48, 0xBA48}, {0xBA49, 0xBA49, 0xBA49}, {0xBA4A, 0xBA4A, 0xBA4A}, {0xBA4B, 0xBA4B, 0xBA4B}, {0xBA4C, 0xBA4C, 0xBA4C}, {0xBA4D, 0xBA4D, 0xBA4D}, {0xBA4E, 0xBA4E, 0xBA4E}, {0xBA4F, 0xBA4F, 0xBA4F}, {0xBA50, 0xBA50, 0xBA50}, {0xBA51, 0xBA51, 0xBA51}, {0xBA52, 0xBA52, 0xBA52}, {0xBA53, 0xBA53, 0xBA53}, {0xBA54, 0xBA54, 0xBA54}, {0xBA55, 0xBA55, 0xBA55}, {0xBA56, 0xBA56, 0xBA56}, {0xBA57, 0xBA57, 0xBA57}, {0xBA58, 0xBA58, 0xBA58}, {0xBA59, 0xBA59, 0xBA59}, {0xBA5A, 0xBA5A, 0xBA5A}, {0xBA5B, 0xBA5B, 0xBA5B}, {0xBA5C, 0xBA5C, 0xBA5C}, {0xBA5D, 0xBA5D, 0xBA5D}, {0xBA5E, 0xBA5E, 0xBA5E}, {0xBA5F, 0xBA5F, 0xBA5F}, {0xBA60, 0xBA60, 0xBA60}, {0xBA61, 0xBA61, 0xBA61}, {0xBA62, 0xBA62, 0xBA62}, {0xBA63, 0xBA63, 0xBA63}, {0xBA64, 0xBA64, 0xBA64}, {0xBA65, 0xBA65, 0xBA65}, {0xBA66, 0xBA66, 0xBA66}, {0xBA67, 0xBA67, 0xBA67}, {0xBA68, 0xBA68, 0xBA68}, {0xBA69, 0xBA69, 0xBA69}, {0xBA6A, 0xBA6A, 0xBA6A}, {0xBA6B, 0xBA6B, 0xBA6B}, {0xBA6C, 0xBA6C, 0xBA6C}, {0xBA6D, 0xBA6D, 0xBA6D}, {0xBA6E, 0xBA6E, 0xBA6E}, {0xBA6F, 0xBA6F, 0xBA6F}, {0xBA70, 0xBA70, 0xBA70}, {0xBA71, 0xBA71, 0xBA71}, {0xBA72, 0xBA72, 0xBA72}, {0xBA73, 0xBA73, 0xBA73}, {0xBA74, 0xBA74, 0xBA74}, {0xBA75, 0xBA75, 0xBA75}, {0xBA76, 0xBA76, 0xBA76}, {0xBA77, 0xBA77, 0xBA77}, {0xBA78, 0xBA78, 0xBA78}, {0xBA79, 0xBA79, 0xBA79}, {0xBA7A, 0xBA7A, 0xBA7A}, {0xBA7B, 0xBA7B, 0xBA7B}, {0xBA7C, 0xBA7C, 0xBA7C}, {0xBA7D, 0xBA7D, 0xBA7D}, {0xBA7E, 0xBA7E, 0xBA7E}, {0xBA7F, 0xBA7F, 0xBA7F}, {0xBA80, 0xBA80, 0xBA80}, {0xBA81, 0xBA81, 0xBA81}, {0xBA82, 0xBA82, 0xBA82}, {0xBA83, 0xBA83, 0xBA83}, {0xBA84, 0xBA84, 0xBA84}, {0xBA85, 0xBA85, 0xBA85}, {0xBA86, 0xBA86, 0xBA86}, {0xBA87, 0xBA87, 0xBA87}, {0xBA88, 0xBA88, 0xBA88}, {0xBA89, 0xBA89, 0xBA89}, {0xBA8A, 0xBA8A, 0xBA8A}, {0xBA8B, 0xBA8B, 0xBA8B}, {0xBA8C, 0xBA8C, 0xBA8C}, {0xBA8D, 0xBA8D, 0xBA8D}, {0xBA8E, 0xBA8E, 0xBA8E}, {0xBA8F, 0xBA8F, 0xBA8F}, {0xBA90, 0xBA90, 0xBA90}, {0xBA91, 0xBA91, 0xBA91}, {0xBA92, 0xBA92, 0xBA92}, {0xBA93, 0xBA93, 0xBA93}, {0xBA94, 0xBA94, 0xBA94}, {0xBA95, 0xBA95, 0xBA95}, {0xBA96, 0xBA96, 0xBA96}, {0xBA97, 0xBA97, 0xBA97}, {0xBA98, 0xBA98, 0xBA98}, {0xBA99, 0xBA99, 0xBA99}, {0xBA9A, 0xBA9A, 0xBA9A}, {0xBA9B, 0xBA9B, 0xBA9B}, {0xBA9C, 0xBA9C, 0xBA9C}, {0xBA9D, 0xBA9D, 0xBA9D}, {0xBA9E, 0xBA9E, 0xBA9E}, {0xBA9F, 0xBA9F, 0xBA9F}, {0xBAA0, 0xBAA0, 0xBAA0}, {0xBAA1, 0xBAA1, 0xBAA1}, {0xBAA2, 0xBAA2, 0xBAA2}, {0xBAA3, 0xBAA3, 0xBAA3}, {0xBAA4, 0xBAA4, 0xBAA4}, {0xBAA5, 0xBAA5, 0xBAA5}, {0xBAA6, 0xBAA6, 0xBAA6}, {0xBAA7, 0xBAA7, 0xBAA7}, {0xBAA8, 0xBAA8, 0xBAA8}, {0xBAA9, 0xBAA9, 0xBAA9}, {0xBAAA, 0xBAAA, 0xBAAA}, {0xBAAB, 0xBAAB, 0xBAAB}, {0xBAAC, 0xBAAC, 0xBAAC}, {0xBAAD, 0xBAAD, 0xBAAD}, {0xBAAE, 0xBAAE, 0xBAAE}, {0xBAAF, 0xBAAF, 0xBAAF}, {0xBAB0, 0xBAB0, 0xBAB0}, {0xBAB1, 0xBAB1, 0xBAB1}, {0xBAB2, 0xBAB2, 0xBAB2}, {0xBAB3, 0xBAB3, 0xBAB3}, {0xBAB4, 0xBAB4, 0xBAB4}, {0xBAB5, 0xBAB5, 0xBAB5}, {0xBAB6, 0xBAB6, 0xBAB6}, {0xBAB7, 0xBAB7, 0xBAB7}, {0xBAB8, 0xBAB8, 0xBAB8}, {0xBAB9, 0xBAB9, 0xBAB9}, {0xBABA, 0xBABA, 0xBABA}, {0xBABB, 0xBABB, 0xBABB}, {0xBABC, 0xBABC, 0xBABC}, {0xBABD, 0xBABD, 0xBABD}, {0xBABE, 0xBABE, 0xBABE}, {0xBABF, 0xBABF, 0xBABF}, {0xBAC0, 0xBAC0, 0xBAC0}, {0xBAC1, 0xBAC1, 0xBAC1}, {0xBAC2, 0xBAC2, 0xBAC2}, {0xBAC3, 0xBAC3, 0xBAC3}, {0xBAC4, 0xBAC4, 0xBAC4}, {0xBAC5, 0xBAC5, 0xBAC5}, {0xBAC6, 0xBAC6, 0xBAC6}, {0xBAC7, 0xBAC7, 0xBAC7}, {0xBAC8, 0xBAC8, 0xBAC8}, {0xBAC9, 0xBAC9, 0xBAC9}, {0xBACA, 0xBACA, 0xBACA}, {0xBACB, 0xBACB, 0xBACB}, {0xBACC, 0xBACC, 0xBACC}, {0xBACD, 0xBACD, 0xBACD}, {0xBACE, 0xBACE, 0xBACE}, {0xBACF, 0xBACF, 0xBACF}, {0xBAD0, 0xBAD0, 0xBAD0}, {0xBAD1, 0xBAD1, 0xBAD1}, {0xBAD2, 0xBAD2, 0xBAD2}, {0xBAD3, 0xBAD3, 0xBAD3}, {0xBAD4, 0xBAD4, 0xBAD4}, {0xBAD5, 0xBAD5, 0xBAD5}, {0xBAD6, 0xBAD6, 0xBAD6}, {0xBAD7, 0xBAD7, 0xBAD7}, {0xBAD8, 0xBAD8, 0xBAD8}, {0xBAD9, 0xBAD9, 0xBAD9}, {0xBADA, 0xBADA, 0xBADA}, {0xBADB, 0xBADB, 0xBADB}, {0xBADC, 0xBADC, 0xBADC}, {0xBADD, 0xBADD, 0xBADD}, {0xBADE, 0xBADE, 0xBADE}, {0xBADF, 0xBADF, 0xBADF}, {0xBAE0, 0xBAE0, 0xBAE0}, {0xBAE1, 0xBAE1, 0xBAE1}, {0xBAE2, 0xBAE2, 0xBAE2}, {0xBAE3, 0xBAE3, 0xBAE3}, {0xBAE4, 0xBAE4, 0xBAE4}, {0xBAE5, 0xBAE5, 0xBAE5}, {0xBAE6, 0xBAE6, 0xBAE6}, {0xBAE7, 0xBAE7, 0xBAE7}, {0xBAE8, 0xBAE8, 0xBAE8}, {0xBAE9, 0xBAE9, 0xBAE9}, {0xBAEA, 0xBAEA, 0xBAEA}, {0xBAEB, 0xBAEB, 0xBAEB}, {0xBAEC, 0xBAEC, 0xBAEC}, {0xBAED, 0xBAED, 0xBAED}, {0xBAEE, 0xBAEE, 0xBAEE}, {0xBAEF, 0xBAEF, 0xBAEF}, {0xBAF0, 0xBAF0, 0xBAF0}, {0xBAF1, 0xBAF1, 0xBAF1}, {0xBAF2, 0xBAF2, 0xBAF2}, {0xBAF3, 0xBAF3, 0xBAF3}, {0xBAF4, 0xBAF4, 0xBAF4}, {0xBAF5, 0xBAF5, 0xBAF5}, {0xBAF6, 0xBAF6, 0xBAF6}, {0xBAF7, 0xBAF7, 0xBAF7}, {0xBAF8, 0xBAF8, 0xBAF8}, {0xBAF9, 0xBAF9, 0xBAF9}, {0xBAFA, 0xBAFA, 0xBAFA}, {0xBAFB, 0xBAFB, 0xBAFB}, {0xBAFC, 0xBAFC, 0xBAFC}, {0xBAFD, 0xBAFD, 0xBAFD}, {0xBAFE, 0xBAFE, 0xBAFE}, {0xBAFF, 0xBAFF, 0xBAFF}, {0xBB00, 0xBB00, 0xBB00}, {0xBB01, 0xBB01, 0xBB01}, {0xBB02, 0xBB02, 0xBB02}, {0xBB03, 0xBB03, 0xBB03}, {0xBB04, 0xBB04, 0xBB04}, {0xBB05, 0xBB05, 0xBB05}, {0xBB06, 0xBB06, 0xBB06}, {0xBB07, 0xBB07, 0xBB07}, {0xBB08, 0xBB08, 0xBB08}, {0xBB09, 0xBB09, 0xBB09}, {0xBB0A, 0xBB0A, 0xBB0A}, {0xBB0B, 0xBB0B, 0xBB0B}, {0xBB0C, 0xBB0C, 0xBB0C}, {0xBB0D, 0xBB0D, 0xBB0D}, {0xBB0E, 0xBB0E, 0xBB0E}, {0xBB0F, 0xBB0F, 0xBB0F}, {0xBB10, 0xBB10, 0xBB10}, {0xBB11, 0xBB11, 0xBB11}, {0xBB12, 0xBB12, 0xBB12}, {0xBB13, 0xBB13, 0xBB13}, {0xBB14, 0xBB14, 0xBB14}, {0xBB15, 0xBB15, 0xBB15}, {0xBB16, 0xBB16, 0xBB16}, {0xBB17, 0xBB17, 0xBB17}, {0xBB18, 0xBB18, 0xBB18}, {0xBB19, 0xBB19, 0xBB19}, {0xBB1A, 0xBB1A, 0xBB1A}, {0xBB1B, 0xBB1B, 0xBB1B}, {0xBB1C, 0xBB1C, 0xBB1C}, {0xBB1D, 0xBB1D, 0xBB1D}, {0xBB1E, 0xBB1E, 0xBB1E}, {0xBB1F, 0xBB1F, 0xBB1F}, {0xBB20, 0xBB20, 0xBB20}, {0xBB21, 0xBB21, 0xBB21}, {0xBB22, 0xBB22, 0xBB22}, {0xBB23, 0xBB23, 0xBB23}, {0xBB24, 0xBB24, 0xBB24}, {0xBB25, 0xBB25, 0xBB25}, {0xBB26, 0xBB26, 0xBB26}, {0xBB27, 0xBB27, 0xBB27}, {0xBB28, 0xBB28, 0xBB28}, {0xBB29, 0xBB29, 0xBB29}, {0xBB2A, 0xBB2A, 0xBB2A}, {0xBB2B, 0xBB2B, 0xBB2B}, {0xBB2C, 0xBB2C, 0xBB2C}, {0xBB2D, 0xBB2D, 0xBB2D}, {0xBB2E, 0xBB2E, 0xBB2E}, {0xBB2F, 0xBB2F, 0xBB2F}, {0xBB30, 0xBB30, 0xBB30}, {0xBB31, 0xBB31, 0xBB31}, {0xBB32, 0xBB32, 0xBB32}, {0xBB33, 0xBB33, 0xBB33}, {0xBB34, 0xBB34, 0xBB34}, {0xBB35, 0xBB35, 0xBB35}, {0xBB36, 0xBB36, 0xBB36}, {0xBB37, 0xBB37, 0xBB37}, {0xBB38, 0xBB38, 0xBB38}, {0xBB39, 0xBB39, 0xBB39}, {0xBB3A, 0xBB3A, 0xBB3A}, {0xBB3B, 0xBB3B, 0xBB3B}, {0xBB3C, 0xBB3C, 0xBB3C}, {0xBB3D, 0xBB3D, 0xBB3D}, {0xBB3E, 0xBB3E, 0xBB3E}, {0xBB3F, 0xBB3F, 0xBB3F}, {0xBB40, 0xBB40, 0xBB40}, {0xBB41, 0xBB41, 0xBB41}, {0xBB42, 0xBB42, 0xBB42}, {0xBB43, 0xBB43, 0xBB43}, {0xBB44, 0xBB44, 0xBB44}, {0xBB45, 0xBB45, 0xBB45}, {0xBB46, 0xBB46, 0xBB46}, {0xBB47, 0xBB47, 0xBB47}, {0xBB48, 0xBB48, 0xBB48}, {0xBB49, 0xBB49, 0xBB49}, {0xBB4A, 0xBB4A, 0xBB4A}, {0xBB4B, 0xBB4B, 0xBB4B}, {0xBB4C, 0xBB4C, 0xBB4C}, {0xBB4D, 0xBB4D, 0xBB4D}, {0xBB4E, 0xBB4E, 0xBB4E}, {0xBB4F, 0xBB4F, 0xBB4F}, {0xBB50, 0xBB50, 0xBB50}, {0xBB51, 0xBB51, 0xBB51}, {0xBB52, 0xBB52, 0xBB52}, {0xBB53, 0xBB53, 0xBB53}, {0xBB54, 0xBB54, 0xBB54}, {0xBB55, 0xBB55, 0xBB55}, {0xBB56, 0xBB56, 0xBB56}, {0xBB57, 0xBB57, 0xBB57}, {0xBB58, 0xBB58, 0xBB58}, {0xBB59, 0xBB59, 0xBB59}, {0xBB5A, 0xBB5A, 0xBB5A}, {0xBB5B, 0xBB5B, 0xBB5B}, {0xBB5C, 0xBB5C, 0xBB5C}, {0xBB5D, 0xBB5D, 0xBB5D}, {0xBB5E, 0xBB5E, 0xBB5E}, {0xBB5F, 0xBB5F, 0xBB5F}, {0xBB60, 0xBB60, 0xBB60}, {0xBB61, 0xBB61, 0xBB61}, {0xBB62, 0xBB62, 0xBB62}, {0xBB63, 0xBB63, 0xBB63}, {0xBB64, 0xBB64, 0xBB64}, {0xBB65, 0xBB65, 0xBB65}, {0xBB66, 0xBB66, 0xBB66}, {0xBB67, 0xBB67, 0xBB67}, {0xBB68, 0xBB68, 0xBB68}, {0xBB69, 0xBB69, 0xBB69}, {0xBB6A, 0xBB6A, 0xBB6A}, {0xBB6B, 0xBB6B, 0xBB6B}, {0xBB6C, 0xBB6C, 0xBB6C}, {0xBB6D, 0xBB6D, 0xBB6D}, {0xBB6E, 0xBB6E, 0xBB6E}, {0xBB6F, 0xBB6F, 0xBB6F}, {0xBB70, 0xBB70, 0xBB70}, {0xBB71, 0xBB71, 0xBB71}, {0xBB72, 0xBB72, 0xBB72}, {0xBB73, 0xBB73, 0xBB73}, {0xBB74, 0xBB74, 0xBB74}, {0xBB75, 0xBB75, 0xBB75}, {0xBB76, 0xBB76, 0xBB76}, {0xBB77, 0xBB77, 0xBB77}, {0xBB78, 0xBB78, 0xBB78}, {0xBB79, 0xBB79, 0xBB79}, {0xBB7A, 0xBB7A, 0xBB7A}, {0xBB7B, 0xBB7B, 0xBB7B}, {0xBB7C, 0xBB7C, 0xBB7C}, {0xBB7D, 0xBB7D, 0xBB7D}, {0xBB7E, 0xBB7E, 0xBB7E}, {0xBB7F, 0xBB7F, 0xBB7F}, {0xBB80, 0xBB80, 0xBB80}, {0xBB81, 0xBB81, 0xBB81}, {0xBB82, 0xBB82, 0xBB82}, {0xBB83, 0xBB83, 0xBB83}, {0xBB84, 0xBB84, 0xBB84}, {0xBB85, 0xBB85, 0xBB85}, {0xBB86, 0xBB86, 0xBB86}, {0xBB87, 0xBB87, 0xBB87}, {0xBB88, 0xBB88, 0xBB88}, {0xBB89, 0xBB89, 0xBB89}, {0xBB8A, 0xBB8A, 0xBB8A}, {0xBB8B, 0xBB8B, 0xBB8B}, {0xBB8C, 0xBB8C, 0xBB8C}, {0xBB8D, 0xBB8D, 0xBB8D}, {0xBB8E, 0xBB8E, 0xBB8E}, {0xBB8F, 0xBB8F, 0xBB8F}, {0xBB90, 0xBB90, 0xBB90}, {0xBB91, 0xBB91, 0xBB91}, {0xBB92, 0xBB92, 0xBB92}, {0xBB93, 0xBB93, 0xBB93}, {0xBB94, 0xBB94, 0xBB94}, {0xBB95, 0xBB95, 0xBB95}, {0xBB96, 0xBB96, 0xBB96}, {0xBB97, 0xBB97, 0xBB97}, {0xBB98, 0xBB98, 0xBB98}, {0xBB99, 0xBB99, 0xBB99}, {0xBB9A, 0xBB9A, 0xBB9A}, {0xBB9B, 0xBB9B, 0xBB9B}, {0xBB9C, 0xBB9C, 0xBB9C}, {0xBB9D, 0xBB9D, 0xBB9D}, {0xBB9E, 0xBB9E, 0xBB9E}, {0xBB9F, 0xBB9F, 0xBB9F}, {0xBBA0, 0xBBA0, 0xBBA0}, {0xBBA1, 0xBBA1, 0xBBA1}, {0xBBA2, 0xBBA2, 0xBBA2}, {0xBBA3, 0xBBA3, 0xBBA3}, {0xBBA4, 0xBBA4, 0xBBA4}, {0xBBA5, 0xBBA5, 0xBBA5}, {0xBBA6, 0xBBA6, 0xBBA6}, {0xBBA7, 0xBBA7, 0xBBA7}, {0xBBA8, 0xBBA8, 0xBBA8}, {0xBBA9, 0xBBA9, 0xBBA9}, {0xBBAA, 0xBBAA, 0xBBAA}, {0xBBAB, 0xBBAB, 0xBBAB}, {0xBBAC, 0xBBAC, 0xBBAC}, {0xBBAD, 0xBBAD, 0xBBAD}, {0xBBAE, 0xBBAE, 0xBBAE}, {0xBBAF, 0xBBAF, 0xBBAF}, {0xBBB0, 0xBBB0, 0xBBB0}, {0xBBB1, 0xBBB1, 0xBBB1}, {0xBBB2, 0xBBB2, 0xBBB2}, {0xBBB3, 0xBBB3, 0xBBB3}, {0xBBB4, 0xBBB4, 0xBBB4}, {0xBBB5, 0xBBB5, 0xBBB5}, {0xBBB6, 0xBBB6, 0xBBB6}, {0xBBB7, 0xBBB7, 0xBBB7}, {0xBBB8, 0xBBB8, 0xBBB8}, {0xBBB9, 0xBBB9, 0xBBB9}, {0xBBBA, 0xBBBA, 0xBBBA}, {0xBBBB, 0xBBBB, 0xBBBB}, {0xBBBC, 0xBBBC, 0xBBBC}, {0xBBBD, 0xBBBD, 0xBBBD}, {0xBBBE, 0xBBBE, 0xBBBE}, {0xBBBF, 0xBBBF, 0xBBBF}, {0xBBC0, 0xBBC0, 0xBBC0}, {0xBBC1, 0xBBC1, 0xBBC1}, {0xBBC2, 0xBBC2, 0xBBC2}, {0xBBC3, 0xBBC3, 0xBBC3}, {0xBBC4, 0xBBC4, 0xBBC4}, {0xBBC5, 0xBBC5, 0xBBC5}, {0xBBC6, 0xBBC6, 0xBBC6}, {0xBBC7, 0xBBC7, 0xBBC7}, {0xBBC8, 0xBBC8, 0xBBC8}, {0xBBC9, 0xBBC9, 0xBBC9}, {0xBBCA, 0xBBCA, 0xBBCA}, {0xBBCB, 0xBBCB, 0xBBCB}, {0xBBCC, 0xBBCC, 0xBBCC}, {0xBBCD, 0xBBCD, 0xBBCD}, {0xBBCE, 0xBBCE, 0xBBCE}, {0xBBCF, 0xBBCF, 0xBBCF}, {0xBBD0, 0xBBD0, 0xBBD0}, {0xBBD1, 0xBBD1, 0xBBD1}, {0xBBD2, 0xBBD2, 0xBBD2}, {0xBBD3, 0xBBD3, 0xBBD3}, {0xBBD4, 0xBBD4, 0xBBD4}, {0xBBD5, 0xBBD5, 0xBBD5}, {0xBBD6, 0xBBD6, 0xBBD6}, {0xBBD7, 0xBBD7, 0xBBD7}, {0xBBD8, 0xBBD8, 0xBBD8}, {0xBBD9, 0xBBD9, 0xBBD9}, {0xBBDA, 0xBBDA, 0xBBDA}, {0xBBDB, 0xBBDB, 0xBBDB}, {0xBBDC, 0xBBDC, 0xBBDC}, {0xBBDD, 0xBBDD, 0xBBDD}, {0xBBDE, 0xBBDE, 0xBBDE}, {0xBBDF, 0xBBDF, 0xBBDF}, {0xBBE0, 0xBBE0, 0xBBE0}, {0xBBE1, 0xBBE1, 0xBBE1}, {0xBBE2, 0xBBE2, 0xBBE2}, {0xBBE3, 0xBBE3, 0xBBE3}, {0xBBE4, 0xBBE4, 0xBBE4}, {0xBBE5, 0xBBE5, 0xBBE5}, {0xBBE6, 0xBBE6, 0xBBE6}, {0xBBE7, 0xBBE7, 0xBBE7}, {0xBBE8, 0xBBE8, 0xBBE8}, {0xBBE9, 0xBBE9, 0xBBE9}, {0xBBEA, 0xBBEA, 0xBBEA}, {0xBBEB, 0xBBEB, 0xBBEB}, {0xBBEC, 0xBBEC, 0xBBEC}, {0xBBED, 0xBBED, 0xBBED}, {0xBBEE, 0xBBEE, 0xBBEE}, {0xBBEF, 0xBBEF, 0xBBEF}, {0xBBF0, 0xBBF0, 0xBBF0}, {0xBBF1, 0xBBF1, 0xBBF1}, {0xBBF2, 0xBBF2, 0xBBF2}, {0xBBF3, 0xBBF3, 0xBBF3}, {0xBBF4, 0xBBF4, 0xBBF4}, {0xBBF5, 0xBBF5, 0xBBF5}, {0xBBF6, 0xBBF6, 0xBBF6}, {0xBBF7, 0xBBF7, 0xBBF7}, {0xBBF8, 0xBBF8, 0xBBF8}, {0xBBF9, 0xBBF9, 0xBBF9}, {0xBBFA, 0xBBFA, 0xBBFA}, {0xBBFB, 0xBBFB, 0xBBFB}, {0xBBFC, 0xBBFC, 0xBBFC}, {0xBBFD, 0xBBFD, 0xBBFD}, {0xBBFE, 0xBBFE, 0xBBFE}, {0xBBFF, 0xBBFF, 0xBBFF}, {0xBC00, 0xBC00, 0xBC00}, {0xBC01, 0xBC01, 0xBC01}, {0xBC02, 0xBC02, 0xBC02}, {0xBC03, 0xBC03, 0xBC03}, {0xBC04, 0xBC04, 0xBC04}, {0xBC05, 0xBC05, 0xBC05}, {0xBC06, 0xBC06, 0xBC06}, {0xBC07, 0xBC07, 0xBC07}, {0xBC08, 0xBC08, 0xBC08}, {0xBC09, 0xBC09, 0xBC09}, {0xBC0A, 0xBC0A, 0xBC0A}, {0xBC0B, 0xBC0B, 0xBC0B}, {0xBC0C, 0xBC0C, 0xBC0C}, {0xBC0D, 0xBC0D, 0xBC0D}, {0xBC0E, 0xBC0E, 0xBC0E}, {0xBC0F, 0xBC0F, 0xBC0F}, {0xBC10, 0xBC10, 0xBC10}, {0xBC11, 0xBC11, 0xBC11}, {0xBC12, 0xBC12, 0xBC12}, {0xBC13, 0xBC13, 0xBC13}, {0xBC14, 0xBC14, 0xBC14}, {0xBC15, 0xBC15, 0xBC15}, {0xBC16, 0xBC16, 0xBC16}, {0xBC17, 0xBC17, 0xBC17}, {0xBC18, 0xBC18, 0xBC18}, {0xBC19, 0xBC19, 0xBC19}, {0xBC1A, 0xBC1A, 0xBC1A}, {0xBC1B, 0xBC1B, 0xBC1B}, {0xBC1C, 0xBC1C, 0xBC1C}, {0xBC1D, 0xBC1D, 0xBC1D}, {0xBC1E, 0xBC1E, 0xBC1E}, {0xBC1F, 0xBC1F, 0xBC1F}, {0xBC20, 0xBC20, 0xBC20}, {0xBC21, 0xBC21, 0xBC21}, {0xBC22, 0xBC22, 0xBC22}, {0xBC23, 0xBC23, 0xBC23}, {0xBC24, 0xBC24, 0xBC24}, {0xBC25, 0xBC25, 0xBC25}, {0xBC26, 0xBC26, 0xBC26}, {0xBC27, 0xBC27, 0xBC27}, {0xBC28, 0xBC28, 0xBC28}, {0xBC29, 0xBC29, 0xBC29}, {0xBC2A, 0xBC2A, 0xBC2A}, {0xBC2B, 0xBC2B, 0xBC2B}, {0xBC2C, 0xBC2C, 0xBC2C}, {0xBC2D, 0xBC2D, 0xBC2D}, {0xBC2E, 0xBC2E, 0xBC2E}, {0xBC2F, 0xBC2F, 0xBC2F}, {0xBC30, 0xBC30, 0xBC30}, {0xBC31, 0xBC31, 0xBC31}, {0xBC32, 0xBC32, 0xBC32}, {0xBC33, 0xBC33, 0xBC33}, {0xBC34, 0xBC34, 0xBC34}, {0xBC35, 0xBC35, 0xBC35}, {0xBC36, 0xBC36, 0xBC36}, {0xBC37, 0xBC37, 0xBC37}, {0xBC38, 0xBC38, 0xBC38}, {0xBC39, 0xBC39, 0xBC39}, {0xBC3A, 0xBC3A, 0xBC3A}, {0xBC3B, 0xBC3B, 0xBC3B}, {0xBC3C, 0xBC3C, 0xBC3C}, {0xBC3D, 0xBC3D, 0xBC3D}, {0xBC3E, 0xBC3E, 0xBC3E}, {0xBC3F, 0xBC3F, 0xBC3F}, {0xBC40, 0xBC40, 0xBC40}, {0xBC41, 0xBC41, 0xBC41}, {0xBC42, 0xBC42, 0xBC42}, {0xBC43, 0xBC43, 0xBC43}, {0xBC44, 0xBC44, 0xBC44}, {0xBC45, 0xBC45, 0xBC45}, {0xBC46, 0xBC46, 0xBC46}, {0xBC47, 0xBC47, 0xBC47}, {0xBC48, 0xBC48, 0xBC48}, {0xBC49, 0xBC49, 0xBC49}, {0xBC4A, 0xBC4A, 0xBC4A}, {0xBC4B, 0xBC4B, 0xBC4B}, {0xBC4C, 0xBC4C, 0xBC4C}, {0xBC4D, 0xBC4D, 0xBC4D}, {0xBC4E, 0xBC4E, 0xBC4E}, {0xBC4F, 0xBC4F, 0xBC4F}, {0xBC50, 0xBC50, 0xBC50}, {0xBC51, 0xBC51, 0xBC51}, {0xBC52, 0xBC52, 0xBC52}, {0xBC53, 0xBC53, 0xBC53}, {0xBC54, 0xBC54, 0xBC54}, {0xBC55, 0xBC55, 0xBC55}, {0xBC56, 0xBC56, 0xBC56}, {0xBC57, 0xBC57, 0xBC57}, {0xBC58, 0xBC58, 0xBC58}, {0xBC59, 0xBC59, 0xBC59}, {0xBC5A, 0xBC5A, 0xBC5A}, {0xBC5B, 0xBC5B, 0xBC5B}, {0xBC5C, 0xBC5C, 0xBC5C}, {0xBC5D, 0xBC5D, 0xBC5D}, {0xBC5E, 0xBC5E, 0xBC5E}, {0xBC5F, 0xBC5F, 0xBC5F}, {0xBC60, 0xBC60, 0xBC60}, {0xBC61, 0xBC61, 0xBC61}, {0xBC62, 0xBC62, 0xBC62}, {0xBC63, 0xBC63, 0xBC63}, {0xBC64, 0xBC64, 0xBC64}, {0xBC65, 0xBC65, 0xBC65}, {0xBC66, 0xBC66, 0xBC66}, {0xBC67, 0xBC67, 0xBC67}, {0xBC68, 0xBC68, 0xBC68}, {0xBC69, 0xBC69, 0xBC69}, {0xBC6A, 0xBC6A, 0xBC6A}, {0xBC6B, 0xBC6B, 0xBC6B}, {0xBC6C, 0xBC6C, 0xBC6C}, {0xBC6D, 0xBC6D, 0xBC6D}, {0xBC6E, 0xBC6E, 0xBC6E}, {0xBC6F, 0xBC6F, 0xBC6F}, {0xBC70, 0xBC70, 0xBC70}, {0xBC71, 0xBC71, 0xBC71}, {0xBC72, 0xBC72, 0xBC72}, {0xBC73, 0xBC73, 0xBC73}, {0xBC74, 0xBC74, 0xBC74}, {0xBC75, 0xBC75, 0xBC75}, {0xBC76, 0xBC76, 0xBC76}, {0xBC77, 0xBC77, 0xBC77}, {0xBC78, 0xBC78, 0xBC78}, {0xBC79, 0xBC79, 0xBC79}, {0xBC7A, 0xBC7A, 0xBC7A}, {0xBC7B, 0xBC7B, 0xBC7B}, {0xBC7C, 0xBC7C, 0xBC7C}, {0xBC7D, 0xBC7D, 0xBC7D}, {0xBC7E, 0xBC7E, 0xBC7E}, {0xBC7F, 0xBC7F, 0xBC7F}, {0xBC80, 0xBC80, 0xBC80}, {0xBC81, 0xBC81, 0xBC81}, {0xBC82, 0xBC82, 0xBC82}, {0xBC83, 0xBC83, 0xBC83}, {0xBC84, 0xBC84, 0xBC84}, {0xBC85, 0xBC85, 0xBC85}, {0xBC86, 0xBC86, 0xBC86}, {0xBC87, 0xBC87, 0xBC87}, {0xBC88, 0xBC88, 0xBC88}, {0xBC89, 0xBC89, 0xBC89}, {0xBC8A, 0xBC8A, 0xBC8A}, {0xBC8B, 0xBC8B, 0xBC8B}, {0xBC8C, 0xBC8C, 0xBC8C}, {0xBC8D, 0xBC8D, 0xBC8D}, {0xBC8E, 0xBC8E, 0xBC8E}, {0xBC8F, 0xBC8F, 0xBC8F}, {0xBC90, 0xBC90, 0xBC90}, {0xBC91, 0xBC91, 0xBC91}, {0xBC92, 0xBC92, 0xBC92}, {0xBC93, 0xBC93, 0xBC93}, {0xBC94, 0xBC94, 0xBC94}, {0xBC95, 0xBC95, 0xBC95}, {0xBC96, 0xBC96, 0xBC96}, {0xBC97, 0xBC97, 0xBC97}, {0xBC98, 0xBC98, 0xBC98}, {0xBC99, 0xBC99, 0xBC99}, {0xBC9A, 0xBC9A, 0xBC9A}, {0xBC9B, 0xBC9B, 0xBC9B}, {0xBC9C, 0xBC9C, 0xBC9C}, {0xBC9D, 0xBC9D, 0xBC9D}, {0xBC9E, 0xBC9E, 0xBC9E}, {0xBC9F, 0xBC9F, 0xBC9F}, {0xBCA0, 0xBCA0, 0xBCA0}, {0xBCA1, 0xBCA1, 0xBCA1}, {0xBCA2, 0xBCA2, 0xBCA2}, {0xBCA3, 0xBCA3, 0xBCA3}, {0xBCA4, 0xBCA4, 0xBCA4}, {0xBCA5, 0xBCA5, 0xBCA5}, {0xBCA6, 0xBCA6, 0xBCA6}, {0xBCA7, 0xBCA7, 0xBCA7}, {0xBCA8, 0xBCA8, 0xBCA8}, {0xBCA9, 0xBCA9, 0xBCA9}, {0xBCAA, 0xBCAA, 0xBCAA}, {0xBCAB, 0xBCAB, 0xBCAB}, {0xBCAC, 0xBCAC, 0xBCAC}, {0xBCAD, 0xBCAD, 0xBCAD}, {0xBCAE, 0xBCAE, 0xBCAE}, {0xBCAF, 0xBCAF, 0xBCAF}, {0xBCB0, 0xBCB0, 0xBCB0}, {0xBCB1, 0xBCB1, 0xBCB1}, {0xBCB2, 0xBCB2, 0xBCB2}, {0xBCB3, 0xBCB3, 0xBCB3}, {0xBCB4, 0xBCB4, 0xBCB4}, {0xBCB5, 0xBCB5, 0xBCB5}, {0xBCB6, 0xBCB6, 0xBCB6}, {0xBCB7, 0xBCB7, 0xBCB7}, {0xBCB8, 0xBCB8, 0xBCB8}, {0xBCB9, 0xBCB9, 0xBCB9}, {0xBCBA, 0xBCBA, 0xBCBA}, {0xBCBB, 0xBCBB, 0xBCBB}, {0xBCBC, 0xBCBC, 0xBCBC}, {0xBCBD, 0xBCBD, 0xBCBD}, {0xBCBE, 0xBCBE, 0xBCBE}, {0xBCBF, 0xBCBF, 0xBCBF}, {0xBCC0, 0xBCC0, 0xBCC0}, {0xBCC1, 0xBCC1, 0xBCC1}, {0xBCC2, 0xBCC2, 0xBCC2}, {0xBCC3, 0xBCC3, 0xBCC3}, {0xBCC4, 0xBCC4, 0xBCC4}, {0xBCC5, 0xBCC5, 0xBCC5}, {0xBCC6, 0xBCC6, 0xBCC6}, {0xBCC7, 0xBCC7, 0xBCC7}, {0xBCC8, 0xBCC8, 0xBCC8}, {0xBCC9, 0xBCC9, 0xBCC9}, {0xBCCA, 0xBCCA, 0xBCCA}, {0xBCCB, 0xBCCB, 0xBCCB}, {0xBCCC, 0xBCCC, 0xBCCC}, {0xBCCD, 0xBCCD, 0xBCCD}, {0xBCCE, 0xBCCE, 0xBCCE}, {0xBCCF, 0xBCCF, 0xBCCF}, {0xBCD0, 0xBCD0, 0xBCD0}, {0xBCD1, 0xBCD1, 0xBCD1}, {0xBCD2, 0xBCD2, 0xBCD2}, {0xBCD3, 0xBCD3, 0xBCD3}, {0xBCD4, 0xBCD4, 0xBCD4}, {0xBCD5, 0xBCD5, 0xBCD5}, {0xBCD6, 0xBCD6, 0xBCD6}, {0xBCD7, 0xBCD7, 0xBCD7}, {0xBCD8, 0xBCD8, 0xBCD8}, {0xBCD9, 0xBCD9, 0xBCD9}, {0xBCDA, 0xBCDA, 0xBCDA}, {0xBCDB, 0xBCDB, 0xBCDB}, {0xBCDC, 0xBCDC, 0xBCDC}, {0xBCDD, 0xBCDD, 0xBCDD}, {0xBCDE, 0xBCDE, 0xBCDE}, {0xBCDF, 0xBCDF, 0xBCDF}, {0xBCE0, 0xBCE0, 0xBCE0}, {0xBCE1, 0xBCE1, 0xBCE1}, {0xBCE2, 0xBCE2, 0xBCE2}, {0xBCE3, 0xBCE3, 0xBCE3}, {0xBCE4, 0xBCE4, 0xBCE4}, {0xBCE5, 0xBCE5, 0xBCE5}, {0xBCE6, 0xBCE6, 0xBCE6}, {0xBCE7, 0xBCE7, 0xBCE7}, {0xBCE8, 0xBCE8, 0xBCE8}, {0xBCE9, 0xBCE9, 0xBCE9}, {0xBCEA, 0xBCEA, 0xBCEA}, {0xBCEB, 0xBCEB, 0xBCEB}, {0xBCEC, 0xBCEC, 0xBCEC}, {0xBCED, 0xBCED, 0xBCED}, {0xBCEE, 0xBCEE, 0xBCEE}, {0xBCEF, 0xBCEF, 0xBCEF}, {0xBCF0, 0xBCF0, 0xBCF0}, {0xBCF1, 0xBCF1, 0xBCF1}, {0xBCF2, 0xBCF2, 0xBCF2}, {0xBCF3, 0xBCF3, 0xBCF3}, {0xBCF4, 0xBCF4, 0xBCF4}, {0xBCF5, 0xBCF5, 0xBCF5}, {0xBCF6, 0xBCF6, 0xBCF6}, {0xBCF7, 0xBCF7, 0xBCF7}, {0xBCF8, 0xBCF8, 0xBCF8}, {0xBCF9, 0xBCF9, 0xBCF9}, {0xBCFA, 0xBCFA, 0xBCFA}, {0xBCFB, 0xBCFB, 0xBCFB}, {0xBCFC, 0xBCFC, 0xBCFC}, {0xBCFD, 0xBCFD, 0xBCFD}, {0xBCFE, 0xBCFE, 0xBCFE}, {0xBCFF, 0xBCFF, 0xBCFF}, {0xBD00, 0xBD00, 0xBD00}, {0xBD01, 0xBD01, 0xBD01}, {0xBD02, 0xBD02, 0xBD02}, {0xBD03, 0xBD03, 0xBD03}, {0xBD04, 0xBD04, 0xBD04}, {0xBD05, 0xBD05, 0xBD05}, {0xBD06, 0xBD06, 0xBD06}, {0xBD07, 0xBD07, 0xBD07}, {0xBD08, 0xBD08, 0xBD08}, {0xBD09, 0xBD09, 0xBD09}, {0xBD0A, 0xBD0A, 0xBD0A}, {0xBD0B, 0xBD0B, 0xBD0B}, {0xBD0C, 0xBD0C, 0xBD0C}, {0xBD0D, 0xBD0D, 0xBD0D}, {0xBD0E, 0xBD0E, 0xBD0E}, {0xBD0F, 0xBD0F, 0xBD0F}, {0xBD10, 0xBD10, 0xBD10}, {0xBD11, 0xBD11, 0xBD11}, {0xBD12, 0xBD12, 0xBD12}, {0xBD13, 0xBD13, 0xBD13}, {0xBD14, 0xBD14, 0xBD14}, {0xBD15, 0xBD15, 0xBD15}, {0xBD16, 0xBD16, 0xBD16}, {0xBD17, 0xBD17, 0xBD17}, {0xBD18, 0xBD18, 0xBD18}, {0xBD19, 0xBD19, 0xBD19}, {0xBD1A, 0xBD1A, 0xBD1A}, {0xBD1B, 0xBD1B, 0xBD1B}, {0xBD1C, 0xBD1C, 0xBD1C}, {0xBD1D, 0xBD1D, 0xBD1D}, {0xBD1E, 0xBD1E, 0xBD1E}, {0xBD1F, 0xBD1F, 0xBD1F}, {0xBD20, 0xBD20, 0xBD20}, {0xBD21, 0xBD21, 0xBD21}, {0xBD22, 0xBD22, 0xBD22}, {0xBD23, 0xBD23, 0xBD23}, {0xBD24, 0xBD24, 0xBD24}, {0xBD25, 0xBD25, 0xBD25}, {0xBD26, 0xBD26, 0xBD26}, {0xBD27, 0xBD27, 0xBD27}, {0xBD28, 0xBD28, 0xBD28}, {0xBD29, 0xBD29, 0xBD29}, {0xBD2A, 0xBD2A, 0xBD2A}, {0xBD2B, 0xBD2B, 0xBD2B}, {0xBD2C, 0xBD2C, 0xBD2C}, {0xBD2D, 0xBD2D, 0xBD2D}, {0xBD2E, 0xBD2E, 0xBD2E}, {0xBD2F, 0xBD2F, 0xBD2F}, {0xBD30, 0xBD30, 0xBD30}, {0xBD31, 0xBD31, 0xBD31}, {0xBD32, 0xBD32, 0xBD32}, {0xBD33, 0xBD33, 0xBD33}, {0xBD34, 0xBD34, 0xBD34}, {0xBD35, 0xBD35, 0xBD35}, {0xBD36, 0xBD36, 0xBD36}, {0xBD37, 0xBD37, 0xBD37}, {0xBD38, 0xBD38, 0xBD38}, {0xBD39, 0xBD39, 0xBD39}, {0xBD3A, 0xBD3A, 0xBD3A}, {0xBD3B, 0xBD3B, 0xBD3B}, {0xBD3C, 0xBD3C, 0xBD3C}, {0xBD3D, 0xBD3D, 0xBD3D}, {0xBD3E, 0xBD3E, 0xBD3E}, {0xBD3F, 0xBD3F, 0xBD3F}, {0xBD40, 0xBD40, 0xBD40}, {0xBD41, 0xBD41, 0xBD41}, {0xBD42, 0xBD42, 0xBD42}, {0xBD43, 0xBD43, 0xBD43}, {0xBD44, 0xBD44, 0xBD44}, {0xBD45, 0xBD45, 0xBD45}, {0xBD46, 0xBD46, 0xBD46}, {0xBD47, 0xBD47, 0xBD47}, {0xBD48, 0xBD48, 0xBD48}, {0xBD49, 0xBD49, 0xBD49}, {0xBD4A, 0xBD4A, 0xBD4A}, {0xBD4B, 0xBD4B, 0xBD4B}, {0xBD4C, 0xBD4C, 0xBD4C}, {0xBD4D, 0xBD4D, 0xBD4D}, {0xBD4E, 0xBD4E, 0xBD4E}, {0xBD4F, 0xBD4F, 0xBD4F}, {0xBD50, 0xBD50, 0xBD50}, {0xBD51, 0xBD51, 0xBD51}, {0xBD52, 0xBD52, 0xBD52}, {0xBD53, 0xBD53, 0xBD53}, {0xBD54, 0xBD54, 0xBD54}, {0xBD55, 0xBD55, 0xBD55}, {0xBD56, 0xBD56, 0xBD56}, {0xBD57, 0xBD57, 0xBD57}, {0xBD58, 0xBD58, 0xBD58}, {0xBD59, 0xBD59, 0xBD59}, {0xBD5A, 0xBD5A, 0xBD5A}, {0xBD5B, 0xBD5B, 0xBD5B}, {0xBD5C, 0xBD5C, 0xBD5C}, {0xBD5D, 0xBD5D, 0xBD5D}, {0xBD5E, 0xBD5E, 0xBD5E}, {0xBD5F, 0xBD5F, 0xBD5F}, {0xBD60, 0xBD60, 0xBD60}, {0xBD61, 0xBD61, 0xBD61}, {0xBD62, 0xBD62, 0xBD62}, {0xBD63, 0xBD63, 0xBD63}, {0xBD64, 0xBD64, 0xBD64}, {0xBD65, 0xBD65, 0xBD65}, {0xBD66, 0xBD66, 0xBD66}, {0xBD67, 0xBD67, 0xBD67}, {0xBD68, 0xBD68, 0xBD68}, {0xBD69, 0xBD69, 0xBD69}, {0xBD6A, 0xBD6A, 0xBD6A}, {0xBD6B, 0xBD6B, 0xBD6B}, {0xBD6C, 0xBD6C, 0xBD6C}, {0xBD6D, 0xBD6D, 0xBD6D}, {0xBD6E, 0xBD6E, 0xBD6E}, {0xBD6F, 0xBD6F, 0xBD6F}, {0xBD70, 0xBD70, 0xBD70}, {0xBD71, 0xBD71, 0xBD71}, {0xBD72, 0xBD72, 0xBD72}, {0xBD73, 0xBD73, 0xBD73}, {0xBD74, 0xBD74, 0xBD74}, {0xBD75, 0xBD75, 0xBD75}, {0xBD76, 0xBD76, 0xBD76}, {0xBD77, 0xBD77, 0xBD77}, {0xBD78, 0xBD78, 0xBD78}, {0xBD79, 0xBD79, 0xBD79}, {0xBD7A, 0xBD7A, 0xBD7A}, {0xBD7B, 0xBD7B, 0xBD7B}, {0xBD7C, 0xBD7C, 0xBD7C}, {0xBD7D, 0xBD7D, 0xBD7D}, {0xBD7E, 0xBD7E, 0xBD7E}, {0xBD7F, 0xBD7F, 0xBD7F}, {0xBD80, 0xBD80, 0xBD80}, {0xBD81, 0xBD81, 0xBD81}, {0xBD82, 0xBD82, 0xBD82}, {0xBD83, 0xBD83, 0xBD83}, {0xBD84, 0xBD84, 0xBD84}, {0xBD85, 0xBD85, 0xBD85}, {0xBD86, 0xBD86, 0xBD86}, {0xBD87, 0xBD87, 0xBD87}, {0xBD88, 0xBD88, 0xBD88}, {0xBD89, 0xBD89, 0xBD89}, {0xBD8A, 0xBD8A, 0xBD8A}, {0xBD8B, 0xBD8B, 0xBD8B}, {0xBD8C, 0xBD8C, 0xBD8C}, {0xBD8D, 0xBD8D, 0xBD8D}, {0xBD8E, 0xBD8E, 0xBD8E}, {0xBD8F, 0xBD8F, 0xBD8F}, {0xBD90, 0xBD90, 0xBD90}, {0xBD91, 0xBD91, 0xBD91}, {0xBD92, 0xBD92, 0xBD92}, {0xBD93, 0xBD93, 0xBD93}, {0xBD94, 0xBD94, 0xBD94}, {0xBD95, 0xBD95, 0xBD95}, {0xBD96, 0xBD96, 0xBD96}, {0xBD97, 0xBD97, 0xBD97}, {0xBD98, 0xBD98, 0xBD98}, {0xBD99, 0xBD99, 0xBD99}, {0xBD9A, 0xBD9A, 0xBD9A}, {0xBD9B, 0xBD9B, 0xBD9B}, {0xBD9C, 0xBD9C, 0xBD9C}, {0xBD9D, 0xBD9D, 0xBD9D}, {0xBD9E, 0xBD9E, 0xBD9E}, {0xBD9F, 0xBD9F, 0xBD9F}, {0xBDA0, 0xBDA0, 0xBDA0}, {0xBDA1, 0xBDA1, 0xBDA1}, {0xBDA2, 0xBDA2, 0xBDA2}, {0xBDA3, 0xBDA3, 0xBDA3}, {0xBDA4, 0xBDA4, 0xBDA4}, {0xBDA5, 0xBDA5, 0xBDA5}, {0xBDA6, 0xBDA6, 0xBDA6}, {0xBDA7, 0xBDA7, 0xBDA7}, {0xBDA8, 0xBDA8, 0xBDA8}, {0xBDA9, 0xBDA9, 0xBDA9}, {0xBDAA, 0xBDAA, 0xBDAA}, {0xBDAB, 0xBDAB, 0xBDAB}, {0xBDAC, 0xBDAC, 0xBDAC}, {0xBDAD, 0xBDAD, 0xBDAD}, {0xBDAE, 0xBDAE, 0xBDAE}, {0xBDAF, 0xBDAF, 0xBDAF}, {0xBDB0, 0xBDB0, 0xBDB0}, {0xBDB1, 0xBDB1, 0xBDB1}, {0xBDB2, 0xBDB2, 0xBDB2}, {0xBDB3, 0xBDB3, 0xBDB3}, {0xBDB4, 0xBDB4, 0xBDB4}, {0xBDB5, 0xBDB5, 0xBDB5}, {0xBDB6, 0xBDB6, 0xBDB6}, {0xBDB7, 0xBDB7, 0xBDB7}, {0xBDB8, 0xBDB8, 0xBDB8}, {0xBDB9, 0xBDB9, 0xBDB9}, {0xBDBA, 0xBDBA, 0xBDBA}, {0xBDBB, 0xBDBB, 0xBDBB}, {0xBDBC, 0xBDBC, 0xBDBC}, {0xBDBD, 0xBDBD, 0xBDBD}, {0xBDBE, 0xBDBE, 0xBDBE}, {0xBDBF, 0xBDBF, 0xBDBF}, {0xBDC0, 0xBDC0, 0xBDC0}, {0xBDC1, 0xBDC1, 0xBDC1}, {0xBDC2, 0xBDC2, 0xBDC2}, {0xBDC3, 0xBDC3, 0xBDC3}, {0xBDC4, 0xBDC4, 0xBDC4}, {0xBDC5, 0xBDC5, 0xBDC5}, {0xBDC6, 0xBDC6, 0xBDC6}, {0xBDC7, 0xBDC7, 0xBDC7}, {0xBDC8, 0xBDC8, 0xBDC8}, {0xBDC9, 0xBDC9, 0xBDC9}, {0xBDCA, 0xBDCA, 0xBDCA}, {0xBDCB, 0xBDCB, 0xBDCB}, {0xBDCC, 0xBDCC, 0xBDCC}, {0xBDCD, 0xBDCD, 0xBDCD}, {0xBDCE, 0xBDCE, 0xBDCE}, {0xBDCF, 0xBDCF, 0xBDCF}, {0xBDD0, 0xBDD0, 0xBDD0}, {0xBDD1, 0xBDD1, 0xBDD1}, {0xBDD2, 0xBDD2, 0xBDD2}, {0xBDD3, 0xBDD3, 0xBDD3}, {0xBDD4, 0xBDD4, 0xBDD4}, {0xBDD5, 0xBDD5, 0xBDD5}, {0xBDD6, 0xBDD6, 0xBDD6}, {0xBDD7, 0xBDD7, 0xBDD7}, {0xBDD8, 0xBDD8, 0xBDD8}, {0xBDD9, 0xBDD9, 0xBDD9}, {0xBDDA, 0xBDDA, 0xBDDA}, {0xBDDB, 0xBDDB, 0xBDDB}, {0xBDDC, 0xBDDC, 0xBDDC}, {0xBDDD, 0xBDDD, 0xBDDD}, {0xBDDE, 0xBDDE, 0xBDDE}, {0xBDDF, 0xBDDF, 0xBDDF}, {0xBDE0, 0xBDE0, 0xBDE0}, {0xBDE1, 0xBDE1, 0xBDE1}, {0xBDE2, 0xBDE2, 0xBDE2}, {0xBDE3, 0xBDE3, 0xBDE3}, {0xBDE4, 0xBDE4, 0xBDE4}, {0xBDE5, 0xBDE5, 0xBDE5}, {0xBDE6, 0xBDE6, 0xBDE6}, {0xBDE7, 0xBDE7, 0xBDE7}, {0xBDE8, 0xBDE8, 0xBDE8}, {0xBDE9, 0xBDE9, 0xBDE9}, {0xBDEA, 0xBDEA, 0xBDEA}, {0xBDEB, 0xBDEB, 0xBDEB}, {0xBDEC, 0xBDEC, 0xBDEC}, {0xBDED, 0xBDED, 0xBDED}, {0xBDEE, 0xBDEE, 0xBDEE}, {0xBDEF, 0xBDEF, 0xBDEF}, {0xBDF0, 0xBDF0, 0xBDF0}, {0xBDF1, 0xBDF1, 0xBDF1}, {0xBDF2, 0xBDF2, 0xBDF2}, {0xBDF3, 0xBDF3, 0xBDF3}, {0xBDF4, 0xBDF4, 0xBDF4}, {0xBDF5, 0xBDF5, 0xBDF5}, {0xBDF6, 0xBDF6, 0xBDF6}, {0xBDF7, 0xBDF7, 0xBDF7}, {0xBDF8, 0xBDF8, 0xBDF8}, {0xBDF9, 0xBDF9, 0xBDF9}, {0xBDFA, 0xBDFA, 0xBDFA}, {0xBDFB, 0xBDFB, 0xBDFB}, {0xBDFC, 0xBDFC, 0xBDFC}, {0xBDFD, 0xBDFD, 0xBDFD}, {0xBDFE, 0xBDFE, 0xBDFE}, {0xBDFF, 0xBDFF, 0xBDFF}, {0xBE00, 0xBE00, 0xBE00}, {0xBE01, 0xBE01, 0xBE01}, {0xBE02, 0xBE02, 0xBE02}, {0xBE03, 0xBE03, 0xBE03}, {0xBE04, 0xBE04, 0xBE04}, {0xBE05, 0xBE05, 0xBE05}, {0xBE06, 0xBE06, 0xBE06}, {0xBE07, 0xBE07, 0xBE07}, {0xBE08, 0xBE08, 0xBE08}, {0xBE09, 0xBE09, 0xBE09}, {0xBE0A, 0xBE0A, 0xBE0A}, {0xBE0B, 0xBE0B, 0xBE0B}, {0xBE0C, 0xBE0C, 0xBE0C}, {0xBE0D, 0xBE0D, 0xBE0D}, {0xBE0E, 0xBE0E, 0xBE0E}, {0xBE0F, 0xBE0F, 0xBE0F}, {0xBE10, 0xBE10, 0xBE10}, {0xBE11, 0xBE11, 0xBE11}, {0xBE12, 0xBE12, 0xBE12}, {0xBE13, 0xBE13, 0xBE13}, {0xBE14, 0xBE14, 0xBE14}, {0xBE15, 0xBE15, 0xBE15}, {0xBE16, 0xBE16, 0xBE16}, {0xBE17, 0xBE17, 0xBE17}, {0xBE18, 0xBE18, 0xBE18}, {0xBE19, 0xBE19, 0xBE19}, {0xBE1A, 0xBE1A, 0xBE1A}, {0xBE1B, 0xBE1B, 0xBE1B}, {0xBE1C, 0xBE1C, 0xBE1C}, {0xBE1D, 0xBE1D, 0xBE1D}, {0xBE1E, 0xBE1E, 0xBE1E}, {0xBE1F, 0xBE1F, 0xBE1F}, {0xBE20, 0xBE20, 0xBE20}, {0xBE21, 0xBE21, 0xBE21}, {0xBE22, 0xBE22, 0xBE22}, {0xBE23, 0xBE23, 0xBE23}, {0xBE24, 0xBE24, 0xBE24}, {0xBE25, 0xBE25, 0xBE25}, {0xBE26, 0xBE26, 0xBE26}, {0xBE27, 0xBE27, 0xBE27}, {0xBE28, 0xBE28, 0xBE28}, {0xBE29, 0xBE29, 0xBE29}, {0xBE2A, 0xBE2A, 0xBE2A}, {0xBE2B, 0xBE2B, 0xBE2B}, {0xBE2C, 0xBE2C, 0xBE2C}, {0xBE2D, 0xBE2D, 0xBE2D}, {0xBE2E, 0xBE2E, 0xBE2E}, {0xBE2F, 0xBE2F, 0xBE2F}, {0xBE30, 0xBE30, 0xBE30}, {0xBE31, 0xBE31, 0xBE31}, {0xBE32, 0xBE32, 0xBE32}, {0xBE33, 0xBE33, 0xBE33}, {0xBE34, 0xBE34, 0xBE34}, {0xBE35, 0xBE35, 0xBE35}, {0xBE36, 0xBE36, 0xBE36}, {0xBE37, 0xBE37, 0xBE37}, {0xBE38, 0xBE38, 0xBE38}, {0xBE39, 0xBE39, 0xBE39}, {0xBE3A, 0xBE3A, 0xBE3A}, {0xBE3B, 0xBE3B, 0xBE3B}, {0xBE3C, 0xBE3C, 0xBE3C}, {0xBE3D, 0xBE3D, 0xBE3D}, {0xBE3E, 0xBE3E, 0xBE3E}, {0xBE3F, 0xBE3F, 0xBE3F}, {0xBE40, 0xBE40, 0xBE40}, {0xBE41, 0xBE41, 0xBE41}, {0xBE42, 0xBE42, 0xBE42}, {0xBE43, 0xBE43, 0xBE43}, {0xBE44, 0xBE44, 0xBE44}, {0xBE45, 0xBE45, 0xBE45}, {0xBE46, 0xBE46, 0xBE46}, {0xBE47, 0xBE47, 0xBE47}, {0xBE48, 0xBE48, 0xBE48}, {0xBE49, 0xBE49, 0xBE49}, {0xBE4A, 0xBE4A, 0xBE4A}, {0xBE4B, 0xBE4B, 0xBE4B}, {0xBE4C, 0xBE4C, 0xBE4C}, {0xBE4D, 0xBE4D, 0xBE4D}, {0xBE4E, 0xBE4E, 0xBE4E}, {0xBE4F, 0xBE4F, 0xBE4F}, {0xBE50, 0xBE50, 0xBE50}, {0xBE51, 0xBE51, 0xBE51}, {0xBE52, 0xBE52, 0xBE52}, {0xBE53, 0xBE53, 0xBE53}, {0xBE54, 0xBE54, 0xBE54}, {0xBE55, 0xBE55, 0xBE55}, {0xBE56, 0xBE56, 0xBE56}, {0xBE57, 0xBE57, 0xBE57}, {0xBE58, 0xBE58, 0xBE58}, {0xBE59, 0xBE59, 0xBE59}, {0xBE5A, 0xBE5A, 0xBE5A}, {0xBE5B, 0xBE5B, 0xBE5B}, {0xBE5C, 0xBE5C, 0xBE5C}, {0xBE5D, 0xBE5D, 0xBE5D}, {0xBE5E, 0xBE5E, 0xBE5E}, {0xBE5F, 0xBE5F, 0xBE5F}, {0xBE60, 0xBE60, 0xBE60}, {0xBE61, 0xBE61, 0xBE61}, {0xBE62, 0xBE62, 0xBE62}, {0xBE63, 0xBE63, 0xBE63}, {0xBE64, 0xBE64, 0xBE64}, {0xBE65, 0xBE65, 0xBE65}, {0xBE66, 0xBE66, 0xBE66}, {0xBE67, 0xBE67, 0xBE67}, {0xBE68, 0xBE68, 0xBE68}, {0xBE69, 0xBE69, 0xBE69}, {0xBE6A, 0xBE6A, 0xBE6A}, {0xBE6B, 0xBE6B, 0xBE6B}, {0xBE6C, 0xBE6C, 0xBE6C}, {0xBE6D, 0xBE6D, 0xBE6D}, {0xBE6E, 0xBE6E, 0xBE6E}, {0xBE6F, 0xBE6F, 0xBE6F}, {0xBE70, 0xBE70, 0xBE70}, {0xBE71, 0xBE71, 0xBE71}, {0xBE72, 0xBE72, 0xBE72}, {0xBE73, 0xBE73, 0xBE73}, {0xBE74, 0xBE74, 0xBE74}, {0xBE75, 0xBE75, 0xBE75}, {0xBE76, 0xBE76, 0xBE76}, {0xBE77, 0xBE77, 0xBE77}, {0xBE78, 0xBE78, 0xBE78}, {0xBE79, 0xBE79, 0xBE79}, {0xBE7A, 0xBE7A, 0xBE7A}, {0xBE7B, 0xBE7B, 0xBE7B}, {0xBE7C, 0xBE7C, 0xBE7C}, {0xBE7D, 0xBE7D, 0xBE7D}, {0xBE7E, 0xBE7E, 0xBE7E}, {0xBE7F, 0xBE7F, 0xBE7F}, {0xBE80, 0xBE80, 0xBE80}, {0xBE81, 0xBE81, 0xBE81}, {0xBE82, 0xBE82, 0xBE82}, {0xBE83, 0xBE83, 0xBE83}, {0xBE84, 0xBE84, 0xBE84}, {0xBE85, 0xBE85, 0xBE85}, {0xBE86, 0xBE86, 0xBE86}, {0xBE87, 0xBE87, 0xBE87}, {0xBE88, 0xBE88, 0xBE88}, {0xBE89, 0xBE89, 0xBE89}, {0xBE8A, 0xBE8A, 0xBE8A}, {0xBE8B, 0xBE8B, 0xBE8B}, {0xBE8C, 0xBE8C, 0xBE8C}, {0xBE8D, 0xBE8D, 0xBE8D}, {0xBE8E, 0xBE8E, 0xBE8E}, {0xBE8F, 0xBE8F, 0xBE8F}, {0xBE90, 0xBE90, 0xBE90}, {0xBE91, 0xBE91, 0xBE91}, {0xBE92, 0xBE92, 0xBE92}, {0xBE93, 0xBE93, 0xBE93}, {0xBE94, 0xBE94, 0xBE94}, {0xBE95, 0xBE95, 0xBE95}, {0xBE96, 0xBE96, 0xBE96}, {0xBE97, 0xBE97, 0xBE97}, {0xBE98, 0xBE98, 0xBE98}, {0xBE99, 0xBE99, 0xBE99}, {0xBE9A, 0xBE9A, 0xBE9A}, {0xBE9B, 0xBE9B, 0xBE9B}, {0xBE9C, 0xBE9C, 0xBE9C}, {0xBE9D, 0xBE9D, 0xBE9D}, {0xBE9E, 0xBE9E, 0xBE9E}, {0xBE9F, 0xBE9F, 0xBE9F}, {0xBEA0, 0xBEA0, 0xBEA0}, {0xBEA1, 0xBEA1, 0xBEA1}, {0xBEA2, 0xBEA2, 0xBEA2}, {0xBEA3, 0xBEA3, 0xBEA3}, {0xBEA4, 0xBEA4, 0xBEA4}, {0xBEA5, 0xBEA5, 0xBEA5}, {0xBEA6, 0xBEA6, 0xBEA6}, {0xBEA7, 0xBEA7, 0xBEA7}, {0xBEA8, 0xBEA8, 0xBEA8}, {0xBEA9, 0xBEA9, 0xBEA9}, {0xBEAA, 0xBEAA, 0xBEAA}, {0xBEAB, 0xBEAB, 0xBEAB}, {0xBEAC, 0xBEAC, 0xBEAC}, {0xBEAD, 0xBEAD, 0xBEAD}, {0xBEAE, 0xBEAE, 0xBEAE}, {0xBEAF, 0xBEAF, 0xBEAF}, {0xBEB0, 0xBEB0, 0xBEB0}, {0xBEB1, 0xBEB1, 0xBEB1}, {0xBEB2, 0xBEB2, 0xBEB2}, {0xBEB3, 0xBEB3, 0xBEB3}, {0xBEB4, 0xBEB4, 0xBEB4}, {0xBEB5, 0xBEB5, 0xBEB5}, {0xBEB6, 0xBEB6, 0xBEB6}, {0xBEB7, 0xBEB7, 0xBEB7}, {0xBEB8, 0xBEB8, 0xBEB8}, {0xBEB9, 0xBEB9, 0xBEB9}, {0xBEBA, 0xBEBA, 0xBEBA}, {0xBEBB, 0xBEBB, 0xBEBB}, {0xBEBC, 0xBEBC, 0xBEBC}, {0xBEBD, 0xBEBD, 0xBEBD}, {0xBEBE, 0xBEBE, 0xBEBE}, {0xBEBF, 0xBEBF, 0xBEBF}, {0xBEC0, 0xBEC0, 0xBEC0}, {0xBEC1, 0xBEC1, 0xBEC1}, {0xBEC2, 0xBEC2, 0xBEC2}, {0xBEC3, 0xBEC3, 0xBEC3}, {0xBEC4, 0xBEC4, 0xBEC4}, {0xBEC5, 0xBEC5, 0xBEC5}, {0xBEC6, 0xBEC6, 0xBEC6}, {0xBEC7, 0xBEC7, 0xBEC7}, {0xBEC8, 0xBEC8, 0xBEC8}, {0xBEC9, 0xBEC9, 0xBEC9}, {0xBECA, 0xBECA, 0xBECA}, {0xBECB, 0xBECB, 0xBECB}, {0xBECC, 0xBECC, 0xBECC}, {0xBECD, 0xBECD, 0xBECD}, {0xBECE, 0xBECE, 0xBECE}, {0xBECF, 0xBECF, 0xBECF}, {0xBED0, 0xBED0, 0xBED0}, {0xBED1, 0xBED1, 0xBED1}, {0xBED2, 0xBED2, 0xBED2}, {0xBED3, 0xBED3, 0xBED3}, {0xBED4, 0xBED4, 0xBED4}, {0xBED5, 0xBED5, 0xBED5}, {0xBED6, 0xBED6, 0xBED6}, {0xBED7, 0xBED7, 0xBED7}, {0xBED8, 0xBED8, 0xBED8}, {0xBED9, 0xBED9, 0xBED9}, {0xBEDA, 0xBEDA, 0xBEDA}, {0xBEDB, 0xBEDB, 0xBEDB}, {0xBEDC, 0xBEDC, 0xBEDC}, {0xBEDD, 0xBEDD, 0xBEDD}, {0xBEDE, 0xBEDE, 0xBEDE}, {0xBEDF, 0xBEDF, 0xBEDF}, {0xBEE0, 0xBEE0, 0xBEE0}, {0xBEE1, 0xBEE1, 0xBEE1}, {0xBEE2, 0xBEE2, 0xBEE2}, {0xBEE3, 0xBEE3, 0xBEE3}, {0xBEE4, 0xBEE4, 0xBEE4}, {0xBEE5, 0xBEE5, 0xBEE5}, {0xBEE6, 0xBEE6, 0xBEE6}, {0xBEE7, 0xBEE7, 0xBEE7}, {0xBEE8, 0xBEE8, 0xBEE8}, {0xBEE9, 0xBEE9, 0xBEE9}, {0xBEEA, 0xBEEA, 0xBEEA}, {0xBEEB, 0xBEEB, 0xBEEB}, {0xBEEC, 0xBEEC, 0xBEEC}, {0xBEED, 0xBEED, 0xBEED}, {0xBEEE, 0xBEEE, 0xBEEE}, {0xBEEF, 0xBEEF, 0xBEEF}, {0xBEF0, 0xBEF0, 0xBEF0}, {0xBEF1, 0xBEF1, 0xBEF1}, {0xBEF2, 0xBEF2, 0xBEF2}, {0xBEF3, 0xBEF3, 0xBEF3}, {0xBEF4, 0xBEF4, 0xBEF4}, {0xBEF5, 0xBEF5, 0xBEF5}, {0xBEF6, 0xBEF6, 0xBEF6}, {0xBEF7, 0xBEF7, 0xBEF7}, {0xBEF8, 0xBEF8, 0xBEF8}, {0xBEF9, 0xBEF9, 0xBEF9}, {0xBEFA, 0xBEFA, 0xBEFA}, {0xBEFB, 0xBEFB, 0xBEFB}, {0xBEFC, 0xBEFC, 0xBEFC}, {0xBEFD, 0xBEFD, 0xBEFD}, {0xBEFE, 0xBEFE, 0xBEFE}, {0xBEFF, 0xBEFF, 0xBEFF}, {0xBF00, 0xBF00, 0xBF00}, {0xBF01, 0xBF01, 0xBF01}, {0xBF02, 0xBF02, 0xBF02}, {0xBF03, 0xBF03, 0xBF03}, {0xBF04, 0xBF04, 0xBF04}, {0xBF05, 0xBF05, 0xBF05}, {0xBF06, 0xBF06, 0xBF06}, {0xBF07, 0xBF07, 0xBF07}, {0xBF08, 0xBF08, 0xBF08}, {0xBF09, 0xBF09, 0xBF09}, {0xBF0A, 0xBF0A, 0xBF0A}, {0xBF0B, 0xBF0B, 0xBF0B}, {0xBF0C, 0xBF0C, 0xBF0C}, {0xBF0D, 0xBF0D, 0xBF0D}, {0xBF0E, 0xBF0E, 0xBF0E}, {0xBF0F, 0xBF0F, 0xBF0F}, {0xBF10, 0xBF10, 0xBF10}, {0xBF11, 0xBF11, 0xBF11}, {0xBF12, 0xBF12, 0xBF12}, {0xBF13, 0xBF13, 0xBF13}, {0xBF14, 0xBF14, 0xBF14}, {0xBF15, 0xBF15, 0xBF15}, {0xBF16, 0xBF16, 0xBF16}, {0xBF17, 0xBF17, 0xBF17}, {0xBF18, 0xBF18, 0xBF18}, {0xBF19, 0xBF19, 0xBF19}, {0xBF1A, 0xBF1A, 0xBF1A}, {0xBF1B, 0xBF1B, 0xBF1B}, {0xBF1C, 0xBF1C, 0xBF1C}, {0xBF1D, 0xBF1D, 0xBF1D}, {0xBF1E, 0xBF1E, 0xBF1E}, {0xBF1F, 0xBF1F, 0xBF1F}, {0xBF20, 0xBF20, 0xBF20}, {0xBF21, 0xBF21, 0xBF21}, {0xBF22, 0xBF22, 0xBF22}, {0xBF23, 0xBF23, 0xBF23}, {0xBF24, 0xBF24, 0xBF24}, {0xBF25, 0xBF25, 0xBF25}, {0xBF26, 0xBF26, 0xBF26}, {0xBF27, 0xBF27, 0xBF27}, {0xBF28, 0xBF28, 0xBF28}, {0xBF29, 0xBF29, 0xBF29}, {0xBF2A, 0xBF2A, 0xBF2A}, {0xBF2B, 0xBF2B, 0xBF2B}, {0xBF2C, 0xBF2C, 0xBF2C}, {0xBF2D, 0xBF2D, 0xBF2D}, {0xBF2E, 0xBF2E, 0xBF2E}, {0xBF2F, 0xBF2F, 0xBF2F}, {0xBF30, 0xBF30, 0xBF30}, {0xBF31, 0xBF31, 0xBF31}, {0xBF32, 0xBF32, 0xBF32}, {0xBF33, 0xBF33, 0xBF33}, {0xBF34, 0xBF34, 0xBF34}, {0xBF35, 0xBF35, 0xBF35}, {0xBF36, 0xBF36, 0xBF36}, {0xBF37, 0xBF37, 0xBF37}, {0xBF38, 0xBF38, 0xBF38}, {0xBF39, 0xBF39, 0xBF39}, {0xBF3A, 0xBF3A, 0xBF3A}, {0xBF3B, 0xBF3B, 0xBF3B}, {0xBF3C, 0xBF3C, 0xBF3C}, {0xBF3D, 0xBF3D, 0xBF3D}, {0xBF3E, 0xBF3E, 0xBF3E}, {0xBF3F, 0xBF3F, 0xBF3F}, {0xBF40, 0xBF40, 0xBF40}, {0xBF41, 0xBF41, 0xBF41}, {0xBF42, 0xBF42, 0xBF42}, {0xBF43, 0xBF43, 0xBF43}, {0xBF44, 0xBF44, 0xBF44}, {0xBF45, 0xBF45, 0xBF45}, {0xBF46, 0xBF46, 0xBF46}, {0xBF47, 0xBF47, 0xBF47}, {0xBF48, 0xBF48, 0xBF48}, {0xBF49, 0xBF49, 0xBF49}, {0xBF4A, 0xBF4A, 0xBF4A}, {0xBF4B, 0xBF4B, 0xBF4B}, {0xBF4C, 0xBF4C, 0xBF4C}, {0xBF4D, 0xBF4D, 0xBF4D}, {0xBF4E, 0xBF4E, 0xBF4E}, {0xBF4F, 0xBF4F, 0xBF4F}, {0xBF50, 0xBF50, 0xBF50}, {0xBF51, 0xBF51, 0xBF51}, {0xBF52, 0xBF52, 0xBF52}, {0xBF53, 0xBF53, 0xBF53}, {0xBF54, 0xBF54, 0xBF54}, {0xBF55, 0xBF55, 0xBF55}, {0xBF56, 0xBF56, 0xBF56}, {0xBF57, 0xBF57, 0xBF57}, {0xBF58, 0xBF58, 0xBF58}, {0xBF59, 0xBF59, 0xBF59}, {0xBF5A, 0xBF5A, 0xBF5A}, {0xBF5B, 0xBF5B, 0xBF5B}, {0xBF5C, 0xBF5C, 0xBF5C}, {0xBF5D, 0xBF5D, 0xBF5D}, {0xBF5E, 0xBF5E, 0xBF5E}, {0xBF5F, 0xBF5F, 0xBF5F}, {0xBF60, 0xBF60, 0xBF60}, {0xBF61, 0xBF61, 0xBF61}, {0xBF62, 0xBF62, 0xBF62}, {0xBF63, 0xBF63, 0xBF63}, {0xBF64, 0xBF64, 0xBF64}, {0xBF65, 0xBF65, 0xBF65}, {0xBF66, 0xBF66, 0xBF66}, {0xBF67, 0xBF67, 0xBF67}, {0xBF68, 0xBF68, 0xBF68}, {0xBF69, 0xBF69, 0xBF69}, {0xBF6A, 0xBF6A, 0xBF6A}, {0xBF6B, 0xBF6B, 0xBF6B}, {0xBF6C, 0xBF6C, 0xBF6C}, {0xBF6D, 0xBF6D, 0xBF6D}, {0xBF6E, 0xBF6E, 0xBF6E}, {0xBF6F, 0xBF6F, 0xBF6F}, {0xBF70, 0xBF70, 0xBF70}, {0xBF71, 0xBF71, 0xBF71}, {0xBF72, 0xBF72, 0xBF72}, {0xBF73, 0xBF73, 0xBF73}, {0xBF74, 0xBF74, 0xBF74}, {0xBF75, 0xBF75, 0xBF75}, {0xBF76, 0xBF76, 0xBF76}, {0xBF77, 0xBF77, 0xBF77}, {0xBF78, 0xBF78, 0xBF78}, {0xBF79, 0xBF79, 0xBF79}, {0xBF7A, 0xBF7A, 0xBF7A}, {0xBF7B, 0xBF7B, 0xBF7B}, {0xBF7C, 0xBF7C, 0xBF7C}, {0xBF7D, 0xBF7D, 0xBF7D}, {0xBF7E, 0xBF7E, 0xBF7E}, {0xBF7F, 0xBF7F, 0xBF7F}, {0xBF80, 0xBF80, 0xBF80}, {0xBF81, 0xBF81, 0xBF81}, {0xBF82, 0xBF82, 0xBF82}, {0xBF83, 0xBF83, 0xBF83}, {0xBF84, 0xBF84, 0xBF84}, {0xBF85, 0xBF85, 0xBF85}, {0xBF86, 0xBF86, 0xBF86}, {0xBF87, 0xBF87, 0xBF87}, {0xBF88, 0xBF88, 0xBF88}, {0xBF89, 0xBF89, 0xBF89}, {0xBF8A, 0xBF8A, 0xBF8A}, {0xBF8B, 0xBF8B, 0xBF8B}, {0xBF8C, 0xBF8C, 0xBF8C}, {0xBF8D, 0xBF8D, 0xBF8D}, {0xBF8E, 0xBF8E, 0xBF8E}, {0xBF8F, 0xBF8F, 0xBF8F}, {0xBF90, 0xBF90, 0xBF90}, {0xBF91, 0xBF91, 0xBF91}, {0xBF92, 0xBF92, 0xBF92}, {0xBF93, 0xBF93, 0xBF93}, {0xBF94, 0xBF94, 0xBF94}, {0xBF95, 0xBF95, 0xBF95}, {0xBF96, 0xBF96, 0xBF96}, {0xBF97, 0xBF97, 0xBF97}, {0xBF98, 0xBF98, 0xBF98}, {0xBF99, 0xBF99, 0xBF99}, {0xBF9A, 0xBF9A, 0xBF9A}, {0xBF9B, 0xBF9B, 0xBF9B}, {0xBF9C, 0xBF9C, 0xBF9C}, {0xBF9D, 0xBF9D, 0xBF9D}, {0xBF9E, 0xBF9E, 0xBF9E}, {0xBF9F, 0xBF9F, 0xBF9F}, {0xBFA0, 0xBFA0, 0xBFA0}, {0xBFA1, 0xBFA1, 0xBFA1}, {0xBFA2, 0xBFA2, 0xBFA2}, {0xBFA3, 0xBFA3, 0xBFA3}, {0xBFA4, 0xBFA4, 0xBFA4}, {0xBFA5, 0xBFA5, 0xBFA5}, {0xBFA6, 0xBFA6, 0xBFA6}, {0xBFA7, 0xBFA7, 0xBFA7}, {0xBFA8, 0xBFA8, 0xBFA8}, {0xBFA9, 0xBFA9, 0xBFA9}, {0xBFAA, 0xBFAA, 0xBFAA}, {0xBFAB, 0xBFAB, 0xBFAB}, {0xBFAC, 0xBFAC, 0xBFAC}, {0xBFAD, 0xBFAD, 0xBFAD}, {0xBFAE, 0xBFAE, 0xBFAE}, {0xBFAF, 0xBFAF, 0xBFAF}, {0xBFB0, 0xBFB0, 0xBFB0}, {0xBFB1, 0xBFB1, 0xBFB1}, {0xBFB2, 0xBFB2, 0xBFB2}, {0xBFB3, 0xBFB3, 0xBFB3}, {0xBFB4, 0xBFB4, 0xBFB4}, {0xBFB5, 0xBFB5, 0xBFB5}, {0xBFB6, 0xBFB6, 0xBFB6}, {0xBFB7, 0xBFB7, 0xBFB7}, {0xBFB8, 0xBFB8, 0xBFB8}, {0xBFB9, 0xBFB9, 0xBFB9}, {0xBFBA, 0xBFBA, 0xBFBA}, {0xBFBB, 0xBFBB, 0xBFBB}, {0xBFBC, 0xBFBC, 0xBFBC}, {0xBFBD, 0xBFBD, 0xBFBD}, {0xBFBE, 0xBFBE, 0xBFBE}, {0xBFBF, 0xBFBF, 0xBFBF}, {0xBFC0, 0xBFC0, 0xBFC0}, {0xBFC1, 0xBFC1, 0xBFC1}, {0xBFC2, 0xBFC2, 0xBFC2}, {0xBFC3, 0xBFC3, 0xBFC3}, {0xBFC4, 0xBFC4, 0xBFC4}, {0xBFC5, 0xBFC5, 0xBFC5}, {0xBFC6, 0xBFC6, 0xBFC6}, {0xBFC7, 0xBFC7, 0xBFC7}, {0xBFC8, 0xBFC8, 0xBFC8}, {0xBFC9, 0xBFC9, 0xBFC9}, {0xBFCA, 0xBFCA, 0xBFCA}, {0xBFCB, 0xBFCB, 0xBFCB}, {0xBFCC, 0xBFCC, 0xBFCC}, {0xBFCD, 0xBFCD, 0xBFCD}, {0xBFCE, 0xBFCE, 0xBFCE}, {0xBFCF, 0xBFCF, 0xBFCF}, {0xBFD0, 0xBFD0, 0xBFD0}, {0xBFD1, 0xBFD1, 0xBFD1}, {0xBFD2, 0xBFD2, 0xBFD2}, {0xBFD3, 0xBFD3, 0xBFD3}, {0xBFD4, 0xBFD4, 0xBFD4}, {0xBFD5, 0xBFD5, 0xBFD5}, {0xBFD6, 0xBFD6, 0xBFD6}, {0xBFD7, 0xBFD7, 0xBFD7}, {0xBFD8, 0xBFD8, 0xBFD8}, {0xBFD9, 0xBFD9, 0xBFD9}, {0xBFDA, 0xBFDA, 0xBFDA}, {0xBFDB, 0xBFDB, 0xBFDB}, {0xBFDC, 0xBFDC, 0xBFDC}, {0xBFDD, 0xBFDD, 0xBFDD}, {0xBFDE, 0xBFDE, 0xBFDE}, {0xBFDF, 0xBFDF, 0xBFDF}, {0xBFE0, 0xBFE0, 0xBFE0}, {0xBFE1, 0xBFE1, 0xBFE1}, {0xBFE2, 0xBFE2, 0xBFE2}, {0xBFE3, 0xBFE3, 0xBFE3}, {0xBFE4, 0xBFE4, 0xBFE4}, {0xBFE5, 0xBFE5, 0xBFE5}, {0xBFE6, 0xBFE6, 0xBFE6}, {0xBFE7, 0xBFE7, 0xBFE7}, {0xBFE8, 0xBFE8, 0xBFE8}, {0xBFE9, 0xBFE9, 0xBFE9}, {0xBFEA, 0xBFEA, 0xBFEA}, {0xBFEB, 0xBFEB, 0xBFEB}, {0xBFEC, 0xBFEC, 0xBFEC}, {0xBFED, 0xBFED, 0xBFED}, {0xBFEE, 0xBFEE, 0xBFEE}, {0xBFEF, 0xBFEF, 0xBFEF}, {0xBFF0, 0xBFF0, 0xBFF0}, {0xBFF1, 0xBFF1, 0xBFF1}, {0xBFF2, 0xBFF2, 0xBFF2}, {0xBFF3, 0xBFF3, 0xBFF3}, {0xBFF4, 0xBFF4, 0xBFF4}, {0xBFF5, 0xBFF5, 0xBFF5}, {0xBFF6, 0xBFF6, 0xBFF6}, {0xBFF7, 0xBFF7, 0xBFF7}, {0xBFF8, 0xBFF8, 0xBFF8}, {0xBFF9, 0xBFF9, 0xBFF9}, {0xBFFA, 0xBFFA, 0xBFFA}, {0xBFFB, 0xBFFB, 0xBFFB}, {0xBFFC, 0xBFFC, 0xBFFC}, {0xBFFD, 0xBFFD, 0xBFFD}, {0xBFFE, 0xBFFE, 0xBFFE}, {0xBFFF, 0xBFFF, 0xBFFF}, {0xC000, 0xC000, 0xC000}, {0xC001, 0xC001, 0xC001}, {0xC002, 0xC002, 0xC002}, {0xC003, 0xC003, 0xC003}, {0xC004, 0xC004, 0xC004}, {0xC005, 0xC005, 0xC005}, {0xC006, 0xC006, 0xC006}, {0xC007, 0xC007, 0xC007}, {0xC008, 0xC008, 0xC008}, {0xC009, 0xC009, 0xC009}, {0xC00A, 0xC00A, 0xC00A}, {0xC00B, 0xC00B, 0xC00B}, {0xC00C, 0xC00C, 0xC00C}, {0xC00D, 0xC00D, 0xC00D}, {0xC00E, 0xC00E, 0xC00E}, {0xC00F, 0xC00F, 0xC00F}, {0xC010, 0xC010, 0xC010}, {0xC011, 0xC011, 0xC011}, {0xC012, 0xC012, 0xC012}, {0xC013, 0xC013, 0xC013}, {0xC014, 0xC014, 0xC014}, {0xC015, 0xC015, 0xC015}, {0xC016, 0xC016, 0xC016}, {0xC017, 0xC017, 0xC017}, {0xC018, 0xC018, 0xC018}, {0xC019, 0xC019, 0xC019}, {0xC01A, 0xC01A, 0xC01A}, {0xC01B, 0xC01B, 0xC01B}, {0xC01C, 0xC01C, 0xC01C}, {0xC01D, 0xC01D, 0xC01D}, {0xC01E, 0xC01E, 0xC01E}, {0xC01F, 0xC01F, 0xC01F}, {0xC020, 0xC020, 0xC020}, {0xC021, 0xC021, 0xC021}, {0xC022, 0xC022, 0xC022}, {0xC023, 0xC023, 0xC023}, {0xC024, 0xC024, 0xC024}, {0xC025, 0xC025, 0xC025}, {0xC026, 0xC026, 0xC026}, {0xC027, 0xC027, 0xC027}, {0xC028, 0xC028, 0xC028}, {0xC029, 0xC029, 0xC029}, {0xC02A, 0xC02A, 0xC02A}, {0xC02B, 0xC02B, 0xC02B}, {0xC02C, 0xC02C, 0xC02C}, {0xC02D, 0xC02D, 0xC02D}, {0xC02E, 0xC02E, 0xC02E}, {0xC02F, 0xC02F, 0xC02F}, {0xC030, 0xC030, 0xC030}, {0xC031, 0xC031, 0xC031}, {0xC032, 0xC032, 0xC032}, {0xC033, 0xC033, 0xC033}, {0xC034, 0xC034, 0xC034}, {0xC035, 0xC035, 0xC035}, {0xC036, 0xC036, 0xC036}, {0xC037, 0xC037, 0xC037}, {0xC038, 0xC038, 0xC038}, {0xC039, 0xC039, 0xC039}, {0xC03A, 0xC03A, 0xC03A}, {0xC03B, 0xC03B, 0xC03B}, {0xC03C, 0xC03C, 0xC03C}, {0xC03D, 0xC03D, 0xC03D}, {0xC03E, 0xC03E, 0xC03E}, {0xC03F, 0xC03F, 0xC03F}, {0xC040, 0xC040, 0xC040}, {0xC041, 0xC041, 0xC041}, {0xC042, 0xC042, 0xC042}, {0xC043, 0xC043, 0xC043}, {0xC044, 0xC044, 0xC044}, {0xC045, 0xC045, 0xC045}, {0xC046, 0xC046, 0xC046}, {0xC047, 0xC047, 0xC047}, {0xC048, 0xC048, 0xC048}, {0xC049, 0xC049, 0xC049}, {0xC04A, 0xC04A, 0xC04A}, {0xC04B, 0xC04B, 0xC04B}, {0xC04C, 0xC04C, 0xC04C}, {0xC04D, 0xC04D, 0xC04D}, {0xC04E, 0xC04E, 0xC04E}, {0xC04F, 0xC04F, 0xC04F}, {0xC050, 0xC050, 0xC050}, {0xC051, 0xC051, 0xC051}, {0xC052, 0xC052, 0xC052}, {0xC053, 0xC053, 0xC053}, {0xC054, 0xC054, 0xC054}, {0xC055, 0xC055, 0xC055}, {0xC056, 0xC056, 0xC056}, {0xC057, 0xC057, 0xC057}, {0xC058, 0xC058, 0xC058}, {0xC059, 0xC059, 0xC059}, {0xC05A, 0xC05A, 0xC05A}, {0xC05B, 0xC05B, 0xC05B}, {0xC05C, 0xC05C, 0xC05C}, {0xC05D, 0xC05D, 0xC05D}, {0xC05E, 0xC05E, 0xC05E}, {0xC05F, 0xC05F, 0xC05F}, {0xC060, 0xC060, 0xC060}, {0xC061, 0xC061, 0xC061}, {0xC062, 0xC062, 0xC062}, {0xC063, 0xC063, 0xC063}, {0xC064, 0xC064, 0xC064}, {0xC065, 0xC065, 0xC065}, {0xC066, 0xC066, 0xC066}, {0xC067, 0xC067, 0xC067}, {0xC068, 0xC068, 0xC068}, {0xC069, 0xC069, 0xC069}, {0xC06A, 0xC06A, 0xC06A}, {0xC06B, 0xC06B, 0xC06B}, {0xC06C, 0xC06C, 0xC06C}, {0xC06D, 0xC06D, 0xC06D}, {0xC06E, 0xC06E, 0xC06E}, {0xC06F, 0xC06F, 0xC06F}, {0xC070, 0xC070, 0xC070}, {0xC071, 0xC071, 0xC071}, {0xC072, 0xC072, 0xC072}, {0xC073, 0xC073, 0xC073}, {0xC074, 0xC074, 0xC074}, {0xC075, 0xC075, 0xC075}, {0xC076, 0xC076, 0xC076}, {0xC077, 0xC077, 0xC077}, {0xC078, 0xC078, 0xC078}, {0xC079, 0xC079, 0xC079}, {0xC07A, 0xC07A, 0xC07A}, {0xC07B, 0xC07B, 0xC07B}, {0xC07C, 0xC07C, 0xC07C}, {0xC07D, 0xC07D, 0xC07D}, {0xC07E, 0xC07E, 0xC07E}, {0xC07F, 0xC07F, 0xC07F}, {0xC080, 0xC080, 0xC080}, {0xC081, 0xC081, 0xC081}, {0xC082, 0xC082, 0xC082}, {0xC083, 0xC083, 0xC083}, {0xC084, 0xC084, 0xC084}, {0xC085, 0xC085, 0xC085}, {0xC086, 0xC086, 0xC086}, {0xC087, 0xC087, 0xC087}, {0xC088, 0xC088, 0xC088}, {0xC089, 0xC089, 0xC089}, {0xC08A, 0xC08A, 0xC08A}, {0xC08B, 0xC08B, 0xC08B}, {0xC08C, 0xC08C, 0xC08C}, {0xC08D, 0xC08D, 0xC08D}, {0xC08E, 0xC08E, 0xC08E}, {0xC08F, 0xC08F, 0xC08F}, {0xC090, 0xC090, 0xC090}, {0xC091, 0xC091, 0xC091}, {0xC092, 0xC092, 0xC092}, {0xC093, 0xC093, 0xC093}, {0xC094, 0xC094, 0xC094}, {0xC095, 0xC095, 0xC095}, {0xC096, 0xC096, 0xC096}, {0xC097, 0xC097, 0xC097}, {0xC098, 0xC098, 0xC098}, {0xC099, 0xC099, 0xC099}, {0xC09A, 0xC09A, 0xC09A}, {0xC09B, 0xC09B, 0xC09B}, {0xC09C, 0xC09C, 0xC09C}, {0xC09D, 0xC09D, 0xC09D}, {0xC09E, 0xC09E, 0xC09E}, {0xC09F, 0xC09F, 0xC09F}, {0xC0A0, 0xC0A0, 0xC0A0}, {0xC0A1, 0xC0A1, 0xC0A1}, {0xC0A2, 0xC0A2, 0xC0A2}, {0xC0A3, 0xC0A3, 0xC0A3}, {0xC0A4, 0xC0A4, 0xC0A4}, {0xC0A5, 0xC0A5, 0xC0A5}, {0xC0A6, 0xC0A6, 0xC0A6}, {0xC0A7, 0xC0A7, 0xC0A7}, {0xC0A8, 0xC0A8, 0xC0A8}, {0xC0A9, 0xC0A9, 0xC0A9}, {0xC0AA, 0xC0AA, 0xC0AA}, {0xC0AB, 0xC0AB, 0xC0AB}, {0xC0AC, 0xC0AC, 0xC0AC}, {0xC0AD, 0xC0AD, 0xC0AD}, {0xC0AE, 0xC0AE, 0xC0AE}, {0xC0AF, 0xC0AF, 0xC0AF}, {0xC0B0, 0xC0B0, 0xC0B0}, {0xC0B1, 0xC0B1, 0xC0B1}, {0xC0B2, 0xC0B2, 0xC0B2}, {0xC0B3, 0xC0B3, 0xC0B3}, {0xC0B4, 0xC0B4, 0xC0B4}, {0xC0B5, 0xC0B5, 0xC0B5}, {0xC0B6, 0xC0B6, 0xC0B6}, {0xC0B7, 0xC0B7, 0xC0B7}, {0xC0B8, 0xC0B8, 0xC0B8}, {0xC0B9, 0xC0B9, 0xC0B9}, {0xC0BA, 0xC0BA, 0xC0BA}, {0xC0BB, 0xC0BB, 0xC0BB}, {0xC0BC, 0xC0BC, 0xC0BC}, {0xC0BD, 0xC0BD, 0xC0BD}, {0xC0BE, 0xC0BE, 0xC0BE}, {0xC0BF, 0xC0BF, 0xC0BF}, {0xC0C0, 0xC0C0, 0xC0C0}, {0xC0C1, 0xC0C1, 0xC0C1}, {0xC0C2, 0xC0C2, 0xC0C2}, {0xC0C3, 0xC0C3, 0xC0C3}, {0xC0C4, 0xC0C4, 0xC0C4}, {0xC0C5, 0xC0C5, 0xC0C5}, {0xC0C6, 0xC0C6, 0xC0C6}, {0xC0C7, 0xC0C7, 0xC0C7}, {0xC0C8, 0xC0C8, 0xC0C8}, {0xC0C9, 0xC0C9, 0xC0C9}, {0xC0CA, 0xC0CA, 0xC0CA}, {0xC0CB, 0xC0CB, 0xC0CB}, {0xC0CC, 0xC0CC, 0xC0CC}, {0xC0CD, 0xC0CD, 0xC0CD}, {0xC0CE, 0xC0CE, 0xC0CE}, {0xC0CF, 0xC0CF, 0xC0CF}, {0xC0D0, 0xC0D0, 0xC0D0}, {0xC0D1, 0xC0D1, 0xC0D1}, {0xC0D2, 0xC0D2, 0xC0D2}, {0xC0D3, 0xC0D3, 0xC0D3}, {0xC0D4, 0xC0D4, 0xC0D4}, {0xC0D5, 0xC0D5, 0xC0D5}, {0xC0D6, 0xC0D6, 0xC0D6}, {0xC0D7, 0xC0D7, 0xC0D7}, {0xC0D8, 0xC0D8, 0xC0D8}, {0xC0D9, 0xC0D9, 0xC0D9}, {0xC0DA, 0xC0DA, 0xC0DA}, {0xC0DB, 0xC0DB, 0xC0DB}, {0xC0DC, 0xC0DC, 0xC0DC}, {0xC0DD, 0xC0DD, 0xC0DD}, {0xC0DE, 0xC0DE, 0xC0DE}, {0xC0DF, 0xC0DF, 0xC0DF}, {0xC0E0, 0xC0E0, 0xC0E0}, {0xC0E1, 0xC0E1, 0xC0E1}, {0xC0E2, 0xC0E2, 0xC0E2}, {0xC0E3, 0xC0E3, 0xC0E3}, {0xC0E4, 0xC0E4, 0xC0E4}, {0xC0E5, 0xC0E5, 0xC0E5}, {0xC0E6, 0xC0E6, 0xC0E6}, {0xC0E7, 0xC0E7, 0xC0E7}, {0xC0E8, 0xC0E8, 0xC0E8}, {0xC0E9, 0xC0E9, 0xC0E9}, {0xC0EA, 0xC0EA, 0xC0EA}, {0xC0EB, 0xC0EB, 0xC0EB}, {0xC0EC, 0xC0EC, 0xC0EC}, {0xC0ED, 0xC0ED, 0xC0ED}, {0xC0EE, 0xC0EE, 0xC0EE}, {0xC0EF, 0xC0EF, 0xC0EF}, {0xC0F0, 0xC0F0, 0xC0F0}, {0xC0F1, 0xC0F1, 0xC0F1}, {0xC0F2, 0xC0F2, 0xC0F2}, {0xC0F3, 0xC0F3, 0xC0F3}, {0xC0F4, 0xC0F4, 0xC0F4}, {0xC0F5, 0xC0F5, 0xC0F5}, {0xC0F6, 0xC0F6, 0xC0F6}, {0xC0F7, 0xC0F7, 0xC0F7}, {0xC0F8, 0xC0F8, 0xC0F8}, {0xC0F9, 0xC0F9, 0xC0F9}, {0xC0FA, 0xC0FA, 0xC0FA}, {0xC0FB, 0xC0FB, 0xC0FB}, {0xC0FC, 0xC0FC, 0xC0FC}, {0xC0FD, 0xC0FD, 0xC0FD}, {0xC0FE, 0xC0FE, 0xC0FE}, {0xC0FF, 0xC0FF, 0xC0FF}, {0xC100, 0xC100, 0xC100}, {0xC101, 0xC101, 0xC101}, {0xC102, 0xC102, 0xC102}, {0xC103, 0xC103, 0xC103}, {0xC104, 0xC104, 0xC104}, {0xC105, 0xC105, 0xC105}, {0xC106, 0xC106, 0xC106}, {0xC107, 0xC107, 0xC107}, {0xC108, 0xC108, 0xC108}, {0xC109, 0xC109, 0xC109}, {0xC10A, 0xC10A, 0xC10A}, {0xC10B, 0xC10B, 0xC10B}, {0xC10C, 0xC10C, 0xC10C}, {0xC10D, 0xC10D, 0xC10D}, {0xC10E, 0xC10E, 0xC10E}, {0xC10F, 0xC10F, 0xC10F}, {0xC110, 0xC110, 0xC110}, {0xC111, 0xC111, 0xC111}, {0xC112, 0xC112, 0xC112}, {0xC113, 0xC113, 0xC113}, {0xC114, 0xC114, 0xC114}, {0xC115, 0xC115, 0xC115}, {0xC116, 0xC116, 0xC116}, {0xC117, 0xC117, 0xC117}, {0xC118, 0xC118, 0xC118}, {0xC119, 0xC119, 0xC119}, {0xC11A, 0xC11A, 0xC11A}, {0xC11B, 0xC11B, 0xC11B}, {0xC11C, 0xC11C, 0xC11C}, {0xC11D, 0xC11D, 0xC11D}, {0xC11E, 0xC11E, 0xC11E}, {0xC11F, 0xC11F, 0xC11F}, {0xC120, 0xC120, 0xC120}, {0xC121, 0xC121, 0xC121}, {0xC122, 0xC122, 0xC122}, {0xC123, 0xC123, 0xC123}, {0xC124, 0xC124, 0xC124}, {0xC125, 0xC125, 0xC125}, {0xC126, 0xC126, 0xC126}, {0xC127, 0xC127, 0xC127}, {0xC128, 0xC128, 0xC128}, {0xC129, 0xC129, 0xC129}, {0xC12A, 0xC12A, 0xC12A}, {0xC12B, 0xC12B, 0xC12B}, {0xC12C, 0xC12C, 0xC12C}, {0xC12D, 0xC12D, 0xC12D}, {0xC12E, 0xC12E, 0xC12E}, {0xC12F, 0xC12F, 0xC12F}, {0xC130, 0xC130, 0xC130}, {0xC131, 0xC131, 0xC131}, {0xC132, 0xC132, 0xC132}, {0xC133, 0xC133, 0xC133}, {0xC134, 0xC134, 0xC134}, {0xC135, 0xC135, 0xC135}, {0xC136, 0xC136, 0xC136}, {0xC137, 0xC137, 0xC137}, {0xC138, 0xC138, 0xC138}, {0xC139, 0xC139, 0xC139}, {0xC13A, 0xC13A, 0xC13A}, {0xC13B, 0xC13B, 0xC13B}, {0xC13C, 0xC13C, 0xC13C}, {0xC13D, 0xC13D, 0xC13D}, {0xC13E, 0xC13E, 0xC13E}, {0xC13F, 0xC13F, 0xC13F}, {0xC140, 0xC140, 0xC140}, {0xC141, 0xC141, 0xC141}, {0xC142, 0xC142, 0xC142}, {0xC143, 0xC143, 0xC143}, {0xC144, 0xC144, 0xC144}, {0xC145, 0xC145, 0xC145}, {0xC146, 0xC146, 0xC146}, {0xC147, 0xC147, 0xC147}, {0xC148, 0xC148, 0xC148}, {0xC149, 0xC149, 0xC149}, {0xC14A, 0xC14A, 0xC14A}, {0xC14B, 0xC14B, 0xC14B}, {0xC14C, 0xC14C, 0xC14C}, {0xC14D, 0xC14D, 0xC14D}, {0xC14E, 0xC14E, 0xC14E}, {0xC14F, 0xC14F, 0xC14F}, {0xC150, 0xC150, 0xC150}, {0xC151, 0xC151, 0xC151}, {0xC152, 0xC152, 0xC152}, {0xC153, 0xC153, 0xC153}, {0xC154, 0xC154, 0xC154}, {0xC155, 0xC155, 0xC155}, {0xC156, 0xC156, 0xC156}, {0xC157, 0xC157, 0xC157}, {0xC158, 0xC158, 0xC158}, {0xC159, 0xC159, 0xC159}, {0xC15A, 0xC15A, 0xC15A}, {0xC15B, 0xC15B, 0xC15B}, {0xC15C, 0xC15C, 0xC15C}, {0xC15D, 0xC15D, 0xC15D}, {0xC15E, 0xC15E, 0xC15E}, {0xC15F, 0xC15F, 0xC15F}, {0xC160, 0xC160, 0xC160}, {0xC161, 0xC161, 0xC161}, {0xC162, 0xC162, 0xC162}, {0xC163, 0xC163, 0xC163}, {0xC164, 0xC164, 0xC164}, {0xC165, 0xC165, 0xC165}, {0xC166, 0xC166, 0xC166}, {0xC167, 0xC167, 0xC167}, {0xC168, 0xC168, 0xC168}, {0xC169, 0xC169, 0xC169}, {0xC16A, 0xC16A, 0xC16A}, {0xC16B, 0xC16B, 0xC16B}, {0xC16C, 0xC16C, 0xC16C}, {0xC16D, 0xC16D, 0xC16D}, {0xC16E, 0xC16E, 0xC16E}, {0xC16F, 0xC16F, 0xC16F}, {0xC170, 0xC170, 0xC170}, {0xC171, 0xC171, 0xC171}, {0xC172, 0xC172, 0xC172}, {0xC173, 0xC173, 0xC173}, {0xC174, 0xC174, 0xC174}, {0xC175, 0xC175, 0xC175}, {0xC176, 0xC176, 0xC176}, {0xC177, 0xC177, 0xC177}, {0xC178, 0xC178, 0xC178}, {0xC179, 0xC179, 0xC179}, {0xC17A, 0xC17A, 0xC17A}, {0xC17B, 0xC17B, 0xC17B}, {0xC17C, 0xC17C, 0xC17C}, {0xC17D, 0xC17D, 0xC17D}, {0xC17E, 0xC17E, 0xC17E}, {0xC17F, 0xC17F, 0xC17F}, {0xC180, 0xC180, 0xC180}, {0xC181, 0xC181, 0xC181}, {0xC182, 0xC182, 0xC182}, {0xC183, 0xC183, 0xC183}, {0xC184, 0xC184, 0xC184}, {0xC185, 0xC185, 0xC185}, {0xC186, 0xC186, 0xC186}, {0xC187, 0xC187, 0xC187}, {0xC188, 0xC188, 0xC188}, {0xC189, 0xC189, 0xC189}, {0xC18A, 0xC18A, 0xC18A}, {0xC18B, 0xC18B, 0xC18B}, {0xC18C, 0xC18C, 0xC18C}, {0xC18D, 0xC18D, 0xC18D}, {0xC18E, 0xC18E, 0xC18E}, {0xC18F, 0xC18F, 0xC18F}, {0xC190, 0xC190, 0xC190}, {0xC191, 0xC191, 0xC191}, {0xC192, 0xC192, 0xC192}, {0xC193, 0xC193, 0xC193}, {0xC194, 0xC194, 0xC194}, {0xC195, 0xC195, 0xC195}, {0xC196, 0xC196, 0xC196}, {0xC197, 0xC197, 0xC197}, {0xC198, 0xC198, 0xC198}, {0xC199, 0xC199, 0xC199}, {0xC19A, 0xC19A, 0xC19A}, {0xC19B, 0xC19B, 0xC19B}, {0xC19C, 0xC19C, 0xC19C}, {0xC19D, 0xC19D, 0xC19D}, {0xC19E, 0xC19E, 0xC19E}, {0xC19F, 0xC19F, 0xC19F}, {0xC1A0, 0xC1A0, 0xC1A0}, {0xC1A1, 0xC1A1, 0xC1A1}, {0xC1A2, 0xC1A2, 0xC1A2}, {0xC1A3, 0xC1A3, 0xC1A3}, {0xC1A4, 0xC1A4, 0xC1A4}, {0xC1A5, 0xC1A5, 0xC1A5}, {0xC1A6, 0xC1A6, 0xC1A6}, {0xC1A7, 0xC1A7, 0xC1A7}, {0xC1A8, 0xC1A8, 0xC1A8}, {0xC1A9, 0xC1A9, 0xC1A9}, {0xC1AA, 0xC1AA, 0xC1AA}, {0xC1AB, 0xC1AB, 0xC1AB}, {0xC1AC, 0xC1AC, 0xC1AC}, {0xC1AD, 0xC1AD, 0xC1AD}, {0xC1AE, 0xC1AE, 0xC1AE}, {0xC1AF, 0xC1AF, 0xC1AF}, {0xC1B0, 0xC1B0, 0xC1B0}, {0xC1B1, 0xC1B1, 0xC1B1}, {0xC1B2, 0xC1B2, 0xC1B2}, {0xC1B3, 0xC1B3, 0xC1B3}, {0xC1B4, 0xC1B4, 0xC1B4}, {0xC1B5, 0xC1B5, 0xC1B5}, {0xC1B6, 0xC1B6, 0xC1B6}, {0xC1B7, 0xC1B7, 0xC1B7}, {0xC1B8, 0xC1B8, 0xC1B8}, {0xC1B9, 0xC1B9, 0xC1B9}, {0xC1BA, 0xC1BA, 0xC1BA}, {0xC1BB, 0xC1BB, 0xC1BB}, {0xC1BC, 0xC1BC, 0xC1BC}, {0xC1BD, 0xC1BD, 0xC1BD}, {0xC1BE, 0xC1BE, 0xC1BE}, {0xC1BF, 0xC1BF, 0xC1BF}, {0xC1C0, 0xC1C0, 0xC1C0}, {0xC1C1, 0xC1C1, 0xC1C1}, {0xC1C2, 0xC1C2, 0xC1C2}, {0xC1C3, 0xC1C3, 0xC1C3}, {0xC1C4, 0xC1C4, 0xC1C4}, {0xC1C5, 0xC1C5, 0xC1C5}, {0xC1C6, 0xC1C6, 0xC1C6}, {0xC1C7, 0xC1C7, 0xC1C7}, {0xC1C8, 0xC1C8, 0xC1C8}, {0xC1C9, 0xC1C9, 0xC1C9}, {0xC1CA, 0xC1CA, 0xC1CA}, {0xC1CB, 0xC1CB, 0xC1CB}, {0xC1CC, 0xC1CC, 0xC1CC}, {0xC1CD, 0xC1CD, 0xC1CD}, {0xC1CE, 0xC1CE, 0xC1CE}, {0xC1CF, 0xC1CF, 0xC1CF}, {0xC1D0, 0xC1D0, 0xC1D0}, {0xC1D1, 0xC1D1, 0xC1D1}, {0xC1D2, 0xC1D2, 0xC1D2}, {0xC1D3, 0xC1D3, 0xC1D3}, {0xC1D4, 0xC1D4, 0xC1D4}, {0xC1D5, 0xC1D5, 0xC1D5}, {0xC1D6, 0xC1D6, 0xC1D6}, {0xC1D7, 0xC1D7, 0xC1D7}, {0xC1D8, 0xC1D8, 0xC1D8}, {0xC1D9, 0xC1D9, 0xC1D9}, {0xC1DA, 0xC1DA, 0xC1DA}, {0xC1DB, 0xC1DB, 0xC1DB}, {0xC1DC, 0xC1DC, 0xC1DC}, {0xC1DD, 0xC1DD, 0xC1DD}, {0xC1DE, 0xC1DE, 0xC1DE}, {0xC1DF, 0xC1DF, 0xC1DF}, {0xC1E0, 0xC1E0, 0xC1E0}, {0xC1E1, 0xC1E1, 0xC1E1}, {0xC1E2, 0xC1E2, 0xC1E2}, {0xC1E3, 0xC1E3, 0xC1E3}, {0xC1E4, 0xC1E4, 0xC1E4}, {0xC1E5, 0xC1E5, 0xC1E5}, {0xC1E6, 0xC1E6, 0xC1E6}, {0xC1E7, 0xC1E7, 0xC1E7}, {0xC1E8, 0xC1E8, 0xC1E8}, {0xC1E9, 0xC1E9, 0xC1E9}, {0xC1EA, 0xC1EA, 0xC1EA}, {0xC1EB, 0xC1EB, 0xC1EB}, {0xC1EC, 0xC1EC, 0xC1EC}, {0xC1ED, 0xC1ED, 0xC1ED}, {0xC1EE, 0xC1EE, 0xC1EE}, {0xC1EF, 0xC1EF, 0xC1EF}, {0xC1F0, 0xC1F0, 0xC1F0}, {0xC1F1, 0xC1F1, 0xC1F1}, {0xC1F2, 0xC1F2, 0xC1F2}, {0xC1F3, 0xC1F3, 0xC1F3}, {0xC1F4, 0xC1F4, 0xC1F4}, {0xC1F5, 0xC1F5, 0xC1F5}, {0xC1F6, 0xC1F6, 0xC1F6}, {0xC1F7, 0xC1F7, 0xC1F7}, {0xC1F8, 0xC1F8, 0xC1F8}, {0xC1F9, 0xC1F9, 0xC1F9}, {0xC1FA, 0xC1FA, 0xC1FA}, {0xC1FB, 0xC1FB, 0xC1FB}, {0xC1FC, 0xC1FC, 0xC1FC}, {0xC1FD, 0xC1FD, 0xC1FD}, {0xC1FE, 0xC1FE, 0xC1FE}, {0xC1FF, 0xC1FF, 0xC1FF}, {0xC200, 0xC200, 0xC200}, {0xC201, 0xC201, 0xC201}, {0xC202, 0xC202, 0xC202}, {0xC203, 0xC203, 0xC203}, {0xC204, 0xC204, 0xC204}, {0xC205, 0xC205, 0xC205}, {0xC206, 0xC206, 0xC206}, {0xC207, 0xC207, 0xC207}, {0xC208, 0xC208, 0xC208}, {0xC209, 0xC209, 0xC209}, {0xC20A, 0xC20A, 0xC20A}, {0xC20B, 0xC20B, 0xC20B}, {0xC20C, 0xC20C, 0xC20C}, {0xC20D, 0xC20D, 0xC20D}, {0xC20E, 0xC20E, 0xC20E}, {0xC20F, 0xC20F, 0xC20F}, {0xC210, 0xC210, 0xC210}, {0xC211, 0xC211, 0xC211}, {0xC212, 0xC212, 0xC212}, {0xC213, 0xC213, 0xC213}, {0xC214, 0xC214, 0xC214}, {0xC215, 0xC215, 0xC215}, {0xC216, 0xC216, 0xC216}, {0xC217, 0xC217, 0xC217}, {0xC218, 0xC218, 0xC218}, {0xC219, 0xC219, 0xC219}, {0xC21A, 0xC21A, 0xC21A}, {0xC21B, 0xC21B, 0xC21B}, {0xC21C, 0xC21C, 0xC21C}, {0xC21D, 0xC21D, 0xC21D}, {0xC21E, 0xC21E, 0xC21E}, {0xC21F, 0xC21F, 0xC21F}, {0xC220, 0xC220, 0xC220}, {0xC221, 0xC221, 0xC221}, {0xC222, 0xC222, 0xC222}, {0xC223, 0xC223, 0xC223}, {0xC224, 0xC224, 0xC224}, {0xC225, 0xC225, 0xC225}, {0xC226, 0xC226, 0xC226}, {0xC227, 0xC227, 0xC227}, {0xC228, 0xC228, 0xC228}, {0xC229, 0xC229, 0xC229}, {0xC22A, 0xC22A, 0xC22A}, {0xC22B, 0xC22B, 0xC22B}, {0xC22C, 0xC22C, 0xC22C}, {0xC22D, 0xC22D, 0xC22D}, {0xC22E, 0xC22E, 0xC22E}, {0xC22F, 0xC22F, 0xC22F}, {0xC230, 0xC230, 0xC230}, {0xC231, 0xC231, 0xC231}, {0xC232, 0xC232, 0xC232}, {0xC233, 0xC233, 0xC233}, {0xC234, 0xC234, 0xC234}, {0xC235, 0xC235, 0xC235}, {0xC236, 0xC236, 0xC236}, {0xC237, 0xC237, 0xC237}, {0xC238, 0xC238, 0xC238}, {0xC239, 0xC239, 0xC239}, {0xC23A, 0xC23A, 0xC23A}, {0xC23B, 0xC23B, 0xC23B}, {0xC23C, 0xC23C, 0xC23C}, {0xC23D, 0xC23D, 0xC23D}, {0xC23E, 0xC23E, 0xC23E}, {0xC23F, 0xC23F, 0xC23F}, {0xC240, 0xC240, 0xC240}, {0xC241, 0xC241, 0xC241}, {0xC242, 0xC242, 0xC242}, {0xC243, 0xC243, 0xC243}, {0xC244, 0xC244, 0xC244}, {0xC245, 0xC245, 0xC245}, {0xC246, 0xC246, 0xC246}, {0xC247, 0xC247, 0xC247}, {0xC248, 0xC248, 0xC248}, {0xC249, 0xC249, 0xC249}, {0xC24A, 0xC24A, 0xC24A}, {0xC24B, 0xC24B, 0xC24B}, {0xC24C, 0xC24C, 0xC24C}, {0xC24D, 0xC24D, 0xC24D}, {0xC24E, 0xC24E, 0xC24E}, {0xC24F, 0xC24F, 0xC24F}, {0xC250, 0xC250, 0xC250}, {0xC251, 0xC251, 0xC251}, {0xC252, 0xC252, 0xC252}, {0xC253, 0xC253, 0xC253}, {0xC254, 0xC254, 0xC254}, {0xC255, 0xC255, 0xC255}, {0xC256, 0xC256, 0xC256}, {0xC257, 0xC257, 0xC257}, {0xC258, 0xC258, 0xC258}, {0xC259, 0xC259, 0xC259}, {0xC25A, 0xC25A, 0xC25A}, {0xC25B, 0xC25B, 0xC25B}, {0xC25C, 0xC25C, 0xC25C}, {0xC25D, 0xC25D, 0xC25D}, {0xC25E, 0xC25E, 0xC25E}, {0xC25F, 0xC25F, 0xC25F}, {0xC260, 0xC260, 0xC260}, {0xC261, 0xC261, 0xC261}, {0xC262, 0xC262, 0xC262}, {0xC263, 0xC263, 0xC263}, {0xC264, 0xC264, 0xC264}, {0xC265, 0xC265, 0xC265}, {0xC266, 0xC266, 0xC266}, {0xC267, 0xC267, 0xC267}, {0xC268, 0xC268, 0xC268}, {0xC269, 0xC269, 0xC269}, {0xC26A, 0xC26A, 0xC26A}, {0xC26B, 0xC26B, 0xC26B}, {0xC26C, 0xC26C, 0xC26C}, {0xC26D, 0xC26D, 0xC26D}, {0xC26E, 0xC26E, 0xC26E}, {0xC26F, 0xC26F, 0xC26F}, {0xC270, 0xC270, 0xC270}, {0xC271, 0xC271, 0xC271}, {0xC272, 0xC272, 0xC272}, {0xC273, 0xC273, 0xC273}, {0xC274, 0xC274, 0xC274}, {0xC275, 0xC275, 0xC275}, {0xC276, 0xC276, 0xC276}, {0xC277, 0xC277, 0xC277}, {0xC278, 0xC278, 0xC278}, {0xC279, 0xC279, 0xC279}, {0xC27A, 0xC27A, 0xC27A}, {0xC27B, 0xC27B, 0xC27B}, {0xC27C, 0xC27C, 0xC27C}, {0xC27D, 0xC27D, 0xC27D}, {0xC27E, 0xC27E, 0xC27E}, {0xC27F, 0xC27F, 0xC27F}, {0xC280, 0xC280, 0xC280}, {0xC281, 0xC281, 0xC281}, {0xC282, 0xC282, 0xC282}, {0xC283, 0xC283, 0xC283}, {0xC284, 0xC284, 0xC284}, {0xC285, 0xC285, 0xC285}, {0xC286, 0xC286, 0xC286}, {0xC287, 0xC287, 0xC287}, {0xC288, 0xC288, 0xC288}, {0xC289, 0xC289, 0xC289}, {0xC28A, 0xC28A, 0xC28A}, {0xC28B, 0xC28B, 0xC28B}, {0xC28C, 0xC28C, 0xC28C}, {0xC28D, 0xC28D, 0xC28D}, {0xC28E, 0xC28E, 0xC28E}, {0xC28F, 0xC28F, 0xC28F}, {0xC290, 0xC290, 0xC290}, {0xC291, 0xC291, 0xC291}, {0xC292, 0xC292, 0xC292}, {0xC293, 0xC293, 0xC293}, {0xC294, 0xC294, 0xC294}, {0xC295, 0xC295, 0xC295}, {0xC296, 0xC296, 0xC296}, {0xC297, 0xC297, 0xC297}, {0xC298, 0xC298, 0xC298}, {0xC299, 0xC299, 0xC299}, {0xC29A, 0xC29A, 0xC29A}, {0xC29B, 0xC29B, 0xC29B}, {0xC29C, 0xC29C, 0xC29C}, {0xC29D, 0xC29D, 0xC29D}, {0xC29E, 0xC29E, 0xC29E}, {0xC29F, 0xC29F, 0xC29F}, {0xC2A0, 0xC2A0, 0xC2A0}, {0xC2A1, 0xC2A1, 0xC2A1}, {0xC2A2, 0xC2A2, 0xC2A2}, {0xC2A3, 0xC2A3, 0xC2A3}, {0xC2A4, 0xC2A4, 0xC2A4}, {0xC2A5, 0xC2A5, 0xC2A5}, {0xC2A6, 0xC2A6, 0xC2A6}, {0xC2A7, 0xC2A7, 0xC2A7}, {0xC2A8, 0xC2A8, 0xC2A8}, {0xC2A9, 0xC2A9, 0xC2A9}, {0xC2AA, 0xC2AA, 0xC2AA}, {0xC2AB, 0xC2AB, 0xC2AB}, {0xC2AC, 0xC2AC, 0xC2AC}, {0xC2AD, 0xC2AD, 0xC2AD}, {0xC2AE, 0xC2AE, 0xC2AE}, {0xC2AF, 0xC2AF, 0xC2AF}, {0xC2B0, 0xC2B0, 0xC2B0}, {0xC2B1, 0xC2B1, 0xC2B1}, {0xC2B2, 0xC2B2, 0xC2B2}, {0xC2B3, 0xC2B3, 0xC2B3}, {0xC2B4, 0xC2B4, 0xC2B4}, {0xC2B5, 0xC2B5, 0xC2B5}, {0xC2B6, 0xC2B6, 0xC2B6}, {0xC2B7, 0xC2B7, 0xC2B7}, {0xC2B8, 0xC2B8, 0xC2B8}, {0xC2B9, 0xC2B9, 0xC2B9}, {0xC2BA, 0xC2BA, 0xC2BA}, {0xC2BB, 0xC2BB, 0xC2BB}, {0xC2BC, 0xC2BC, 0xC2BC}, {0xC2BD, 0xC2BD, 0xC2BD}, {0xC2BE, 0xC2BE, 0xC2BE}, {0xC2BF, 0xC2BF, 0xC2BF}, {0xC2C0, 0xC2C0, 0xC2C0}, {0xC2C1, 0xC2C1, 0xC2C1}, {0xC2C2, 0xC2C2, 0xC2C2}, {0xC2C3, 0xC2C3, 0xC2C3}, {0xC2C4, 0xC2C4, 0xC2C4}, {0xC2C5, 0xC2C5, 0xC2C5}, {0xC2C6, 0xC2C6, 0xC2C6}, {0xC2C7, 0xC2C7, 0xC2C7}, {0xC2C8, 0xC2C8, 0xC2C8}, {0xC2C9, 0xC2C9, 0xC2C9}, {0xC2CA, 0xC2CA, 0xC2CA}, {0xC2CB, 0xC2CB, 0xC2CB}, {0xC2CC, 0xC2CC, 0xC2CC}, {0xC2CD, 0xC2CD, 0xC2CD}, {0xC2CE, 0xC2CE, 0xC2CE}, {0xC2CF, 0xC2CF, 0xC2CF}, {0xC2D0, 0xC2D0, 0xC2D0}, {0xC2D1, 0xC2D1, 0xC2D1}, {0xC2D2, 0xC2D2, 0xC2D2}, {0xC2D3, 0xC2D3, 0xC2D3}, {0xC2D4, 0xC2D4, 0xC2D4}, {0xC2D5, 0xC2D5, 0xC2D5}, {0xC2D6, 0xC2D6, 0xC2D6}, {0xC2D7, 0xC2D7, 0xC2D7}, {0xC2D8, 0xC2D8, 0xC2D8}, {0xC2D9, 0xC2D9, 0xC2D9}, {0xC2DA, 0xC2DA, 0xC2DA}, {0xC2DB, 0xC2DB, 0xC2DB}, {0xC2DC, 0xC2DC, 0xC2DC}, {0xC2DD, 0xC2DD, 0xC2DD}, {0xC2DE, 0xC2DE, 0xC2DE}, {0xC2DF, 0xC2DF, 0xC2DF}, {0xC2E0, 0xC2E0, 0xC2E0}, {0xC2E1, 0xC2E1, 0xC2E1}, {0xC2E2, 0xC2E2, 0xC2E2}, {0xC2E3, 0xC2E3, 0xC2E3}, {0xC2E4, 0xC2E4, 0xC2E4}, {0xC2E5, 0xC2E5, 0xC2E5}, {0xC2E6, 0xC2E6, 0xC2E6}, {0xC2E7, 0xC2E7, 0xC2E7}, {0xC2E8, 0xC2E8, 0xC2E8}, {0xC2E9, 0xC2E9, 0xC2E9}, {0xC2EA, 0xC2EA, 0xC2EA}, {0xC2EB, 0xC2EB, 0xC2EB}, {0xC2EC, 0xC2EC, 0xC2EC}, {0xC2ED, 0xC2ED, 0xC2ED}, {0xC2EE, 0xC2EE, 0xC2EE}, {0xC2EF, 0xC2EF, 0xC2EF}, {0xC2F0, 0xC2F0, 0xC2F0}, {0xC2F1, 0xC2F1, 0xC2F1}, {0xC2F2, 0xC2F2, 0xC2F2}, {0xC2F3, 0xC2F3, 0xC2F3}, {0xC2F4, 0xC2F4, 0xC2F4}, {0xC2F5, 0xC2F5, 0xC2F5}, {0xC2F6, 0xC2F6, 0xC2F6}, {0xC2F7, 0xC2F7, 0xC2F7}, {0xC2F8, 0xC2F8, 0xC2F8}, {0xC2F9, 0xC2F9, 0xC2F9}, {0xC2FA, 0xC2FA, 0xC2FA}, {0xC2FB, 0xC2FB, 0xC2FB}, {0xC2FC, 0xC2FC, 0xC2FC}, {0xC2FD, 0xC2FD, 0xC2FD}, {0xC2FE, 0xC2FE, 0xC2FE}, {0xC2FF, 0xC2FF, 0xC2FF}, {0xC300, 0xC300, 0xC300}, {0xC301, 0xC301, 0xC301}, {0xC302, 0xC302, 0xC302}, {0xC303, 0xC303, 0xC303}, {0xC304, 0xC304, 0xC304}, {0xC305, 0xC305, 0xC305}, {0xC306, 0xC306, 0xC306}, {0xC307, 0xC307, 0xC307}, {0xC308, 0xC308, 0xC308}, {0xC309, 0xC309, 0xC309}, {0xC30A, 0xC30A, 0xC30A}, {0xC30B, 0xC30B, 0xC30B}, {0xC30C, 0xC30C, 0xC30C}, {0xC30D, 0xC30D, 0xC30D}, {0xC30E, 0xC30E, 0xC30E}, {0xC30F, 0xC30F, 0xC30F}, {0xC310, 0xC310, 0xC310}, {0xC311, 0xC311, 0xC311}, {0xC312, 0xC312, 0xC312}, {0xC313, 0xC313, 0xC313}, {0xC314, 0xC314, 0xC314}, {0xC315, 0xC315, 0xC315}, {0xC316, 0xC316, 0xC316}, {0xC317, 0xC317, 0xC317}, {0xC318, 0xC318, 0xC318}, {0xC319, 0xC319, 0xC319}, {0xC31A, 0xC31A, 0xC31A}, {0xC31B, 0xC31B, 0xC31B}, {0xC31C, 0xC31C, 0xC31C}, {0xC31D, 0xC31D, 0xC31D}, {0xC31E, 0xC31E, 0xC31E}, {0xC31F, 0xC31F, 0xC31F}, {0xC320, 0xC320, 0xC320}, {0xC321, 0xC321, 0xC321}, {0xC322, 0xC322, 0xC322}, {0xC323, 0xC323, 0xC323}, {0xC324, 0xC324, 0xC324}, {0xC325, 0xC325, 0xC325}, {0xC326, 0xC326, 0xC326}, {0xC327, 0xC327, 0xC327}, {0xC328, 0xC328, 0xC328}, {0xC329, 0xC329, 0xC329}, {0xC32A, 0xC32A, 0xC32A}, {0xC32B, 0xC32B, 0xC32B}, {0xC32C, 0xC32C, 0xC32C}, {0xC32D, 0xC32D, 0xC32D}, {0xC32E, 0xC32E, 0xC32E}, {0xC32F, 0xC32F, 0xC32F}, {0xC330, 0xC330, 0xC330}, {0xC331, 0xC331, 0xC331}, {0xC332, 0xC332, 0xC332}, {0xC333, 0xC333, 0xC333}, {0xC334, 0xC334, 0xC334}, {0xC335, 0xC335, 0xC335}, {0xC336, 0xC336, 0xC336}, {0xC337, 0xC337, 0xC337}, {0xC338, 0xC338, 0xC338}, {0xC339, 0xC339, 0xC339}, {0xC33A, 0xC33A, 0xC33A}, {0xC33B, 0xC33B, 0xC33B}, {0xC33C, 0xC33C, 0xC33C}, {0xC33D, 0xC33D, 0xC33D}, {0xC33E, 0xC33E, 0xC33E}, {0xC33F, 0xC33F, 0xC33F}, {0xC340, 0xC340, 0xC340}, {0xC341, 0xC341, 0xC341}, {0xC342, 0xC342, 0xC342}, {0xC343, 0xC343, 0xC343}, {0xC344, 0xC344, 0xC344}, {0xC345, 0xC345, 0xC345}, {0xC346, 0xC346, 0xC346}, {0xC347, 0xC347, 0xC347}, {0xC348, 0xC348, 0xC348}, {0xC349, 0xC349, 0xC349}, {0xC34A, 0xC34A, 0xC34A}, {0xC34B, 0xC34B, 0xC34B}, {0xC34C, 0xC34C, 0xC34C}, {0xC34D, 0xC34D, 0xC34D}, {0xC34E, 0xC34E, 0xC34E}, {0xC34F, 0xC34F, 0xC34F}, {0xC350, 0xC350, 0xC350}, {0xC351, 0xC351, 0xC351}, {0xC352, 0xC352, 0xC352}, {0xC353, 0xC353, 0xC353}, {0xC354, 0xC354, 0xC354}, {0xC355, 0xC355, 0xC355}, {0xC356, 0xC356, 0xC356}, {0xC357, 0xC357, 0xC357}, {0xC358, 0xC358, 0xC358}, {0xC359, 0xC359, 0xC359}, {0xC35A, 0xC35A, 0xC35A}, {0xC35B, 0xC35B, 0xC35B}, {0xC35C, 0xC35C, 0xC35C}, {0xC35D, 0xC35D, 0xC35D}, {0xC35E, 0xC35E, 0xC35E}, {0xC35F, 0xC35F, 0xC35F}, {0xC360, 0xC360, 0xC360}, {0xC361, 0xC361, 0xC361}, {0xC362, 0xC362, 0xC362}, {0xC363, 0xC363, 0xC363}, {0xC364, 0xC364, 0xC364}, {0xC365, 0xC365, 0xC365}, {0xC366, 0xC366, 0xC366}, {0xC367, 0xC367, 0xC367}, {0xC368, 0xC368, 0xC368}, {0xC369, 0xC369, 0xC369}, {0xC36A, 0xC36A, 0xC36A}, {0xC36B, 0xC36B, 0xC36B}, {0xC36C, 0xC36C, 0xC36C}, {0xC36D, 0xC36D, 0xC36D}, {0xC36E, 0xC36E, 0xC36E}, {0xC36F, 0xC36F, 0xC36F}, {0xC370, 0xC370, 0xC370}, {0xC371, 0xC371, 0xC371}, {0xC372, 0xC372, 0xC372}, {0xC373, 0xC373, 0xC373}, {0xC374, 0xC374, 0xC374}, {0xC375, 0xC375, 0xC375}, {0xC376, 0xC376, 0xC376}, {0xC377, 0xC377, 0xC377}, {0xC378, 0xC378, 0xC378}, {0xC379, 0xC379, 0xC379}, {0xC37A, 0xC37A, 0xC37A}, {0xC37B, 0xC37B, 0xC37B}, {0xC37C, 0xC37C, 0xC37C}, {0xC37D, 0xC37D, 0xC37D}, {0xC37E, 0xC37E, 0xC37E}, {0xC37F, 0xC37F, 0xC37F}, {0xC380, 0xC380, 0xC380}, {0xC381, 0xC381, 0xC381}, {0xC382, 0xC382, 0xC382}, {0xC383, 0xC383, 0xC383}, {0xC384, 0xC384, 0xC384}, {0xC385, 0xC385, 0xC385}, {0xC386, 0xC386, 0xC386}, {0xC387, 0xC387, 0xC387}, {0xC388, 0xC388, 0xC388}, {0xC389, 0xC389, 0xC389}, {0xC38A, 0xC38A, 0xC38A}, {0xC38B, 0xC38B, 0xC38B}, {0xC38C, 0xC38C, 0xC38C}, {0xC38D, 0xC38D, 0xC38D}, {0xC38E, 0xC38E, 0xC38E}, {0xC38F, 0xC38F, 0xC38F}, {0xC390, 0xC390, 0xC390}, {0xC391, 0xC391, 0xC391}, {0xC392, 0xC392, 0xC392}, {0xC393, 0xC393, 0xC393}, {0xC394, 0xC394, 0xC394}, {0xC395, 0xC395, 0xC395}, {0xC396, 0xC396, 0xC396}, {0xC397, 0xC397, 0xC397}, {0xC398, 0xC398, 0xC398}, {0xC399, 0xC399, 0xC399}, {0xC39A, 0xC39A, 0xC39A}, {0xC39B, 0xC39B, 0xC39B}, {0xC39C, 0xC39C, 0xC39C}, {0xC39D, 0xC39D, 0xC39D}, {0xC39E, 0xC39E, 0xC39E}, {0xC39F, 0xC39F, 0xC39F}, {0xC3A0, 0xC3A0, 0xC3A0}, {0xC3A1, 0xC3A1, 0xC3A1}, {0xC3A2, 0xC3A2, 0xC3A2}, {0xC3A3, 0xC3A3, 0xC3A3}, {0xC3A4, 0xC3A4, 0xC3A4}, {0xC3A5, 0xC3A5, 0xC3A5}, {0xC3A6, 0xC3A6, 0xC3A6}, {0xC3A7, 0xC3A7, 0xC3A7}, {0xC3A8, 0xC3A8, 0xC3A8}, {0xC3A9, 0xC3A9, 0xC3A9}, {0xC3AA, 0xC3AA, 0xC3AA}, {0xC3AB, 0xC3AB, 0xC3AB}, {0xC3AC, 0xC3AC, 0xC3AC}, {0xC3AD, 0xC3AD, 0xC3AD}, {0xC3AE, 0xC3AE, 0xC3AE}, {0xC3AF, 0xC3AF, 0xC3AF}, {0xC3B0, 0xC3B0, 0xC3B0}, {0xC3B1, 0xC3B1, 0xC3B1}, {0xC3B2, 0xC3B2, 0xC3B2}, {0xC3B3, 0xC3B3, 0xC3B3}, {0xC3B4, 0xC3B4, 0xC3B4}, {0xC3B5, 0xC3B5, 0xC3B5}, {0xC3B6, 0xC3B6, 0xC3B6}, {0xC3B7, 0xC3B7, 0xC3B7}, {0xC3B8, 0xC3B8, 0xC3B8}, {0xC3B9, 0xC3B9, 0xC3B9}, {0xC3BA, 0xC3BA, 0xC3BA}, {0xC3BB, 0xC3BB, 0xC3BB}, {0xC3BC, 0xC3BC, 0xC3BC}, {0xC3BD, 0xC3BD, 0xC3BD}, {0xC3BE, 0xC3BE, 0xC3BE}, {0xC3BF, 0xC3BF, 0xC3BF}, {0xC3C0, 0xC3C0, 0xC3C0}, {0xC3C1, 0xC3C1, 0xC3C1}, {0xC3C2, 0xC3C2, 0xC3C2}, {0xC3C3, 0xC3C3, 0xC3C3}, {0xC3C4, 0xC3C4, 0xC3C4}, {0xC3C5, 0xC3C5, 0xC3C5}, {0xC3C6, 0xC3C6, 0xC3C6}, {0xC3C7, 0xC3C7, 0xC3C7}, {0xC3C8, 0xC3C8, 0xC3C8}, {0xC3C9, 0xC3C9, 0xC3C9}, {0xC3CA, 0xC3CA, 0xC3CA}, {0xC3CB, 0xC3CB, 0xC3CB}, {0xC3CC, 0xC3CC, 0xC3CC}, {0xC3CD, 0xC3CD, 0xC3CD}, {0xC3CE, 0xC3CE, 0xC3CE}, {0xC3CF, 0xC3CF, 0xC3CF}, {0xC3D0, 0xC3D0, 0xC3D0}, {0xC3D1, 0xC3D1, 0xC3D1}, {0xC3D2, 0xC3D2, 0xC3D2}, {0xC3D3, 0xC3D3, 0xC3D3}, {0xC3D4, 0xC3D4, 0xC3D4}, {0xC3D5, 0xC3D5, 0xC3D5}, {0xC3D6, 0xC3D6, 0xC3D6}, {0xC3D7, 0xC3D7, 0xC3D7}, {0xC3D8, 0xC3D8, 0xC3D8}, {0xC3D9, 0xC3D9, 0xC3D9}, {0xC3DA, 0xC3DA, 0xC3DA}, {0xC3DB, 0xC3DB, 0xC3DB}, {0xC3DC, 0xC3DC, 0xC3DC}, {0xC3DD, 0xC3DD, 0xC3DD}, {0xC3DE, 0xC3DE, 0xC3DE}, {0xC3DF, 0xC3DF, 0xC3DF}, {0xC3E0, 0xC3E0, 0xC3E0}, {0xC3E1, 0xC3E1, 0xC3E1}, {0xC3E2, 0xC3E2, 0xC3E2}, {0xC3E3, 0xC3E3, 0xC3E3}, {0xC3E4, 0xC3E4, 0xC3E4}, {0xC3E5, 0xC3E5, 0xC3E5}, {0xC3E6, 0xC3E6, 0xC3E6}, {0xC3E7, 0xC3E7, 0xC3E7}, {0xC3E8, 0xC3E8, 0xC3E8}, {0xC3E9, 0xC3E9, 0xC3E9}, {0xC3EA, 0xC3EA, 0xC3EA}, {0xC3EB, 0xC3EB, 0xC3EB}, {0xC3EC, 0xC3EC, 0xC3EC}, {0xC3ED, 0xC3ED, 0xC3ED}, {0xC3EE, 0xC3EE, 0xC3EE}, {0xC3EF, 0xC3EF, 0xC3EF}, {0xC3F0, 0xC3F0, 0xC3F0}, {0xC3F1, 0xC3F1, 0xC3F1}, {0xC3F2, 0xC3F2, 0xC3F2}, {0xC3F3, 0xC3F3, 0xC3F3}, {0xC3F4, 0xC3F4, 0xC3F4}, {0xC3F5, 0xC3F5, 0xC3F5}, {0xC3F6, 0xC3F6, 0xC3F6}, {0xC3F7, 0xC3F7, 0xC3F7}, {0xC3F8, 0xC3F8, 0xC3F8}, {0xC3F9, 0xC3F9, 0xC3F9}, {0xC3FA, 0xC3FA, 0xC3FA}, {0xC3FB, 0xC3FB, 0xC3FB}, {0xC3FC, 0xC3FC, 0xC3FC}, {0xC3FD, 0xC3FD, 0xC3FD}, {0xC3FE, 0xC3FE, 0xC3FE}, {0xC3FF, 0xC3FF, 0xC3FF}, {0xC400, 0xC400, 0xC400}, {0xC401, 0xC401, 0xC401}, {0xC402, 0xC402, 0xC402}, {0xC403, 0xC403, 0xC403}, {0xC404, 0xC404, 0xC404}, {0xC405, 0xC405, 0xC405}, {0xC406, 0xC406, 0xC406}, {0xC407, 0xC407, 0xC407}, {0xC408, 0xC408, 0xC408}, {0xC409, 0xC409, 0xC409}, {0xC40A, 0xC40A, 0xC40A}, {0xC40B, 0xC40B, 0xC40B}, {0xC40C, 0xC40C, 0xC40C}, {0xC40D, 0xC40D, 0xC40D}, {0xC40E, 0xC40E, 0xC40E}, {0xC40F, 0xC40F, 0xC40F}, {0xC410, 0xC410, 0xC410}, {0xC411, 0xC411, 0xC411}, {0xC412, 0xC412, 0xC412}, {0xC413, 0xC413, 0xC413}, {0xC414, 0xC414, 0xC414}, {0xC415, 0xC415, 0xC415}, {0xC416, 0xC416, 0xC416}, {0xC417, 0xC417, 0xC417}, {0xC418, 0xC418, 0xC418}, {0xC419, 0xC419, 0xC419}, {0xC41A, 0xC41A, 0xC41A}, {0xC41B, 0xC41B, 0xC41B}, {0xC41C, 0xC41C, 0xC41C}, {0xC41D, 0xC41D, 0xC41D}, {0xC41E, 0xC41E, 0xC41E}, {0xC41F, 0xC41F, 0xC41F}, {0xC420, 0xC420, 0xC420}, {0xC421, 0xC421, 0xC421}, {0xC422, 0xC422, 0xC422}, {0xC423, 0xC423, 0xC423}, {0xC424, 0xC424, 0xC424}, {0xC425, 0xC425, 0xC425}, {0xC426, 0xC426, 0xC426}, {0xC427, 0xC427, 0xC427}, {0xC428, 0xC428, 0xC428}, {0xC429, 0xC429, 0xC429}, {0xC42A, 0xC42A, 0xC42A}, {0xC42B, 0xC42B, 0xC42B}, {0xC42C, 0xC42C, 0xC42C}, {0xC42D, 0xC42D, 0xC42D}, {0xC42E, 0xC42E, 0xC42E}, {0xC42F, 0xC42F, 0xC42F}, {0xC430, 0xC430, 0xC430}, {0xC431, 0xC431, 0xC431}, {0xC432, 0xC432, 0xC432}, {0xC433, 0xC433, 0xC433}, {0xC434, 0xC434, 0xC434}, {0xC435, 0xC435, 0xC435}, {0xC436, 0xC436, 0xC436}, {0xC437, 0xC437, 0xC437}, {0xC438, 0xC438, 0xC438}, {0xC439, 0xC439, 0xC439}, {0xC43A, 0xC43A, 0xC43A}, {0xC43B, 0xC43B, 0xC43B}, {0xC43C, 0xC43C, 0xC43C}, {0xC43D, 0xC43D, 0xC43D}, {0xC43E, 0xC43E, 0xC43E}, {0xC43F, 0xC43F, 0xC43F}, {0xC440, 0xC440, 0xC440}, {0xC441, 0xC441, 0xC441}, {0xC442, 0xC442, 0xC442}, {0xC443, 0xC443, 0xC443}, {0xC444, 0xC444, 0xC444}, {0xC445, 0xC445, 0xC445}, {0xC446, 0xC446, 0xC446}, {0xC447, 0xC447, 0xC447}, {0xC448, 0xC448, 0xC448}, {0xC449, 0xC449, 0xC449}, {0xC44A, 0xC44A, 0xC44A}, {0xC44B, 0xC44B, 0xC44B}, {0xC44C, 0xC44C, 0xC44C}, {0xC44D, 0xC44D, 0xC44D}, {0xC44E, 0xC44E, 0xC44E}, {0xC44F, 0xC44F, 0xC44F}, {0xC450, 0xC450, 0xC450}, {0xC451, 0xC451, 0xC451}, {0xC452, 0xC452, 0xC452}, {0xC453, 0xC453, 0xC453}, {0xC454, 0xC454, 0xC454}, {0xC455, 0xC455, 0xC455}, {0xC456, 0xC456, 0xC456}, {0xC457, 0xC457, 0xC457}, {0xC458, 0xC458, 0xC458}, {0xC459, 0xC459, 0xC459}, {0xC45A, 0xC45A, 0xC45A}, {0xC45B, 0xC45B, 0xC45B}, {0xC45C, 0xC45C, 0xC45C}, {0xC45D, 0xC45D, 0xC45D}, {0xC45E, 0xC45E, 0xC45E}, {0xC45F, 0xC45F, 0xC45F}, {0xC460, 0xC460, 0xC460}, {0xC461, 0xC461, 0xC461}, {0xC462, 0xC462, 0xC462}, {0xC463, 0xC463, 0xC463}, {0xC464, 0xC464, 0xC464}, {0xC465, 0xC465, 0xC465}, {0xC466, 0xC466, 0xC466}, {0xC467, 0xC467, 0xC467}, {0xC468, 0xC468, 0xC468}, {0xC469, 0xC469, 0xC469}, {0xC46A, 0xC46A, 0xC46A}, {0xC46B, 0xC46B, 0xC46B}, {0xC46C, 0xC46C, 0xC46C}, {0xC46D, 0xC46D, 0xC46D}, {0xC46E, 0xC46E, 0xC46E}, {0xC46F, 0xC46F, 0xC46F}, {0xC470, 0xC470, 0xC470}, {0xC471, 0xC471, 0xC471}, {0xC472, 0xC472, 0xC472}, {0xC473, 0xC473, 0xC473}, {0xC474, 0xC474, 0xC474}, {0xC475, 0xC475, 0xC475}, {0xC476, 0xC476, 0xC476}, {0xC477, 0xC477, 0xC477}, {0xC478, 0xC478, 0xC478}, {0xC479, 0xC479, 0xC479}, {0xC47A, 0xC47A, 0xC47A}, {0xC47B, 0xC47B, 0xC47B}, {0xC47C, 0xC47C, 0xC47C}, {0xC47D, 0xC47D, 0xC47D}, {0xC47E, 0xC47E, 0xC47E}, {0xC47F, 0xC47F, 0xC47F}, {0xC480, 0xC480, 0xC480}, {0xC481, 0xC481, 0xC481}, {0xC482, 0xC482, 0xC482}, {0xC483, 0xC483, 0xC483}, {0xC484, 0xC484, 0xC484}, {0xC485, 0xC485, 0xC485}, {0xC486, 0xC486, 0xC486}, {0xC487, 0xC487, 0xC487}, {0xC488, 0xC488, 0xC488}, {0xC489, 0xC489, 0xC489}, {0xC48A, 0xC48A, 0xC48A}, {0xC48B, 0xC48B, 0xC48B}, {0xC48C, 0xC48C, 0xC48C}, {0xC48D, 0xC48D, 0xC48D}, {0xC48E, 0xC48E, 0xC48E}, {0xC48F, 0xC48F, 0xC48F}, {0xC490, 0xC490, 0xC490}, {0xC491, 0xC491, 0xC491}, {0xC492, 0xC492, 0xC492}, {0xC493, 0xC493, 0xC493}, {0xC494, 0xC494, 0xC494}, {0xC495, 0xC495, 0xC495}, {0xC496, 0xC496, 0xC496}, {0xC497, 0xC497, 0xC497}, {0xC498, 0xC498, 0xC498}, {0xC499, 0xC499, 0xC499}, {0xC49A, 0xC49A, 0xC49A}, {0xC49B, 0xC49B, 0xC49B}, {0xC49C, 0xC49C, 0xC49C}, {0xC49D, 0xC49D, 0xC49D}, {0xC49E, 0xC49E, 0xC49E}, {0xC49F, 0xC49F, 0xC49F}, {0xC4A0, 0xC4A0, 0xC4A0}, {0xC4A1, 0xC4A1, 0xC4A1}, {0xC4A2, 0xC4A2, 0xC4A2}, {0xC4A3, 0xC4A3, 0xC4A3}, {0xC4A4, 0xC4A4, 0xC4A4}, {0xC4A5, 0xC4A5, 0xC4A5}, {0xC4A6, 0xC4A6, 0xC4A6}, {0xC4A7, 0xC4A7, 0xC4A7}, {0xC4A8, 0xC4A8, 0xC4A8}, {0xC4A9, 0xC4A9, 0xC4A9}, {0xC4AA, 0xC4AA, 0xC4AA}, {0xC4AB, 0xC4AB, 0xC4AB}, {0xC4AC, 0xC4AC, 0xC4AC}, {0xC4AD, 0xC4AD, 0xC4AD}, {0xC4AE, 0xC4AE, 0xC4AE}, {0xC4AF, 0xC4AF, 0xC4AF}, {0xC4B0, 0xC4B0, 0xC4B0}, {0xC4B1, 0xC4B1, 0xC4B1}, {0xC4B2, 0xC4B2, 0xC4B2}, {0xC4B3, 0xC4B3, 0xC4B3}, {0xC4B4, 0xC4B4, 0xC4B4}, {0xC4B5, 0xC4B5, 0xC4B5}, {0xC4B6, 0xC4B6, 0xC4B6}, {0xC4B7, 0xC4B7, 0xC4B7}, {0xC4B8, 0xC4B8, 0xC4B8}, {0xC4B9, 0xC4B9, 0xC4B9}, {0xC4BA, 0xC4BA, 0xC4BA}, {0xC4BB, 0xC4BB, 0xC4BB}, {0xC4BC, 0xC4BC, 0xC4BC}, {0xC4BD, 0xC4BD, 0xC4BD}, {0xC4BE, 0xC4BE, 0xC4BE}, {0xC4BF, 0xC4BF, 0xC4BF}, {0xC4C0, 0xC4C0, 0xC4C0}, {0xC4C1, 0xC4C1, 0xC4C1}, {0xC4C2, 0xC4C2, 0xC4C2}, {0xC4C3, 0xC4C3, 0xC4C3}, {0xC4C4, 0xC4C4, 0xC4C4}, {0xC4C5, 0xC4C5, 0xC4C5}, {0xC4C6, 0xC4C6, 0xC4C6}, {0xC4C7, 0xC4C7, 0xC4C7}, {0xC4C8, 0xC4C8, 0xC4C8}, {0xC4C9, 0xC4C9, 0xC4C9}, {0xC4CA, 0xC4CA, 0xC4CA}, {0xC4CB, 0xC4CB, 0xC4CB}, {0xC4CC, 0xC4CC, 0xC4CC}, {0xC4CD, 0xC4CD, 0xC4CD}, {0xC4CE, 0xC4CE, 0xC4CE}, {0xC4CF, 0xC4CF, 0xC4CF}, {0xC4D0, 0xC4D0, 0xC4D0}, {0xC4D1, 0xC4D1, 0xC4D1}, {0xC4D2, 0xC4D2, 0xC4D2}, {0xC4D3, 0xC4D3, 0xC4D3}, {0xC4D4, 0xC4D4, 0xC4D4}, {0xC4D5, 0xC4D5, 0xC4D5}, {0xC4D6, 0xC4D6, 0xC4D6}, {0xC4D7, 0xC4D7, 0xC4D7}, {0xC4D8, 0xC4D8, 0xC4D8}, {0xC4D9, 0xC4D9, 0xC4D9}, {0xC4DA, 0xC4DA, 0xC4DA}, {0xC4DB, 0xC4DB, 0xC4DB}, {0xC4DC, 0xC4DC, 0xC4DC}, {0xC4DD, 0xC4DD, 0xC4DD}, {0xC4DE, 0xC4DE, 0xC4DE}, {0xC4DF, 0xC4DF, 0xC4DF}, {0xC4E0, 0xC4E0, 0xC4E0}, {0xC4E1, 0xC4E1, 0xC4E1}, {0xC4E2, 0xC4E2, 0xC4E2}, {0xC4E3, 0xC4E3, 0xC4E3}, {0xC4E4, 0xC4E4, 0xC4E4}, {0xC4E5, 0xC4E5, 0xC4E5}, {0xC4E6, 0xC4E6, 0xC4E6}, {0xC4E7, 0xC4E7, 0xC4E7}, {0xC4E8, 0xC4E8, 0xC4E8}, {0xC4E9, 0xC4E9, 0xC4E9}, {0xC4EA, 0xC4EA, 0xC4EA}, {0xC4EB, 0xC4EB, 0xC4EB}, {0xC4EC, 0xC4EC, 0xC4EC}, {0xC4ED, 0xC4ED, 0xC4ED}, {0xC4EE, 0xC4EE, 0xC4EE}, {0xC4EF, 0xC4EF, 0xC4EF}, {0xC4F0, 0xC4F0, 0xC4F0}, {0xC4F1, 0xC4F1, 0xC4F1}, {0xC4F2, 0xC4F2, 0xC4F2}, {0xC4F3, 0xC4F3, 0xC4F3}, {0xC4F4, 0xC4F4, 0xC4F4}, {0xC4F5, 0xC4F5, 0xC4F5}, {0xC4F6, 0xC4F6, 0xC4F6}, {0xC4F7, 0xC4F7, 0xC4F7}, {0xC4F8, 0xC4F8, 0xC4F8}, {0xC4F9, 0xC4F9, 0xC4F9}, {0xC4FA, 0xC4FA, 0xC4FA}, {0xC4FB, 0xC4FB, 0xC4FB}, {0xC4FC, 0xC4FC, 0xC4FC}, {0xC4FD, 0xC4FD, 0xC4FD}, {0xC4FE, 0xC4FE, 0xC4FE}, {0xC4FF, 0xC4FF, 0xC4FF}, {0xC500, 0xC500, 0xC500}, {0xC501, 0xC501, 0xC501}, {0xC502, 0xC502, 0xC502}, {0xC503, 0xC503, 0xC503}, {0xC504, 0xC504, 0xC504}, {0xC505, 0xC505, 0xC505}, {0xC506, 0xC506, 0xC506}, {0xC507, 0xC507, 0xC507}, {0xC508, 0xC508, 0xC508}, {0xC509, 0xC509, 0xC509}, {0xC50A, 0xC50A, 0xC50A}, {0xC50B, 0xC50B, 0xC50B}, {0xC50C, 0xC50C, 0xC50C}, {0xC50D, 0xC50D, 0xC50D}, {0xC50E, 0xC50E, 0xC50E}, {0xC50F, 0xC50F, 0xC50F}, {0xC510, 0xC510, 0xC510}, {0xC511, 0xC511, 0xC511}, {0xC512, 0xC512, 0xC512}, {0xC513, 0xC513, 0xC513}, {0xC514, 0xC514, 0xC514}, {0xC515, 0xC515, 0xC515}, {0xC516, 0xC516, 0xC516}, {0xC517, 0xC517, 0xC517}, {0xC518, 0xC518, 0xC518}, {0xC519, 0xC519, 0xC519}, {0xC51A, 0xC51A, 0xC51A}, {0xC51B, 0xC51B, 0xC51B}, {0xC51C, 0xC51C, 0xC51C}, {0xC51D, 0xC51D, 0xC51D}, {0xC51E, 0xC51E, 0xC51E}, {0xC51F, 0xC51F, 0xC51F}, {0xC520, 0xC520, 0xC520}, {0xC521, 0xC521, 0xC521}, {0xC522, 0xC522, 0xC522}, {0xC523, 0xC523, 0xC523}, {0xC524, 0xC524, 0xC524}, {0xC525, 0xC525, 0xC525}, {0xC526, 0xC526, 0xC526}, {0xC527, 0xC527, 0xC527}, {0xC528, 0xC528, 0xC528}, {0xC529, 0xC529, 0xC529}, {0xC52A, 0xC52A, 0xC52A}, {0xC52B, 0xC52B, 0xC52B}, {0xC52C, 0xC52C, 0xC52C}, {0xC52D, 0xC52D, 0xC52D}, {0xC52E, 0xC52E, 0xC52E}, {0xC52F, 0xC52F, 0xC52F}, {0xC530, 0xC530, 0xC530}, {0xC531, 0xC531, 0xC531}, {0xC532, 0xC532, 0xC532}, {0xC533, 0xC533, 0xC533}, {0xC534, 0xC534, 0xC534}, {0xC535, 0xC535, 0xC535}, {0xC536, 0xC536, 0xC536}, {0xC537, 0xC537, 0xC537}, {0xC538, 0xC538, 0xC538}, {0xC539, 0xC539, 0xC539}, {0xC53A, 0xC53A, 0xC53A}, {0xC53B, 0xC53B, 0xC53B}, {0xC53C, 0xC53C, 0xC53C}, {0xC53D, 0xC53D, 0xC53D}, {0xC53E, 0xC53E, 0xC53E}, {0xC53F, 0xC53F, 0xC53F}, {0xC540, 0xC540, 0xC540}, {0xC541, 0xC541, 0xC541}, {0xC542, 0xC542, 0xC542}, {0xC543, 0xC543, 0xC543}, {0xC544, 0xC544, 0xC544}, {0xC545, 0xC545, 0xC545}, {0xC546, 0xC546, 0xC546}, {0xC547, 0xC547, 0xC547}, {0xC548, 0xC548, 0xC548}, {0xC549, 0xC549, 0xC549}, {0xC54A, 0xC54A, 0xC54A}, {0xC54B, 0xC54B, 0xC54B}, {0xC54C, 0xC54C, 0xC54C}, {0xC54D, 0xC54D, 0xC54D}, {0xC54E, 0xC54E, 0xC54E}, {0xC54F, 0xC54F, 0xC54F}, {0xC550, 0xC550, 0xC550}, {0xC551, 0xC551, 0xC551}, {0xC552, 0xC552, 0xC552}, {0xC553, 0xC553, 0xC553}, {0xC554, 0xC554, 0xC554}, {0xC555, 0xC555, 0xC555}, {0xC556, 0xC556, 0xC556}, {0xC557, 0xC557, 0xC557}, {0xC558, 0xC558, 0xC558}, {0xC559, 0xC559, 0xC559}, {0xC55A, 0xC55A, 0xC55A}, {0xC55B, 0xC55B, 0xC55B}, {0xC55C, 0xC55C, 0xC55C}, {0xC55D, 0xC55D, 0xC55D}, {0xC55E, 0xC55E, 0xC55E}, {0xC55F, 0xC55F, 0xC55F}, {0xC560, 0xC560, 0xC560}, {0xC561, 0xC561, 0xC561}, {0xC562, 0xC562, 0xC562}, {0xC563, 0xC563, 0xC563}, {0xC564, 0xC564, 0xC564}, {0xC565, 0xC565, 0xC565}, {0xC566, 0xC566, 0xC566}, {0xC567, 0xC567, 0xC567}, {0xC568, 0xC568, 0xC568}, {0xC569, 0xC569, 0xC569}, {0xC56A, 0xC56A, 0xC56A}, {0xC56B, 0xC56B, 0xC56B}, {0xC56C, 0xC56C, 0xC56C}, {0xC56D, 0xC56D, 0xC56D}, {0xC56E, 0xC56E, 0xC56E}, {0xC56F, 0xC56F, 0xC56F}, {0xC570, 0xC570, 0xC570}, {0xC571, 0xC571, 0xC571}, {0xC572, 0xC572, 0xC572}, {0xC573, 0xC573, 0xC573}, {0xC574, 0xC574, 0xC574}, {0xC575, 0xC575, 0xC575}, {0xC576, 0xC576, 0xC576}, {0xC577, 0xC577, 0xC577}, {0xC578, 0xC578, 0xC578}, {0xC579, 0xC579, 0xC579}, {0xC57A, 0xC57A, 0xC57A}, {0xC57B, 0xC57B, 0xC57B}, {0xC57C, 0xC57C, 0xC57C}, {0xC57D, 0xC57D, 0xC57D}, {0xC57E, 0xC57E, 0xC57E}, {0xC57F, 0xC57F, 0xC57F}, {0xC580, 0xC580, 0xC580}, {0xC581, 0xC581, 0xC581}, {0xC582, 0xC582, 0xC582}, {0xC583, 0xC583, 0xC583}, {0xC584, 0xC584, 0xC584}, {0xC585, 0xC585, 0xC585}, {0xC586, 0xC586, 0xC586}, {0xC587, 0xC587, 0xC587}, {0xC588, 0xC588, 0xC588}, {0xC589, 0xC589, 0xC589}, {0xC58A, 0xC58A, 0xC58A}, {0xC58B, 0xC58B, 0xC58B}, {0xC58C, 0xC58C, 0xC58C}, {0xC58D, 0xC58D, 0xC58D}, {0xC58E, 0xC58E, 0xC58E}, {0xC58F, 0xC58F, 0xC58F}, {0xC590, 0xC590, 0xC590}, {0xC591, 0xC591, 0xC591}, {0xC592, 0xC592, 0xC592}, {0xC593, 0xC593, 0xC593}, {0xC594, 0xC594, 0xC594}, {0xC595, 0xC595, 0xC595}, {0xC596, 0xC596, 0xC596}, {0xC597, 0xC597, 0xC597}, {0xC598, 0xC598, 0xC598}, {0xC599, 0xC599, 0xC599}, {0xC59A, 0xC59A, 0xC59A}, {0xC59B, 0xC59B, 0xC59B}, {0xC59C, 0xC59C, 0xC59C}, {0xC59D, 0xC59D, 0xC59D}, {0xC59E, 0xC59E, 0xC59E}, {0xC59F, 0xC59F, 0xC59F}, {0xC5A0, 0xC5A0, 0xC5A0}, {0xC5A1, 0xC5A1, 0xC5A1}, {0xC5A2, 0xC5A2, 0xC5A2}, {0xC5A3, 0xC5A3, 0xC5A3}, {0xC5A4, 0xC5A4, 0xC5A4}, {0xC5A5, 0xC5A5, 0xC5A5}, {0xC5A6, 0xC5A6, 0xC5A6}, {0xC5A7, 0xC5A7, 0xC5A7}, {0xC5A8, 0xC5A8, 0xC5A8}, {0xC5A9, 0xC5A9, 0xC5A9}, {0xC5AA, 0xC5AA, 0xC5AA}, {0xC5AB, 0xC5AB, 0xC5AB}, {0xC5AC, 0xC5AC, 0xC5AC}, {0xC5AD, 0xC5AD, 0xC5AD}, {0xC5AE, 0xC5AE, 0xC5AE}, {0xC5AF, 0xC5AF, 0xC5AF}, {0xC5B0, 0xC5B0, 0xC5B0}, {0xC5B1, 0xC5B1, 0xC5B1}, {0xC5B2, 0xC5B2, 0xC5B2}, {0xC5B3, 0xC5B3, 0xC5B3}, {0xC5B4, 0xC5B4, 0xC5B4}, {0xC5B5, 0xC5B5, 0xC5B5}, {0xC5B6, 0xC5B6, 0xC5B6}, {0xC5B7, 0xC5B7, 0xC5B7}, {0xC5B8, 0xC5B8, 0xC5B8}, {0xC5B9, 0xC5B9, 0xC5B9}, {0xC5BA, 0xC5BA, 0xC5BA}, {0xC5BB, 0xC5BB, 0xC5BB}, {0xC5BC, 0xC5BC, 0xC5BC}, {0xC5BD, 0xC5BD, 0xC5BD}, {0xC5BE, 0xC5BE, 0xC5BE}, {0xC5BF, 0xC5BF, 0xC5BF}, {0xC5C0, 0xC5C0, 0xC5C0}, {0xC5C1, 0xC5C1, 0xC5C1}, {0xC5C2, 0xC5C2, 0xC5C2}, {0xC5C3, 0xC5C3, 0xC5C3}, {0xC5C4, 0xC5C4, 0xC5C4}, {0xC5C5, 0xC5C5, 0xC5C5}, {0xC5C6, 0xC5C6, 0xC5C6}, {0xC5C7, 0xC5C7, 0xC5C7}, {0xC5C8, 0xC5C8, 0xC5C8}, {0xC5C9, 0xC5C9, 0xC5C9}, {0xC5CA, 0xC5CA, 0xC5CA}, {0xC5CB, 0xC5CB, 0xC5CB}, {0xC5CC, 0xC5CC, 0xC5CC}, {0xC5CD, 0xC5CD, 0xC5CD}, {0xC5CE, 0xC5CE, 0xC5CE}, {0xC5CF, 0xC5CF, 0xC5CF}, {0xC5D0, 0xC5D0, 0xC5D0}, {0xC5D1, 0xC5D1, 0xC5D1}, {0xC5D2, 0xC5D2, 0xC5D2}, {0xC5D3, 0xC5D3, 0xC5D3}, {0xC5D4, 0xC5D4, 0xC5D4}, {0xC5D5, 0xC5D5, 0xC5D5}, {0xC5D6, 0xC5D6, 0xC5D6}, {0xC5D7, 0xC5D7, 0xC5D7}, {0xC5D8, 0xC5D8, 0xC5D8}, {0xC5D9, 0xC5D9, 0xC5D9}, {0xC5DA, 0xC5DA, 0xC5DA}, {0xC5DB, 0xC5DB, 0xC5DB}, {0xC5DC, 0xC5DC, 0xC5DC}, {0xC5DD, 0xC5DD, 0xC5DD}, {0xC5DE, 0xC5DE, 0xC5DE}, {0xC5DF, 0xC5DF, 0xC5DF}, {0xC5E0, 0xC5E0, 0xC5E0}, {0xC5E1, 0xC5E1, 0xC5E1}, {0xC5E2, 0xC5E2, 0xC5E2}, {0xC5E3, 0xC5E3, 0xC5E3}, {0xC5E4, 0xC5E4, 0xC5E4}, {0xC5E5, 0xC5E5, 0xC5E5}, {0xC5E6, 0xC5E6, 0xC5E6}, {0xC5E7, 0xC5E7, 0xC5E7}, {0xC5E8, 0xC5E8, 0xC5E8}, {0xC5E9, 0xC5E9, 0xC5E9}, {0xC5EA, 0xC5EA, 0xC5EA}, {0xC5EB, 0xC5EB, 0xC5EB}, {0xC5EC, 0xC5EC, 0xC5EC}, {0xC5ED, 0xC5ED, 0xC5ED}, {0xC5EE, 0xC5EE, 0xC5EE}, {0xC5EF, 0xC5EF, 0xC5EF}, {0xC5F0, 0xC5F0, 0xC5F0}, {0xC5F1, 0xC5F1, 0xC5F1}, {0xC5F2, 0xC5F2, 0xC5F2}, {0xC5F3, 0xC5F3, 0xC5F3}, {0xC5F4, 0xC5F4, 0xC5F4}, {0xC5F5, 0xC5F5, 0xC5F5}, {0xC5F6, 0xC5F6, 0xC5F6}, {0xC5F7, 0xC5F7, 0xC5F7}, {0xC5F8, 0xC5F8, 0xC5F8}, {0xC5F9, 0xC5F9, 0xC5F9}, {0xC5FA, 0xC5FA, 0xC5FA}, {0xC5FB, 0xC5FB, 0xC5FB}, {0xC5FC, 0xC5FC, 0xC5FC}, {0xC5FD, 0xC5FD, 0xC5FD}, {0xC5FE, 0xC5FE, 0xC5FE}, {0xC5FF, 0xC5FF, 0xC5FF}, {0xC600, 0xC600, 0xC600}, {0xC601, 0xC601, 0xC601}, {0xC602, 0xC602, 0xC602}, {0xC603, 0xC603, 0xC603}, {0xC604, 0xC604, 0xC604}, {0xC605, 0xC605, 0xC605}, {0xC606, 0xC606, 0xC606}, {0xC607, 0xC607, 0xC607}, {0xC608, 0xC608, 0xC608}, {0xC609, 0xC609, 0xC609}, {0xC60A, 0xC60A, 0xC60A}, {0xC60B, 0xC60B, 0xC60B}, {0xC60C, 0xC60C, 0xC60C}, {0xC60D, 0xC60D, 0xC60D}, {0xC60E, 0xC60E, 0xC60E}, {0xC60F, 0xC60F, 0xC60F}, {0xC610, 0xC610, 0xC610}, {0xC611, 0xC611, 0xC611}, {0xC612, 0xC612, 0xC612}, {0xC613, 0xC613, 0xC613}, {0xC614, 0xC614, 0xC614}, {0xC615, 0xC615, 0xC615}, {0xC616, 0xC616, 0xC616}, {0xC617, 0xC617, 0xC617}, {0xC618, 0xC618, 0xC618}, {0xC619, 0xC619, 0xC619}, {0xC61A, 0xC61A, 0xC61A}, {0xC61B, 0xC61B, 0xC61B}, {0xC61C, 0xC61C, 0xC61C}, {0xC61D, 0xC61D, 0xC61D}, {0xC61E, 0xC61E, 0xC61E}, {0xC61F, 0xC61F, 0xC61F}, {0xC620, 0xC620, 0xC620}, {0xC621, 0xC621, 0xC621}, {0xC622, 0xC622, 0xC622}, {0xC623, 0xC623, 0xC623}, {0xC624, 0xC624, 0xC624}, {0xC625, 0xC625, 0xC625}, {0xC626, 0xC626, 0xC626}, {0xC627, 0xC627, 0xC627}, {0xC628, 0xC628, 0xC628}, {0xC629, 0xC629, 0xC629}, {0xC62A, 0xC62A, 0xC62A}, {0xC62B, 0xC62B, 0xC62B}, {0xC62C, 0xC62C, 0xC62C}, {0xC62D, 0xC62D, 0xC62D}, {0xC62E, 0xC62E, 0xC62E}, {0xC62F, 0xC62F, 0xC62F}, {0xC630, 0xC630, 0xC630}, {0xC631, 0xC631, 0xC631}, {0xC632, 0xC632, 0xC632}, {0xC633, 0xC633, 0xC633}, {0xC634, 0xC634, 0xC634}, {0xC635, 0xC635, 0xC635}, {0xC636, 0xC636, 0xC636}, {0xC637, 0xC637, 0xC637}, {0xC638, 0xC638, 0xC638}, {0xC639, 0xC639, 0xC639}, {0xC63A, 0xC63A, 0xC63A}, {0xC63B, 0xC63B, 0xC63B}, {0xC63C, 0xC63C, 0xC63C}, {0xC63D, 0xC63D, 0xC63D}, {0xC63E, 0xC63E, 0xC63E}, {0xC63F, 0xC63F, 0xC63F}, {0xC640, 0xC640, 0xC640}, {0xC641, 0xC641, 0xC641}, {0xC642, 0xC642, 0xC642}, {0xC643, 0xC643, 0xC643}, {0xC644, 0xC644, 0xC644}, {0xC645, 0xC645, 0xC645}, {0xC646, 0xC646, 0xC646}, {0xC647, 0xC647, 0xC647}, {0xC648, 0xC648, 0xC648}, {0xC649, 0xC649, 0xC649}, {0xC64A, 0xC64A, 0xC64A}, {0xC64B, 0xC64B, 0xC64B}, {0xC64C, 0xC64C, 0xC64C}, {0xC64D, 0xC64D, 0xC64D}, {0xC64E, 0xC64E, 0xC64E}, {0xC64F, 0xC64F, 0xC64F}, {0xC650, 0xC650, 0xC650}, {0xC651, 0xC651, 0xC651}, {0xC652, 0xC652, 0xC652}, {0xC653, 0xC653, 0xC653}, {0xC654, 0xC654, 0xC654}, {0xC655, 0xC655, 0xC655}, {0xC656, 0xC656, 0xC656}, {0xC657, 0xC657, 0xC657}, {0xC658, 0xC658, 0xC658}, {0xC659, 0xC659, 0xC659}, {0xC65A, 0xC65A, 0xC65A}, {0xC65B, 0xC65B, 0xC65B}, {0xC65C, 0xC65C, 0xC65C}, {0xC65D, 0xC65D, 0xC65D}, {0xC65E, 0xC65E, 0xC65E}, {0xC65F, 0xC65F, 0xC65F}, {0xC660, 0xC660, 0xC660}, {0xC661, 0xC661, 0xC661}, {0xC662, 0xC662, 0xC662}, {0xC663, 0xC663, 0xC663}, {0xC664, 0xC664, 0xC664}, {0xC665, 0xC665, 0xC665}, {0xC666, 0xC666, 0xC666}, {0xC667, 0xC667, 0xC667}, {0xC668, 0xC668, 0xC668}, {0xC669, 0xC669, 0xC669}, {0xC66A, 0xC66A, 0xC66A}, {0xC66B, 0xC66B, 0xC66B}, {0xC66C, 0xC66C, 0xC66C}, {0xC66D, 0xC66D, 0xC66D}, {0xC66E, 0xC66E, 0xC66E}, {0xC66F, 0xC66F, 0xC66F}, {0xC670, 0xC670, 0xC670}, {0xC671, 0xC671, 0xC671}, {0xC672, 0xC672, 0xC672}, {0xC673, 0xC673, 0xC673}, {0xC674, 0xC674, 0xC674}, {0xC675, 0xC675, 0xC675}, {0xC676, 0xC676, 0xC676}, {0xC677, 0xC677, 0xC677}, {0xC678, 0xC678, 0xC678}, {0xC679, 0xC679, 0xC679}, {0xC67A, 0xC67A, 0xC67A}, {0xC67B, 0xC67B, 0xC67B}, {0xC67C, 0xC67C, 0xC67C}, {0xC67D, 0xC67D, 0xC67D}, {0xC67E, 0xC67E, 0xC67E}, {0xC67F, 0xC67F, 0xC67F}, {0xC680, 0xC680, 0xC680}, {0xC681, 0xC681, 0xC681}, {0xC682, 0xC682, 0xC682}, {0xC683, 0xC683, 0xC683}, {0xC684, 0xC684, 0xC684}, {0xC685, 0xC685, 0xC685}, {0xC686, 0xC686, 0xC686}, {0xC687, 0xC687, 0xC687}, {0xC688, 0xC688, 0xC688}, {0xC689, 0xC689, 0xC689}, {0xC68A, 0xC68A, 0xC68A}, {0xC68B, 0xC68B, 0xC68B}, {0xC68C, 0xC68C, 0xC68C}, {0xC68D, 0xC68D, 0xC68D}, {0xC68E, 0xC68E, 0xC68E}, {0xC68F, 0xC68F, 0xC68F}, {0xC690, 0xC690, 0xC690}, {0xC691, 0xC691, 0xC691}, {0xC692, 0xC692, 0xC692}, {0xC693, 0xC693, 0xC693}, {0xC694, 0xC694, 0xC694}, {0xC695, 0xC695, 0xC695}, {0xC696, 0xC696, 0xC696}, {0xC697, 0xC697, 0xC697}, {0xC698, 0xC698, 0xC698}, {0xC699, 0xC699, 0xC699}, {0xC69A, 0xC69A, 0xC69A}, {0xC69B, 0xC69B, 0xC69B}, {0xC69C, 0xC69C, 0xC69C}, {0xC69D, 0xC69D, 0xC69D}, {0xC69E, 0xC69E, 0xC69E}, {0xC69F, 0xC69F, 0xC69F}, {0xC6A0, 0xC6A0, 0xC6A0}, {0xC6A1, 0xC6A1, 0xC6A1}, {0xC6A2, 0xC6A2, 0xC6A2}, {0xC6A3, 0xC6A3, 0xC6A3}, {0xC6A4, 0xC6A4, 0xC6A4}, {0xC6A5, 0xC6A5, 0xC6A5}, {0xC6A6, 0xC6A6, 0xC6A6}, {0xC6A7, 0xC6A7, 0xC6A7}, {0xC6A8, 0xC6A8, 0xC6A8}, {0xC6A9, 0xC6A9, 0xC6A9}, {0xC6AA, 0xC6AA, 0xC6AA}, {0xC6AB, 0xC6AB, 0xC6AB}, {0xC6AC, 0xC6AC, 0xC6AC}, {0xC6AD, 0xC6AD, 0xC6AD}, {0xC6AE, 0xC6AE, 0xC6AE}, {0xC6AF, 0xC6AF, 0xC6AF}, {0xC6B0, 0xC6B0, 0xC6B0}, {0xC6B1, 0xC6B1, 0xC6B1}, {0xC6B2, 0xC6B2, 0xC6B2}, {0xC6B3, 0xC6B3, 0xC6B3}, {0xC6B4, 0xC6B4, 0xC6B4}, {0xC6B5, 0xC6B5, 0xC6B5}, {0xC6B6, 0xC6B6, 0xC6B6}, {0xC6B7, 0xC6B7, 0xC6B7}, {0xC6B8, 0xC6B8, 0xC6B8}, {0xC6B9, 0xC6B9, 0xC6B9}, {0xC6BA, 0xC6BA, 0xC6BA}, {0xC6BB, 0xC6BB, 0xC6BB}, {0xC6BC, 0xC6BC, 0xC6BC}, {0xC6BD, 0xC6BD, 0xC6BD}, {0xC6BE, 0xC6BE, 0xC6BE}, {0xC6BF, 0xC6BF, 0xC6BF}, {0xC6C0, 0xC6C0, 0xC6C0}, {0xC6C1, 0xC6C1, 0xC6C1}, {0xC6C2, 0xC6C2, 0xC6C2}, {0xC6C3, 0xC6C3, 0xC6C3}, {0xC6C4, 0xC6C4, 0xC6C4}, {0xC6C5, 0xC6C5, 0xC6C5}, {0xC6C6, 0xC6C6, 0xC6C6}, {0xC6C7, 0xC6C7, 0xC6C7}, {0xC6C8, 0xC6C8, 0xC6C8}, {0xC6C9, 0xC6C9, 0xC6C9}, {0xC6CA, 0xC6CA, 0xC6CA}, {0xC6CB, 0xC6CB, 0xC6CB}, {0xC6CC, 0xC6CC, 0xC6CC}, {0xC6CD, 0xC6CD, 0xC6CD}, {0xC6CE, 0xC6CE, 0xC6CE}, {0xC6CF, 0xC6CF, 0xC6CF}, {0xC6D0, 0xC6D0, 0xC6D0}, {0xC6D1, 0xC6D1, 0xC6D1}, {0xC6D2, 0xC6D2, 0xC6D2}, {0xC6D3, 0xC6D3, 0xC6D3}, {0xC6D4, 0xC6D4, 0xC6D4}, {0xC6D5, 0xC6D5, 0xC6D5}, {0xC6D6, 0xC6D6, 0xC6D6}, {0xC6D7, 0xC6D7, 0xC6D7}, {0xC6D8, 0xC6D8, 0xC6D8}, {0xC6D9, 0xC6D9, 0xC6D9}, {0xC6DA, 0xC6DA, 0xC6DA}, {0xC6DB, 0xC6DB, 0xC6DB}, {0xC6DC, 0xC6DC, 0xC6DC}, {0xC6DD, 0xC6DD, 0xC6DD}, {0xC6DE, 0xC6DE, 0xC6DE}, {0xC6DF, 0xC6DF, 0xC6DF}, {0xC6E0, 0xC6E0, 0xC6E0}, {0xC6E1, 0xC6E1, 0xC6E1}, {0xC6E2, 0xC6E2, 0xC6E2}, {0xC6E3, 0xC6E3, 0xC6E3}, {0xC6E4, 0xC6E4, 0xC6E4}, {0xC6E5, 0xC6E5, 0xC6E5}, {0xC6E6, 0xC6E6, 0xC6E6}, {0xC6E7, 0xC6E7, 0xC6E7}, {0xC6E8, 0xC6E8, 0xC6E8}, {0xC6E9, 0xC6E9, 0xC6E9}, {0xC6EA, 0xC6EA, 0xC6EA}, {0xC6EB, 0xC6EB, 0xC6EB}, {0xC6EC, 0xC6EC, 0xC6EC}, {0xC6ED, 0xC6ED, 0xC6ED}, {0xC6EE, 0xC6EE, 0xC6EE}, {0xC6EF, 0xC6EF, 0xC6EF}, {0xC6F0, 0xC6F0, 0xC6F0}, {0xC6F1, 0xC6F1, 0xC6F1}, {0xC6F2, 0xC6F2, 0xC6F2}, {0xC6F3, 0xC6F3, 0xC6F3}, {0xC6F4, 0xC6F4, 0xC6F4}, {0xC6F5, 0xC6F5, 0xC6F5}, {0xC6F6, 0xC6F6, 0xC6F6}, {0xC6F7, 0xC6F7, 0xC6F7}, {0xC6F8, 0xC6F8, 0xC6F8}, {0xC6F9, 0xC6F9, 0xC6F9}, {0xC6FA, 0xC6FA, 0xC6FA}, {0xC6FB, 0xC6FB, 0xC6FB}, {0xC6FC, 0xC6FC, 0xC6FC}, {0xC6FD, 0xC6FD, 0xC6FD}, {0xC6FE, 0xC6FE, 0xC6FE}, {0xC6FF, 0xC6FF, 0xC6FF}, {0xC700, 0xC700, 0xC700}, {0xC701, 0xC701, 0xC701}, {0xC702, 0xC702, 0xC702}, {0xC703, 0xC703, 0xC703}, {0xC704, 0xC704, 0xC704}, {0xC705, 0xC705, 0xC705}, {0xC706, 0xC706, 0xC706}, {0xC707, 0xC707, 0xC707}, {0xC708, 0xC708, 0xC708}, {0xC709, 0xC709, 0xC709}, {0xC70A, 0xC70A, 0xC70A}, {0xC70B, 0xC70B, 0xC70B}, {0xC70C, 0xC70C, 0xC70C}, {0xC70D, 0xC70D, 0xC70D}, {0xC70E, 0xC70E, 0xC70E}, {0xC70F, 0xC70F, 0xC70F}, {0xC710, 0xC710, 0xC710}, {0xC711, 0xC711, 0xC711}, {0xC712, 0xC712, 0xC712}, {0xC713, 0xC713, 0xC713}, {0xC714, 0xC714, 0xC714}, {0xC715, 0xC715, 0xC715}, {0xC716, 0xC716, 0xC716}, {0xC717, 0xC717, 0xC717}, {0xC718, 0xC718, 0xC718}, {0xC719, 0xC719, 0xC719}, {0xC71A, 0xC71A, 0xC71A}, {0xC71B, 0xC71B, 0xC71B}, {0xC71C, 0xC71C, 0xC71C}, {0xC71D, 0xC71D, 0xC71D}, {0xC71E, 0xC71E, 0xC71E}, {0xC71F, 0xC71F, 0xC71F}, {0xC720, 0xC720, 0xC720}, {0xC721, 0xC721, 0xC721}, {0xC722, 0xC722, 0xC722}, {0xC723, 0xC723, 0xC723}, {0xC724, 0xC724, 0xC724}, {0xC725, 0xC725, 0xC725}, {0xC726, 0xC726, 0xC726}, {0xC727, 0xC727, 0xC727}, {0xC728, 0xC728, 0xC728}, {0xC729, 0xC729, 0xC729}, {0xC72A, 0xC72A, 0xC72A}, {0xC72B, 0xC72B, 0xC72B}, {0xC72C, 0xC72C, 0xC72C}, {0xC72D, 0xC72D, 0xC72D}, {0xC72E, 0xC72E, 0xC72E}, {0xC72F, 0xC72F, 0xC72F}, {0xC730, 0xC730, 0xC730}, {0xC731, 0xC731, 0xC731}, {0xC732, 0xC732, 0xC732}, {0xC733, 0xC733, 0xC733}, {0xC734, 0xC734, 0xC734}, {0xC735, 0xC735, 0xC735}, {0xC736, 0xC736, 0xC736}, {0xC737, 0xC737, 0xC737}, {0xC738, 0xC738, 0xC738}, {0xC739, 0xC739, 0xC739}, {0xC73A, 0xC73A, 0xC73A}, {0xC73B, 0xC73B, 0xC73B}, {0xC73C, 0xC73C, 0xC73C}, {0xC73D, 0xC73D, 0xC73D}, {0xC73E, 0xC73E, 0xC73E}, {0xC73F, 0xC73F, 0xC73F}, {0xC740, 0xC740, 0xC740}, {0xC741, 0xC741, 0xC741}, {0xC742, 0xC742, 0xC742}, {0xC743, 0xC743, 0xC743}, {0xC744, 0xC744, 0xC744}, {0xC745, 0xC745, 0xC745}, {0xC746, 0xC746, 0xC746}, {0xC747, 0xC747, 0xC747}, {0xC748, 0xC748, 0xC748}, {0xC749, 0xC749, 0xC749}, {0xC74A, 0xC74A, 0xC74A}, {0xC74B, 0xC74B, 0xC74B}, {0xC74C, 0xC74C, 0xC74C}, {0xC74D, 0xC74D, 0xC74D}, {0xC74E, 0xC74E, 0xC74E}, {0xC74F, 0xC74F, 0xC74F}, {0xC750, 0xC750, 0xC750}, {0xC751, 0xC751, 0xC751}, {0xC752, 0xC752, 0xC752}, {0xC753, 0xC753, 0xC753}, {0xC754, 0xC754, 0xC754}, {0xC755, 0xC755, 0xC755}, {0xC756, 0xC756, 0xC756}, {0xC757, 0xC757, 0xC757}, {0xC758, 0xC758, 0xC758}, {0xC759, 0xC759, 0xC759}, {0xC75A, 0xC75A, 0xC75A}, {0xC75B, 0xC75B, 0xC75B}, {0xC75C, 0xC75C, 0xC75C}, {0xC75D, 0xC75D, 0xC75D}, {0xC75E, 0xC75E, 0xC75E}, {0xC75F, 0xC75F, 0xC75F}, {0xC760, 0xC760, 0xC760}, {0xC761, 0xC761, 0xC761}, {0xC762, 0xC762, 0xC762}, {0xC763, 0xC763, 0xC763}, {0xC764, 0xC764, 0xC764}, {0xC765, 0xC765, 0xC765}, {0xC766, 0xC766, 0xC766}, {0xC767, 0xC767, 0xC767}, {0xC768, 0xC768, 0xC768}, {0xC769, 0xC769, 0xC769}, {0xC76A, 0xC76A, 0xC76A}, {0xC76B, 0xC76B, 0xC76B}, {0xC76C, 0xC76C, 0xC76C}, {0xC76D, 0xC76D, 0xC76D}, {0xC76E, 0xC76E, 0xC76E}, {0xC76F, 0xC76F, 0xC76F}, {0xC770, 0xC770, 0xC770}, {0xC771, 0xC771, 0xC771}, {0xC772, 0xC772, 0xC772}, {0xC773, 0xC773, 0xC773}, {0xC774, 0xC774, 0xC774}, {0xC775, 0xC775, 0xC775}, {0xC776, 0xC776, 0xC776}, {0xC777, 0xC777, 0xC777}, {0xC778, 0xC778, 0xC778}, {0xC779, 0xC779, 0xC779}, {0xC77A, 0xC77A, 0xC77A}, {0xC77B, 0xC77B, 0xC77B}, {0xC77C, 0xC77C, 0xC77C}, {0xC77D, 0xC77D, 0xC77D}, {0xC77E, 0xC77E, 0xC77E}, {0xC77F, 0xC77F, 0xC77F}, {0xC780, 0xC780, 0xC780}, {0xC781, 0xC781, 0xC781}, {0xC782, 0xC782, 0xC782}, {0xC783, 0xC783, 0xC783}, {0xC784, 0xC784, 0xC784}, {0xC785, 0xC785, 0xC785}, {0xC786, 0xC786, 0xC786}, {0xC787, 0xC787, 0xC787}, {0xC788, 0xC788, 0xC788}, {0xC789, 0xC789, 0xC789}, {0xC78A, 0xC78A, 0xC78A}, {0xC78B, 0xC78B, 0xC78B}, {0xC78C, 0xC78C, 0xC78C}, {0xC78D, 0xC78D, 0xC78D}, {0xC78E, 0xC78E, 0xC78E}, {0xC78F, 0xC78F, 0xC78F}, {0xC790, 0xC790, 0xC790}, {0xC791, 0xC791, 0xC791}, {0xC792, 0xC792, 0xC792}, {0xC793, 0xC793, 0xC793}, {0xC794, 0xC794, 0xC794}, {0xC795, 0xC795, 0xC795}, {0xC796, 0xC796, 0xC796}, {0xC797, 0xC797, 0xC797}, {0xC798, 0xC798, 0xC798}, {0xC799, 0xC799, 0xC799}, {0xC79A, 0xC79A, 0xC79A}, {0xC79B, 0xC79B, 0xC79B}, {0xC79C, 0xC79C, 0xC79C}, {0xC79D, 0xC79D, 0xC79D}, {0xC79E, 0xC79E, 0xC79E}, {0xC79F, 0xC79F, 0xC79F}, {0xC7A0, 0xC7A0, 0xC7A0}, {0xC7A1, 0xC7A1, 0xC7A1}, {0xC7A2, 0xC7A2, 0xC7A2}, {0xC7A3, 0xC7A3, 0xC7A3}, {0xC7A4, 0xC7A4, 0xC7A4}, {0xC7A5, 0xC7A5, 0xC7A5}, {0xC7A6, 0xC7A6, 0xC7A6}, {0xC7A7, 0xC7A7, 0xC7A7}, {0xC7A8, 0xC7A8, 0xC7A8}, {0xC7A9, 0xC7A9, 0xC7A9}, {0xC7AA, 0xC7AA, 0xC7AA}, {0xC7AB, 0xC7AB, 0xC7AB}, {0xC7AC, 0xC7AC, 0xC7AC}, {0xC7AD, 0xC7AD, 0xC7AD}, {0xC7AE, 0xC7AE, 0xC7AE}, {0xC7AF, 0xC7AF, 0xC7AF}, {0xC7B0, 0xC7B0, 0xC7B0}, {0xC7B1, 0xC7B1, 0xC7B1}, {0xC7B2, 0xC7B2, 0xC7B2}, {0xC7B3, 0xC7B3, 0xC7B3}, {0xC7B4, 0xC7B4, 0xC7B4}, {0xC7B5, 0xC7B5, 0xC7B5}, {0xC7B6, 0xC7B6, 0xC7B6}, {0xC7B7, 0xC7B7, 0xC7B7}, {0xC7B8, 0xC7B8, 0xC7B8}, {0xC7B9, 0xC7B9, 0xC7B9}, {0xC7BA, 0xC7BA, 0xC7BA}, {0xC7BB, 0xC7BB, 0xC7BB}, {0xC7BC, 0xC7BC, 0xC7BC}, {0xC7BD, 0xC7BD, 0xC7BD}, {0xC7BE, 0xC7BE, 0xC7BE}, {0xC7BF, 0xC7BF, 0xC7BF}, {0xC7C0, 0xC7C0, 0xC7C0}, {0xC7C1, 0xC7C1, 0xC7C1}, {0xC7C2, 0xC7C2, 0xC7C2}, {0xC7C3, 0xC7C3, 0xC7C3}, {0xC7C4, 0xC7C4, 0xC7C4}, {0xC7C5, 0xC7C5, 0xC7C5}, {0xC7C6, 0xC7C6, 0xC7C6}, {0xC7C7, 0xC7C7, 0xC7C7}, {0xC7C8, 0xC7C8, 0xC7C8}, {0xC7C9, 0xC7C9, 0xC7C9}, {0xC7CA, 0xC7CA, 0xC7CA}, {0xC7CB, 0xC7CB, 0xC7CB}, {0xC7CC, 0xC7CC, 0xC7CC}, {0xC7CD, 0xC7CD, 0xC7CD}, {0xC7CE, 0xC7CE, 0xC7CE}, {0xC7CF, 0xC7CF, 0xC7CF}, {0xC7D0, 0xC7D0, 0xC7D0}, {0xC7D1, 0xC7D1, 0xC7D1}, {0xC7D2, 0xC7D2, 0xC7D2}, {0xC7D3, 0xC7D3, 0xC7D3}, {0xC7D4, 0xC7D4, 0xC7D4}, {0xC7D5, 0xC7D5, 0xC7D5}, {0xC7D6, 0xC7D6, 0xC7D6}, {0xC7D7, 0xC7D7, 0xC7D7}, {0xC7D8, 0xC7D8, 0xC7D8}, {0xC7D9, 0xC7D9, 0xC7D9}, {0xC7DA, 0xC7DA, 0xC7DA}, {0xC7DB, 0xC7DB, 0xC7DB}, {0xC7DC, 0xC7DC, 0xC7DC}, {0xC7DD, 0xC7DD, 0xC7DD}, {0xC7DE, 0xC7DE, 0xC7DE}, {0xC7DF, 0xC7DF, 0xC7DF}, {0xC7E0, 0xC7E0, 0xC7E0}, {0xC7E1, 0xC7E1, 0xC7E1}, {0xC7E2, 0xC7E2, 0xC7E2}, {0xC7E3, 0xC7E3, 0xC7E3}, {0xC7E4, 0xC7E4, 0xC7E4}, {0xC7E5, 0xC7E5, 0xC7E5}, {0xC7E6, 0xC7E6, 0xC7E6}, {0xC7E7, 0xC7E7, 0xC7E7}, {0xC7E8, 0xC7E8, 0xC7E8}, {0xC7E9, 0xC7E9, 0xC7E9}, {0xC7EA, 0xC7EA, 0xC7EA}, {0xC7EB, 0xC7EB, 0xC7EB}, {0xC7EC, 0xC7EC, 0xC7EC}, {0xC7ED, 0xC7ED, 0xC7ED}, {0xC7EE, 0xC7EE, 0xC7EE}, {0xC7EF, 0xC7EF, 0xC7EF}, {0xC7F0, 0xC7F0, 0xC7F0}, {0xC7F1, 0xC7F1, 0xC7F1}, {0xC7F2, 0xC7F2, 0xC7F2}, {0xC7F3, 0xC7F3, 0xC7F3}, {0xC7F4, 0xC7F4, 0xC7F4}, {0xC7F5, 0xC7F5, 0xC7F5}, {0xC7F6, 0xC7F6, 0xC7F6}, {0xC7F7, 0xC7F7, 0xC7F7}, {0xC7F8, 0xC7F8, 0xC7F8}, {0xC7F9, 0xC7F9, 0xC7F9}, {0xC7FA, 0xC7FA, 0xC7FA}, {0xC7FB, 0xC7FB, 0xC7FB}, {0xC7FC, 0xC7FC, 0xC7FC}, {0xC7FD, 0xC7FD, 0xC7FD}, {0xC7FE, 0xC7FE, 0xC7FE}, {0xC7FF, 0xC7FF, 0xC7FF}, {0xC800, 0xC800, 0xC800}, {0xC801, 0xC801, 0xC801}, {0xC802, 0xC802, 0xC802}, {0xC803, 0xC803, 0xC803}, {0xC804, 0xC804, 0xC804}, {0xC805, 0xC805, 0xC805}, {0xC806, 0xC806, 0xC806}, {0xC807, 0xC807, 0xC807}, {0xC808, 0xC808, 0xC808}, {0xC809, 0xC809, 0xC809}, {0xC80A, 0xC80A, 0xC80A}, {0xC80B, 0xC80B, 0xC80B}, {0xC80C, 0xC80C, 0xC80C}, {0xC80D, 0xC80D, 0xC80D}, {0xC80E, 0xC80E, 0xC80E}, {0xC80F, 0xC80F, 0xC80F}, {0xC810, 0xC810, 0xC810}, {0xC811, 0xC811, 0xC811}, {0xC812, 0xC812, 0xC812}, {0xC813, 0xC813, 0xC813}, {0xC814, 0xC814, 0xC814}, {0xC815, 0xC815, 0xC815}, {0xC816, 0xC816, 0xC816}, {0xC817, 0xC817, 0xC817}, {0xC818, 0xC818, 0xC818}, {0xC819, 0xC819, 0xC819}, {0xC81A, 0xC81A, 0xC81A}, {0xC81B, 0xC81B, 0xC81B}, {0xC81C, 0xC81C, 0xC81C}, {0xC81D, 0xC81D, 0xC81D}, {0xC81E, 0xC81E, 0xC81E}, {0xC81F, 0xC81F, 0xC81F}, {0xC820, 0xC820, 0xC820}, {0xC821, 0xC821, 0xC821}, {0xC822, 0xC822, 0xC822}, {0xC823, 0xC823, 0xC823}, {0xC824, 0xC824, 0xC824}, {0xC825, 0xC825, 0xC825}, {0xC826, 0xC826, 0xC826}, {0xC827, 0xC827, 0xC827}, {0xC828, 0xC828, 0xC828}, {0xC829, 0xC829, 0xC829}, {0xC82A, 0xC82A, 0xC82A}, {0xC82B, 0xC82B, 0xC82B}, {0xC82C, 0xC82C, 0xC82C}, {0xC82D, 0xC82D, 0xC82D}, {0xC82E, 0xC82E, 0xC82E}, {0xC82F, 0xC82F, 0xC82F}, {0xC830, 0xC830, 0xC830}, {0xC831, 0xC831, 0xC831}, {0xC832, 0xC832, 0xC832}, {0xC833, 0xC833, 0xC833}, {0xC834, 0xC834, 0xC834}, {0xC835, 0xC835, 0xC835}, {0xC836, 0xC836, 0xC836}, {0xC837, 0xC837, 0xC837}, {0xC838, 0xC838, 0xC838}, {0xC839, 0xC839, 0xC839}, {0xC83A, 0xC83A, 0xC83A}, {0xC83B, 0xC83B, 0xC83B}, {0xC83C, 0xC83C, 0xC83C}, {0xC83D, 0xC83D, 0xC83D}, {0xC83E, 0xC83E, 0xC83E}, {0xC83F, 0xC83F, 0xC83F}, {0xC840, 0xC840, 0xC840}, {0xC841, 0xC841, 0xC841}, {0xC842, 0xC842, 0xC842}, {0xC843, 0xC843, 0xC843}, {0xC844, 0xC844, 0xC844}, {0xC845, 0xC845, 0xC845}, {0xC846, 0xC846, 0xC846}, {0xC847, 0xC847, 0xC847}, {0xC848, 0xC848, 0xC848}, {0xC849, 0xC849, 0xC849}, {0xC84A, 0xC84A, 0xC84A}, {0xC84B, 0xC84B, 0xC84B}, {0xC84C, 0xC84C, 0xC84C}, {0xC84D, 0xC84D, 0xC84D}, {0xC84E, 0xC84E, 0xC84E}, {0xC84F, 0xC84F, 0xC84F}, {0xC850, 0xC850, 0xC850}, {0xC851, 0xC851, 0xC851}, {0xC852, 0xC852, 0xC852}, {0xC853, 0xC853, 0xC853}, {0xC854, 0xC854, 0xC854}, {0xC855, 0xC855, 0xC855}, {0xC856, 0xC856, 0xC856}, {0xC857, 0xC857, 0xC857}, {0xC858, 0xC858, 0xC858}, {0xC859, 0xC859, 0xC859}, {0xC85A, 0xC85A, 0xC85A}, {0xC85B, 0xC85B, 0xC85B}, {0xC85C, 0xC85C, 0xC85C}, {0xC85D, 0xC85D, 0xC85D}, {0xC85E, 0xC85E, 0xC85E}, {0xC85F, 0xC85F, 0xC85F}, {0xC860, 0xC860, 0xC860}, {0xC861, 0xC861, 0xC861}, {0xC862, 0xC862, 0xC862}, {0xC863, 0xC863, 0xC863}, {0xC864, 0xC864, 0xC864}, {0xC865, 0xC865, 0xC865}, {0xC866, 0xC866, 0xC866}, {0xC867, 0xC867, 0xC867}, {0xC868, 0xC868, 0xC868}, {0xC869, 0xC869, 0xC869}, {0xC86A, 0xC86A, 0xC86A}, {0xC86B, 0xC86B, 0xC86B}, {0xC86C, 0xC86C, 0xC86C}, {0xC86D, 0xC86D, 0xC86D}, {0xC86E, 0xC86E, 0xC86E}, {0xC86F, 0xC86F, 0xC86F}, {0xC870, 0xC870, 0xC870}, {0xC871, 0xC871, 0xC871}, {0xC872, 0xC872, 0xC872}, {0xC873, 0xC873, 0xC873}, {0xC874, 0xC874, 0xC874}, {0xC875, 0xC875, 0xC875}, {0xC876, 0xC876, 0xC876}, {0xC877, 0xC877, 0xC877}, {0xC878, 0xC878, 0xC878}, {0xC879, 0xC879, 0xC879}, {0xC87A, 0xC87A, 0xC87A}, {0xC87B, 0xC87B, 0xC87B}, {0xC87C, 0xC87C, 0xC87C}, {0xC87D, 0xC87D, 0xC87D}, {0xC87E, 0xC87E, 0xC87E}, {0xC87F, 0xC87F, 0xC87F}, {0xC880, 0xC880, 0xC880}, {0xC881, 0xC881, 0xC881}, {0xC882, 0xC882, 0xC882}, {0xC883, 0xC883, 0xC883}, {0xC884, 0xC884, 0xC884}, {0xC885, 0xC885, 0xC885}, {0xC886, 0xC886, 0xC886}, {0xC887, 0xC887, 0xC887}, {0xC888, 0xC888, 0xC888}, {0xC889, 0xC889, 0xC889}, {0xC88A, 0xC88A, 0xC88A}, {0xC88B, 0xC88B, 0xC88B}, {0xC88C, 0xC88C, 0xC88C}, {0xC88D, 0xC88D, 0xC88D}, {0xC88E, 0xC88E, 0xC88E}, {0xC88F, 0xC88F, 0xC88F}, {0xC890, 0xC890, 0xC890}, {0xC891, 0xC891, 0xC891}, {0xC892, 0xC892, 0xC892}, {0xC893, 0xC893, 0xC893}, {0xC894, 0xC894, 0xC894}, {0xC895, 0xC895, 0xC895}, {0xC896, 0xC896, 0xC896}, {0xC897, 0xC897, 0xC897}, {0xC898, 0xC898, 0xC898}, {0xC899, 0xC899, 0xC899}, {0xC89A, 0xC89A, 0xC89A}, {0xC89B, 0xC89B, 0xC89B}, {0xC89C, 0xC89C, 0xC89C}, {0xC89D, 0xC89D, 0xC89D}, {0xC89E, 0xC89E, 0xC89E}, {0xC89F, 0xC89F, 0xC89F}, {0xC8A0, 0xC8A0, 0xC8A0}, {0xC8A1, 0xC8A1, 0xC8A1}, {0xC8A2, 0xC8A2, 0xC8A2}, {0xC8A3, 0xC8A3, 0xC8A3}, {0xC8A4, 0xC8A4, 0xC8A4}, {0xC8A5, 0xC8A5, 0xC8A5}, {0xC8A6, 0xC8A6, 0xC8A6}, {0xC8A7, 0xC8A7, 0xC8A7}, {0xC8A8, 0xC8A8, 0xC8A8}, {0xC8A9, 0xC8A9, 0xC8A9}, {0xC8AA, 0xC8AA, 0xC8AA}, {0xC8AB, 0xC8AB, 0xC8AB}, {0xC8AC, 0xC8AC, 0xC8AC}, {0xC8AD, 0xC8AD, 0xC8AD}, {0xC8AE, 0xC8AE, 0xC8AE}, {0xC8AF, 0xC8AF, 0xC8AF}, {0xC8B0, 0xC8B0, 0xC8B0}, {0xC8B1, 0xC8B1, 0xC8B1}, {0xC8B2, 0xC8B2, 0xC8B2}, {0xC8B3, 0xC8B3, 0xC8B3}, {0xC8B4, 0xC8B4, 0xC8B4}, {0xC8B5, 0xC8B5, 0xC8B5}, {0xC8B6, 0xC8B6, 0xC8B6}, {0xC8B7, 0xC8B7, 0xC8B7}, {0xC8B8, 0xC8B8, 0xC8B8}, {0xC8B9, 0xC8B9, 0xC8B9}, {0xC8BA, 0xC8BA, 0xC8BA}, {0xC8BB, 0xC8BB, 0xC8BB}, {0xC8BC, 0xC8BC, 0xC8BC}, {0xC8BD, 0xC8BD, 0xC8BD}, {0xC8BE, 0xC8BE, 0xC8BE}, {0xC8BF, 0xC8BF, 0xC8BF}, {0xC8C0, 0xC8C0, 0xC8C0}, {0xC8C1, 0xC8C1, 0xC8C1}, {0xC8C2, 0xC8C2, 0xC8C2}, {0xC8C3, 0xC8C3, 0xC8C3}, {0xC8C4, 0xC8C4, 0xC8C4}, {0xC8C5, 0xC8C5, 0xC8C5}, {0xC8C6, 0xC8C6, 0xC8C6}, {0xC8C7, 0xC8C7, 0xC8C7}, {0xC8C8, 0xC8C8, 0xC8C8}, {0xC8C9, 0xC8C9, 0xC8C9}, {0xC8CA, 0xC8CA, 0xC8CA}, {0xC8CB, 0xC8CB, 0xC8CB}, {0xC8CC, 0xC8CC, 0xC8CC}, {0xC8CD, 0xC8CD, 0xC8CD}, {0xC8CE, 0xC8CE, 0xC8CE}, {0xC8CF, 0xC8CF, 0xC8CF}, {0xC8D0, 0xC8D0, 0xC8D0}, {0xC8D1, 0xC8D1, 0xC8D1}, {0xC8D2, 0xC8D2, 0xC8D2}, {0xC8D3, 0xC8D3, 0xC8D3}, {0xC8D4, 0xC8D4, 0xC8D4}, {0xC8D5, 0xC8D5, 0xC8D5}, {0xC8D6, 0xC8D6, 0xC8D6}, {0xC8D7, 0xC8D7, 0xC8D7}, {0xC8D8, 0xC8D8, 0xC8D8}, {0xC8D9, 0xC8D9, 0xC8D9}, {0xC8DA, 0xC8DA, 0xC8DA}, {0xC8DB, 0xC8DB, 0xC8DB}, {0xC8DC, 0xC8DC, 0xC8DC}, {0xC8DD, 0xC8DD, 0xC8DD}, {0xC8DE, 0xC8DE, 0xC8DE}, {0xC8DF, 0xC8DF, 0xC8DF}, {0xC8E0, 0xC8E0, 0xC8E0}, {0xC8E1, 0xC8E1, 0xC8E1}, {0xC8E2, 0xC8E2, 0xC8E2}, {0xC8E3, 0xC8E3, 0xC8E3}, {0xC8E4, 0xC8E4, 0xC8E4}, {0xC8E5, 0xC8E5, 0xC8E5}, {0xC8E6, 0xC8E6, 0xC8E6}, {0xC8E7, 0xC8E7, 0xC8E7}, {0xC8E8, 0xC8E8, 0xC8E8}, {0xC8E9, 0xC8E9, 0xC8E9}, {0xC8EA, 0xC8EA, 0xC8EA}, {0xC8EB, 0xC8EB, 0xC8EB}, {0xC8EC, 0xC8EC, 0xC8EC}, {0xC8ED, 0xC8ED, 0xC8ED}, {0xC8EE, 0xC8EE, 0xC8EE}, {0xC8EF, 0xC8EF, 0xC8EF}, {0xC8F0, 0xC8F0, 0xC8F0}, {0xC8F1, 0xC8F1, 0xC8F1}, {0xC8F2, 0xC8F2, 0xC8F2}, {0xC8F3, 0xC8F3, 0xC8F3}, {0xC8F4, 0xC8F4, 0xC8F4}, {0xC8F5, 0xC8F5, 0xC8F5}, {0xC8F6, 0xC8F6, 0xC8F6}, {0xC8F7, 0xC8F7, 0xC8F7}, {0xC8F8, 0xC8F8, 0xC8F8}, {0xC8F9, 0xC8F9, 0xC8F9}, {0xC8FA, 0xC8FA, 0xC8FA}, {0xC8FB, 0xC8FB, 0xC8FB}, {0xC8FC, 0xC8FC, 0xC8FC}, {0xC8FD, 0xC8FD, 0xC8FD}, {0xC8FE, 0xC8FE, 0xC8FE}, {0xC8FF, 0xC8FF, 0xC8FF}, {0xC900, 0xC900, 0xC900}, {0xC901, 0xC901, 0xC901}, {0xC902, 0xC902, 0xC902}, {0xC903, 0xC903, 0xC903}, {0xC904, 0xC904, 0xC904}, {0xC905, 0xC905, 0xC905}, {0xC906, 0xC906, 0xC906}, {0xC907, 0xC907, 0xC907}, {0xC908, 0xC908, 0xC908}, {0xC909, 0xC909, 0xC909}, {0xC90A, 0xC90A, 0xC90A}, {0xC90B, 0xC90B, 0xC90B}, {0xC90C, 0xC90C, 0xC90C}, {0xC90D, 0xC90D, 0xC90D}, {0xC90E, 0xC90E, 0xC90E}, {0xC90F, 0xC90F, 0xC90F}, {0xC910, 0xC910, 0xC910}, {0xC911, 0xC911, 0xC911}, {0xC912, 0xC912, 0xC912}, {0xC913, 0xC913, 0xC913}, {0xC914, 0xC914, 0xC914}, {0xC915, 0xC915, 0xC915}, {0xC916, 0xC916, 0xC916}, {0xC917, 0xC917, 0xC917}, {0xC918, 0xC918, 0xC918}, {0xC919, 0xC919, 0xC919}, {0xC91A, 0xC91A, 0xC91A}, {0xC91B, 0xC91B, 0xC91B}, {0xC91C, 0xC91C, 0xC91C}, {0xC91D, 0xC91D, 0xC91D}, {0xC91E, 0xC91E, 0xC91E}, {0xC91F, 0xC91F, 0xC91F}, {0xC920, 0xC920, 0xC920}, {0xC921, 0xC921, 0xC921}, {0xC922, 0xC922, 0xC922}, {0xC923, 0xC923, 0xC923}, {0xC924, 0xC924, 0xC924}, {0xC925, 0xC925, 0xC925}, {0xC926, 0xC926, 0xC926}, {0xC927, 0xC927, 0xC927}, {0xC928, 0xC928, 0xC928}, {0xC929, 0xC929, 0xC929}, {0xC92A, 0xC92A, 0xC92A}, {0xC92B, 0xC92B, 0xC92B}, {0xC92C, 0xC92C, 0xC92C}, {0xC92D, 0xC92D, 0xC92D}, {0xC92E, 0xC92E, 0xC92E}, {0xC92F, 0xC92F, 0xC92F}, {0xC930, 0xC930, 0xC930}, {0xC931, 0xC931, 0xC931}, {0xC932, 0xC932, 0xC932}, {0xC933, 0xC933, 0xC933}, {0xC934, 0xC934, 0xC934}, {0xC935, 0xC935, 0xC935}, {0xC936, 0xC936, 0xC936}, {0xC937, 0xC937, 0xC937}, {0xC938, 0xC938, 0xC938}, {0xC939, 0xC939, 0xC939}, {0xC93A, 0xC93A, 0xC93A}, {0xC93B, 0xC93B, 0xC93B}, {0xC93C, 0xC93C, 0xC93C}, {0xC93D, 0xC93D, 0xC93D}, {0xC93E, 0xC93E, 0xC93E}, {0xC93F, 0xC93F, 0xC93F}, {0xC940, 0xC940, 0xC940}, {0xC941, 0xC941, 0xC941}, {0xC942, 0xC942, 0xC942}, {0xC943, 0xC943, 0xC943}, {0xC944, 0xC944, 0xC944}, {0xC945, 0xC945, 0xC945}, {0xC946, 0xC946, 0xC946}, {0xC947, 0xC947, 0xC947}, {0xC948, 0xC948, 0xC948}, {0xC949, 0xC949, 0xC949}, {0xC94A, 0xC94A, 0xC94A}, {0xC94B, 0xC94B, 0xC94B}, {0xC94C, 0xC94C, 0xC94C}, {0xC94D, 0xC94D, 0xC94D}, {0xC94E, 0xC94E, 0xC94E}, {0xC94F, 0xC94F, 0xC94F}, {0xC950, 0xC950, 0xC950}, {0xC951, 0xC951, 0xC951}, {0xC952, 0xC952, 0xC952}, {0xC953, 0xC953, 0xC953}, {0xC954, 0xC954, 0xC954}, {0xC955, 0xC955, 0xC955}, {0xC956, 0xC956, 0xC956}, {0xC957, 0xC957, 0xC957}, {0xC958, 0xC958, 0xC958}, {0xC959, 0xC959, 0xC959}, {0xC95A, 0xC95A, 0xC95A}, {0xC95B, 0xC95B, 0xC95B}, {0xC95C, 0xC95C, 0xC95C}, {0xC95D, 0xC95D, 0xC95D}, {0xC95E, 0xC95E, 0xC95E}, {0xC95F, 0xC95F, 0xC95F}, {0xC960, 0xC960, 0xC960}, {0xC961, 0xC961, 0xC961}, {0xC962, 0xC962, 0xC962}, {0xC963, 0xC963, 0xC963}, {0xC964, 0xC964, 0xC964}, {0xC965, 0xC965, 0xC965}, {0xC966, 0xC966, 0xC966}, {0xC967, 0xC967, 0xC967}, {0xC968, 0xC968, 0xC968}, {0xC969, 0xC969, 0xC969}, {0xC96A, 0xC96A, 0xC96A}, {0xC96B, 0xC96B, 0xC96B}, {0xC96C, 0xC96C, 0xC96C}, {0xC96D, 0xC96D, 0xC96D}, {0xC96E, 0xC96E, 0xC96E}, {0xC96F, 0xC96F, 0xC96F}, {0xC970, 0xC970, 0xC970}, {0xC971, 0xC971, 0xC971}, {0xC972, 0xC972, 0xC972}, {0xC973, 0xC973, 0xC973}, {0xC974, 0xC974, 0xC974}, {0xC975, 0xC975, 0xC975}, {0xC976, 0xC976, 0xC976}, {0xC977, 0xC977, 0xC977}, {0xC978, 0xC978, 0xC978}, {0xC979, 0xC979, 0xC979}, {0xC97A, 0xC97A, 0xC97A}, {0xC97B, 0xC97B, 0xC97B}, {0xC97C, 0xC97C, 0xC97C}, {0xC97D, 0xC97D, 0xC97D}, {0xC97E, 0xC97E, 0xC97E}, {0xC97F, 0xC97F, 0xC97F}, {0xC980, 0xC980, 0xC980}, {0xC981, 0xC981, 0xC981}, {0xC982, 0xC982, 0xC982}, {0xC983, 0xC983, 0xC983}, {0xC984, 0xC984, 0xC984}, {0xC985, 0xC985, 0xC985}, {0xC986, 0xC986, 0xC986}, {0xC987, 0xC987, 0xC987}, {0xC988, 0xC988, 0xC988}, {0xC989, 0xC989, 0xC989}, {0xC98A, 0xC98A, 0xC98A}, {0xC98B, 0xC98B, 0xC98B}, {0xC98C, 0xC98C, 0xC98C}, {0xC98D, 0xC98D, 0xC98D}, {0xC98E, 0xC98E, 0xC98E}, {0xC98F, 0xC98F, 0xC98F}, {0xC990, 0xC990, 0xC990}, {0xC991, 0xC991, 0xC991}, {0xC992, 0xC992, 0xC992}, {0xC993, 0xC993, 0xC993}, {0xC994, 0xC994, 0xC994}, {0xC995, 0xC995, 0xC995}, {0xC996, 0xC996, 0xC996}, {0xC997, 0xC997, 0xC997}, {0xC998, 0xC998, 0xC998}, {0xC999, 0xC999, 0xC999}, {0xC99A, 0xC99A, 0xC99A}, {0xC99B, 0xC99B, 0xC99B}, {0xC99C, 0xC99C, 0xC99C}, {0xC99D, 0xC99D, 0xC99D}, {0xC99E, 0xC99E, 0xC99E}, {0xC99F, 0xC99F, 0xC99F}, {0xC9A0, 0xC9A0, 0xC9A0}, {0xC9A1, 0xC9A1, 0xC9A1}, {0xC9A2, 0xC9A2, 0xC9A2}, {0xC9A3, 0xC9A3, 0xC9A3}, {0xC9A4, 0xC9A4, 0xC9A4}, {0xC9A5, 0xC9A5, 0xC9A5}, {0xC9A6, 0xC9A6, 0xC9A6}, {0xC9A7, 0xC9A7, 0xC9A7}, {0xC9A8, 0xC9A8, 0xC9A8}, {0xC9A9, 0xC9A9, 0xC9A9}, {0xC9AA, 0xC9AA, 0xC9AA}, {0xC9AB, 0xC9AB, 0xC9AB}, {0xC9AC, 0xC9AC, 0xC9AC}, {0xC9AD, 0xC9AD, 0xC9AD}, {0xC9AE, 0xC9AE, 0xC9AE}, {0xC9AF, 0xC9AF, 0xC9AF}, {0xC9B0, 0xC9B0, 0xC9B0}, {0xC9B1, 0xC9B1, 0xC9B1}, {0xC9B2, 0xC9B2, 0xC9B2}, {0xC9B3, 0xC9B3, 0xC9B3}, {0xC9B4, 0xC9B4, 0xC9B4}, {0xC9B5, 0xC9B5, 0xC9B5}, {0xC9B6, 0xC9B6, 0xC9B6}, {0xC9B7, 0xC9B7, 0xC9B7}, {0xC9B8, 0xC9B8, 0xC9B8}, {0xC9B9, 0xC9B9, 0xC9B9}, {0xC9BA, 0xC9BA, 0xC9BA}, {0xC9BB, 0xC9BB, 0xC9BB}, {0xC9BC, 0xC9BC, 0xC9BC}, {0xC9BD, 0xC9BD, 0xC9BD}, {0xC9BE, 0xC9BE, 0xC9BE}, {0xC9BF, 0xC9BF, 0xC9BF}, {0xC9C0, 0xC9C0, 0xC9C0}, {0xC9C1, 0xC9C1, 0xC9C1}, {0xC9C2, 0xC9C2, 0xC9C2}, {0xC9C3, 0xC9C3, 0xC9C3}, {0xC9C4, 0xC9C4, 0xC9C4}, {0xC9C5, 0xC9C5, 0xC9C5}, {0xC9C6, 0xC9C6, 0xC9C6}, {0xC9C7, 0xC9C7, 0xC9C7}, {0xC9C8, 0xC9C8, 0xC9C8}, {0xC9C9, 0xC9C9, 0xC9C9}, {0xC9CA, 0xC9CA, 0xC9CA}, {0xC9CB, 0xC9CB, 0xC9CB}, {0xC9CC, 0xC9CC, 0xC9CC}, {0xC9CD, 0xC9CD, 0xC9CD}, {0xC9CE, 0xC9CE, 0xC9CE}, {0xC9CF, 0xC9CF, 0xC9CF}, {0xC9D0, 0xC9D0, 0xC9D0}, {0xC9D1, 0xC9D1, 0xC9D1}, {0xC9D2, 0xC9D2, 0xC9D2}, {0xC9D3, 0xC9D3, 0xC9D3}, {0xC9D4, 0xC9D4, 0xC9D4}, {0xC9D5, 0xC9D5, 0xC9D5}, {0xC9D6, 0xC9D6, 0xC9D6}, {0xC9D7, 0xC9D7, 0xC9D7}, {0xC9D8, 0xC9D8, 0xC9D8}, {0xC9D9, 0xC9D9, 0xC9D9}, {0xC9DA, 0xC9DA, 0xC9DA}, {0xC9DB, 0xC9DB, 0xC9DB}, {0xC9DC, 0xC9DC, 0xC9DC}, {0xC9DD, 0xC9DD, 0xC9DD}, {0xC9DE, 0xC9DE, 0xC9DE}, {0xC9DF, 0xC9DF, 0xC9DF}, {0xC9E0, 0xC9E0, 0xC9E0}, {0xC9E1, 0xC9E1, 0xC9E1}, {0xC9E2, 0xC9E2, 0xC9E2}, {0xC9E3, 0xC9E3, 0xC9E3}, {0xC9E4, 0xC9E4, 0xC9E4}, {0xC9E5, 0xC9E5, 0xC9E5}, {0xC9E6, 0xC9E6, 0xC9E6}, {0xC9E7, 0xC9E7, 0xC9E7}, {0xC9E8, 0xC9E8, 0xC9E8}, {0xC9E9, 0xC9E9, 0xC9E9}, {0xC9EA, 0xC9EA, 0xC9EA}, {0xC9EB, 0xC9EB, 0xC9EB}, {0xC9EC, 0xC9EC, 0xC9EC}, {0xC9ED, 0xC9ED, 0xC9ED}, {0xC9EE, 0xC9EE, 0xC9EE}, {0xC9EF, 0xC9EF, 0xC9EF}, {0xC9F0, 0xC9F0, 0xC9F0}, {0xC9F1, 0xC9F1, 0xC9F1}, {0xC9F2, 0xC9F2, 0xC9F2}, {0xC9F3, 0xC9F3, 0xC9F3}, {0xC9F4, 0xC9F4, 0xC9F4}, {0xC9F5, 0xC9F5, 0xC9F5}, {0xC9F6, 0xC9F6, 0xC9F6}, {0xC9F7, 0xC9F7, 0xC9F7}, {0xC9F8, 0xC9F8, 0xC9F8}, {0xC9F9, 0xC9F9, 0xC9F9}, {0xC9FA, 0xC9FA, 0xC9FA}, {0xC9FB, 0xC9FB, 0xC9FB}, {0xC9FC, 0xC9FC, 0xC9FC}, {0xC9FD, 0xC9FD, 0xC9FD}, {0xC9FE, 0xC9FE, 0xC9FE}, {0xC9FF, 0xC9FF, 0xC9FF}, {0xCA00, 0xCA00, 0xCA00}, {0xCA01, 0xCA01, 0xCA01}, {0xCA02, 0xCA02, 0xCA02}, {0xCA03, 0xCA03, 0xCA03}, {0xCA04, 0xCA04, 0xCA04}, {0xCA05, 0xCA05, 0xCA05}, {0xCA06, 0xCA06, 0xCA06}, {0xCA07, 0xCA07, 0xCA07}, {0xCA08, 0xCA08, 0xCA08}, {0xCA09, 0xCA09, 0xCA09}, {0xCA0A, 0xCA0A, 0xCA0A}, {0xCA0B, 0xCA0B, 0xCA0B}, {0xCA0C, 0xCA0C, 0xCA0C}, {0xCA0D, 0xCA0D, 0xCA0D}, {0xCA0E, 0xCA0E, 0xCA0E}, {0xCA0F, 0xCA0F, 0xCA0F}, {0xCA10, 0xCA10, 0xCA10}, {0xCA11, 0xCA11, 0xCA11}, {0xCA12, 0xCA12, 0xCA12}, {0xCA13, 0xCA13, 0xCA13}, {0xCA14, 0xCA14, 0xCA14}, {0xCA15, 0xCA15, 0xCA15}, {0xCA16, 0xCA16, 0xCA16}, {0xCA17, 0xCA17, 0xCA17}, {0xCA18, 0xCA18, 0xCA18}, {0xCA19, 0xCA19, 0xCA19}, {0xCA1A, 0xCA1A, 0xCA1A}, {0xCA1B, 0xCA1B, 0xCA1B}, {0xCA1C, 0xCA1C, 0xCA1C}, {0xCA1D, 0xCA1D, 0xCA1D}, {0xCA1E, 0xCA1E, 0xCA1E}, {0xCA1F, 0xCA1F, 0xCA1F}, {0xCA20, 0xCA20, 0xCA20}, {0xCA21, 0xCA21, 0xCA21}, {0xCA22, 0xCA22, 0xCA22}, {0xCA23, 0xCA23, 0xCA23}, {0xCA24, 0xCA24, 0xCA24}, {0xCA25, 0xCA25, 0xCA25}, {0xCA26, 0xCA26, 0xCA26}, {0xCA27, 0xCA27, 0xCA27}, {0xCA28, 0xCA28, 0xCA28}, {0xCA29, 0xCA29, 0xCA29}, {0xCA2A, 0xCA2A, 0xCA2A}, {0xCA2B, 0xCA2B, 0xCA2B}, {0xCA2C, 0xCA2C, 0xCA2C}, {0xCA2D, 0xCA2D, 0xCA2D}, {0xCA2E, 0xCA2E, 0xCA2E}, {0xCA2F, 0xCA2F, 0xCA2F}, {0xCA30, 0xCA30, 0xCA30}, {0xCA31, 0xCA31, 0xCA31}, {0xCA32, 0xCA32, 0xCA32}, {0xCA33, 0xCA33, 0xCA33}, {0xCA34, 0xCA34, 0xCA34}, {0xCA35, 0xCA35, 0xCA35}, {0xCA36, 0xCA36, 0xCA36}, {0xCA37, 0xCA37, 0xCA37}, {0xCA38, 0xCA38, 0xCA38}, {0xCA39, 0xCA39, 0xCA39}, {0xCA3A, 0xCA3A, 0xCA3A}, {0xCA3B, 0xCA3B, 0xCA3B}, {0xCA3C, 0xCA3C, 0xCA3C}, {0xCA3D, 0xCA3D, 0xCA3D}, {0xCA3E, 0xCA3E, 0xCA3E}, {0xCA3F, 0xCA3F, 0xCA3F}, {0xCA40, 0xCA40, 0xCA40}, {0xCA41, 0xCA41, 0xCA41}, {0xCA42, 0xCA42, 0xCA42}, {0xCA43, 0xCA43, 0xCA43}, {0xCA44, 0xCA44, 0xCA44}, {0xCA45, 0xCA45, 0xCA45}, {0xCA46, 0xCA46, 0xCA46}, {0xCA47, 0xCA47, 0xCA47}, {0xCA48, 0xCA48, 0xCA48}, {0xCA49, 0xCA49, 0xCA49}, {0xCA4A, 0xCA4A, 0xCA4A}, {0xCA4B, 0xCA4B, 0xCA4B}, {0xCA4C, 0xCA4C, 0xCA4C}, {0xCA4D, 0xCA4D, 0xCA4D}, {0xCA4E, 0xCA4E, 0xCA4E}, {0xCA4F, 0xCA4F, 0xCA4F}, {0xCA50, 0xCA50, 0xCA50}, {0xCA51, 0xCA51, 0xCA51}, {0xCA52, 0xCA52, 0xCA52}, {0xCA53, 0xCA53, 0xCA53}, {0xCA54, 0xCA54, 0xCA54}, {0xCA55, 0xCA55, 0xCA55}, {0xCA56, 0xCA56, 0xCA56}, {0xCA57, 0xCA57, 0xCA57}, {0xCA58, 0xCA58, 0xCA58}, {0xCA59, 0xCA59, 0xCA59}, {0xCA5A, 0xCA5A, 0xCA5A}, {0xCA5B, 0xCA5B, 0xCA5B}, {0xCA5C, 0xCA5C, 0xCA5C}, {0xCA5D, 0xCA5D, 0xCA5D}, {0xCA5E, 0xCA5E, 0xCA5E}, {0xCA5F, 0xCA5F, 0xCA5F}, {0xCA60, 0xCA60, 0xCA60}, {0xCA61, 0xCA61, 0xCA61}, {0xCA62, 0xCA62, 0xCA62}, {0xCA63, 0xCA63, 0xCA63}, {0xCA64, 0xCA64, 0xCA64}, {0xCA65, 0xCA65, 0xCA65}, {0xCA66, 0xCA66, 0xCA66}, {0xCA67, 0xCA67, 0xCA67}, {0xCA68, 0xCA68, 0xCA68}, {0xCA69, 0xCA69, 0xCA69}, {0xCA6A, 0xCA6A, 0xCA6A}, {0xCA6B, 0xCA6B, 0xCA6B}, {0xCA6C, 0xCA6C, 0xCA6C}, {0xCA6D, 0xCA6D, 0xCA6D}, {0xCA6E, 0xCA6E, 0xCA6E}, {0xCA6F, 0xCA6F, 0xCA6F}, {0xCA70, 0xCA70, 0xCA70}, {0xCA71, 0xCA71, 0xCA71}, {0xCA72, 0xCA72, 0xCA72}, {0xCA73, 0xCA73, 0xCA73}, {0xCA74, 0xCA74, 0xCA74}, {0xCA75, 0xCA75, 0xCA75}, {0xCA76, 0xCA76, 0xCA76}, {0xCA77, 0xCA77, 0xCA77}, {0xCA78, 0xCA78, 0xCA78}, {0xCA79, 0xCA79, 0xCA79}, {0xCA7A, 0xCA7A, 0xCA7A}, {0xCA7B, 0xCA7B, 0xCA7B}, {0xCA7C, 0xCA7C, 0xCA7C}, {0xCA7D, 0xCA7D, 0xCA7D}, {0xCA7E, 0xCA7E, 0xCA7E}, {0xCA7F, 0xCA7F, 0xCA7F}, {0xCA80, 0xCA80, 0xCA80}, {0xCA81, 0xCA81, 0xCA81}, {0xCA82, 0xCA82, 0xCA82}, {0xCA83, 0xCA83, 0xCA83}, {0xCA84, 0xCA84, 0xCA84}, {0xCA85, 0xCA85, 0xCA85}, {0xCA86, 0xCA86, 0xCA86}, {0xCA87, 0xCA87, 0xCA87}, {0xCA88, 0xCA88, 0xCA88}, {0xCA89, 0xCA89, 0xCA89}, {0xCA8A, 0xCA8A, 0xCA8A}, {0xCA8B, 0xCA8B, 0xCA8B}, {0xCA8C, 0xCA8C, 0xCA8C}, {0xCA8D, 0xCA8D, 0xCA8D}, {0xCA8E, 0xCA8E, 0xCA8E}, {0xCA8F, 0xCA8F, 0xCA8F}, {0xCA90, 0xCA90, 0xCA90}, {0xCA91, 0xCA91, 0xCA91}, {0xCA92, 0xCA92, 0xCA92}, {0xCA93, 0xCA93, 0xCA93}, {0xCA94, 0xCA94, 0xCA94}, {0xCA95, 0xCA95, 0xCA95}, {0xCA96, 0xCA96, 0xCA96}, {0xCA97, 0xCA97, 0xCA97}, {0xCA98, 0xCA98, 0xCA98}, {0xCA99, 0xCA99, 0xCA99}, {0xCA9A, 0xCA9A, 0xCA9A}, {0xCA9B, 0xCA9B, 0xCA9B}, {0xCA9C, 0xCA9C, 0xCA9C}, {0xCA9D, 0xCA9D, 0xCA9D}, {0xCA9E, 0xCA9E, 0xCA9E}, {0xCA9F, 0xCA9F, 0xCA9F}, {0xCAA0, 0xCAA0, 0xCAA0}, {0xCAA1, 0xCAA1, 0xCAA1}, {0xCAA2, 0xCAA2, 0xCAA2}, {0xCAA3, 0xCAA3, 0xCAA3}, {0xCAA4, 0xCAA4, 0xCAA4}, {0xCAA5, 0xCAA5, 0xCAA5}, {0xCAA6, 0xCAA6, 0xCAA6}, {0xCAA7, 0xCAA7, 0xCAA7}, {0xCAA8, 0xCAA8, 0xCAA8}, {0xCAA9, 0xCAA9, 0xCAA9}, {0xCAAA, 0xCAAA, 0xCAAA}, {0xCAAB, 0xCAAB, 0xCAAB}, {0xCAAC, 0xCAAC, 0xCAAC}, {0xCAAD, 0xCAAD, 0xCAAD}, {0xCAAE, 0xCAAE, 0xCAAE}, {0xCAAF, 0xCAAF, 0xCAAF}, {0xCAB0, 0xCAB0, 0xCAB0}, {0xCAB1, 0xCAB1, 0xCAB1}, {0xCAB2, 0xCAB2, 0xCAB2}, {0xCAB3, 0xCAB3, 0xCAB3}, {0xCAB4, 0xCAB4, 0xCAB4}, {0xCAB5, 0xCAB5, 0xCAB5}, {0xCAB6, 0xCAB6, 0xCAB6}, {0xCAB7, 0xCAB7, 0xCAB7}, {0xCAB8, 0xCAB8, 0xCAB8}, {0xCAB9, 0xCAB9, 0xCAB9}, {0xCABA, 0xCABA, 0xCABA}, {0xCABB, 0xCABB, 0xCABB}, {0xCABC, 0xCABC, 0xCABC}, {0xCABD, 0xCABD, 0xCABD}, {0xCABE, 0xCABE, 0xCABE}, {0xCABF, 0xCABF, 0xCABF}, {0xCAC0, 0xCAC0, 0xCAC0}, {0xCAC1, 0xCAC1, 0xCAC1}, {0xCAC2, 0xCAC2, 0xCAC2}, {0xCAC3, 0xCAC3, 0xCAC3}, {0xCAC4, 0xCAC4, 0xCAC4}, {0xCAC5, 0xCAC5, 0xCAC5}, {0xCAC6, 0xCAC6, 0xCAC6}, {0xCAC7, 0xCAC7, 0xCAC7}, {0xCAC8, 0xCAC8, 0xCAC8}, {0xCAC9, 0xCAC9, 0xCAC9}, {0xCACA, 0xCACA, 0xCACA}, {0xCACB, 0xCACB, 0xCACB}, {0xCACC, 0xCACC, 0xCACC}, {0xCACD, 0xCACD, 0xCACD}, {0xCACE, 0xCACE, 0xCACE}, {0xCACF, 0xCACF, 0xCACF}, {0xCAD0, 0xCAD0, 0xCAD0}, {0xCAD1, 0xCAD1, 0xCAD1}, {0xCAD2, 0xCAD2, 0xCAD2}, {0xCAD3, 0xCAD3, 0xCAD3}, {0xCAD4, 0xCAD4, 0xCAD4}, {0xCAD5, 0xCAD5, 0xCAD5}, {0xCAD6, 0xCAD6, 0xCAD6}, {0xCAD7, 0xCAD7, 0xCAD7}, {0xCAD8, 0xCAD8, 0xCAD8}, {0xCAD9, 0xCAD9, 0xCAD9}, {0xCADA, 0xCADA, 0xCADA}, {0xCADB, 0xCADB, 0xCADB}, {0xCADC, 0xCADC, 0xCADC}, {0xCADD, 0xCADD, 0xCADD}, {0xCADE, 0xCADE, 0xCADE}, {0xCADF, 0xCADF, 0xCADF}, {0xCAE0, 0xCAE0, 0xCAE0}, {0xCAE1, 0xCAE1, 0xCAE1}, {0xCAE2, 0xCAE2, 0xCAE2}, {0xCAE3, 0xCAE3, 0xCAE3}, {0xCAE4, 0xCAE4, 0xCAE4}, {0xCAE5, 0xCAE5, 0xCAE5}, {0xCAE6, 0xCAE6, 0xCAE6}, {0xCAE7, 0xCAE7, 0xCAE7}, {0xCAE8, 0xCAE8, 0xCAE8}, {0xCAE9, 0xCAE9, 0xCAE9}, {0xCAEA, 0xCAEA, 0xCAEA}, {0xCAEB, 0xCAEB, 0xCAEB}, {0xCAEC, 0xCAEC, 0xCAEC}, {0xCAED, 0xCAED, 0xCAED}, {0xCAEE, 0xCAEE, 0xCAEE}, {0xCAEF, 0xCAEF, 0xCAEF}, {0xCAF0, 0xCAF0, 0xCAF0}, {0xCAF1, 0xCAF1, 0xCAF1}, {0xCAF2, 0xCAF2, 0xCAF2}, {0xCAF3, 0xCAF3, 0xCAF3}, {0xCAF4, 0xCAF4, 0xCAF4}, {0xCAF5, 0xCAF5, 0xCAF5}, {0xCAF6, 0xCAF6, 0xCAF6}, {0xCAF7, 0xCAF7, 0xCAF7}, {0xCAF8, 0xCAF8, 0xCAF8}, {0xCAF9, 0xCAF9, 0xCAF9}, {0xCAFA, 0xCAFA, 0xCAFA}, {0xCAFB, 0xCAFB, 0xCAFB}, {0xCAFC, 0xCAFC, 0xCAFC}, {0xCAFD, 0xCAFD, 0xCAFD}, {0xCAFE, 0xCAFE, 0xCAFE}, {0xCAFF, 0xCAFF, 0xCAFF}, {0xCB00, 0xCB00, 0xCB00}, {0xCB01, 0xCB01, 0xCB01}, {0xCB02, 0xCB02, 0xCB02}, {0xCB03, 0xCB03, 0xCB03}, {0xCB04, 0xCB04, 0xCB04}, {0xCB05, 0xCB05, 0xCB05}, {0xCB06, 0xCB06, 0xCB06}, {0xCB07, 0xCB07, 0xCB07}, {0xCB08, 0xCB08, 0xCB08}, {0xCB09, 0xCB09, 0xCB09}, {0xCB0A, 0xCB0A, 0xCB0A}, {0xCB0B, 0xCB0B, 0xCB0B}, {0xCB0C, 0xCB0C, 0xCB0C}, {0xCB0D, 0xCB0D, 0xCB0D}, {0xCB0E, 0xCB0E, 0xCB0E}, {0xCB0F, 0xCB0F, 0xCB0F}, {0xCB10, 0xCB10, 0xCB10}, {0xCB11, 0xCB11, 0xCB11}, {0xCB12, 0xCB12, 0xCB12}, {0xCB13, 0xCB13, 0xCB13}, {0xCB14, 0xCB14, 0xCB14}, {0xCB15, 0xCB15, 0xCB15}, {0xCB16, 0xCB16, 0xCB16}, {0xCB17, 0xCB17, 0xCB17}, {0xCB18, 0xCB18, 0xCB18}, {0xCB19, 0xCB19, 0xCB19}, {0xCB1A, 0xCB1A, 0xCB1A}, {0xCB1B, 0xCB1B, 0xCB1B}, {0xCB1C, 0xCB1C, 0xCB1C}, {0xCB1D, 0xCB1D, 0xCB1D}, {0xCB1E, 0xCB1E, 0xCB1E}, {0xCB1F, 0xCB1F, 0xCB1F}, {0xCB20, 0xCB20, 0xCB20}, {0xCB21, 0xCB21, 0xCB21}, {0xCB22, 0xCB22, 0xCB22}, {0xCB23, 0xCB23, 0xCB23}, {0xCB24, 0xCB24, 0xCB24}, {0xCB25, 0xCB25, 0xCB25}, {0xCB26, 0xCB26, 0xCB26}, {0xCB27, 0xCB27, 0xCB27}, {0xCB28, 0xCB28, 0xCB28}, {0xCB29, 0xCB29, 0xCB29}, {0xCB2A, 0xCB2A, 0xCB2A}, {0xCB2B, 0xCB2B, 0xCB2B}, {0xCB2C, 0xCB2C, 0xCB2C}, {0xCB2D, 0xCB2D, 0xCB2D}, {0xCB2E, 0xCB2E, 0xCB2E}, {0xCB2F, 0xCB2F, 0xCB2F}, {0xCB30, 0xCB30, 0xCB30}, {0xCB31, 0xCB31, 0xCB31}, {0xCB32, 0xCB32, 0xCB32}, {0xCB33, 0xCB33, 0xCB33}, {0xCB34, 0xCB34, 0xCB34}, {0xCB35, 0xCB35, 0xCB35}, {0xCB36, 0xCB36, 0xCB36}, {0xCB37, 0xCB37, 0xCB37}, {0xCB38, 0xCB38, 0xCB38}, {0xCB39, 0xCB39, 0xCB39}, {0xCB3A, 0xCB3A, 0xCB3A}, {0xCB3B, 0xCB3B, 0xCB3B}, {0xCB3C, 0xCB3C, 0xCB3C}, {0xCB3D, 0xCB3D, 0xCB3D}, {0xCB3E, 0xCB3E, 0xCB3E}, {0xCB3F, 0xCB3F, 0xCB3F}, {0xCB40, 0xCB40, 0xCB40}, {0xCB41, 0xCB41, 0xCB41}, {0xCB42, 0xCB42, 0xCB42}, {0xCB43, 0xCB43, 0xCB43}, {0xCB44, 0xCB44, 0xCB44}, {0xCB45, 0xCB45, 0xCB45}, {0xCB46, 0xCB46, 0xCB46}, {0xCB47, 0xCB47, 0xCB47}, {0xCB48, 0xCB48, 0xCB48}, {0xCB49, 0xCB49, 0xCB49}, {0xCB4A, 0xCB4A, 0xCB4A}, {0xCB4B, 0xCB4B, 0xCB4B}, {0xCB4C, 0xCB4C, 0xCB4C}, {0xCB4D, 0xCB4D, 0xCB4D}, {0xCB4E, 0xCB4E, 0xCB4E}, {0xCB4F, 0xCB4F, 0xCB4F}, {0xCB50, 0xCB50, 0xCB50}, {0xCB51, 0xCB51, 0xCB51}, {0xCB52, 0xCB52, 0xCB52}, {0xCB53, 0xCB53, 0xCB53}, {0xCB54, 0xCB54, 0xCB54}, {0xCB55, 0xCB55, 0xCB55}, {0xCB56, 0xCB56, 0xCB56}, {0xCB57, 0xCB57, 0xCB57}, {0xCB58, 0xCB58, 0xCB58}, {0xCB59, 0xCB59, 0xCB59}, {0xCB5A, 0xCB5A, 0xCB5A}, {0xCB5B, 0xCB5B, 0xCB5B}, {0xCB5C, 0xCB5C, 0xCB5C}, {0xCB5D, 0xCB5D, 0xCB5D}, {0xCB5E, 0xCB5E, 0xCB5E}, {0xCB5F, 0xCB5F, 0xCB5F}, {0xCB60, 0xCB60, 0xCB60}, {0xCB61, 0xCB61, 0xCB61}, {0xCB62, 0xCB62, 0xCB62}, {0xCB63, 0xCB63, 0xCB63}, {0xCB64, 0xCB64, 0xCB64}, {0xCB65, 0xCB65, 0xCB65}, {0xCB66, 0xCB66, 0xCB66}, {0xCB67, 0xCB67, 0xCB67}, {0xCB68, 0xCB68, 0xCB68}, {0xCB69, 0xCB69, 0xCB69}, {0xCB6A, 0xCB6A, 0xCB6A}, {0xCB6B, 0xCB6B, 0xCB6B}, {0xCB6C, 0xCB6C, 0xCB6C}, {0xCB6D, 0xCB6D, 0xCB6D}, {0xCB6E, 0xCB6E, 0xCB6E}, {0xCB6F, 0xCB6F, 0xCB6F}, {0xCB70, 0xCB70, 0xCB70}, {0xCB71, 0xCB71, 0xCB71}, {0xCB72, 0xCB72, 0xCB72}, {0xCB73, 0xCB73, 0xCB73}, {0xCB74, 0xCB74, 0xCB74}, {0xCB75, 0xCB75, 0xCB75}, {0xCB76, 0xCB76, 0xCB76}, {0xCB77, 0xCB77, 0xCB77}, {0xCB78, 0xCB78, 0xCB78}, {0xCB79, 0xCB79, 0xCB79}, {0xCB7A, 0xCB7A, 0xCB7A}, {0xCB7B, 0xCB7B, 0xCB7B}, {0xCB7C, 0xCB7C, 0xCB7C}, {0xCB7D, 0xCB7D, 0xCB7D}, {0xCB7E, 0xCB7E, 0xCB7E}, {0xCB7F, 0xCB7F, 0xCB7F}, {0xCB80, 0xCB80, 0xCB80}, {0xCB81, 0xCB81, 0xCB81}, {0xCB82, 0xCB82, 0xCB82}, {0xCB83, 0xCB83, 0xCB83}, {0xCB84, 0xCB84, 0xCB84}, {0xCB85, 0xCB85, 0xCB85}, {0xCB86, 0xCB86, 0xCB86}, {0xCB87, 0xCB87, 0xCB87}, {0xCB88, 0xCB88, 0xCB88}, {0xCB89, 0xCB89, 0xCB89}, {0xCB8A, 0xCB8A, 0xCB8A}, {0xCB8B, 0xCB8B, 0xCB8B}, {0xCB8C, 0xCB8C, 0xCB8C}, {0xCB8D, 0xCB8D, 0xCB8D}, {0xCB8E, 0xCB8E, 0xCB8E}, {0xCB8F, 0xCB8F, 0xCB8F}, {0xCB90, 0xCB90, 0xCB90}, {0xCB91, 0xCB91, 0xCB91}, {0xCB92, 0xCB92, 0xCB92}, {0xCB93, 0xCB93, 0xCB93}, {0xCB94, 0xCB94, 0xCB94}, {0xCB95, 0xCB95, 0xCB95}, {0xCB96, 0xCB96, 0xCB96}, {0xCB97, 0xCB97, 0xCB97}, {0xCB98, 0xCB98, 0xCB98}, {0xCB99, 0xCB99, 0xCB99}, {0xCB9A, 0xCB9A, 0xCB9A}, {0xCB9B, 0xCB9B, 0xCB9B}, {0xCB9C, 0xCB9C, 0xCB9C}, {0xCB9D, 0xCB9D, 0xCB9D}, {0xCB9E, 0xCB9E, 0xCB9E}, {0xCB9F, 0xCB9F, 0xCB9F}, {0xCBA0, 0xCBA0, 0xCBA0}, {0xCBA1, 0xCBA1, 0xCBA1}, {0xCBA2, 0xCBA2, 0xCBA2}, {0xCBA3, 0xCBA3, 0xCBA3}, {0xCBA4, 0xCBA4, 0xCBA4}, {0xCBA5, 0xCBA5, 0xCBA5}, {0xCBA6, 0xCBA6, 0xCBA6}, {0xCBA7, 0xCBA7, 0xCBA7}, {0xCBA8, 0xCBA8, 0xCBA8}, {0xCBA9, 0xCBA9, 0xCBA9}, {0xCBAA, 0xCBAA, 0xCBAA}, {0xCBAB, 0xCBAB, 0xCBAB}, {0xCBAC, 0xCBAC, 0xCBAC}, {0xCBAD, 0xCBAD, 0xCBAD}, {0xCBAE, 0xCBAE, 0xCBAE}, {0xCBAF, 0xCBAF, 0xCBAF}, {0xCBB0, 0xCBB0, 0xCBB0}, {0xCBB1, 0xCBB1, 0xCBB1}, {0xCBB2, 0xCBB2, 0xCBB2}, {0xCBB3, 0xCBB3, 0xCBB3}, {0xCBB4, 0xCBB4, 0xCBB4}, {0xCBB5, 0xCBB5, 0xCBB5}, {0xCBB6, 0xCBB6, 0xCBB6}, {0xCBB7, 0xCBB7, 0xCBB7}, {0xCBB8, 0xCBB8, 0xCBB8}, {0xCBB9, 0xCBB9, 0xCBB9}, {0xCBBA, 0xCBBA, 0xCBBA}, {0xCBBB, 0xCBBB, 0xCBBB}, {0xCBBC, 0xCBBC, 0xCBBC}, {0xCBBD, 0xCBBD, 0xCBBD}, {0xCBBE, 0xCBBE, 0xCBBE}, {0xCBBF, 0xCBBF, 0xCBBF}, {0xCBC0, 0xCBC0, 0xCBC0}, {0xCBC1, 0xCBC1, 0xCBC1}, {0xCBC2, 0xCBC2, 0xCBC2}, {0xCBC3, 0xCBC3, 0xCBC3}, {0xCBC4, 0xCBC4, 0xCBC4}, {0xCBC5, 0xCBC5, 0xCBC5}, {0xCBC6, 0xCBC6, 0xCBC6}, {0xCBC7, 0xCBC7, 0xCBC7}, {0xCBC8, 0xCBC8, 0xCBC8}, {0xCBC9, 0xCBC9, 0xCBC9}, {0xCBCA, 0xCBCA, 0xCBCA}, {0xCBCB, 0xCBCB, 0xCBCB}, {0xCBCC, 0xCBCC, 0xCBCC}, {0xCBCD, 0xCBCD, 0xCBCD}, {0xCBCE, 0xCBCE, 0xCBCE}, {0xCBCF, 0xCBCF, 0xCBCF}, {0xCBD0, 0xCBD0, 0xCBD0}, {0xCBD1, 0xCBD1, 0xCBD1}, {0xCBD2, 0xCBD2, 0xCBD2}, {0xCBD3, 0xCBD3, 0xCBD3}, {0xCBD4, 0xCBD4, 0xCBD4}, {0xCBD5, 0xCBD5, 0xCBD5}, {0xCBD6, 0xCBD6, 0xCBD6}, {0xCBD7, 0xCBD7, 0xCBD7}, {0xCBD8, 0xCBD8, 0xCBD8}, {0xCBD9, 0xCBD9, 0xCBD9}, {0xCBDA, 0xCBDA, 0xCBDA}, {0xCBDB, 0xCBDB, 0xCBDB}, {0xCBDC, 0xCBDC, 0xCBDC}, {0xCBDD, 0xCBDD, 0xCBDD}, {0xCBDE, 0xCBDE, 0xCBDE}, {0xCBDF, 0xCBDF, 0xCBDF}, {0xCBE0, 0xCBE0, 0xCBE0}, {0xCBE1, 0xCBE1, 0xCBE1}, {0xCBE2, 0xCBE2, 0xCBE2}, {0xCBE3, 0xCBE3, 0xCBE3}, {0xCBE4, 0xCBE4, 0xCBE4}, {0xCBE5, 0xCBE5, 0xCBE5}, {0xCBE6, 0xCBE6, 0xCBE6}, {0xCBE7, 0xCBE7, 0xCBE7}, {0xCBE8, 0xCBE8, 0xCBE8}, {0xCBE9, 0xCBE9, 0xCBE9}, {0xCBEA, 0xCBEA, 0xCBEA}, {0xCBEB, 0xCBEB, 0xCBEB}, {0xCBEC, 0xCBEC, 0xCBEC}, {0xCBED, 0xCBED, 0xCBED}, {0xCBEE, 0xCBEE, 0xCBEE}, {0xCBEF, 0xCBEF, 0xCBEF}, {0xCBF0, 0xCBF0, 0xCBF0}, {0xCBF1, 0xCBF1, 0xCBF1}, {0xCBF2, 0xCBF2, 0xCBF2}, {0xCBF3, 0xCBF3, 0xCBF3}, {0xCBF4, 0xCBF4, 0xCBF4}, {0xCBF5, 0xCBF5, 0xCBF5}, {0xCBF6, 0xCBF6, 0xCBF6}, {0xCBF7, 0xCBF7, 0xCBF7}, {0xCBF8, 0xCBF8, 0xCBF8}, {0xCBF9, 0xCBF9, 0xCBF9}, {0xCBFA, 0xCBFA, 0xCBFA}, {0xCBFB, 0xCBFB, 0xCBFB}, {0xCBFC, 0xCBFC, 0xCBFC}, {0xCBFD, 0xCBFD, 0xCBFD}, {0xCBFE, 0xCBFE, 0xCBFE}, {0xCBFF, 0xCBFF, 0xCBFF}, {0xCC00, 0xCC00, 0xCC00}, {0xCC01, 0xCC01, 0xCC01}, {0xCC02, 0xCC02, 0xCC02}, {0xCC03, 0xCC03, 0xCC03}, {0xCC04, 0xCC04, 0xCC04}, {0xCC05, 0xCC05, 0xCC05}, {0xCC06, 0xCC06, 0xCC06}, {0xCC07, 0xCC07, 0xCC07}, {0xCC08, 0xCC08, 0xCC08}, {0xCC09, 0xCC09, 0xCC09}, {0xCC0A, 0xCC0A, 0xCC0A}, {0xCC0B, 0xCC0B, 0xCC0B}, {0xCC0C, 0xCC0C, 0xCC0C}, {0xCC0D, 0xCC0D, 0xCC0D}, {0xCC0E, 0xCC0E, 0xCC0E}, {0xCC0F, 0xCC0F, 0xCC0F}, {0xCC10, 0xCC10, 0xCC10}, {0xCC11, 0xCC11, 0xCC11}, {0xCC12, 0xCC12, 0xCC12}, {0xCC13, 0xCC13, 0xCC13}, {0xCC14, 0xCC14, 0xCC14}, {0xCC15, 0xCC15, 0xCC15}, {0xCC16, 0xCC16, 0xCC16}, {0xCC17, 0xCC17, 0xCC17}, {0xCC18, 0xCC18, 0xCC18}, {0xCC19, 0xCC19, 0xCC19}, {0xCC1A, 0xCC1A, 0xCC1A}, {0xCC1B, 0xCC1B, 0xCC1B}, {0xCC1C, 0xCC1C, 0xCC1C}, {0xCC1D, 0xCC1D, 0xCC1D}, {0xCC1E, 0xCC1E, 0xCC1E}, {0xCC1F, 0xCC1F, 0xCC1F}, {0xCC20, 0xCC20, 0xCC20}, {0xCC21, 0xCC21, 0xCC21}, {0xCC22, 0xCC22, 0xCC22}, {0xCC23, 0xCC23, 0xCC23}, {0xCC24, 0xCC24, 0xCC24}, {0xCC25, 0xCC25, 0xCC25}, {0xCC26, 0xCC26, 0xCC26}, {0xCC27, 0xCC27, 0xCC27}, {0xCC28, 0xCC28, 0xCC28}, {0xCC29, 0xCC29, 0xCC29}, {0xCC2A, 0xCC2A, 0xCC2A}, {0xCC2B, 0xCC2B, 0xCC2B}, {0xCC2C, 0xCC2C, 0xCC2C}, {0xCC2D, 0xCC2D, 0xCC2D}, {0xCC2E, 0xCC2E, 0xCC2E}, {0xCC2F, 0xCC2F, 0xCC2F}, {0xCC30, 0xCC30, 0xCC30}, {0xCC31, 0xCC31, 0xCC31}, {0xCC32, 0xCC32, 0xCC32}, {0xCC33, 0xCC33, 0xCC33}, {0xCC34, 0xCC34, 0xCC34}, {0xCC35, 0xCC35, 0xCC35}, {0xCC36, 0xCC36, 0xCC36}, {0xCC37, 0xCC37, 0xCC37}, {0xCC38, 0xCC38, 0xCC38}, {0xCC39, 0xCC39, 0xCC39}, {0xCC3A, 0xCC3A, 0xCC3A}, {0xCC3B, 0xCC3B, 0xCC3B}, {0xCC3C, 0xCC3C, 0xCC3C}, {0xCC3D, 0xCC3D, 0xCC3D}, {0xCC3E, 0xCC3E, 0xCC3E}, {0xCC3F, 0xCC3F, 0xCC3F}, {0xCC40, 0xCC40, 0xCC40}, {0xCC41, 0xCC41, 0xCC41}, {0xCC42, 0xCC42, 0xCC42}, {0xCC43, 0xCC43, 0xCC43}, {0xCC44, 0xCC44, 0xCC44}, {0xCC45, 0xCC45, 0xCC45}, {0xCC46, 0xCC46, 0xCC46}, {0xCC47, 0xCC47, 0xCC47}, {0xCC48, 0xCC48, 0xCC48}, {0xCC49, 0xCC49, 0xCC49}, {0xCC4A, 0xCC4A, 0xCC4A}, {0xCC4B, 0xCC4B, 0xCC4B}, {0xCC4C, 0xCC4C, 0xCC4C}, {0xCC4D, 0xCC4D, 0xCC4D}, {0xCC4E, 0xCC4E, 0xCC4E}, {0xCC4F, 0xCC4F, 0xCC4F}, {0xCC50, 0xCC50, 0xCC50}, {0xCC51, 0xCC51, 0xCC51}, {0xCC52, 0xCC52, 0xCC52}, {0xCC53, 0xCC53, 0xCC53}, {0xCC54, 0xCC54, 0xCC54}, {0xCC55, 0xCC55, 0xCC55}, {0xCC56, 0xCC56, 0xCC56}, {0xCC57, 0xCC57, 0xCC57}, {0xCC58, 0xCC58, 0xCC58}, {0xCC59, 0xCC59, 0xCC59}, {0xCC5A, 0xCC5A, 0xCC5A}, {0xCC5B, 0xCC5B, 0xCC5B}, {0xCC5C, 0xCC5C, 0xCC5C}, {0xCC5D, 0xCC5D, 0xCC5D}, {0xCC5E, 0xCC5E, 0xCC5E}, {0xCC5F, 0xCC5F, 0xCC5F}, {0xCC60, 0xCC60, 0xCC60}, {0xCC61, 0xCC61, 0xCC61}, {0xCC62, 0xCC62, 0xCC62}, {0xCC63, 0xCC63, 0xCC63}, {0xCC64, 0xCC64, 0xCC64}, {0xCC65, 0xCC65, 0xCC65}, {0xCC66, 0xCC66, 0xCC66}, {0xCC67, 0xCC67, 0xCC67}, {0xCC68, 0xCC68, 0xCC68}, {0xCC69, 0xCC69, 0xCC69}, {0xCC6A, 0xCC6A, 0xCC6A}, {0xCC6B, 0xCC6B, 0xCC6B}, {0xCC6C, 0xCC6C, 0xCC6C}, {0xCC6D, 0xCC6D, 0xCC6D}, {0xCC6E, 0xCC6E, 0xCC6E}, {0xCC6F, 0xCC6F, 0xCC6F}, {0xCC70, 0xCC70, 0xCC70}, {0xCC71, 0xCC71, 0xCC71}, {0xCC72, 0xCC72, 0xCC72}, {0xCC73, 0xCC73, 0xCC73}, {0xCC74, 0xCC74, 0xCC74}, {0xCC75, 0xCC75, 0xCC75}, {0xCC76, 0xCC76, 0xCC76}, {0xCC77, 0xCC77, 0xCC77}, {0xCC78, 0xCC78, 0xCC78}, {0xCC79, 0xCC79, 0xCC79}, {0xCC7A, 0xCC7A, 0xCC7A}, {0xCC7B, 0xCC7B, 0xCC7B}, {0xCC7C, 0xCC7C, 0xCC7C}, {0xCC7D, 0xCC7D, 0xCC7D}, {0xCC7E, 0xCC7E, 0xCC7E}, {0xCC7F, 0xCC7F, 0xCC7F}, {0xCC80, 0xCC80, 0xCC80}, {0xCC81, 0xCC81, 0xCC81}, {0xCC82, 0xCC82, 0xCC82}, {0xCC83, 0xCC83, 0xCC83}, {0xCC84, 0xCC84, 0xCC84}, {0xCC85, 0xCC85, 0xCC85}, {0xCC86, 0xCC86, 0xCC86}, {0xCC87, 0xCC87, 0xCC87}, {0xCC88, 0xCC88, 0xCC88}, {0xCC89, 0xCC89, 0xCC89}, {0xCC8A, 0xCC8A, 0xCC8A}, {0xCC8B, 0xCC8B, 0xCC8B}, {0xCC8C, 0xCC8C, 0xCC8C}, {0xCC8D, 0xCC8D, 0xCC8D}, {0xCC8E, 0xCC8E, 0xCC8E}, {0xCC8F, 0xCC8F, 0xCC8F}, {0xCC90, 0xCC90, 0xCC90}, {0xCC91, 0xCC91, 0xCC91}, {0xCC92, 0xCC92, 0xCC92}, {0xCC93, 0xCC93, 0xCC93}, {0xCC94, 0xCC94, 0xCC94}, {0xCC95, 0xCC95, 0xCC95}, {0xCC96, 0xCC96, 0xCC96}, {0xCC97, 0xCC97, 0xCC97}, {0xCC98, 0xCC98, 0xCC98}, {0xCC99, 0xCC99, 0xCC99}, {0xCC9A, 0xCC9A, 0xCC9A}, {0xCC9B, 0xCC9B, 0xCC9B}, {0xCC9C, 0xCC9C, 0xCC9C}, {0xCC9D, 0xCC9D, 0xCC9D}, {0xCC9E, 0xCC9E, 0xCC9E}, {0xCC9F, 0xCC9F, 0xCC9F}, {0xCCA0, 0xCCA0, 0xCCA0}, {0xCCA1, 0xCCA1, 0xCCA1}, {0xCCA2, 0xCCA2, 0xCCA2}, {0xCCA3, 0xCCA3, 0xCCA3}, {0xCCA4, 0xCCA4, 0xCCA4}, {0xCCA5, 0xCCA5, 0xCCA5}, {0xCCA6, 0xCCA6, 0xCCA6}, {0xCCA7, 0xCCA7, 0xCCA7}, {0xCCA8, 0xCCA8, 0xCCA8}, {0xCCA9, 0xCCA9, 0xCCA9}, {0xCCAA, 0xCCAA, 0xCCAA}, {0xCCAB, 0xCCAB, 0xCCAB}, {0xCCAC, 0xCCAC, 0xCCAC}, {0xCCAD, 0xCCAD, 0xCCAD}, {0xCCAE, 0xCCAE, 0xCCAE}, {0xCCAF, 0xCCAF, 0xCCAF}, {0xCCB0, 0xCCB0, 0xCCB0}, {0xCCB1, 0xCCB1, 0xCCB1}, {0xCCB2, 0xCCB2, 0xCCB2}, {0xCCB3, 0xCCB3, 0xCCB3}, {0xCCB4, 0xCCB4, 0xCCB4}, {0xCCB5, 0xCCB5, 0xCCB5}, {0xCCB6, 0xCCB6, 0xCCB6}, {0xCCB7, 0xCCB7, 0xCCB7}, {0xCCB8, 0xCCB8, 0xCCB8}, {0xCCB9, 0xCCB9, 0xCCB9}, {0xCCBA, 0xCCBA, 0xCCBA}, {0xCCBB, 0xCCBB, 0xCCBB}, {0xCCBC, 0xCCBC, 0xCCBC}, {0xCCBD, 0xCCBD, 0xCCBD}, {0xCCBE, 0xCCBE, 0xCCBE}, {0xCCBF, 0xCCBF, 0xCCBF}, {0xCCC0, 0xCCC0, 0xCCC0}, {0xCCC1, 0xCCC1, 0xCCC1}, {0xCCC2, 0xCCC2, 0xCCC2}, {0xCCC3, 0xCCC3, 0xCCC3}, {0xCCC4, 0xCCC4, 0xCCC4}, {0xCCC5, 0xCCC5, 0xCCC5}, {0xCCC6, 0xCCC6, 0xCCC6}, {0xCCC7, 0xCCC7, 0xCCC7}, {0xCCC8, 0xCCC8, 0xCCC8}, {0xCCC9, 0xCCC9, 0xCCC9}, {0xCCCA, 0xCCCA, 0xCCCA}, {0xCCCB, 0xCCCB, 0xCCCB}, {0xCCCC, 0xCCCC, 0xCCCC}, {0xCCCD, 0xCCCD, 0xCCCD}, {0xCCCE, 0xCCCE, 0xCCCE}, {0xCCCF, 0xCCCF, 0xCCCF}, {0xCCD0, 0xCCD0, 0xCCD0}, {0xCCD1, 0xCCD1, 0xCCD1}, {0xCCD2, 0xCCD2, 0xCCD2}, {0xCCD3, 0xCCD3, 0xCCD3}, {0xCCD4, 0xCCD4, 0xCCD4}, {0xCCD5, 0xCCD5, 0xCCD5}, {0xCCD6, 0xCCD6, 0xCCD6}, {0xCCD7, 0xCCD7, 0xCCD7}, {0xCCD8, 0xCCD8, 0xCCD8}, {0xCCD9, 0xCCD9, 0xCCD9}, {0xCCDA, 0xCCDA, 0xCCDA}, {0xCCDB, 0xCCDB, 0xCCDB}, {0xCCDC, 0xCCDC, 0xCCDC}, {0xCCDD, 0xCCDD, 0xCCDD}, {0xCCDE, 0xCCDE, 0xCCDE}, {0xCCDF, 0xCCDF, 0xCCDF}, {0xCCE0, 0xCCE0, 0xCCE0}, {0xCCE1, 0xCCE1, 0xCCE1}, {0xCCE2, 0xCCE2, 0xCCE2}, {0xCCE3, 0xCCE3, 0xCCE3}, {0xCCE4, 0xCCE4, 0xCCE4}, {0xCCE5, 0xCCE5, 0xCCE5}, {0xCCE6, 0xCCE6, 0xCCE6}, {0xCCE7, 0xCCE7, 0xCCE7}, {0xCCE8, 0xCCE8, 0xCCE8}, {0xCCE9, 0xCCE9, 0xCCE9}, {0xCCEA, 0xCCEA, 0xCCEA}, {0xCCEB, 0xCCEB, 0xCCEB}, {0xCCEC, 0xCCEC, 0xCCEC}, {0xCCED, 0xCCED, 0xCCED}, {0xCCEE, 0xCCEE, 0xCCEE}, {0xCCEF, 0xCCEF, 0xCCEF}, {0xCCF0, 0xCCF0, 0xCCF0}, {0xCCF1, 0xCCF1, 0xCCF1}, {0xCCF2, 0xCCF2, 0xCCF2}, {0xCCF3, 0xCCF3, 0xCCF3}, {0xCCF4, 0xCCF4, 0xCCF4}, {0xCCF5, 0xCCF5, 0xCCF5}, {0xCCF6, 0xCCF6, 0xCCF6}, {0xCCF7, 0xCCF7, 0xCCF7}, {0xCCF8, 0xCCF8, 0xCCF8}, {0xCCF9, 0xCCF9, 0xCCF9}, {0xCCFA, 0xCCFA, 0xCCFA}, {0xCCFB, 0xCCFB, 0xCCFB}, {0xCCFC, 0xCCFC, 0xCCFC}, {0xCCFD, 0xCCFD, 0xCCFD}, {0xCCFE, 0xCCFE, 0xCCFE}, {0xCCFF, 0xCCFF, 0xCCFF}, {0xCD00, 0xCD00, 0xCD00}, {0xCD01, 0xCD01, 0xCD01}, {0xCD02, 0xCD02, 0xCD02}, {0xCD03, 0xCD03, 0xCD03}, {0xCD04, 0xCD04, 0xCD04}, {0xCD05, 0xCD05, 0xCD05}, {0xCD06, 0xCD06, 0xCD06}, {0xCD07, 0xCD07, 0xCD07}, {0xCD08, 0xCD08, 0xCD08}, {0xCD09, 0xCD09, 0xCD09}, {0xCD0A, 0xCD0A, 0xCD0A}, {0xCD0B, 0xCD0B, 0xCD0B}, {0xCD0C, 0xCD0C, 0xCD0C}, {0xCD0D, 0xCD0D, 0xCD0D}, {0xCD0E, 0xCD0E, 0xCD0E}, {0xCD0F, 0xCD0F, 0xCD0F}, {0xCD10, 0xCD10, 0xCD10}, {0xCD11, 0xCD11, 0xCD11}, {0xCD12, 0xCD12, 0xCD12}, {0xCD13, 0xCD13, 0xCD13}, {0xCD14, 0xCD14, 0xCD14}, {0xCD15, 0xCD15, 0xCD15}, {0xCD16, 0xCD16, 0xCD16}, {0xCD17, 0xCD17, 0xCD17}, {0xCD18, 0xCD18, 0xCD18}, {0xCD19, 0xCD19, 0xCD19}, {0xCD1A, 0xCD1A, 0xCD1A}, {0xCD1B, 0xCD1B, 0xCD1B}, {0xCD1C, 0xCD1C, 0xCD1C}, {0xCD1D, 0xCD1D, 0xCD1D}, {0xCD1E, 0xCD1E, 0xCD1E}, {0xCD1F, 0xCD1F, 0xCD1F}, {0xCD20, 0xCD20, 0xCD20}, {0xCD21, 0xCD21, 0xCD21}, {0xCD22, 0xCD22, 0xCD22}, {0xCD23, 0xCD23, 0xCD23}, {0xCD24, 0xCD24, 0xCD24}, {0xCD25, 0xCD25, 0xCD25}, {0xCD26, 0xCD26, 0xCD26}, {0xCD27, 0xCD27, 0xCD27}, {0xCD28, 0xCD28, 0xCD28}, {0xCD29, 0xCD29, 0xCD29}, {0xCD2A, 0xCD2A, 0xCD2A}, {0xCD2B, 0xCD2B, 0xCD2B}, {0xCD2C, 0xCD2C, 0xCD2C}, {0xCD2D, 0xCD2D, 0xCD2D}, {0xCD2E, 0xCD2E, 0xCD2E}, {0xCD2F, 0xCD2F, 0xCD2F}, {0xCD30, 0xCD30, 0xCD30}, {0xCD31, 0xCD31, 0xCD31}, {0xCD32, 0xCD32, 0xCD32}, {0xCD33, 0xCD33, 0xCD33}, {0xCD34, 0xCD34, 0xCD34}, {0xCD35, 0xCD35, 0xCD35}, {0xCD36, 0xCD36, 0xCD36}, {0xCD37, 0xCD37, 0xCD37}, {0xCD38, 0xCD38, 0xCD38}, {0xCD39, 0xCD39, 0xCD39}, {0xCD3A, 0xCD3A, 0xCD3A}, {0xCD3B, 0xCD3B, 0xCD3B}, {0xCD3C, 0xCD3C, 0xCD3C}, {0xCD3D, 0xCD3D, 0xCD3D}, {0xCD3E, 0xCD3E, 0xCD3E}, {0xCD3F, 0xCD3F, 0xCD3F}, {0xCD40, 0xCD40, 0xCD40}, {0xCD41, 0xCD41, 0xCD41}, {0xCD42, 0xCD42, 0xCD42}, {0xCD43, 0xCD43, 0xCD43}, {0xCD44, 0xCD44, 0xCD44}, {0xCD45, 0xCD45, 0xCD45}, {0xCD46, 0xCD46, 0xCD46}, {0xCD47, 0xCD47, 0xCD47}, {0xCD48, 0xCD48, 0xCD48}, {0xCD49, 0xCD49, 0xCD49}, {0xCD4A, 0xCD4A, 0xCD4A}, {0xCD4B, 0xCD4B, 0xCD4B}, {0xCD4C, 0xCD4C, 0xCD4C}, {0xCD4D, 0xCD4D, 0xCD4D}, {0xCD4E, 0xCD4E, 0xCD4E}, {0xCD4F, 0xCD4F, 0xCD4F}, {0xCD50, 0xCD50, 0xCD50}, {0xCD51, 0xCD51, 0xCD51}, {0xCD52, 0xCD52, 0xCD52}, {0xCD53, 0xCD53, 0xCD53}, {0xCD54, 0xCD54, 0xCD54}, {0xCD55, 0xCD55, 0xCD55}, {0xCD56, 0xCD56, 0xCD56}, {0xCD57, 0xCD57, 0xCD57}, {0xCD58, 0xCD58, 0xCD58}, {0xCD59, 0xCD59, 0xCD59}, {0xCD5A, 0xCD5A, 0xCD5A}, {0xCD5B, 0xCD5B, 0xCD5B}, {0xCD5C, 0xCD5C, 0xCD5C}, {0xCD5D, 0xCD5D, 0xCD5D}, {0xCD5E, 0xCD5E, 0xCD5E}, {0xCD5F, 0xCD5F, 0xCD5F}, {0xCD60, 0xCD60, 0xCD60}, {0xCD61, 0xCD61, 0xCD61}, {0xCD62, 0xCD62, 0xCD62}, {0xCD63, 0xCD63, 0xCD63}, {0xCD64, 0xCD64, 0xCD64}, {0xCD65, 0xCD65, 0xCD65}, {0xCD66, 0xCD66, 0xCD66}, {0xCD67, 0xCD67, 0xCD67}, {0xCD68, 0xCD68, 0xCD68}, {0xCD69, 0xCD69, 0xCD69}, {0xCD6A, 0xCD6A, 0xCD6A}, {0xCD6B, 0xCD6B, 0xCD6B}, {0xCD6C, 0xCD6C, 0xCD6C}, {0xCD6D, 0xCD6D, 0xCD6D}, {0xCD6E, 0xCD6E, 0xCD6E}, {0xCD6F, 0xCD6F, 0xCD6F}, {0xCD70, 0xCD70, 0xCD70}, {0xCD71, 0xCD71, 0xCD71}, {0xCD72, 0xCD72, 0xCD72}, {0xCD73, 0xCD73, 0xCD73}, {0xCD74, 0xCD74, 0xCD74}, {0xCD75, 0xCD75, 0xCD75}, {0xCD76, 0xCD76, 0xCD76}, {0xCD77, 0xCD77, 0xCD77}, {0xCD78, 0xCD78, 0xCD78}, {0xCD79, 0xCD79, 0xCD79}, {0xCD7A, 0xCD7A, 0xCD7A}, {0xCD7B, 0xCD7B, 0xCD7B}, {0xCD7C, 0xCD7C, 0xCD7C}, {0xCD7D, 0xCD7D, 0xCD7D}, {0xCD7E, 0xCD7E, 0xCD7E}, {0xCD7F, 0xCD7F, 0xCD7F}, {0xCD80, 0xCD80, 0xCD80}, {0xCD81, 0xCD81, 0xCD81}, {0xCD82, 0xCD82, 0xCD82}, {0xCD83, 0xCD83, 0xCD83}, {0xCD84, 0xCD84, 0xCD84}, {0xCD85, 0xCD85, 0xCD85}, {0xCD86, 0xCD86, 0xCD86}, {0xCD87, 0xCD87, 0xCD87}, {0xCD88, 0xCD88, 0xCD88}, {0xCD89, 0xCD89, 0xCD89}, {0xCD8A, 0xCD8A, 0xCD8A}, {0xCD8B, 0xCD8B, 0xCD8B}, {0xCD8C, 0xCD8C, 0xCD8C}, {0xCD8D, 0xCD8D, 0xCD8D}, {0xCD8E, 0xCD8E, 0xCD8E}, {0xCD8F, 0xCD8F, 0xCD8F}, {0xCD90, 0xCD90, 0xCD90}, {0xCD91, 0xCD91, 0xCD91}, {0xCD92, 0xCD92, 0xCD92}, {0xCD93, 0xCD93, 0xCD93}, {0xCD94, 0xCD94, 0xCD94}, {0xCD95, 0xCD95, 0xCD95}, {0xCD96, 0xCD96, 0xCD96}, {0xCD97, 0xCD97, 0xCD97}, {0xCD98, 0xCD98, 0xCD98}, {0xCD99, 0xCD99, 0xCD99}, {0xCD9A, 0xCD9A, 0xCD9A}, {0xCD9B, 0xCD9B, 0xCD9B}, {0xCD9C, 0xCD9C, 0xCD9C}, {0xCD9D, 0xCD9D, 0xCD9D}, {0xCD9E, 0xCD9E, 0xCD9E}, {0xCD9F, 0xCD9F, 0xCD9F}, {0xCDA0, 0xCDA0, 0xCDA0}, {0xCDA1, 0xCDA1, 0xCDA1}, {0xCDA2, 0xCDA2, 0xCDA2}, {0xCDA3, 0xCDA3, 0xCDA3}, {0xCDA4, 0xCDA4, 0xCDA4}, {0xCDA5, 0xCDA5, 0xCDA5}, {0xCDA6, 0xCDA6, 0xCDA6}, {0xCDA7, 0xCDA7, 0xCDA7}, {0xCDA8, 0xCDA8, 0xCDA8}, {0xCDA9, 0xCDA9, 0xCDA9}, {0xCDAA, 0xCDAA, 0xCDAA}, {0xCDAB, 0xCDAB, 0xCDAB}, {0xCDAC, 0xCDAC, 0xCDAC}, {0xCDAD, 0xCDAD, 0xCDAD}, {0xCDAE, 0xCDAE, 0xCDAE}, {0xCDAF, 0xCDAF, 0xCDAF}, {0xCDB0, 0xCDB0, 0xCDB0}, {0xCDB1, 0xCDB1, 0xCDB1}, {0xCDB2, 0xCDB2, 0xCDB2}, {0xCDB3, 0xCDB3, 0xCDB3}, {0xCDB4, 0xCDB4, 0xCDB4}, {0xCDB5, 0xCDB5, 0xCDB5}, {0xCDB6, 0xCDB6, 0xCDB6}, {0xCDB7, 0xCDB7, 0xCDB7}, {0xCDB8, 0xCDB8, 0xCDB8}, {0xCDB9, 0xCDB9, 0xCDB9}, {0xCDBA, 0xCDBA, 0xCDBA}, {0xCDBB, 0xCDBB, 0xCDBB}, {0xCDBC, 0xCDBC, 0xCDBC}, {0xCDBD, 0xCDBD, 0xCDBD}, {0xCDBE, 0xCDBE, 0xCDBE}, {0xCDBF, 0xCDBF, 0xCDBF}, {0xCDC0, 0xCDC0, 0xCDC0}, {0xCDC1, 0xCDC1, 0xCDC1}, {0xCDC2, 0xCDC2, 0xCDC2}, {0xCDC3, 0xCDC3, 0xCDC3}, {0xCDC4, 0xCDC4, 0xCDC4}, {0xCDC5, 0xCDC5, 0xCDC5}, {0xCDC6, 0xCDC6, 0xCDC6}, {0xCDC7, 0xCDC7, 0xCDC7}, {0xCDC8, 0xCDC8, 0xCDC8}, {0xCDC9, 0xCDC9, 0xCDC9}, {0xCDCA, 0xCDCA, 0xCDCA}, {0xCDCB, 0xCDCB, 0xCDCB}, {0xCDCC, 0xCDCC, 0xCDCC}, {0xCDCD, 0xCDCD, 0xCDCD}, {0xCDCE, 0xCDCE, 0xCDCE}, {0xCDCF, 0xCDCF, 0xCDCF}, {0xCDD0, 0xCDD0, 0xCDD0}, {0xCDD1, 0xCDD1, 0xCDD1}, {0xCDD2, 0xCDD2, 0xCDD2}, {0xCDD3, 0xCDD3, 0xCDD3}, {0xCDD4, 0xCDD4, 0xCDD4}, {0xCDD5, 0xCDD5, 0xCDD5}, {0xCDD6, 0xCDD6, 0xCDD6}, {0xCDD7, 0xCDD7, 0xCDD7}, {0xCDD8, 0xCDD8, 0xCDD8}, {0xCDD9, 0xCDD9, 0xCDD9}, {0xCDDA, 0xCDDA, 0xCDDA}, {0xCDDB, 0xCDDB, 0xCDDB}, {0xCDDC, 0xCDDC, 0xCDDC}, {0xCDDD, 0xCDDD, 0xCDDD}, {0xCDDE, 0xCDDE, 0xCDDE}, {0xCDDF, 0xCDDF, 0xCDDF}, {0xCDE0, 0xCDE0, 0xCDE0}, {0xCDE1, 0xCDE1, 0xCDE1}, {0xCDE2, 0xCDE2, 0xCDE2}, {0xCDE3, 0xCDE3, 0xCDE3}, {0xCDE4, 0xCDE4, 0xCDE4}, {0xCDE5, 0xCDE5, 0xCDE5}, {0xCDE6, 0xCDE6, 0xCDE6}, {0xCDE7, 0xCDE7, 0xCDE7}, {0xCDE8, 0xCDE8, 0xCDE8}, {0xCDE9, 0xCDE9, 0xCDE9}, {0xCDEA, 0xCDEA, 0xCDEA}, {0xCDEB, 0xCDEB, 0xCDEB}, {0xCDEC, 0xCDEC, 0xCDEC}, {0xCDED, 0xCDED, 0xCDED}, {0xCDEE, 0xCDEE, 0xCDEE}, {0xCDEF, 0xCDEF, 0xCDEF}, {0xCDF0, 0xCDF0, 0xCDF0}, {0xCDF1, 0xCDF1, 0xCDF1}, {0xCDF2, 0xCDF2, 0xCDF2}, {0xCDF3, 0xCDF3, 0xCDF3}, {0xCDF4, 0xCDF4, 0xCDF4}, {0xCDF5, 0xCDF5, 0xCDF5}, {0xCDF6, 0xCDF6, 0xCDF6}, {0xCDF7, 0xCDF7, 0xCDF7}, {0xCDF8, 0xCDF8, 0xCDF8}, {0xCDF9, 0xCDF9, 0xCDF9}, {0xCDFA, 0xCDFA, 0xCDFA}, {0xCDFB, 0xCDFB, 0xCDFB}, {0xCDFC, 0xCDFC, 0xCDFC}, {0xCDFD, 0xCDFD, 0xCDFD}, {0xCDFE, 0xCDFE, 0xCDFE}, {0xCDFF, 0xCDFF, 0xCDFF}, {0xCE00, 0xCE00, 0xCE00}, {0xCE01, 0xCE01, 0xCE01}, {0xCE02, 0xCE02, 0xCE02}, {0xCE03, 0xCE03, 0xCE03}, {0xCE04, 0xCE04, 0xCE04}, {0xCE05, 0xCE05, 0xCE05}, {0xCE06, 0xCE06, 0xCE06}, {0xCE07, 0xCE07, 0xCE07}, {0xCE08, 0xCE08, 0xCE08}, {0xCE09, 0xCE09, 0xCE09}, {0xCE0A, 0xCE0A, 0xCE0A}, {0xCE0B, 0xCE0B, 0xCE0B}, {0xCE0C, 0xCE0C, 0xCE0C}, {0xCE0D, 0xCE0D, 0xCE0D}, {0xCE0E, 0xCE0E, 0xCE0E}, {0xCE0F, 0xCE0F, 0xCE0F}, {0xCE10, 0xCE10, 0xCE10}, {0xCE11, 0xCE11, 0xCE11}, {0xCE12, 0xCE12, 0xCE12}, {0xCE13, 0xCE13, 0xCE13}, {0xCE14, 0xCE14, 0xCE14}, {0xCE15, 0xCE15, 0xCE15}, {0xCE16, 0xCE16, 0xCE16}, {0xCE17, 0xCE17, 0xCE17}, {0xCE18, 0xCE18, 0xCE18}, {0xCE19, 0xCE19, 0xCE19}, {0xCE1A, 0xCE1A, 0xCE1A}, {0xCE1B, 0xCE1B, 0xCE1B}, {0xCE1C, 0xCE1C, 0xCE1C}, {0xCE1D, 0xCE1D, 0xCE1D}, {0xCE1E, 0xCE1E, 0xCE1E}, {0xCE1F, 0xCE1F, 0xCE1F}, {0xCE20, 0xCE20, 0xCE20}, {0xCE21, 0xCE21, 0xCE21}, {0xCE22, 0xCE22, 0xCE22}, {0xCE23, 0xCE23, 0xCE23}, {0xCE24, 0xCE24, 0xCE24}, {0xCE25, 0xCE25, 0xCE25}, {0xCE26, 0xCE26, 0xCE26}, {0xCE27, 0xCE27, 0xCE27}, {0xCE28, 0xCE28, 0xCE28}, {0xCE29, 0xCE29, 0xCE29}, {0xCE2A, 0xCE2A, 0xCE2A}, {0xCE2B, 0xCE2B, 0xCE2B}, {0xCE2C, 0xCE2C, 0xCE2C}, {0xCE2D, 0xCE2D, 0xCE2D}, {0xCE2E, 0xCE2E, 0xCE2E}, {0xCE2F, 0xCE2F, 0xCE2F}, {0xCE30, 0xCE30, 0xCE30}, {0xCE31, 0xCE31, 0xCE31}, {0xCE32, 0xCE32, 0xCE32}, {0xCE33, 0xCE33, 0xCE33}, {0xCE34, 0xCE34, 0xCE34}, {0xCE35, 0xCE35, 0xCE35}, {0xCE36, 0xCE36, 0xCE36}, {0xCE37, 0xCE37, 0xCE37}, {0xCE38, 0xCE38, 0xCE38}, {0xCE39, 0xCE39, 0xCE39}, {0xCE3A, 0xCE3A, 0xCE3A}, {0xCE3B, 0xCE3B, 0xCE3B}, {0xCE3C, 0xCE3C, 0xCE3C}, {0xCE3D, 0xCE3D, 0xCE3D}, {0xCE3E, 0xCE3E, 0xCE3E}, {0xCE3F, 0xCE3F, 0xCE3F}, {0xCE40, 0xCE40, 0xCE40}, {0xCE41, 0xCE41, 0xCE41}, {0xCE42, 0xCE42, 0xCE42}, {0xCE43, 0xCE43, 0xCE43}, {0xCE44, 0xCE44, 0xCE44}, {0xCE45, 0xCE45, 0xCE45}, {0xCE46, 0xCE46, 0xCE46}, {0xCE47, 0xCE47, 0xCE47}, {0xCE48, 0xCE48, 0xCE48}, {0xCE49, 0xCE49, 0xCE49}, {0xCE4A, 0xCE4A, 0xCE4A}, {0xCE4B, 0xCE4B, 0xCE4B}, {0xCE4C, 0xCE4C, 0xCE4C}, {0xCE4D, 0xCE4D, 0xCE4D}, {0xCE4E, 0xCE4E, 0xCE4E}, {0xCE4F, 0xCE4F, 0xCE4F}, {0xCE50, 0xCE50, 0xCE50}, {0xCE51, 0xCE51, 0xCE51}, {0xCE52, 0xCE52, 0xCE52}, {0xCE53, 0xCE53, 0xCE53}, {0xCE54, 0xCE54, 0xCE54}, {0xCE55, 0xCE55, 0xCE55}, {0xCE56, 0xCE56, 0xCE56}, {0xCE57, 0xCE57, 0xCE57}, {0xCE58, 0xCE58, 0xCE58}, {0xCE59, 0xCE59, 0xCE59}, {0xCE5A, 0xCE5A, 0xCE5A}, {0xCE5B, 0xCE5B, 0xCE5B}, {0xCE5C, 0xCE5C, 0xCE5C}, {0xCE5D, 0xCE5D, 0xCE5D}, {0xCE5E, 0xCE5E, 0xCE5E}, {0xCE5F, 0xCE5F, 0xCE5F}, {0xCE60, 0xCE60, 0xCE60}, {0xCE61, 0xCE61, 0xCE61}, {0xCE62, 0xCE62, 0xCE62}, {0xCE63, 0xCE63, 0xCE63}, {0xCE64, 0xCE64, 0xCE64}, {0xCE65, 0xCE65, 0xCE65}, {0xCE66, 0xCE66, 0xCE66}, {0xCE67, 0xCE67, 0xCE67}, {0xCE68, 0xCE68, 0xCE68}, {0xCE69, 0xCE69, 0xCE69}, {0xCE6A, 0xCE6A, 0xCE6A}, {0xCE6B, 0xCE6B, 0xCE6B}, {0xCE6C, 0xCE6C, 0xCE6C}, {0xCE6D, 0xCE6D, 0xCE6D}, {0xCE6E, 0xCE6E, 0xCE6E}, {0xCE6F, 0xCE6F, 0xCE6F}, {0xCE70, 0xCE70, 0xCE70}, {0xCE71, 0xCE71, 0xCE71}, {0xCE72, 0xCE72, 0xCE72}, {0xCE73, 0xCE73, 0xCE73}, {0xCE74, 0xCE74, 0xCE74}, {0xCE75, 0xCE75, 0xCE75}, {0xCE76, 0xCE76, 0xCE76}, {0xCE77, 0xCE77, 0xCE77}, {0xCE78, 0xCE78, 0xCE78}, {0xCE79, 0xCE79, 0xCE79}, {0xCE7A, 0xCE7A, 0xCE7A}, {0xCE7B, 0xCE7B, 0xCE7B}, {0xCE7C, 0xCE7C, 0xCE7C}, {0xCE7D, 0xCE7D, 0xCE7D}, {0xCE7E, 0xCE7E, 0xCE7E}, {0xCE7F, 0xCE7F, 0xCE7F}, {0xCE80, 0xCE80, 0xCE80}, {0xCE81, 0xCE81, 0xCE81}, {0xCE82, 0xCE82, 0xCE82}, {0xCE83, 0xCE83, 0xCE83}, {0xCE84, 0xCE84, 0xCE84}, {0xCE85, 0xCE85, 0xCE85}, {0xCE86, 0xCE86, 0xCE86}, {0xCE87, 0xCE87, 0xCE87}, {0xCE88, 0xCE88, 0xCE88}, {0xCE89, 0xCE89, 0xCE89}, {0xCE8A, 0xCE8A, 0xCE8A}, {0xCE8B, 0xCE8B, 0xCE8B}, {0xCE8C, 0xCE8C, 0xCE8C}, {0xCE8D, 0xCE8D, 0xCE8D}, {0xCE8E, 0xCE8E, 0xCE8E}, {0xCE8F, 0xCE8F, 0xCE8F}, {0xCE90, 0xCE90, 0xCE90}, {0xCE91, 0xCE91, 0xCE91}, {0xCE92, 0xCE92, 0xCE92}, {0xCE93, 0xCE93, 0xCE93}, {0xCE94, 0xCE94, 0xCE94}, {0xCE95, 0xCE95, 0xCE95}, {0xCE96, 0xCE96, 0xCE96}, {0xCE97, 0xCE97, 0xCE97}, {0xCE98, 0xCE98, 0xCE98}, {0xCE99, 0xCE99, 0xCE99}, {0xCE9A, 0xCE9A, 0xCE9A}, {0xCE9B, 0xCE9B, 0xCE9B}, {0xCE9C, 0xCE9C, 0xCE9C}, {0xCE9D, 0xCE9D, 0xCE9D}, {0xCE9E, 0xCE9E, 0xCE9E}, {0xCE9F, 0xCE9F, 0xCE9F}, {0xCEA0, 0xCEA0, 0xCEA0}, {0xCEA1, 0xCEA1, 0xCEA1}, {0xCEA2, 0xCEA2, 0xCEA2}, {0xCEA3, 0xCEA3, 0xCEA3}, {0xCEA4, 0xCEA4, 0xCEA4}, {0xCEA5, 0xCEA5, 0xCEA5}, {0xCEA6, 0xCEA6, 0xCEA6}, {0xCEA7, 0xCEA7, 0xCEA7}, {0xCEA8, 0xCEA8, 0xCEA8}, {0xCEA9, 0xCEA9, 0xCEA9}, {0xCEAA, 0xCEAA, 0xCEAA}, {0xCEAB, 0xCEAB, 0xCEAB}, {0xCEAC, 0xCEAC, 0xCEAC}, {0xCEAD, 0xCEAD, 0xCEAD}, {0xCEAE, 0xCEAE, 0xCEAE}, {0xCEAF, 0xCEAF, 0xCEAF}, {0xCEB0, 0xCEB0, 0xCEB0}, {0xCEB1, 0xCEB1, 0xCEB1}, {0xCEB2, 0xCEB2, 0xCEB2}, {0xCEB3, 0xCEB3, 0xCEB3}, {0xCEB4, 0xCEB4, 0xCEB4}, {0xCEB5, 0xCEB5, 0xCEB5}, {0xCEB6, 0xCEB6, 0xCEB6}, {0xCEB7, 0xCEB7, 0xCEB7}, {0xCEB8, 0xCEB8, 0xCEB8}, {0xCEB9, 0xCEB9, 0xCEB9}, {0xCEBA, 0xCEBA, 0xCEBA}, {0xCEBB, 0xCEBB, 0xCEBB}, {0xCEBC, 0xCEBC, 0xCEBC}, {0xCEBD, 0xCEBD, 0xCEBD}, {0xCEBE, 0xCEBE, 0xCEBE}, {0xCEBF, 0xCEBF, 0xCEBF}, {0xCEC0, 0xCEC0, 0xCEC0}, {0xCEC1, 0xCEC1, 0xCEC1}, {0xCEC2, 0xCEC2, 0xCEC2}, {0xCEC3, 0xCEC3, 0xCEC3}, {0xCEC4, 0xCEC4, 0xCEC4}, {0xCEC5, 0xCEC5, 0xCEC5}, {0xCEC6, 0xCEC6, 0xCEC6}, {0xCEC7, 0xCEC7, 0xCEC7}, {0xCEC8, 0xCEC8, 0xCEC8}, {0xCEC9, 0xCEC9, 0xCEC9}, {0xCECA, 0xCECA, 0xCECA}, {0xCECB, 0xCECB, 0xCECB}, {0xCECC, 0xCECC, 0xCECC}, {0xCECD, 0xCECD, 0xCECD}, {0xCECE, 0xCECE, 0xCECE}, {0xCECF, 0xCECF, 0xCECF}, {0xCED0, 0xCED0, 0xCED0}, {0xCED1, 0xCED1, 0xCED1}, {0xCED2, 0xCED2, 0xCED2}, {0xCED3, 0xCED3, 0xCED3}, {0xCED4, 0xCED4, 0xCED4}, {0xCED5, 0xCED5, 0xCED5}, {0xCED6, 0xCED6, 0xCED6}, {0xCED7, 0xCED7, 0xCED7}, {0xCED8, 0xCED8, 0xCED8}, {0xCED9, 0xCED9, 0xCED9}, {0xCEDA, 0xCEDA, 0xCEDA}, {0xCEDB, 0xCEDB, 0xCEDB}, {0xCEDC, 0xCEDC, 0xCEDC}, {0xCEDD, 0xCEDD, 0xCEDD}, {0xCEDE, 0xCEDE, 0xCEDE}, {0xCEDF, 0xCEDF, 0xCEDF}, {0xCEE0, 0xCEE0, 0xCEE0}, {0xCEE1, 0xCEE1, 0xCEE1}, {0xCEE2, 0xCEE2, 0xCEE2}, {0xCEE3, 0xCEE3, 0xCEE3}, {0xCEE4, 0xCEE4, 0xCEE4}, {0xCEE5, 0xCEE5, 0xCEE5}, {0xCEE6, 0xCEE6, 0xCEE6}, {0xCEE7, 0xCEE7, 0xCEE7}, {0xCEE8, 0xCEE8, 0xCEE8}, {0xCEE9, 0xCEE9, 0xCEE9}, {0xCEEA, 0xCEEA, 0xCEEA}, {0xCEEB, 0xCEEB, 0xCEEB}, {0xCEEC, 0xCEEC, 0xCEEC}, {0xCEED, 0xCEED, 0xCEED}, {0xCEEE, 0xCEEE, 0xCEEE}, {0xCEEF, 0xCEEF, 0xCEEF}, {0xCEF0, 0xCEF0, 0xCEF0}, {0xCEF1, 0xCEF1, 0xCEF1}, {0xCEF2, 0xCEF2, 0xCEF2}, {0xCEF3, 0xCEF3, 0xCEF3}, {0xCEF4, 0xCEF4, 0xCEF4}, {0xCEF5, 0xCEF5, 0xCEF5}, {0xCEF6, 0xCEF6, 0xCEF6}, {0xCEF7, 0xCEF7, 0xCEF7}, {0xCEF8, 0xCEF8, 0xCEF8}, {0xCEF9, 0xCEF9, 0xCEF9}, {0xCEFA, 0xCEFA, 0xCEFA}, {0xCEFB, 0xCEFB, 0xCEFB}, {0xCEFC, 0xCEFC, 0xCEFC}, {0xCEFD, 0xCEFD, 0xCEFD}, {0xCEFE, 0xCEFE, 0xCEFE}, {0xCEFF, 0xCEFF, 0xCEFF}, {0xCF00, 0xCF00, 0xCF00}, {0xCF01, 0xCF01, 0xCF01}, {0xCF02, 0xCF02, 0xCF02}, {0xCF03, 0xCF03, 0xCF03}, {0xCF04, 0xCF04, 0xCF04}, {0xCF05, 0xCF05, 0xCF05}, {0xCF06, 0xCF06, 0xCF06}, {0xCF07, 0xCF07, 0xCF07}, {0xCF08, 0xCF08, 0xCF08}, {0xCF09, 0xCF09, 0xCF09}, {0xCF0A, 0xCF0A, 0xCF0A}, {0xCF0B, 0xCF0B, 0xCF0B}, {0xCF0C, 0xCF0C, 0xCF0C}, {0xCF0D, 0xCF0D, 0xCF0D}, {0xCF0E, 0xCF0E, 0xCF0E}, {0xCF0F, 0xCF0F, 0xCF0F}, {0xCF10, 0xCF10, 0xCF10}, {0xCF11, 0xCF11, 0xCF11}, {0xCF12, 0xCF12, 0xCF12}, {0xCF13, 0xCF13, 0xCF13}, {0xCF14, 0xCF14, 0xCF14}, {0xCF15, 0xCF15, 0xCF15}, {0xCF16, 0xCF16, 0xCF16}, {0xCF17, 0xCF17, 0xCF17}, {0xCF18, 0xCF18, 0xCF18}, {0xCF19, 0xCF19, 0xCF19}, {0xCF1A, 0xCF1A, 0xCF1A}, {0xCF1B, 0xCF1B, 0xCF1B}, {0xCF1C, 0xCF1C, 0xCF1C}, {0xCF1D, 0xCF1D, 0xCF1D}, {0xCF1E, 0xCF1E, 0xCF1E}, {0xCF1F, 0xCF1F, 0xCF1F}, {0xCF20, 0xCF20, 0xCF20}, {0xCF21, 0xCF21, 0xCF21}, {0xCF22, 0xCF22, 0xCF22}, {0xCF23, 0xCF23, 0xCF23}, {0xCF24, 0xCF24, 0xCF24}, {0xCF25, 0xCF25, 0xCF25}, {0xCF26, 0xCF26, 0xCF26}, {0xCF27, 0xCF27, 0xCF27}, {0xCF28, 0xCF28, 0xCF28}, {0xCF29, 0xCF29, 0xCF29}, {0xCF2A, 0xCF2A, 0xCF2A}, {0xCF2B, 0xCF2B, 0xCF2B}, {0xCF2C, 0xCF2C, 0xCF2C}, {0xCF2D, 0xCF2D, 0xCF2D}, {0xCF2E, 0xCF2E, 0xCF2E}, {0xCF2F, 0xCF2F, 0xCF2F}, {0xCF30, 0xCF30, 0xCF30}, {0xCF31, 0xCF31, 0xCF31}, {0xCF32, 0xCF32, 0xCF32}, {0xCF33, 0xCF33, 0xCF33}, {0xCF34, 0xCF34, 0xCF34}, {0xCF35, 0xCF35, 0xCF35}, {0xCF36, 0xCF36, 0xCF36}, {0xCF37, 0xCF37, 0xCF37}, {0xCF38, 0xCF38, 0xCF38}, {0xCF39, 0xCF39, 0xCF39}, {0xCF3A, 0xCF3A, 0xCF3A}, {0xCF3B, 0xCF3B, 0xCF3B}, {0xCF3C, 0xCF3C, 0xCF3C}, {0xCF3D, 0xCF3D, 0xCF3D}, {0xCF3E, 0xCF3E, 0xCF3E}, {0xCF3F, 0xCF3F, 0xCF3F}, {0xCF40, 0xCF40, 0xCF40}, {0xCF41, 0xCF41, 0xCF41}, {0xCF42, 0xCF42, 0xCF42}, {0xCF43, 0xCF43, 0xCF43}, {0xCF44, 0xCF44, 0xCF44}, {0xCF45, 0xCF45, 0xCF45}, {0xCF46, 0xCF46, 0xCF46}, {0xCF47, 0xCF47, 0xCF47}, {0xCF48, 0xCF48, 0xCF48}, {0xCF49, 0xCF49, 0xCF49}, {0xCF4A, 0xCF4A, 0xCF4A}, {0xCF4B, 0xCF4B, 0xCF4B}, {0xCF4C, 0xCF4C, 0xCF4C}, {0xCF4D, 0xCF4D, 0xCF4D}, {0xCF4E, 0xCF4E, 0xCF4E}, {0xCF4F, 0xCF4F, 0xCF4F}, {0xCF50, 0xCF50, 0xCF50}, {0xCF51, 0xCF51, 0xCF51}, {0xCF52, 0xCF52, 0xCF52}, {0xCF53, 0xCF53, 0xCF53}, {0xCF54, 0xCF54, 0xCF54}, {0xCF55, 0xCF55, 0xCF55}, {0xCF56, 0xCF56, 0xCF56}, {0xCF57, 0xCF57, 0xCF57}, {0xCF58, 0xCF58, 0xCF58}, {0xCF59, 0xCF59, 0xCF59}, {0xCF5A, 0xCF5A, 0xCF5A}, {0xCF5B, 0xCF5B, 0xCF5B}, {0xCF5C, 0xCF5C, 0xCF5C}, {0xCF5D, 0xCF5D, 0xCF5D}, {0xCF5E, 0xCF5E, 0xCF5E}, {0xCF5F, 0xCF5F, 0xCF5F}, {0xCF60, 0xCF60, 0xCF60}, {0xCF61, 0xCF61, 0xCF61}, {0xCF62, 0xCF62, 0xCF62}, {0xCF63, 0xCF63, 0xCF63}, {0xCF64, 0xCF64, 0xCF64}, {0xCF65, 0xCF65, 0xCF65}, {0xCF66, 0xCF66, 0xCF66}, {0xCF67, 0xCF67, 0xCF67}, {0xCF68, 0xCF68, 0xCF68}, {0xCF69, 0xCF69, 0xCF69}, {0xCF6A, 0xCF6A, 0xCF6A}, {0xCF6B, 0xCF6B, 0xCF6B}, {0xCF6C, 0xCF6C, 0xCF6C}, {0xCF6D, 0xCF6D, 0xCF6D}, {0xCF6E, 0xCF6E, 0xCF6E}, {0xCF6F, 0xCF6F, 0xCF6F}, {0xCF70, 0xCF70, 0xCF70}, {0xCF71, 0xCF71, 0xCF71}, {0xCF72, 0xCF72, 0xCF72}, {0xCF73, 0xCF73, 0xCF73}, {0xCF74, 0xCF74, 0xCF74}, {0xCF75, 0xCF75, 0xCF75}, {0xCF76, 0xCF76, 0xCF76}, {0xCF77, 0xCF77, 0xCF77}, {0xCF78, 0xCF78, 0xCF78}, {0xCF79, 0xCF79, 0xCF79}, {0xCF7A, 0xCF7A, 0xCF7A}, {0xCF7B, 0xCF7B, 0xCF7B}, {0xCF7C, 0xCF7C, 0xCF7C}, {0xCF7D, 0xCF7D, 0xCF7D}, {0xCF7E, 0xCF7E, 0xCF7E}, {0xCF7F, 0xCF7F, 0xCF7F}, {0xCF80, 0xCF80, 0xCF80}, {0xCF81, 0xCF81, 0xCF81}, {0xCF82, 0xCF82, 0xCF82}, {0xCF83, 0xCF83, 0xCF83}, {0xCF84, 0xCF84, 0xCF84}, {0xCF85, 0xCF85, 0xCF85}, {0xCF86, 0xCF86, 0xCF86}, {0xCF87, 0xCF87, 0xCF87}, {0xCF88, 0xCF88, 0xCF88}, {0xCF89, 0xCF89, 0xCF89}, {0xCF8A, 0xCF8A, 0xCF8A}, {0xCF8B, 0xCF8B, 0xCF8B}, {0xCF8C, 0xCF8C, 0xCF8C}, {0xCF8D, 0xCF8D, 0xCF8D}, {0xCF8E, 0xCF8E, 0xCF8E}, {0xCF8F, 0xCF8F, 0xCF8F}, {0xCF90, 0xCF90, 0xCF90}, {0xCF91, 0xCF91, 0xCF91}, {0xCF92, 0xCF92, 0xCF92}, {0xCF93, 0xCF93, 0xCF93}, {0xCF94, 0xCF94, 0xCF94}, {0xCF95, 0xCF95, 0xCF95}, {0xCF96, 0xCF96, 0xCF96}, {0xCF97, 0xCF97, 0xCF97}, {0xCF98, 0xCF98, 0xCF98}, {0xCF99, 0xCF99, 0xCF99}, {0xCF9A, 0xCF9A, 0xCF9A}, {0xCF9B, 0xCF9B, 0xCF9B}, {0xCF9C, 0xCF9C, 0xCF9C}, {0xCF9D, 0xCF9D, 0xCF9D}, {0xCF9E, 0xCF9E, 0xCF9E}, {0xCF9F, 0xCF9F, 0xCF9F}, {0xCFA0, 0xCFA0, 0xCFA0}, {0xCFA1, 0xCFA1, 0xCFA1}, {0xCFA2, 0xCFA2, 0xCFA2}, {0xCFA3, 0xCFA3, 0xCFA3}, {0xCFA4, 0xCFA4, 0xCFA4}, {0xCFA5, 0xCFA5, 0xCFA5}, {0xCFA6, 0xCFA6, 0xCFA6}, {0xCFA7, 0xCFA7, 0xCFA7}, {0xCFA8, 0xCFA8, 0xCFA8}, {0xCFA9, 0xCFA9, 0xCFA9}, {0xCFAA, 0xCFAA, 0xCFAA}, {0xCFAB, 0xCFAB, 0xCFAB}, {0xCFAC, 0xCFAC, 0xCFAC}, {0xCFAD, 0xCFAD, 0xCFAD}, {0xCFAE, 0xCFAE, 0xCFAE}, {0xCFAF, 0xCFAF, 0xCFAF}, {0xCFB0, 0xCFB0, 0xCFB0}, {0xCFB1, 0xCFB1, 0xCFB1}, {0xCFB2, 0xCFB2, 0xCFB2}, {0xCFB3, 0xCFB3, 0xCFB3}, {0xCFB4, 0xCFB4, 0xCFB4}, {0xCFB5, 0xCFB5, 0xCFB5}, {0xCFB6, 0xCFB6, 0xCFB6}, {0xCFB7, 0xCFB7, 0xCFB7}, {0xCFB8, 0xCFB8, 0xCFB8}, {0xCFB9, 0xCFB9, 0xCFB9}, {0xCFBA, 0xCFBA, 0xCFBA}, {0xCFBB, 0xCFBB, 0xCFBB}, {0xCFBC, 0xCFBC, 0xCFBC}, {0xCFBD, 0xCFBD, 0xCFBD}, {0xCFBE, 0xCFBE, 0xCFBE}, {0xCFBF, 0xCFBF, 0xCFBF}, {0xCFC0, 0xCFC0, 0xCFC0}, {0xCFC1, 0xCFC1, 0xCFC1}, {0xCFC2, 0xCFC2, 0xCFC2}, {0xCFC3, 0xCFC3, 0xCFC3}, {0xCFC4, 0xCFC4, 0xCFC4}, {0xCFC5, 0xCFC5, 0xCFC5}, {0xCFC6, 0xCFC6, 0xCFC6}, {0xCFC7, 0xCFC7, 0xCFC7}, {0xCFC8, 0xCFC8, 0xCFC8}, {0xCFC9, 0xCFC9, 0xCFC9}, {0xCFCA, 0xCFCA, 0xCFCA}, {0xCFCB, 0xCFCB, 0xCFCB}, {0xCFCC, 0xCFCC, 0xCFCC}, {0xCFCD, 0xCFCD, 0xCFCD}, {0xCFCE, 0xCFCE, 0xCFCE}, {0xCFCF, 0xCFCF, 0xCFCF}, {0xCFD0, 0xCFD0, 0xCFD0}, {0xCFD1, 0xCFD1, 0xCFD1}, {0xCFD2, 0xCFD2, 0xCFD2}, {0xCFD3, 0xCFD3, 0xCFD3}, {0xCFD4, 0xCFD4, 0xCFD4}, {0xCFD5, 0xCFD5, 0xCFD5}, {0xCFD6, 0xCFD6, 0xCFD6}, {0xCFD7, 0xCFD7, 0xCFD7}, {0xCFD8, 0xCFD8, 0xCFD8}, {0xCFD9, 0xCFD9, 0xCFD9}, {0xCFDA, 0xCFDA, 0xCFDA}, {0xCFDB, 0xCFDB, 0xCFDB}, {0xCFDC, 0xCFDC, 0xCFDC}, {0xCFDD, 0xCFDD, 0xCFDD}, {0xCFDE, 0xCFDE, 0xCFDE}, {0xCFDF, 0xCFDF, 0xCFDF}, {0xCFE0, 0xCFE0, 0xCFE0}, {0xCFE1, 0xCFE1, 0xCFE1}, {0xCFE2, 0xCFE2, 0xCFE2}, {0xCFE3, 0xCFE3, 0xCFE3}, {0xCFE4, 0xCFE4, 0xCFE4}, {0xCFE5, 0xCFE5, 0xCFE5}, {0xCFE6, 0xCFE6, 0xCFE6}, {0xCFE7, 0xCFE7, 0xCFE7}, {0xCFE8, 0xCFE8, 0xCFE8}, {0xCFE9, 0xCFE9, 0xCFE9}, {0xCFEA, 0xCFEA, 0xCFEA}, {0xCFEB, 0xCFEB, 0xCFEB}, {0xCFEC, 0xCFEC, 0xCFEC}, {0xCFED, 0xCFED, 0xCFED}, {0xCFEE, 0xCFEE, 0xCFEE}, {0xCFEF, 0xCFEF, 0xCFEF}, {0xCFF0, 0xCFF0, 0xCFF0}, {0xCFF1, 0xCFF1, 0xCFF1}, {0xCFF2, 0xCFF2, 0xCFF2}, {0xCFF3, 0xCFF3, 0xCFF3}, {0xCFF4, 0xCFF4, 0xCFF4}, {0xCFF5, 0xCFF5, 0xCFF5}, {0xCFF6, 0xCFF6, 0xCFF6}, {0xCFF7, 0xCFF7, 0xCFF7}, {0xCFF8, 0xCFF8, 0xCFF8}, {0xCFF9, 0xCFF9, 0xCFF9}, {0xCFFA, 0xCFFA, 0xCFFA}, {0xCFFB, 0xCFFB, 0xCFFB}, {0xCFFC, 0xCFFC, 0xCFFC}, {0xCFFD, 0xCFFD, 0xCFFD}, {0xCFFE, 0xCFFE, 0xCFFE}, {0xCFFF, 0xCFFF, 0xCFFF}, {0xD000, 0xD000, 0xD000}, {0xD001, 0xD001, 0xD001}, {0xD002, 0xD002, 0xD002}, {0xD003, 0xD003, 0xD003}, {0xD004, 0xD004, 0xD004}, {0xD005, 0xD005, 0xD005}, {0xD006, 0xD006, 0xD006}, {0xD007, 0xD007, 0xD007}, {0xD008, 0xD008, 0xD008}, {0xD009, 0xD009, 0xD009}, {0xD00A, 0xD00A, 0xD00A}, {0xD00B, 0xD00B, 0xD00B}, {0xD00C, 0xD00C, 0xD00C}, {0xD00D, 0xD00D, 0xD00D}, {0xD00E, 0xD00E, 0xD00E}, {0xD00F, 0xD00F, 0xD00F}, {0xD010, 0xD010, 0xD010}, {0xD011, 0xD011, 0xD011}, {0xD012, 0xD012, 0xD012}, {0xD013, 0xD013, 0xD013}, {0xD014, 0xD014, 0xD014}, {0xD015, 0xD015, 0xD015}, {0xD016, 0xD016, 0xD016}, {0xD017, 0xD017, 0xD017}, {0xD018, 0xD018, 0xD018}, {0xD019, 0xD019, 0xD019}, {0xD01A, 0xD01A, 0xD01A}, {0xD01B, 0xD01B, 0xD01B}, {0xD01C, 0xD01C, 0xD01C}, {0xD01D, 0xD01D, 0xD01D}, {0xD01E, 0xD01E, 0xD01E}, {0xD01F, 0xD01F, 0xD01F}, {0xD020, 0xD020, 0xD020}, {0xD021, 0xD021, 0xD021}, {0xD022, 0xD022, 0xD022}, {0xD023, 0xD023, 0xD023}, {0xD024, 0xD024, 0xD024}, {0xD025, 0xD025, 0xD025}, {0xD026, 0xD026, 0xD026}, {0xD027, 0xD027, 0xD027}, {0xD028, 0xD028, 0xD028}, {0xD029, 0xD029, 0xD029}, {0xD02A, 0xD02A, 0xD02A}, {0xD02B, 0xD02B, 0xD02B}, {0xD02C, 0xD02C, 0xD02C}, {0xD02D, 0xD02D, 0xD02D}, {0xD02E, 0xD02E, 0xD02E}, {0xD02F, 0xD02F, 0xD02F}, {0xD030, 0xD030, 0xD030}, {0xD031, 0xD031, 0xD031}, {0xD032, 0xD032, 0xD032}, {0xD033, 0xD033, 0xD033}, {0xD034, 0xD034, 0xD034}, {0xD035, 0xD035, 0xD035}, {0xD036, 0xD036, 0xD036}, {0xD037, 0xD037, 0xD037}, {0xD038, 0xD038, 0xD038}, {0xD039, 0xD039, 0xD039}, {0xD03A, 0xD03A, 0xD03A}, {0xD03B, 0xD03B, 0xD03B}, {0xD03C, 0xD03C, 0xD03C}, {0xD03D, 0xD03D, 0xD03D}, {0xD03E, 0xD03E, 0xD03E}, {0xD03F, 0xD03F, 0xD03F}, {0xD040, 0xD040, 0xD040}, {0xD041, 0xD041, 0xD041}, {0xD042, 0xD042, 0xD042}, {0xD043, 0xD043, 0xD043}, {0xD044, 0xD044, 0xD044}, {0xD045, 0xD045, 0xD045}, {0xD046, 0xD046, 0xD046}, {0xD047, 0xD047, 0xD047}, {0xD048, 0xD048, 0xD048}, {0xD049, 0xD049, 0xD049}, {0xD04A, 0xD04A, 0xD04A}, {0xD04B, 0xD04B, 0xD04B}, {0xD04C, 0xD04C, 0xD04C}, {0xD04D, 0xD04D, 0xD04D}, {0xD04E, 0xD04E, 0xD04E}, {0xD04F, 0xD04F, 0xD04F}, {0xD050, 0xD050, 0xD050}, {0xD051, 0xD051, 0xD051}, {0xD052, 0xD052, 0xD052}, {0xD053, 0xD053, 0xD053}, {0xD054, 0xD054, 0xD054}, {0xD055, 0xD055, 0xD055}, {0xD056, 0xD056, 0xD056}, {0xD057, 0xD057, 0xD057}, {0xD058, 0xD058, 0xD058}, {0xD059, 0xD059, 0xD059}, {0xD05A, 0xD05A, 0xD05A}, {0xD05B, 0xD05B, 0xD05B}, {0xD05C, 0xD05C, 0xD05C}, {0xD05D, 0xD05D, 0xD05D}, {0xD05E, 0xD05E, 0xD05E}, {0xD05F, 0xD05F, 0xD05F}, {0xD060, 0xD060, 0xD060}, {0xD061, 0xD061, 0xD061}, {0xD062, 0xD062, 0xD062}, {0xD063, 0xD063, 0xD063}, {0xD064, 0xD064, 0xD064}, {0xD065, 0xD065, 0xD065}, {0xD066, 0xD066, 0xD066}, {0xD067, 0xD067, 0xD067}, {0xD068, 0xD068, 0xD068}, {0xD069, 0xD069, 0xD069}, {0xD06A, 0xD06A, 0xD06A}, {0xD06B, 0xD06B, 0xD06B}, {0xD06C, 0xD06C, 0xD06C}, {0xD06D, 0xD06D, 0xD06D}, {0xD06E, 0xD06E, 0xD06E}, {0xD06F, 0xD06F, 0xD06F}, {0xD070, 0xD070, 0xD070}, {0xD071, 0xD071, 0xD071}, {0xD072, 0xD072, 0xD072}, {0xD073, 0xD073, 0xD073}, {0xD074, 0xD074, 0xD074}, {0xD075, 0xD075, 0xD075}, {0xD076, 0xD076, 0xD076}, {0xD077, 0xD077, 0xD077}, {0xD078, 0xD078, 0xD078}, {0xD079, 0xD079, 0xD079}, {0xD07A, 0xD07A, 0xD07A}, {0xD07B, 0xD07B, 0xD07B}, {0xD07C, 0xD07C, 0xD07C}, {0xD07D, 0xD07D, 0xD07D}, {0xD07E, 0xD07E, 0xD07E}, {0xD07F, 0xD07F, 0xD07F}, {0xD080, 0xD080, 0xD080}, {0xD081, 0xD081, 0xD081}, {0xD082, 0xD082, 0xD082}, {0xD083, 0xD083, 0xD083}, {0xD084, 0xD084, 0xD084}, {0xD085, 0xD085, 0xD085}, {0xD086, 0xD086, 0xD086}, {0xD087, 0xD087, 0xD087}, {0xD088, 0xD088, 0xD088}, {0xD089, 0xD089, 0xD089}, {0xD08A, 0xD08A, 0xD08A}, {0xD08B, 0xD08B, 0xD08B}, {0xD08C, 0xD08C, 0xD08C}, {0xD08D, 0xD08D, 0xD08D}, {0xD08E, 0xD08E, 0xD08E}, {0xD08F, 0xD08F, 0xD08F}, {0xD090, 0xD090, 0xD090}, {0xD091, 0xD091, 0xD091}, {0xD092, 0xD092, 0xD092}, {0xD093, 0xD093, 0xD093}, {0xD094, 0xD094, 0xD094}, {0xD095, 0xD095, 0xD095}, {0xD096, 0xD096, 0xD096}, {0xD097, 0xD097, 0xD097}, {0xD098, 0xD098, 0xD098}, {0xD099, 0xD099, 0xD099}, {0xD09A, 0xD09A, 0xD09A}, {0xD09B, 0xD09B, 0xD09B}, {0xD09C, 0xD09C, 0xD09C}, {0xD09D, 0xD09D, 0xD09D}, {0xD09E, 0xD09E, 0xD09E}, {0xD09F, 0xD09F, 0xD09F}, {0xD0A0, 0xD0A0, 0xD0A0}, {0xD0A1, 0xD0A1, 0xD0A1}, {0xD0A2, 0xD0A2, 0xD0A2}, {0xD0A3, 0xD0A3, 0xD0A3}, {0xD0A4, 0xD0A4, 0xD0A4}, {0xD0A5, 0xD0A5, 0xD0A5}, {0xD0A6, 0xD0A6, 0xD0A6}, {0xD0A7, 0xD0A7, 0xD0A7}, {0xD0A8, 0xD0A8, 0xD0A8}, {0xD0A9, 0xD0A9, 0xD0A9}, {0xD0AA, 0xD0AA, 0xD0AA}, {0xD0AB, 0xD0AB, 0xD0AB}, {0xD0AC, 0xD0AC, 0xD0AC}, {0xD0AD, 0xD0AD, 0xD0AD}, {0xD0AE, 0xD0AE, 0xD0AE}, {0xD0AF, 0xD0AF, 0xD0AF}, {0xD0B0, 0xD0B0, 0xD0B0}, {0xD0B1, 0xD0B1, 0xD0B1}, {0xD0B2, 0xD0B2, 0xD0B2}, {0xD0B3, 0xD0B3, 0xD0B3}, {0xD0B4, 0xD0B4, 0xD0B4}, {0xD0B5, 0xD0B5, 0xD0B5}, {0xD0B6, 0xD0B6, 0xD0B6}, {0xD0B7, 0xD0B7, 0xD0B7}, {0xD0B8, 0xD0B8, 0xD0B8}, {0xD0B9, 0xD0B9, 0xD0B9}, {0xD0BA, 0xD0BA, 0xD0BA}, {0xD0BB, 0xD0BB, 0xD0BB}, {0xD0BC, 0xD0BC, 0xD0BC}, {0xD0BD, 0xD0BD, 0xD0BD}, {0xD0BE, 0xD0BE, 0xD0BE}, {0xD0BF, 0xD0BF, 0xD0BF}, {0xD0C0, 0xD0C0, 0xD0C0}, {0xD0C1, 0xD0C1, 0xD0C1}, {0xD0C2, 0xD0C2, 0xD0C2}, {0xD0C3, 0xD0C3, 0xD0C3}, {0xD0C4, 0xD0C4, 0xD0C4}, {0xD0C5, 0xD0C5, 0xD0C5}, {0xD0C6, 0xD0C6, 0xD0C6}, {0xD0C7, 0xD0C7, 0xD0C7}, {0xD0C8, 0xD0C8, 0xD0C8}, {0xD0C9, 0xD0C9, 0xD0C9}, {0xD0CA, 0xD0CA, 0xD0CA}, {0xD0CB, 0xD0CB, 0xD0CB}, {0xD0CC, 0xD0CC, 0xD0CC}, {0xD0CD, 0xD0CD, 0xD0CD}, {0xD0CE, 0xD0CE, 0xD0CE}, {0xD0CF, 0xD0CF, 0xD0CF}, {0xD0D0, 0xD0D0, 0xD0D0}, {0xD0D1, 0xD0D1, 0xD0D1}, {0xD0D2, 0xD0D2, 0xD0D2}, {0xD0D3, 0xD0D3, 0xD0D3}, {0xD0D4, 0xD0D4, 0xD0D4}, {0xD0D5, 0xD0D5, 0xD0D5}, {0xD0D6, 0xD0D6, 0xD0D6}, {0xD0D7, 0xD0D7, 0xD0D7}, {0xD0D8, 0xD0D8, 0xD0D8}, {0xD0D9, 0xD0D9, 0xD0D9}, {0xD0DA, 0xD0DA, 0xD0DA}, {0xD0DB, 0xD0DB, 0xD0DB}, {0xD0DC, 0xD0DC, 0xD0DC}, {0xD0DD, 0xD0DD, 0xD0DD}, {0xD0DE, 0xD0DE, 0xD0DE}, {0xD0DF, 0xD0DF, 0xD0DF}, {0xD0E0, 0xD0E0, 0xD0E0}, {0xD0E1, 0xD0E1, 0xD0E1}, {0xD0E2, 0xD0E2, 0xD0E2}, {0xD0E3, 0xD0E3, 0xD0E3}, {0xD0E4, 0xD0E4, 0xD0E4}, {0xD0E5, 0xD0E5, 0xD0E5}, {0xD0E6, 0xD0E6, 0xD0E6}, {0xD0E7, 0xD0E7, 0xD0E7}, {0xD0E8, 0xD0E8, 0xD0E8}, {0xD0E9, 0xD0E9, 0xD0E9}, {0xD0EA, 0xD0EA, 0xD0EA}, {0xD0EB, 0xD0EB, 0xD0EB}, {0xD0EC, 0xD0EC, 0xD0EC}, {0xD0ED, 0xD0ED, 0xD0ED}, {0xD0EE, 0xD0EE, 0xD0EE}, {0xD0EF, 0xD0EF, 0xD0EF}, {0xD0F0, 0xD0F0, 0xD0F0}, {0xD0F1, 0xD0F1, 0xD0F1}, {0xD0F2, 0xD0F2, 0xD0F2}, {0xD0F3, 0xD0F3, 0xD0F3}, {0xD0F4, 0xD0F4, 0xD0F4}, {0xD0F5, 0xD0F5, 0xD0F5}, {0xD0F6, 0xD0F6, 0xD0F6}, {0xD0F7, 0xD0F7, 0xD0F7}, {0xD0F8, 0xD0F8, 0xD0F8}, {0xD0F9, 0xD0F9, 0xD0F9}, {0xD0FA, 0xD0FA, 0xD0FA}, {0xD0FB, 0xD0FB, 0xD0FB}, {0xD0FC, 0xD0FC, 0xD0FC}, {0xD0FD, 0xD0FD, 0xD0FD}, {0xD0FE, 0xD0FE, 0xD0FE}, {0xD0FF, 0xD0FF, 0xD0FF}, {0xD100, 0xD100, 0xD100}, {0xD101, 0xD101, 0xD101}, {0xD102, 0xD102, 0xD102}, {0xD103, 0xD103, 0xD103}, {0xD104, 0xD104, 0xD104}, {0xD105, 0xD105, 0xD105}, {0xD106, 0xD106, 0xD106}, {0xD107, 0xD107, 0xD107}, {0xD108, 0xD108, 0xD108}, {0xD109, 0xD109, 0xD109}, {0xD10A, 0xD10A, 0xD10A}, {0xD10B, 0xD10B, 0xD10B}, {0xD10C, 0xD10C, 0xD10C}, {0xD10D, 0xD10D, 0xD10D}, {0xD10E, 0xD10E, 0xD10E}, {0xD10F, 0xD10F, 0xD10F}, {0xD110, 0xD110, 0xD110}, {0xD111, 0xD111, 0xD111}, {0xD112, 0xD112, 0xD112}, {0xD113, 0xD113, 0xD113}, {0xD114, 0xD114, 0xD114}, {0xD115, 0xD115, 0xD115}, {0xD116, 0xD116, 0xD116}, {0xD117, 0xD117, 0xD117}, {0xD118, 0xD118, 0xD118}, {0xD119, 0xD119, 0xD119}, {0xD11A, 0xD11A, 0xD11A}, {0xD11B, 0xD11B, 0xD11B}, {0xD11C, 0xD11C, 0xD11C}, {0xD11D, 0xD11D, 0xD11D}, {0xD11E, 0xD11E, 0xD11E}, {0xD11F, 0xD11F, 0xD11F}, {0xD120, 0xD120, 0xD120}, {0xD121, 0xD121, 0xD121}, {0xD122, 0xD122, 0xD122}, {0xD123, 0xD123, 0xD123}, {0xD124, 0xD124, 0xD124}, {0xD125, 0xD125, 0xD125}, {0xD126, 0xD126, 0xD126}, {0xD127, 0xD127, 0xD127}, {0xD128, 0xD128, 0xD128}, {0xD129, 0xD129, 0xD129}, {0xD12A, 0xD12A, 0xD12A}, {0xD12B, 0xD12B, 0xD12B}, {0xD12C, 0xD12C, 0xD12C}, {0xD12D, 0xD12D, 0xD12D}, {0xD12E, 0xD12E, 0xD12E}, {0xD12F, 0xD12F, 0xD12F}, {0xD130, 0xD130, 0xD130}, {0xD131, 0xD131, 0xD131}, {0xD132, 0xD132, 0xD132}, {0xD133, 0xD133, 0xD133}, {0xD134, 0xD134, 0xD134}, {0xD135, 0xD135, 0xD135}, {0xD136, 0xD136, 0xD136}, {0xD137, 0xD137, 0xD137}, {0xD138, 0xD138, 0xD138}, {0xD139, 0xD139, 0xD139}, {0xD13A, 0xD13A, 0xD13A}, {0xD13B, 0xD13B, 0xD13B}, {0xD13C, 0xD13C, 0xD13C}, {0xD13D, 0xD13D, 0xD13D}, {0xD13E, 0xD13E, 0xD13E}, {0xD13F, 0xD13F, 0xD13F}, {0xD140, 0xD140, 0xD140}, {0xD141, 0xD141, 0xD141}, {0xD142, 0xD142, 0xD142}, {0xD143, 0xD143, 0xD143}, {0xD144, 0xD144, 0xD144}, {0xD145, 0xD145, 0xD145}, {0xD146, 0xD146, 0xD146}, {0xD147, 0xD147, 0xD147}, {0xD148, 0xD148, 0xD148}, {0xD149, 0xD149, 0xD149}, {0xD14A, 0xD14A, 0xD14A}, {0xD14B, 0xD14B, 0xD14B}, {0xD14C, 0xD14C, 0xD14C}, {0xD14D, 0xD14D, 0xD14D}, {0xD14E, 0xD14E, 0xD14E}, {0xD14F, 0xD14F, 0xD14F}, {0xD150, 0xD150, 0xD150}, {0xD151, 0xD151, 0xD151}, {0xD152, 0xD152, 0xD152}, {0xD153, 0xD153, 0xD153}, {0xD154, 0xD154, 0xD154}, {0xD155, 0xD155, 0xD155}, {0xD156, 0xD156, 0xD156}, {0xD157, 0xD157, 0xD157}, {0xD158, 0xD158, 0xD158}, {0xD159, 0xD159, 0xD159}, {0xD15A, 0xD15A, 0xD15A}, {0xD15B, 0xD15B, 0xD15B}, {0xD15C, 0xD15C, 0xD15C}, {0xD15D, 0xD15D, 0xD15D}, {0xD15E, 0xD15E, 0xD15E}, {0xD15F, 0xD15F, 0xD15F}, {0xD160, 0xD160, 0xD160}, {0xD161, 0xD161, 0xD161}, {0xD162, 0xD162, 0xD162}, {0xD163, 0xD163, 0xD163}, {0xD164, 0xD164, 0xD164}, {0xD165, 0xD165, 0xD165}, {0xD166, 0xD166, 0xD166}, {0xD167, 0xD167, 0xD167}, {0xD168, 0xD168, 0xD168}, {0xD169, 0xD169, 0xD169}, {0xD16A, 0xD16A, 0xD16A}, {0xD16B, 0xD16B, 0xD16B}, {0xD16C, 0xD16C, 0xD16C}, {0xD16D, 0xD16D, 0xD16D}, {0xD16E, 0xD16E, 0xD16E}, {0xD16F, 0xD16F, 0xD16F}, {0xD170, 0xD170, 0xD170}, {0xD171, 0xD171, 0xD171}, {0xD172, 0xD172, 0xD172}, {0xD173, 0xD173, 0xD173}, {0xD174, 0xD174, 0xD174}, {0xD175, 0xD175, 0xD175}, {0xD176, 0xD176, 0xD176}, {0xD177, 0xD177, 0xD177}, {0xD178, 0xD178, 0xD178}, {0xD179, 0xD179, 0xD179}, {0xD17A, 0xD17A, 0xD17A}, {0xD17B, 0xD17B, 0xD17B}, {0xD17C, 0xD17C, 0xD17C}, {0xD17D, 0xD17D, 0xD17D}, {0xD17E, 0xD17E, 0xD17E}, {0xD17F, 0xD17F, 0xD17F}, {0xD180, 0xD180, 0xD180}, {0xD181, 0xD181, 0xD181}, {0xD182, 0xD182, 0xD182}, {0xD183, 0xD183, 0xD183}, {0xD184, 0xD184, 0xD184}, {0xD185, 0xD185, 0xD185}, {0xD186, 0xD186, 0xD186}, {0xD187, 0xD187, 0xD187}, {0xD188, 0xD188, 0xD188}, {0xD189, 0xD189, 0xD189}, {0xD18A, 0xD18A, 0xD18A}, {0xD18B, 0xD18B, 0xD18B}, {0xD18C, 0xD18C, 0xD18C}, {0xD18D, 0xD18D, 0xD18D}, {0xD18E, 0xD18E, 0xD18E}, {0xD18F, 0xD18F, 0xD18F}, {0xD190, 0xD190, 0xD190}, {0xD191, 0xD191, 0xD191}, {0xD192, 0xD192, 0xD192}, {0xD193, 0xD193, 0xD193}, {0xD194, 0xD194, 0xD194}, {0xD195, 0xD195, 0xD195}, {0xD196, 0xD196, 0xD196}, {0xD197, 0xD197, 0xD197}, {0xD198, 0xD198, 0xD198}, {0xD199, 0xD199, 0xD199}, {0xD19A, 0xD19A, 0xD19A}, {0xD19B, 0xD19B, 0xD19B}, {0xD19C, 0xD19C, 0xD19C}, {0xD19D, 0xD19D, 0xD19D}, {0xD19E, 0xD19E, 0xD19E}, {0xD19F, 0xD19F, 0xD19F}, {0xD1A0, 0xD1A0, 0xD1A0}, {0xD1A1, 0xD1A1, 0xD1A1}, {0xD1A2, 0xD1A2, 0xD1A2}, {0xD1A3, 0xD1A3, 0xD1A3}, {0xD1A4, 0xD1A4, 0xD1A4}, {0xD1A5, 0xD1A5, 0xD1A5}, {0xD1A6, 0xD1A6, 0xD1A6}, {0xD1A7, 0xD1A7, 0xD1A7}, {0xD1A8, 0xD1A8, 0xD1A8}, {0xD1A9, 0xD1A9, 0xD1A9}, {0xD1AA, 0xD1AA, 0xD1AA}, {0xD1AB, 0xD1AB, 0xD1AB}, {0xD1AC, 0xD1AC, 0xD1AC}, {0xD1AD, 0xD1AD, 0xD1AD}, {0xD1AE, 0xD1AE, 0xD1AE}, {0xD1AF, 0xD1AF, 0xD1AF}, {0xD1B0, 0xD1B0, 0xD1B0}, {0xD1B1, 0xD1B1, 0xD1B1}, {0xD1B2, 0xD1B2, 0xD1B2}, {0xD1B3, 0xD1B3, 0xD1B3}, {0xD1B4, 0xD1B4, 0xD1B4}, {0xD1B5, 0xD1B5, 0xD1B5}, {0xD1B6, 0xD1B6, 0xD1B6}, {0xD1B7, 0xD1B7, 0xD1B7}, {0xD1B8, 0xD1B8, 0xD1B8}, {0xD1B9, 0xD1B9, 0xD1B9}, {0xD1BA, 0xD1BA, 0xD1BA}, {0xD1BB, 0xD1BB, 0xD1BB}, {0xD1BC, 0xD1BC, 0xD1BC}, {0xD1BD, 0xD1BD, 0xD1BD}, {0xD1BE, 0xD1BE, 0xD1BE}, {0xD1BF, 0xD1BF, 0xD1BF}, {0xD1C0, 0xD1C0, 0xD1C0}, {0xD1C1, 0xD1C1, 0xD1C1}, {0xD1C2, 0xD1C2, 0xD1C2}, {0xD1C3, 0xD1C3, 0xD1C3}, {0xD1C4, 0xD1C4, 0xD1C4}, {0xD1C5, 0xD1C5, 0xD1C5}, {0xD1C6, 0xD1C6, 0xD1C6}, {0xD1C7, 0xD1C7, 0xD1C7}, {0xD1C8, 0xD1C8, 0xD1C8}, {0xD1C9, 0xD1C9, 0xD1C9}, {0xD1CA, 0xD1CA, 0xD1CA}, {0xD1CB, 0xD1CB, 0xD1CB}, {0xD1CC, 0xD1CC, 0xD1CC}, {0xD1CD, 0xD1CD, 0xD1CD}, {0xD1CE, 0xD1CE, 0xD1CE}, {0xD1CF, 0xD1CF, 0xD1CF}, {0xD1D0, 0xD1D0, 0xD1D0}, {0xD1D1, 0xD1D1, 0xD1D1}, {0xD1D2, 0xD1D2, 0xD1D2}, {0xD1D3, 0xD1D3, 0xD1D3}, {0xD1D4, 0xD1D4, 0xD1D4}, {0xD1D5, 0xD1D5, 0xD1D5}, {0xD1D6, 0xD1D6, 0xD1D6}, {0xD1D7, 0xD1D7, 0xD1D7}, {0xD1D8, 0xD1D8, 0xD1D8}, {0xD1D9, 0xD1D9, 0xD1D9}, {0xD1DA, 0xD1DA, 0xD1DA}, {0xD1DB, 0xD1DB, 0xD1DB}, {0xD1DC, 0xD1DC, 0xD1DC}, {0xD1DD, 0xD1DD, 0xD1DD}, {0xD1DE, 0xD1DE, 0xD1DE}, {0xD1DF, 0xD1DF, 0xD1DF}, {0xD1E0, 0xD1E0, 0xD1E0}, {0xD1E1, 0xD1E1, 0xD1E1}, {0xD1E2, 0xD1E2, 0xD1E2}, {0xD1E3, 0xD1E3, 0xD1E3}, {0xD1E4, 0xD1E4, 0xD1E4}, {0xD1E5, 0xD1E5, 0xD1E5}, {0xD1E6, 0xD1E6, 0xD1E6}, {0xD1E7, 0xD1E7, 0xD1E7}, {0xD1E8, 0xD1E8, 0xD1E8}, {0xD1E9, 0xD1E9, 0xD1E9}, {0xD1EA, 0xD1EA, 0xD1EA}, {0xD1EB, 0xD1EB, 0xD1EB}, {0xD1EC, 0xD1EC, 0xD1EC}, {0xD1ED, 0xD1ED, 0xD1ED}, {0xD1EE, 0xD1EE, 0xD1EE}, {0xD1EF, 0xD1EF, 0xD1EF}, {0xD1F0, 0xD1F0, 0xD1F0}, {0xD1F1, 0xD1F1, 0xD1F1}, {0xD1F2, 0xD1F2, 0xD1F2}, {0xD1F3, 0xD1F3, 0xD1F3}, {0xD1F4, 0xD1F4, 0xD1F4}, {0xD1F5, 0xD1F5, 0xD1F5}, {0xD1F6, 0xD1F6, 0xD1F6}, {0xD1F7, 0xD1F7, 0xD1F7}, {0xD1F8, 0xD1F8, 0xD1F8}, {0xD1F9, 0xD1F9, 0xD1F9}, {0xD1FA, 0xD1FA, 0xD1FA}, {0xD1FB, 0xD1FB, 0xD1FB}, {0xD1FC, 0xD1FC, 0xD1FC}, {0xD1FD, 0xD1FD, 0xD1FD}, {0xD1FE, 0xD1FE, 0xD1FE}, {0xD1FF, 0xD1FF, 0xD1FF}, {0xD200, 0xD200, 0xD200}, {0xD201, 0xD201, 0xD201}, {0xD202, 0xD202, 0xD202}, {0xD203, 0xD203, 0xD203}, {0xD204, 0xD204, 0xD204}, {0xD205, 0xD205, 0xD205}, {0xD206, 0xD206, 0xD206}, {0xD207, 0xD207, 0xD207}, {0xD208, 0xD208, 0xD208}, {0xD209, 0xD209, 0xD209}, {0xD20A, 0xD20A, 0xD20A}, {0xD20B, 0xD20B, 0xD20B}, {0xD20C, 0xD20C, 0xD20C}, {0xD20D, 0xD20D, 0xD20D}, {0xD20E, 0xD20E, 0xD20E}, {0xD20F, 0xD20F, 0xD20F}, {0xD210, 0xD210, 0xD210}, {0xD211, 0xD211, 0xD211}, {0xD212, 0xD212, 0xD212}, {0xD213, 0xD213, 0xD213}, {0xD214, 0xD214, 0xD214}, {0xD215, 0xD215, 0xD215}, {0xD216, 0xD216, 0xD216}, {0xD217, 0xD217, 0xD217}, {0xD218, 0xD218, 0xD218}, {0xD219, 0xD219, 0xD219}, {0xD21A, 0xD21A, 0xD21A}, {0xD21B, 0xD21B, 0xD21B}, {0xD21C, 0xD21C, 0xD21C}, {0xD21D, 0xD21D, 0xD21D}, {0xD21E, 0xD21E, 0xD21E}, {0xD21F, 0xD21F, 0xD21F}, {0xD220, 0xD220, 0xD220}, {0xD221, 0xD221, 0xD221}, {0xD222, 0xD222, 0xD222}, {0xD223, 0xD223, 0xD223}, {0xD224, 0xD224, 0xD224}, {0xD225, 0xD225, 0xD225}, {0xD226, 0xD226, 0xD226}, {0xD227, 0xD227, 0xD227}, {0xD228, 0xD228, 0xD228}, {0xD229, 0xD229, 0xD229}, {0xD22A, 0xD22A, 0xD22A}, {0xD22B, 0xD22B, 0xD22B}, {0xD22C, 0xD22C, 0xD22C}, {0xD22D, 0xD22D, 0xD22D}, {0xD22E, 0xD22E, 0xD22E}, {0xD22F, 0xD22F, 0xD22F}, {0xD230, 0xD230, 0xD230}, {0xD231, 0xD231, 0xD231}, {0xD232, 0xD232, 0xD232}, {0xD233, 0xD233, 0xD233}, {0xD234, 0xD234, 0xD234}, {0xD235, 0xD235, 0xD235}, {0xD236, 0xD236, 0xD236}, {0xD237, 0xD237, 0xD237}, {0xD238, 0xD238, 0xD238}, {0xD239, 0xD239, 0xD239}, {0xD23A, 0xD23A, 0xD23A}, {0xD23B, 0xD23B, 0xD23B}, {0xD23C, 0xD23C, 0xD23C}, {0xD23D, 0xD23D, 0xD23D}, {0xD23E, 0xD23E, 0xD23E}, {0xD23F, 0xD23F, 0xD23F}, {0xD240, 0xD240, 0xD240}, {0xD241, 0xD241, 0xD241}, {0xD242, 0xD242, 0xD242}, {0xD243, 0xD243, 0xD243}, {0xD244, 0xD244, 0xD244}, {0xD245, 0xD245, 0xD245}, {0xD246, 0xD246, 0xD246}, {0xD247, 0xD247, 0xD247}, {0xD248, 0xD248, 0xD248}, {0xD249, 0xD249, 0xD249}, {0xD24A, 0xD24A, 0xD24A}, {0xD24B, 0xD24B, 0xD24B}, {0xD24C, 0xD24C, 0xD24C}, {0xD24D, 0xD24D, 0xD24D}, {0xD24E, 0xD24E, 0xD24E}, {0xD24F, 0xD24F, 0xD24F}, {0xD250, 0xD250, 0xD250}, {0xD251, 0xD251, 0xD251}, {0xD252, 0xD252, 0xD252}, {0xD253, 0xD253, 0xD253}, {0xD254, 0xD254, 0xD254}, {0xD255, 0xD255, 0xD255}, {0xD256, 0xD256, 0xD256}, {0xD257, 0xD257, 0xD257}, {0xD258, 0xD258, 0xD258}, {0xD259, 0xD259, 0xD259}, {0xD25A, 0xD25A, 0xD25A}, {0xD25B, 0xD25B, 0xD25B}, {0xD25C, 0xD25C, 0xD25C}, {0xD25D, 0xD25D, 0xD25D}, {0xD25E, 0xD25E, 0xD25E}, {0xD25F, 0xD25F, 0xD25F}, {0xD260, 0xD260, 0xD260}, {0xD261, 0xD261, 0xD261}, {0xD262, 0xD262, 0xD262}, {0xD263, 0xD263, 0xD263}, {0xD264, 0xD264, 0xD264}, {0xD265, 0xD265, 0xD265}, {0xD266, 0xD266, 0xD266}, {0xD267, 0xD267, 0xD267}, {0xD268, 0xD268, 0xD268}, {0xD269, 0xD269, 0xD269}, {0xD26A, 0xD26A, 0xD26A}, {0xD26B, 0xD26B, 0xD26B}, {0xD26C, 0xD26C, 0xD26C}, {0xD26D, 0xD26D, 0xD26D}, {0xD26E, 0xD26E, 0xD26E}, {0xD26F, 0xD26F, 0xD26F}, {0xD270, 0xD270, 0xD270}, {0xD271, 0xD271, 0xD271}, {0xD272, 0xD272, 0xD272}, {0xD273, 0xD273, 0xD273}, {0xD274, 0xD274, 0xD274}, {0xD275, 0xD275, 0xD275}, {0xD276, 0xD276, 0xD276}, {0xD277, 0xD277, 0xD277}, {0xD278, 0xD278, 0xD278}, {0xD279, 0xD279, 0xD279}, {0xD27A, 0xD27A, 0xD27A}, {0xD27B, 0xD27B, 0xD27B}, {0xD27C, 0xD27C, 0xD27C}, {0xD27D, 0xD27D, 0xD27D}, {0xD27E, 0xD27E, 0xD27E}, {0xD27F, 0xD27F, 0xD27F}, {0xD280, 0xD280, 0xD280}, {0xD281, 0xD281, 0xD281}, {0xD282, 0xD282, 0xD282}, {0xD283, 0xD283, 0xD283}, {0xD284, 0xD284, 0xD284}, {0xD285, 0xD285, 0xD285}, {0xD286, 0xD286, 0xD286}, {0xD287, 0xD287, 0xD287}, {0xD288, 0xD288, 0xD288}, {0xD289, 0xD289, 0xD289}, {0xD28A, 0xD28A, 0xD28A}, {0xD28B, 0xD28B, 0xD28B}, {0xD28C, 0xD28C, 0xD28C}, {0xD28D, 0xD28D, 0xD28D}, {0xD28E, 0xD28E, 0xD28E}, {0xD28F, 0xD28F, 0xD28F}, {0xD290, 0xD290, 0xD290}, {0xD291, 0xD291, 0xD291}, {0xD292, 0xD292, 0xD292}, {0xD293, 0xD293, 0xD293}, {0xD294, 0xD294, 0xD294}, {0xD295, 0xD295, 0xD295}, {0xD296, 0xD296, 0xD296}, {0xD297, 0xD297, 0xD297}, {0xD298, 0xD298, 0xD298}, {0xD299, 0xD299, 0xD299}, {0xD29A, 0xD29A, 0xD29A}, {0xD29B, 0xD29B, 0xD29B}, {0xD29C, 0xD29C, 0xD29C}, {0xD29D, 0xD29D, 0xD29D}, {0xD29E, 0xD29E, 0xD29E}, {0xD29F, 0xD29F, 0xD29F}, {0xD2A0, 0xD2A0, 0xD2A0}, {0xD2A1, 0xD2A1, 0xD2A1}, {0xD2A2, 0xD2A2, 0xD2A2}, {0xD2A3, 0xD2A3, 0xD2A3}, {0xD2A4, 0xD2A4, 0xD2A4}, {0xD2A5, 0xD2A5, 0xD2A5}, {0xD2A6, 0xD2A6, 0xD2A6}, {0xD2A7, 0xD2A7, 0xD2A7}, {0xD2A8, 0xD2A8, 0xD2A8}, {0xD2A9, 0xD2A9, 0xD2A9}, {0xD2AA, 0xD2AA, 0xD2AA}, {0xD2AB, 0xD2AB, 0xD2AB}, {0xD2AC, 0xD2AC, 0xD2AC}, {0xD2AD, 0xD2AD, 0xD2AD}, {0xD2AE, 0xD2AE, 0xD2AE}, {0xD2AF, 0xD2AF, 0xD2AF}, {0xD2B0, 0xD2B0, 0xD2B0}, {0xD2B1, 0xD2B1, 0xD2B1}, {0xD2B2, 0xD2B2, 0xD2B2}, {0xD2B3, 0xD2B3, 0xD2B3}, {0xD2B4, 0xD2B4, 0xD2B4}, {0xD2B5, 0xD2B5, 0xD2B5}, {0xD2B6, 0xD2B6, 0xD2B6}, {0xD2B7, 0xD2B7, 0xD2B7}, {0xD2B8, 0xD2B8, 0xD2B8}, {0xD2B9, 0xD2B9, 0xD2B9}, {0xD2BA, 0xD2BA, 0xD2BA}, {0xD2BB, 0xD2BB, 0xD2BB}, {0xD2BC, 0xD2BC, 0xD2BC}, {0xD2BD, 0xD2BD, 0xD2BD}, {0xD2BE, 0xD2BE, 0xD2BE}, {0xD2BF, 0xD2BF, 0xD2BF}, {0xD2C0, 0xD2C0, 0xD2C0}, {0xD2C1, 0xD2C1, 0xD2C1}, {0xD2C2, 0xD2C2, 0xD2C2}, {0xD2C3, 0xD2C3, 0xD2C3}, {0xD2C4, 0xD2C4, 0xD2C4}, {0xD2C5, 0xD2C5, 0xD2C5}, {0xD2C6, 0xD2C6, 0xD2C6}, {0xD2C7, 0xD2C7, 0xD2C7}, {0xD2C8, 0xD2C8, 0xD2C8}, {0xD2C9, 0xD2C9, 0xD2C9}, {0xD2CA, 0xD2CA, 0xD2CA}, {0xD2CB, 0xD2CB, 0xD2CB}, {0xD2CC, 0xD2CC, 0xD2CC}, {0xD2CD, 0xD2CD, 0xD2CD}, {0xD2CE, 0xD2CE, 0xD2CE}, {0xD2CF, 0xD2CF, 0xD2CF}, {0xD2D0, 0xD2D0, 0xD2D0}, {0xD2D1, 0xD2D1, 0xD2D1}, {0xD2D2, 0xD2D2, 0xD2D2}, {0xD2D3, 0xD2D3, 0xD2D3}, {0xD2D4, 0xD2D4, 0xD2D4}, {0xD2D5, 0xD2D5, 0xD2D5}, {0xD2D6, 0xD2D6, 0xD2D6}, {0xD2D7, 0xD2D7, 0xD2D7}, {0xD2D8, 0xD2D8, 0xD2D8}, {0xD2D9, 0xD2D9, 0xD2D9}, {0xD2DA, 0xD2DA, 0xD2DA}, {0xD2DB, 0xD2DB, 0xD2DB}, {0xD2DC, 0xD2DC, 0xD2DC}, {0xD2DD, 0xD2DD, 0xD2DD}, {0xD2DE, 0xD2DE, 0xD2DE}, {0xD2DF, 0xD2DF, 0xD2DF}, {0xD2E0, 0xD2E0, 0xD2E0}, {0xD2E1, 0xD2E1, 0xD2E1}, {0xD2E2, 0xD2E2, 0xD2E2}, {0xD2E3, 0xD2E3, 0xD2E3}, {0xD2E4, 0xD2E4, 0xD2E4}, {0xD2E5, 0xD2E5, 0xD2E5}, {0xD2E6, 0xD2E6, 0xD2E6}, {0xD2E7, 0xD2E7, 0xD2E7}, {0xD2E8, 0xD2E8, 0xD2E8}, {0xD2E9, 0xD2E9, 0xD2E9}, {0xD2EA, 0xD2EA, 0xD2EA}, {0xD2EB, 0xD2EB, 0xD2EB}, {0xD2EC, 0xD2EC, 0xD2EC}, {0xD2ED, 0xD2ED, 0xD2ED}, {0xD2EE, 0xD2EE, 0xD2EE}, {0xD2EF, 0xD2EF, 0xD2EF}, {0xD2F0, 0xD2F0, 0xD2F0}, {0xD2F1, 0xD2F1, 0xD2F1}, {0xD2F2, 0xD2F2, 0xD2F2}, {0xD2F3, 0xD2F3, 0xD2F3}, {0xD2F4, 0xD2F4, 0xD2F4}, {0xD2F5, 0xD2F5, 0xD2F5}, {0xD2F6, 0xD2F6, 0xD2F6}, {0xD2F7, 0xD2F7, 0xD2F7}, {0xD2F8, 0xD2F8, 0xD2F8}, {0xD2F9, 0xD2F9, 0xD2F9}, {0xD2FA, 0xD2FA, 0xD2FA}, {0xD2FB, 0xD2FB, 0xD2FB}, {0xD2FC, 0xD2FC, 0xD2FC}, {0xD2FD, 0xD2FD, 0xD2FD}, {0xD2FE, 0xD2FE, 0xD2FE}, {0xD2FF, 0xD2FF, 0xD2FF}, {0xD300, 0xD300, 0xD300}, {0xD301, 0xD301, 0xD301}, {0xD302, 0xD302, 0xD302}, {0xD303, 0xD303, 0xD303}, {0xD304, 0xD304, 0xD304}, {0xD305, 0xD305, 0xD305}, {0xD306, 0xD306, 0xD306}, {0xD307, 0xD307, 0xD307}, {0xD308, 0xD308, 0xD308}, {0xD309, 0xD309, 0xD309}, {0xD30A, 0xD30A, 0xD30A}, {0xD30B, 0xD30B, 0xD30B}, {0xD30C, 0xD30C, 0xD30C}, {0xD30D, 0xD30D, 0xD30D}, {0xD30E, 0xD30E, 0xD30E}, {0xD30F, 0xD30F, 0xD30F}, {0xD310, 0xD310, 0xD310}, {0xD311, 0xD311, 0xD311}, {0xD312, 0xD312, 0xD312}, {0xD313, 0xD313, 0xD313}, {0xD314, 0xD314, 0xD314}, {0xD315, 0xD315, 0xD315}, {0xD316, 0xD316, 0xD316}, {0xD317, 0xD317, 0xD317}, {0xD318, 0xD318, 0xD318}, {0xD319, 0xD319, 0xD319}, {0xD31A, 0xD31A, 0xD31A}, {0xD31B, 0xD31B, 0xD31B}, {0xD31C, 0xD31C, 0xD31C}, {0xD31D, 0xD31D, 0xD31D}, {0xD31E, 0xD31E, 0xD31E}, {0xD31F, 0xD31F, 0xD31F}, {0xD320, 0xD320, 0xD320}, {0xD321, 0xD321, 0xD321}, {0xD322, 0xD322, 0xD322}, {0xD323, 0xD323, 0xD323}, {0xD324, 0xD324, 0xD324}, {0xD325, 0xD325, 0xD325}, {0xD326, 0xD326, 0xD326}, {0xD327, 0xD327, 0xD327}, {0xD328, 0xD328, 0xD328}, {0xD329, 0xD329, 0xD329}, {0xD32A, 0xD32A, 0xD32A}, {0xD32B, 0xD32B, 0xD32B}, {0xD32C, 0xD32C, 0xD32C}, {0xD32D, 0xD32D, 0xD32D}, {0xD32E, 0xD32E, 0xD32E}, {0xD32F, 0xD32F, 0xD32F}, {0xD330, 0xD330, 0xD330}, {0xD331, 0xD331, 0xD331}, {0xD332, 0xD332, 0xD332}, {0xD333, 0xD333, 0xD333}, {0xD334, 0xD334, 0xD334}, {0xD335, 0xD335, 0xD335}, {0xD336, 0xD336, 0xD336}, {0xD337, 0xD337, 0xD337}, {0xD338, 0xD338, 0xD338}, {0xD339, 0xD339, 0xD339}, {0xD33A, 0xD33A, 0xD33A}, {0xD33B, 0xD33B, 0xD33B}, {0xD33C, 0xD33C, 0xD33C}, {0xD33D, 0xD33D, 0xD33D}, {0xD33E, 0xD33E, 0xD33E}, {0xD33F, 0xD33F, 0xD33F}, {0xD340, 0xD340, 0xD340}, {0xD341, 0xD341, 0xD341}, {0xD342, 0xD342, 0xD342}, {0xD343, 0xD343, 0xD343}, {0xD344, 0xD344, 0xD344}, {0xD345, 0xD345, 0xD345}, {0xD346, 0xD346, 0xD346}, {0xD347, 0xD347, 0xD347}, {0xD348, 0xD348, 0xD348}, {0xD349, 0xD349, 0xD349}, {0xD34A, 0xD34A, 0xD34A}, {0xD34B, 0xD34B, 0xD34B}, {0xD34C, 0xD34C, 0xD34C}, {0xD34D, 0xD34D, 0xD34D}, {0xD34E, 0xD34E, 0xD34E}, {0xD34F, 0xD34F, 0xD34F}, {0xD350, 0xD350, 0xD350}, {0xD351, 0xD351, 0xD351}, {0xD352, 0xD352, 0xD352}, {0xD353, 0xD353, 0xD353}, {0xD354, 0xD354, 0xD354}, {0xD355, 0xD355, 0xD355}, {0xD356, 0xD356, 0xD356}, {0xD357, 0xD357, 0xD357}, {0xD358, 0xD358, 0xD358}, {0xD359, 0xD359, 0xD359}, {0xD35A, 0xD35A, 0xD35A}, {0xD35B, 0xD35B, 0xD35B}, {0xD35C, 0xD35C, 0xD35C}, {0xD35D, 0xD35D, 0xD35D}, {0xD35E, 0xD35E, 0xD35E}, {0xD35F, 0xD35F, 0xD35F}, {0xD360, 0xD360, 0xD360}, {0xD361, 0xD361, 0xD361}, {0xD362, 0xD362, 0xD362}, {0xD363, 0xD363, 0xD363}, {0xD364, 0xD364, 0xD364}, {0xD365, 0xD365, 0xD365}, {0xD366, 0xD366, 0xD366}, {0xD367, 0xD367, 0xD367}, {0xD368, 0xD368, 0xD368}, {0xD369, 0xD369, 0xD369}, {0xD36A, 0xD36A, 0xD36A}, {0xD36B, 0xD36B, 0xD36B}, {0xD36C, 0xD36C, 0xD36C}, {0xD36D, 0xD36D, 0xD36D}, {0xD36E, 0xD36E, 0xD36E}, {0xD36F, 0xD36F, 0xD36F}, {0xD370, 0xD370, 0xD370}, {0xD371, 0xD371, 0xD371}, {0xD372, 0xD372, 0xD372}, {0xD373, 0xD373, 0xD373}, {0xD374, 0xD374, 0xD374}, {0xD375, 0xD375, 0xD375}, {0xD376, 0xD376, 0xD376}, {0xD377, 0xD377, 0xD377}, {0xD378, 0xD378, 0xD378}, {0xD379, 0xD379, 0xD379}, {0xD37A, 0xD37A, 0xD37A}, {0xD37B, 0xD37B, 0xD37B}, {0xD37C, 0xD37C, 0xD37C}, {0xD37D, 0xD37D, 0xD37D}, {0xD37E, 0xD37E, 0xD37E}, {0xD37F, 0xD37F, 0xD37F}, {0xD380, 0xD380, 0xD380}, {0xD381, 0xD381, 0xD381}, {0xD382, 0xD382, 0xD382}, {0xD383, 0xD383, 0xD383}, {0xD384, 0xD384, 0xD384}, {0xD385, 0xD385, 0xD385}, {0xD386, 0xD386, 0xD386}, {0xD387, 0xD387, 0xD387}, {0xD388, 0xD388, 0xD388}, {0xD389, 0xD389, 0xD389}, {0xD38A, 0xD38A, 0xD38A}, {0xD38B, 0xD38B, 0xD38B}, {0xD38C, 0xD38C, 0xD38C}, {0xD38D, 0xD38D, 0xD38D}, {0xD38E, 0xD38E, 0xD38E}, {0xD38F, 0xD38F, 0xD38F}, {0xD390, 0xD390, 0xD390}, {0xD391, 0xD391, 0xD391}, {0xD392, 0xD392, 0xD392}, {0xD393, 0xD393, 0xD393}, {0xD394, 0xD394, 0xD394}, {0xD395, 0xD395, 0xD395}, {0xD396, 0xD396, 0xD396}, {0xD397, 0xD397, 0xD397}, {0xD398, 0xD398, 0xD398}, {0xD399, 0xD399, 0xD399}, {0xD39A, 0xD39A, 0xD39A}, {0xD39B, 0xD39B, 0xD39B}, {0xD39C, 0xD39C, 0xD39C}, {0xD39D, 0xD39D, 0xD39D}, {0xD39E, 0xD39E, 0xD39E}, {0xD39F, 0xD39F, 0xD39F}, {0xD3A0, 0xD3A0, 0xD3A0}, {0xD3A1, 0xD3A1, 0xD3A1}, {0xD3A2, 0xD3A2, 0xD3A2}, {0xD3A3, 0xD3A3, 0xD3A3}, {0xD3A4, 0xD3A4, 0xD3A4}, {0xD3A5, 0xD3A5, 0xD3A5}, {0xD3A6, 0xD3A6, 0xD3A6}, {0xD3A7, 0xD3A7, 0xD3A7}, {0xD3A8, 0xD3A8, 0xD3A8}, {0xD3A9, 0xD3A9, 0xD3A9}, {0xD3AA, 0xD3AA, 0xD3AA}, {0xD3AB, 0xD3AB, 0xD3AB}, {0xD3AC, 0xD3AC, 0xD3AC}, {0xD3AD, 0xD3AD, 0xD3AD}, {0xD3AE, 0xD3AE, 0xD3AE}, {0xD3AF, 0xD3AF, 0xD3AF}, {0xD3B0, 0xD3B0, 0xD3B0}, {0xD3B1, 0xD3B1, 0xD3B1}, {0xD3B2, 0xD3B2, 0xD3B2}, {0xD3B3, 0xD3B3, 0xD3B3}, {0xD3B4, 0xD3B4, 0xD3B4}, {0xD3B5, 0xD3B5, 0xD3B5}, {0xD3B6, 0xD3B6, 0xD3B6}, {0xD3B7, 0xD3B7, 0xD3B7}, {0xD3B8, 0xD3B8, 0xD3B8}, {0xD3B9, 0xD3B9, 0xD3B9}, {0xD3BA, 0xD3BA, 0xD3BA}, {0xD3BB, 0xD3BB, 0xD3BB}, {0xD3BC, 0xD3BC, 0xD3BC}, {0xD3BD, 0xD3BD, 0xD3BD}, {0xD3BE, 0xD3BE, 0xD3BE}, {0xD3BF, 0xD3BF, 0xD3BF}, {0xD3C0, 0xD3C0, 0xD3C0}, {0xD3C1, 0xD3C1, 0xD3C1}, {0xD3C2, 0xD3C2, 0xD3C2}, {0xD3C3, 0xD3C3, 0xD3C3}, {0xD3C4, 0xD3C4, 0xD3C4}, {0xD3C5, 0xD3C5, 0xD3C5}, {0xD3C6, 0xD3C6, 0xD3C6}, {0xD3C7, 0xD3C7, 0xD3C7}, {0xD3C8, 0xD3C8, 0xD3C8}, {0xD3C9, 0xD3C9, 0xD3C9}, {0xD3CA, 0xD3CA, 0xD3CA}, {0xD3CB, 0xD3CB, 0xD3CB}, {0xD3CC, 0xD3CC, 0xD3CC}, {0xD3CD, 0xD3CD, 0xD3CD}, {0xD3CE, 0xD3CE, 0xD3CE}, {0xD3CF, 0xD3CF, 0xD3CF}, {0xD3D0, 0xD3D0, 0xD3D0}, {0xD3D1, 0xD3D1, 0xD3D1}, {0xD3D2, 0xD3D2, 0xD3D2}, {0xD3D3, 0xD3D3, 0xD3D3}, {0xD3D4, 0xD3D4, 0xD3D4}, {0xD3D5, 0xD3D5, 0xD3D5}, {0xD3D6, 0xD3D6, 0xD3D6}, {0xD3D7, 0xD3D7, 0xD3D7}, {0xD3D8, 0xD3D8, 0xD3D8}, {0xD3D9, 0xD3D9, 0xD3D9}, {0xD3DA, 0xD3DA, 0xD3DA}, {0xD3DB, 0xD3DB, 0xD3DB}, {0xD3DC, 0xD3DC, 0xD3DC}, {0xD3DD, 0xD3DD, 0xD3DD}, {0xD3DE, 0xD3DE, 0xD3DE}, {0xD3DF, 0xD3DF, 0xD3DF}, {0xD3E0, 0xD3E0, 0xD3E0}, {0xD3E1, 0xD3E1, 0xD3E1}, {0xD3E2, 0xD3E2, 0xD3E2}, {0xD3E3, 0xD3E3, 0xD3E3}, {0xD3E4, 0xD3E4, 0xD3E4}, {0xD3E5, 0xD3E5, 0xD3E5}, {0xD3E6, 0xD3E6, 0xD3E6}, {0xD3E7, 0xD3E7, 0xD3E7}, {0xD3E8, 0xD3E8, 0xD3E8}, {0xD3E9, 0xD3E9, 0xD3E9}, {0xD3EA, 0xD3EA, 0xD3EA}, {0xD3EB, 0xD3EB, 0xD3EB}, {0xD3EC, 0xD3EC, 0xD3EC}, {0xD3ED, 0xD3ED, 0xD3ED}, {0xD3EE, 0xD3EE, 0xD3EE}, {0xD3EF, 0xD3EF, 0xD3EF}, {0xD3F0, 0xD3F0, 0xD3F0}, {0xD3F1, 0xD3F1, 0xD3F1}, {0xD3F2, 0xD3F2, 0xD3F2}, {0xD3F3, 0xD3F3, 0xD3F3}, {0xD3F4, 0xD3F4, 0xD3F4}, {0xD3F5, 0xD3F5, 0xD3F5}, {0xD3F6, 0xD3F6, 0xD3F6}, {0xD3F7, 0xD3F7, 0xD3F7}, {0xD3F8, 0xD3F8, 0xD3F8}, {0xD3F9, 0xD3F9, 0xD3F9}, {0xD3FA, 0xD3FA, 0xD3FA}, {0xD3FB, 0xD3FB, 0xD3FB}, {0xD3FC, 0xD3FC, 0xD3FC}, {0xD3FD, 0xD3FD, 0xD3FD}, {0xD3FE, 0xD3FE, 0xD3FE}, {0xD3FF, 0xD3FF, 0xD3FF}, {0xD400, 0xD400, 0xD400}, {0xD401, 0xD401, 0xD401}, {0xD402, 0xD402, 0xD402}, {0xD403, 0xD403, 0xD403}, {0xD404, 0xD404, 0xD404}, {0xD405, 0xD405, 0xD405}, {0xD406, 0xD406, 0xD406}, {0xD407, 0xD407, 0xD407}, {0xD408, 0xD408, 0xD408}, {0xD409, 0xD409, 0xD409}, {0xD40A, 0xD40A, 0xD40A}, {0xD40B, 0xD40B, 0xD40B}, {0xD40C, 0xD40C, 0xD40C}, {0xD40D, 0xD40D, 0xD40D}, {0xD40E, 0xD40E, 0xD40E}, {0xD40F, 0xD40F, 0xD40F}, {0xD410, 0xD410, 0xD410}, {0xD411, 0xD411, 0xD411}, {0xD412, 0xD412, 0xD412}, {0xD413, 0xD413, 0xD413}, {0xD414, 0xD414, 0xD414}, {0xD415, 0xD415, 0xD415}, {0xD416, 0xD416, 0xD416}, {0xD417, 0xD417, 0xD417}, {0xD418, 0xD418, 0xD418}, {0xD419, 0xD419, 0xD419}, {0xD41A, 0xD41A, 0xD41A}, {0xD41B, 0xD41B, 0xD41B}, {0xD41C, 0xD41C, 0xD41C}, {0xD41D, 0xD41D, 0xD41D}, {0xD41E, 0xD41E, 0xD41E}, {0xD41F, 0xD41F, 0xD41F}, {0xD420, 0xD420, 0xD420}, {0xD421, 0xD421, 0xD421}, {0xD422, 0xD422, 0xD422}, {0xD423, 0xD423, 0xD423}, {0xD424, 0xD424, 0xD424}, {0xD425, 0xD425, 0xD425}, {0xD426, 0xD426, 0xD426}, {0xD427, 0xD427, 0xD427}, {0xD428, 0xD428, 0xD428}, {0xD429, 0xD429, 0xD429}, {0xD42A, 0xD42A, 0xD42A}, {0xD42B, 0xD42B, 0xD42B}, {0xD42C, 0xD42C, 0xD42C}, {0xD42D, 0xD42D, 0xD42D}, {0xD42E, 0xD42E, 0xD42E}, {0xD42F, 0xD42F, 0xD42F}, {0xD430, 0xD430, 0xD430}, {0xD431, 0xD431, 0xD431}, {0xD432, 0xD432, 0xD432}, {0xD433, 0xD433, 0xD433}, {0xD434, 0xD434, 0xD434}, {0xD435, 0xD435, 0xD435}, {0xD436, 0xD436, 0xD436}, {0xD437, 0xD437, 0xD437}, {0xD438, 0xD438, 0xD438}, {0xD439, 0xD439, 0xD439}, {0xD43A, 0xD43A, 0xD43A}, {0xD43B, 0xD43B, 0xD43B}, {0xD43C, 0xD43C, 0xD43C}, {0xD43D, 0xD43D, 0xD43D}, {0xD43E, 0xD43E, 0xD43E}, {0xD43F, 0xD43F, 0xD43F}, {0xD440, 0xD440, 0xD440}, {0xD441, 0xD441, 0xD441}, {0xD442, 0xD442, 0xD442}, {0xD443, 0xD443, 0xD443}, {0xD444, 0xD444, 0xD444}, {0xD445, 0xD445, 0xD445}, {0xD446, 0xD446, 0xD446}, {0xD447, 0xD447, 0xD447}, {0xD448, 0xD448, 0xD448}, {0xD449, 0xD449, 0xD449}, {0xD44A, 0xD44A, 0xD44A}, {0xD44B, 0xD44B, 0xD44B}, {0xD44C, 0xD44C, 0xD44C}, {0xD44D, 0xD44D, 0xD44D}, {0xD44E, 0xD44E, 0xD44E}, {0xD44F, 0xD44F, 0xD44F}, {0xD450, 0xD450, 0xD450}, {0xD451, 0xD451, 0xD451}, {0xD452, 0xD452, 0xD452}, {0xD453, 0xD453, 0xD453}, {0xD454, 0xD454, 0xD454}, {0xD455, 0xD455, 0xD455}, {0xD456, 0xD456, 0xD456}, {0xD457, 0xD457, 0xD457}, {0xD458, 0xD458, 0xD458}, {0xD459, 0xD459, 0xD459}, {0xD45A, 0xD45A, 0xD45A}, {0xD45B, 0xD45B, 0xD45B}, {0xD45C, 0xD45C, 0xD45C}, {0xD45D, 0xD45D, 0xD45D}, {0xD45E, 0xD45E, 0xD45E}, {0xD45F, 0xD45F, 0xD45F}, {0xD460, 0xD460, 0xD460}, {0xD461, 0xD461, 0xD461}, {0xD462, 0xD462, 0xD462}, {0xD463, 0xD463, 0xD463}, {0xD464, 0xD464, 0xD464}, {0xD465, 0xD465, 0xD465}, {0xD466, 0xD466, 0xD466}, {0xD467, 0xD467, 0xD467}, {0xD468, 0xD468, 0xD468}, {0xD469, 0xD469, 0xD469}, {0xD46A, 0xD46A, 0xD46A}, {0xD46B, 0xD46B, 0xD46B}, {0xD46C, 0xD46C, 0xD46C}, {0xD46D, 0xD46D, 0xD46D}, {0xD46E, 0xD46E, 0xD46E}, {0xD46F, 0xD46F, 0xD46F}, {0xD470, 0xD470, 0xD470}, {0xD471, 0xD471, 0xD471}, {0xD472, 0xD472, 0xD472}, {0xD473, 0xD473, 0xD473}, {0xD474, 0xD474, 0xD474}, {0xD475, 0xD475, 0xD475}, {0xD476, 0xD476, 0xD476}, {0xD477, 0xD477, 0xD477}, {0xD478, 0xD478, 0xD478}, {0xD479, 0xD479, 0xD479}, {0xD47A, 0xD47A, 0xD47A}, {0xD47B, 0xD47B, 0xD47B}, {0xD47C, 0xD47C, 0xD47C}, {0xD47D, 0xD47D, 0xD47D}, {0xD47E, 0xD47E, 0xD47E}, {0xD47F, 0xD47F, 0xD47F}, {0xD480, 0xD480, 0xD480}, {0xD481, 0xD481, 0xD481}, {0xD482, 0xD482, 0xD482}, {0xD483, 0xD483, 0xD483}, {0xD484, 0xD484, 0xD484}, {0xD485, 0xD485, 0xD485}, {0xD486, 0xD486, 0xD486}, {0xD487, 0xD487, 0xD487}, {0xD488, 0xD488, 0xD488}, {0xD489, 0xD489, 0xD489}, {0xD48A, 0xD48A, 0xD48A}, {0xD48B, 0xD48B, 0xD48B}, {0xD48C, 0xD48C, 0xD48C}, {0xD48D, 0xD48D, 0xD48D}, {0xD48E, 0xD48E, 0xD48E}, {0xD48F, 0xD48F, 0xD48F}, {0xD490, 0xD490, 0xD490}, {0xD491, 0xD491, 0xD491}, {0xD492, 0xD492, 0xD492}, {0xD493, 0xD493, 0xD493}, {0xD494, 0xD494, 0xD494}, {0xD495, 0xD495, 0xD495}, {0xD496, 0xD496, 0xD496}, {0xD497, 0xD497, 0xD497}, {0xD498, 0xD498, 0xD498}, {0xD499, 0xD499, 0xD499}, {0xD49A, 0xD49A, 0xD49A}, {0xD49B, 0xD49B, 0xD49B}, {0xD49C, 0xD49C, 0xD49C}, {0xD49D, 0xD49D, 0xD49D}, {0xD49E, 0xD49E, 0xD49E}, {0xD49F, 0xD49F, 0xD49F}, {0xD4A0, 0xD4A0, 0xD4A0}, {0xD4A1, 0xD4A1, 0xD4A1}, {0xD4A2, 0xD4A2, 0xD4A2}, {0xD4A3, 0xD4A3, 0xD4A3}, {0xD4A4, 0xD4A4, 0xD4A4}, {0xD4A5, 0xD4A5, 0xD4A5}, {0xD4A6, 0xD4A6, 0xD4A6}, {0xD4A7, 0xD4A7, 0xD4A7}, {0xD4A8, 0xD4A8, 0xD4A8}, {0xD4A9, 0xD4A9, 0xD4A9}, {0xD4AA, 0xD4AA, 0xD4AA}, {0xD4AB, 0xD4AB, 0xD4AB}, {0xD4AC, 0xD4AC, 0xD4AC}, {0xD4AD, 0xD4AD, 0xD4AD}, {0xD4AE, 0xD4AE, 0xD4AE}, {0xD4AF, 0xD4AF, 0xD4AF}, {0xD4B0, 0xD4B0, 0xD4B0}, {0xD4B1, 0xD4B1, 0xD4B1}, {0xD4B2, 0xD4B2, 0xD4B2}, {0xD4B3, 0xD4B3, 0xD4B3}, {0xD4B4, 0xD4B4, 0xD4B4}, {0xD4B5, 0xD4B5, 0xD4B5}, {0xD4B6, 0xD4B6, 0xD4B6}, {0xD4B7, 0xD4B7, 0xD4B7}, {0xD4B8, 0xD4B8, 0xD4B8}, {0xD4B9, 0xD4B9, 0xD4B9}, {0xD4BA, 0xD4BA, 0xD4BA}, {0xD4BB, 0xD4BB, 0xD4BB}, {0xD4BC, 0xD4BC, 0xD4BC}, {0xD4BD, 0xD4BD, 0xD4BD}, {0xD4BE, 0xD4BE, 0xD4BE}, {0xD4BF, 0xD4BF, 0xD4BF}, {0xD4C0, 0xD4C0, 0xD4C0}, {0xD4C1, 0xD4C1, 0xD4C1}, {0xD4C2, 0xD4C2, 0xD4C2}, {0xD4C3, 0xD4C3, 0xD4C3}, {0xD4C4, 0xD4C4, 0xD4C4}, {0xD4C5, 0xD4C5, 0xD4C5}, {0xD4C6, 0xD4C6, 0xD4C6}, {0xD4C7, 0xD4C7, 0xD4C7}, {0xD4C8, 0xD4C8, 0xD4C8}, {0xD4C9, 0xD4C9, 0xD4C9}, {0xD4CA, 0xD4CA, 0xD4CA}, {0xD4CB, 0xD4CB, 0xD4CB}, {0xD4CC, 0xD4CC, 0xD4CC}, {0xD4CD, 0xD4CD, 0xD4CD}, {0xD4CE, 0xD4CE, 0xD4CE}, {0xD4CF, 0xD4CF, 0xD4CF}, {0xD4D0, 0xD4D0, 0xD4D0}, {0xD4D1, 0xD4D1, 0xD4D1}, {0xD4D2, 0xD4D2, 0xD4D2}, {0xD4D3, 0xD4D3, 0xD4D3}, {0xD4D4, 0xD4D4, 0xD4D4}, {0xD4D5, 0xD4D5, 0xD4D5}, {0xD4D6, 0xD4D6, 0xD4D6}, {0xD4D7, 0xD4D7, 0xD4D7}, {0xD4D8, 0xD4D8, 0xD4D8}, {0xD4D9, 0xD4D9, 0xD4D9}, {0xD4DA, 0xD4DA, 0xD4DA}, {0xD4DB, 0xD4DB, 0xD4DB}, {0xD4DC, 0xD4DC, 0xD4DC}, {0xD4DD, 0xD4DD, 0xD4DD}, {0xD4DE, 0xD4DE, 0xD4DE}, {0xD4DF, 0xD4DF, 0xD4DF}, {0xD4E0, 0xD4E0, 0xD4E0}, {0xD4E1, 0xD4E1, 0xD4E1}, {0xD4E2, 0xD4E2, 0xD4E2}, {0xD4E3, 0xD4E3, 0xD4E3}, {0xD4E4, 0xD4E4, 0xD4E4}, {0xD4E5, 0xD4E5, 0xD4E5}, {0xD4E6, 0xD4E6, 0xD4E6}, {0xD4E7, 0xD4E7, 0xD4E7}, {0xD4E8, 0xD4E8, 0xD4E8}, {0xD4E9, 0xD4E9, 0xD4E9}, {0xD4EA, 0xD4EA, 0xD4EA}, {0xD4EB, 0xD4EB, 0xD4EB}, {0xD4EC, 0xD4EC, 0xD4EC}, {0xD4ED, 0xD4ED, 0xD4ED}, {0xD4EE, 0xD4EE, 0xD4EE}, {0xD4EF, 0xD4EF, 0xD4EF}, {0xD4F0, 0xD4F0, 0xD4F0}, {0xD4F1, 0xD4F1, 0xD4F1}, {0xD4F2, 0xD4F2, 0xD4F2}, {0xD4F3, 0xD4F3, 0xD4F3}, {0xD4F4, 0xD4F4, 0xD4F4}, {0xD4F5, 0xD4F5, 0xD4F5}, {0xD4F6, 0xD4F6, 0xD4F6}, {0xD4F7, 0xD4F7, 0xD4F7}, {0xD4F8, 0xD4F8, 0xD4F8}, {0xD4F9, 0xD4F9, 0xD4F9}, {0xD4FA, 0xD4FA, 0xD4FA}, {0xD4FB, 0xD4FB, 0xD4FB}, {0xD4FC, 0xD4FC, 0xD4FC}, {0xD4FD, 0xD4FD, 0xD4FD}, {0xD4FE, 0xD4FE, 0xD4FE}, {0xD4FF, 0xD4FF, 0xD4FF}, {0xD500, 0xD500, 0xD500}, {0xD501, 0xD501, 0xD501}, {0xD502, 0xD502, 0xD502}, {0xD503, 0xD503, 0xD503}, {0xD504, 0xD504, 0xD504}, {0xD505, 0xD505, 0xD505}, {0xD506, 0xD506, 0xD506}, {0xD507, 0xD507, 0xD507}, {0xD508, 0xD508, 0xD508}, {0xD509, 0xD509, 0xD509}, {0xD50A, 0xD50A, 0xD50A}, {0xD50B, 0xD50B, 0xD50B}, {0xD50C, 0xD50C, 0xD50C}, {0xD50D, 0xD50D, 0xD50D}, {0xD50E, 0xD50E, 0xD50E}, {0xD50F, 0xD50F, 0xD50F}, {0xD510, 0xD510, 0xD510}, {0xD511, 0xD511, 0xD511}, {0xD512, 0xD512, 0xD512}, {0xD513, 0xD513, 0xD513}, {0xD514, 0xD514, 0xD514}, {0xD515, 0xD515, 0xD515}, {0xD516, 0xD516, 0xD516}, {0xD517, 0xD517, 0xD517}, {0xD518, 0xD518, 0xD518}, {0xD519, 0xD519, 0xD519}, {0xD51A, 0xD51A, 0xD51A}, {0xD51B, 0xD51B, 0xD51B}, {0xD51C, 0xD51C, 0xD51C}, {0xD51D, 0xD51D, 0xD51D}, {0xD51E, 0xD51E, 0xD51E}, {0xD51F, 0xD51F, 0xD51F}, {0xD520, 0xD520, 0xD520}, {0xD521, 0xD521, 0xD521}, {0xD522, 0xD522, 0xD522}, {0xD523, 0xD523, 0xD523}, {0xD524, 0xD524, 0xD524}, {0xD525, 0xD525, 0xD525}, {0xD526, 0xD526, 0xD526}, {0xD527, 0xD527, 0xD527}, {0xD528, 0xD528, 0xD528}, {0xD529, 0xD529, 0xD529}, {0xD52A, 0xD52A, 0xD52A}, {0xD52B, 0xD52B, 0xD52B}, {0xD52C, 0xD52C, 0xD52C}, {0xD52D, 0xD52D, 0xD52D}, {0xD52E, 0xD52E, 0xD52E}, {0xD52F, 0xD52F, 0xD52F}, {0xD530, 0xD530, 0xD530}, {0xD531, 0xD531, 0xD531}, {0xD532, 0xD532, 0xD532}, {0xD533, 0xD533, 0xD533}, {0xD534, 0xD534, 0xD534}, {0xD535, 0xD535, 0xD535}, {0xD536, 0xD536, 0xD536}, {0xD537, 0xD537, 0xD537}, {0xD538, 0xD538, 0xD538}, {0xD539, 0xD539, 0xD539}, {0xD53A, 0xD53A, 0xD53A}, {0xD53B, 0xD53B, 0xD53B}, {0xD53C, 0xD53C, 0xD53C}, {0xD53D, 0xD53D, 0xD53D}, {0xD53E, 0xD53E, 0xD53E}, {0xD53F, 0xD53F, 0xD53F}, {0xD540, 0xD540, 0xD540}, {0xD541, 0xD541, 0xD541}, {0xD542, 0xD542, 0xD542}, {0xD543, 0xD543, 0xD543}, {0xD544, 0xD544, 0xD544}, {0xD545, 0xD545, 0xD545}, {0xD546, 0xD546, 0xD546}, {0xD547, 0xD547, 0xD547}, {0xD548, 0xD548, 0xD548}, {0xD549, 0xD549, 0xD549}, {0xD54A, 0xD54A, 0xD54A}, {0xD54B, 0xD54B, 0xD54B}, {0xD54C, 0xD54C, 0xD54C}, {0xD54D, 0xD54D, 0xD54D}, {0xD54E, 0xD54E, 0xD54E}, {0xD54F, 0xD54F, 0xD54F}, {0xD550, 0xD550, 0xD550}, {0xD551, 0xD551, 0xD551}, {0xD552, 0xD552, 0xD552}, {0xD553, 0xD553, 0xD553}, {0xD554, 0xD554, 0xD554}, {0xD555, 0xD555, 0xD555}, {0xD556, 0xD556, 0xD556}, {0xD557, 0xD557, 0xD557}, {0xD558, 0xD558, 0xD558}, {0xD559, 0xD559, 0xD559}, {0xD55A, 0xD55A, 0xD55A}, {0xD55B, 0xD55B, 0xD55B}, {0xD55C, 0xD55C, 0xD55C}, {0xD55D, 0xD55D, 0xD55D}, {0xD55E, 0xD55E, 0xD55E}, {0xD55F, 0xD55F, 0xD55F}, {0xD560, 0xD560, 0xD560}, {0xD561, 0xD561, 0xD561}, {0xD562, 0xD562, 0xD562}, {0xD563, 0xD563, 0xD563}, {0xD564, 0xD564, 0xD564}, {0xD565, 0xD565, 0xD565}, {0xD566, 0xD566, 0xD566}, {0xD567, 0xD567, 0xD567}, {0xD568, 0xD568, 0xD568}, {0xD569, 0xD569, 0xD569}, {0xD56A, 0xD56A, 0xD56A}, {0xD56B, 0xD56B, 0xD56B}, {0xD56C, 0xD56C, 0xD56C}, {0xD56D, 0xD56D, 0xD56D}, {0xD56E, 0xD56E, 0xD56E}, {0xD56F, 0xD56F, 0xD56F}, {0xD570, 0xD570, 0xD570}, {0xD571, 0xD571, 0xD571}, {0xD572, 0xD572, 0xD572}, {0xD573, 0xD573, 0xD573}, {0xD574, 0xD574, 0xD574}, {0xD575, 0xD575, 0xD575}, {0xD576, 0xD576, 0xD576}, {0xD577, 0xD577, 0xD577}, {0xD578, 0xD578, 0xD578}, {0xD579, 0xD579, 0xD579}, {0xD57A, 0xD57A, 0xD57A}, {0xD57B, 0xD57B, 0xD57B}, {0xD57C, 0xD57C, 0xD57C}, {0xD57D, 0xD57D, 0xD57D}, {0xD57E, 0xD57E, 0xD57E}, {0xD57F, 0xD57F, 0xD57F}, {0xD580, 0xD580, 0xD580}, {0xD581, 0xD581, 0xD581}, {0xD582, 0xD582, 0xD582}, {0xD583, 0xD583, 0xD583}, {0xD584, 0xD584, 0xD584}, {0xD585, 0xD585, 0xD585}, {0xD586, 0xD586, 0xD586}, {0xD587, 0xD587, 0xD587}, {0xD588, 0xD588, 0xD588}, {0xD589, 0xD589, 0xD589}, {0xD58A, 0xD58A, 0xD58A}, {0xD58B, 0xD58B, 0xD58B}, {0xD58C, 0xD58C, 0xD58C}, {0xD58D, 0xD58D, 0xD58D}, {0xD58E, 0xD58E, 0xD58E}, {0xD58F, 0xD58F, 0xD58F}, {0xD590, 0xD590, 0xD590}, {0xD591, 0xD591, 0xD591}, {0xD592, 0xD592, 0xD592}, {0xD593, 0xD593, 0xD593}, {0xD594, 0xD594, 0xD594}, {0xD595, 0xD595, 0xD595}, {0xD596, 0xD596, 0xD596}, {0xD597, 0xD597, 0xD597}, {0xD598, 0xD598, 0xD598}, {0xD599, 0xD599, 0xD599}, {0xD59A, 0xD59A, 0xD59A}, {0xD59B, 0xD59B, 0xD59B}, {0xD59C, 0xD59C, 0xD59C}, {0xD59D, 0xD59D, 0xD59D}, {0xD59E, 0xD59E, 0xD59E}, {0xD59F, 0xD59F, 0xD59F}, {0xD5A0, 0xD5A0, 0xD5A0}, {0xD5A1, 0xD5A1, 0xD5A1}, {0xD5A2, 0xD5A2, 0xD5A2}, {0xD5A3, 0xD5A3, 0xD5A3}, {0xD5A4, 0xD5A4, 0xD5A4}, {0xD5A5, 0xD5A5, 0xD5A5}, {0xD5A6, 0xD5A6, 0xD5A6}, {0xD5A7, 0xD5A7, 0xD5A7}, {0xD5A8, 0xD5A8, 0xD5A8}, {0xD5A9, 0xD5A9, 0xD5A9}, {0xD5AA, 0xD5AA, 0xD5AA}, {0xD5AB, 0xD5AB, 0xD5AB}, {0xD5AC, 0xD5AC, 0xD5AC}, {0xD5AD, 0xD5AD, 0xD5AD}, {0xD5AE, 0xD5AE, 0xD5AE}, {0xD5AF, 0xD5AF, 0xD5AF}, {0xD5B0, 0xD5B0, 0xD5B0}, {0xD5B1, 0xD5B1, 0xD5B1}, {0xD5B2, 0xD5B2, 0xD5B2}, {0xD5B3, 0xD5B3, 0xD5B3}, {0xD5B4, 0xD5B4, 0xD5B4}, {0xD5B5, 0xD5B5, 0xD5B5}, {0xD5B6, 0xD5B6, 0xD5B6}, {0xD5B7, 0xD5B7, 0xD5B7}, {0xD5B8, 0xD5B8, 0xD5B8}, {0xD5B9, 0xD5B9, 0xD5B9}, {0xD5BA, 0xD5BA, 0xD5BA}, {0xD5BB, 0xD5BB, 0xD5BB}, {0xD5BC, 0xD5BC, 0xD5BC}, {0xD5BD, 0xD5BD, 0xD5BD}, {0xD5BE, 0xD5BE, 0xD5BE}, {0xD5BF, 0xD5BF, 0xD5BF}, {0xD5C0, 0xD5C0, 0xD5C0}, {0xD5C1, 0xD5C1, 0xD5C1}, {0xD5C2, 0xD5C2, 0xD5C2}, {0xD5C3, 0xD5C3, 0xD5C3}, {0xD5C4, 0xD5C4, 0xD5C4}, {0xD5C5, 0xD5C5, 0xD5C5}, {0xD5C6, 0xD5C6, 0xD5C6}, {0xD5C7, 0xD5C7, 0xD5C7}, {0xD5C8, 0xD5C8, 0xD5C8}, {0xD5C9, 0xD5C9, 0xD5C9}, {0xD5CA, 0xD5CA, 0xD5CA}, {0xD5CB, 0xD5CB, 0xD5CB}, {0xD5CC, 0xD5CC, 0xD5CC}, {0xD5CD, 0xD5CD, 0xD5CD}, {0xD5CE, 0xD5CE, 0xD5CE}, {0xD5CF, 0xD5CF, 0xD5CF}, {0xD5D0, 0xD5D0, 0xD5D0}, {0xD5D1, 0xD5D1, 0xD5D1}, {0xD5D2, 0xD5D2, 0xD5D2}, {0xD5D3, 0xD5D3, 0xD5D3}, {0xD5D4, 0xD5D4, 0xD5D4}, {0xD5D5, 0xD5D5, 0xD5D5}, {0xD5D6, 0xD5D6, 0xD5D6}, {0xD5D7, 0xD5D7, 0xD5D7}, {0xD5D8, 0xD5D8, 0xD5D8}, {0xD5D9, 0xD5D9, 0xD5D9}, {0xD5DA, 0xD5DA, 0xD5DA}, {0xD5DB, 0xD5DB, 0xD5DB}, {0xD5DC, 0xD5DC, 0xD5DC}, {0xD5DD, 0xD5DD, 0xD5DD}, {0xD5DE, 0xD5DE, 0xD5DE}, {0xD5DF, 0xD5DF, 0xD5DF}, {0xD5E0, 0xD5E0, 0xD5E0}, {0xD5E1, 0xD5E1, 0xD5E1}, {0xD5E2, 0xD5E2, 0xD5E2}, {0xD5E3, 0xD5E3, 0xD5E3}, {0xD5E4, 0xD5E4, 0xD5E4}, {0xD5E5, 0xD5E5, 0xD5E5}, {0xD5E6, 0xD5E6, 0xD5E6}, {0xD5E7, 0xD5E7, 0xD5E7}, {0xD5E8, 0xD5E8, 0xD5E8}, {0xD5E9, 0xD5E9, 0xD5E9}, {0xD5EA, 0xD5EA, 0xD5EA}, {0xD5EB, 0xD5EB, 0xD5EB}, {0xD5EC, 0xD5EC, 0xD5EC}, {0xD5ED, 0xD5ED, 0xD5ED}, {0xD5EE, 0xD5EE, 0xD5EE}, {0xD5EF, 0xD5EF, 0xD5EF}, {0xD5F0, 0xD5F0, 0xD5F0}, {0xD5F1, 0xD5F1, 0xD5F1}, {0xD5F2, 0xD5F2, 0xD5F2}, {0xD5F3, 0xD5F3, 0xD5F3}, {0xD5F4, 0xD5F4, 0xD5F4}, {0xD5F5, 0xD5F5, 0xD5F5}, {0xD5F6, 0xD5F6, 0xD5F6}, {0xD5F7, 0xD5F7, 0xD5F7}, {0xD5F8, 0xD5F8, 0xD5F8}, {0xD5F9, 0xD5F9, 0xD5F9}, {0xD5FA, 0xD5FA, 0xD5FA}, {0xD5FB, 0xD5FB, 0xD5FB}, {0xD5FC, 0xD5FC, 0xD5FC}, {0xD5FD, 0xD5FD, 0xD5FD}, {0xD5FE, 0xD5FE, 0xD5FE}, {0xD5FF, 0xD5FF, 0xD5FF}, {0xD600, 0xD600, 0xD600}, {0xD601, 0xD601, 0xD601}, {0xD602, 0xD602, 0xD602}, {0xD603, 0xD603, 0xD603}, {0xD604, 0xD604, 0xD604}, {0xD605, 0xD605, 0xD605}, {0xD606, 0xD606, 0xD606}, {0xD607, 0xD607, 0xD607}, {0xD608, 0xD608, 0xD608}, {0xD609, 0xD609, 0xD609}, {0xD60A, 0xD60A, 0xD60A}, {0xD60B, 0xD60B, 0xD60B}, {0xD60C, 0xD60C, 0xD60C}, {0xD60D, 0xD60D, 0xD60D}, {0xD60E, 0xD60E, 0xD60E}, {0xD60F, 0xD60F, 0xD60F}, {0xD610, 0xD610, 0xD610}, {0xD611, 0xD611, 0xD611}, {0xD612, 0xD612, 0xD612}, {0xD613, 0xD613, 0xD613}, {0xD614, 0xD614, 0xD614}, {0xD615, 0xD615, 0xD615}, {0xD616, 0xD616, 0xD616}, {0xD617, 0xD617, 0xD617}, {0xD618, 0xD618, 0xD618}, {0xD619, 0xD619, 0xD619}, {0xD61A, 0xD61A, 0xD61A}, {0xD61B, 0xD61B, 0xD61B}, {0xD61C, 0xD61C, 0xD61C}, {0xD61D, 0xD61D, 0xD61D}, {0xD61E, 0xD61E, 0xD61E}, {0xD61F, 0xD61F, 0xD61F}, {0xD620, 0xD620, 0xD620}, {0xD621, 0xD621, 0xD621}, {0xD622, 0xD622, 0xD622}, {0xD623, 0xD623, 0xD623}, {0xD624, 0xD624, 0xD624}, {0xD625, 0xD625, 0xD625}, {0xD626, 0xD626, 0xD626}, {0xD627, 0xD627, 0xD627}, {0xD628, 0xD628, 0xD628}, {0xD629, 0xD629, 0xD629}, {0xD62A, 0xD62A, 0xD62A}, {0xD62B, 0xD62B, 0xD62B}, {0xD62C, 0xD62C, 0xD62C}, {0xD62D, 0xD62D, 0xD62D}, {0xD62E, 0xD62E, 0xD62E}, {0xD62F, 0xD62F, 0xD62F}, {0xD630, 0xD630, 0xD630}, {0xD631, 0xD631, 0xD631}, {0xD632, 0xD632, 0xD632}, {0xD633, 0xD633, 0xD633}, {0xD634, 0xD634, 0xD634}, {0xD635, 0xD635, 0xD635}, {0xD636, 0xD636, 0xD636}, {0xD637, 0xD637, 0xD637}, {0xD638, 0xD638, 0xD638}, {0xD639, 0xD639, 0xD639}, {0xD63A, 0xD63A, 0xD63A}, {0xD63B, 0xD63B, 0xD63B}, {0xD63C, 0xD63C, 0xD63C}, {0xD63D, 0xD63D, 0xD63D}, {0xD63E, 0xD63E, 0xD63E}, {0xD63F, 0xD63F, 0xD63F}, {0xD640, 0xD640, 0xD640}, {0xD641, 0xD641, 0xD641}, {0xD642, 0xD642, 0xD642}, {0xD643, 0xD643, 0xD643}, {0xD644, 0xD644, 0xD644}, {0xD645, 0xD645, 0xD645}, {0xD646, 0xD646, 0xD646}, {0xD647, 0xD647, 0xD647}, {0xD648, 0xD648, 0xD648}, {0xD649, 0xD649, 0xD649}, {0xD64A, 0xD64A, 0xD64A}, {0xD64B, 0xD64B, 0xD64B}, {0xD64C, 0xD64C, 0xD64C}, {0xD64D, 0xD64D, 0xD64D}, {0xD64E, 0xD64E, 0xD64E}, {0xD64F, 0xD64F, 0xD64F}, {0xD650, 0xD650, 0xD650}, {0xD651, 0xD651, 0xD651}, {0xD652, 0xD652, 0xD652}, {0xD653, 0xD653, 0xD653}, {0xD654, 0xD654, 0xD654}, {0xD655, 0xD655, 0xD655}, {0xD656, 0xD656, 0xD656}, {0xD657, 0xD657, 0xD657}, {0xD658, 0xD658, 0xD658}, {0xD659, 0xD659, 0xD659}, {0xD65A, 0xD65A, 0xD65A}, {0xD65B, 0xD65B, 0xD65B}, {0xD65C, 0xD65C, 0xD65C}, {0xD65D, 0xD65D, 0xD65D}, {0xD65E, 0xD65E, 0xD65E}, {0xD65F, 0xD65F, 0xD65F}, {0xD660, 0xD660, 0xD660}, {0xD661, 0xD661, 0xD661}, {0xD662, 0xD662, 0xD662}, {0xD663, 0xD663, 0xD663}, {0xD664, 0xD664, 0xD664}, {0xD665, 0xD665, 0xD665}, {0xD666, 0xD666, 0xD666}, {0xD667, 0xD667, 0xD667}, {0xD668, 0xD668, 0xD668}, {0xD669, 0xD669, 0xD669}, {0xD66A, 0xD66A, 0xD66A}, {0xD66B, 0xD66B, 0xD66B}, {0xD66C, 0xD66C, 0xD66C}, {0xD66D, 0xD66D, 0xD66D}, {0xD66E, 0xD66E, 0xD66E}, {0xD66F, 0xD66F, 0xD66F}, {0xD670, 0xD670, 0xD670}, {0xD671, 0xD671, 0xD671}, {0xD672, 0xD672, 0xD672}, {0xD673, 0xD673, 0xD673}, {0xD674, 0xD674, 0xD674}, {0xD675, 0xD675, 0xD675}, {0xD676, 0xD676, 0xD676}, {0xD677, 0xD677, 0xD677}, {0xD678, 0xD678, 0xD678}, {0xD679, 0xD679, 0xD679}, {0xD67A, 0xD67A, 0xD67A}, {0xD67B, 0xD67B, 0xD67B}, {0xD67C, 0xD67C, 0xD67C}, {0xD67D, 0xD67D, 0xD67D}, {0xD67E, 0xD67E, 0xD67E}, {0xD67F, 0xD67F, 0xD67F}, {0xD680, 0xD680, 0xD680}, {0xD681, 0xD681, 0xD681}, {0xD682, 0xD682, 0xD682}, {0xD683, 0xD683, 0xD683}, {0xD684, 0xD684, 0xD684}, {0xD685, 0xD685, 0xD685}, {0xD686, 0xD686, 0xD686}, {0xD687, 0xD687, 0xD687}, {0xD688, 0xD688, 0xD688}, {0xD689, 0xD689, 0xD689}, {0xD68A, 0xD68A, 0xD68A}, {0xD68B, 0xD68B, 0xD68B}, {0xD68C, 0xD68C, 0xD68C}, {0xD68D, 0xD68D, 0xD68D}, {0xD68E, 0xD68E, 0xD68E}, {0xD68F, 0xD68F, 0xD68F}, {0xD690, 0xD690, 0xD690}, {0xD691, 0xD691, 0xD691}, {0xD692, 0xD692, 0xD692}, {0xD693, 0xD693, 0xD693}, {0xD694, 0xD694, 0xD694}, {0xD695, 0xD695, 0xD695}, {0xD696, 0xD696, 0xD696}, {0xD697, 0xD697, 0xD697}, {0xD698, 0xD698, 0xD698}, {0xD699, 0xD699, 0xD699}, {0xD69A, 0xD69A, 0xD69A}, {0xD69B, 0xD69B, 0xD69B}, {0xD69C, 0xD69C, 0xD69C}, {0xD69D, 0xD69D, 0xD69D}, {0xD69E, 0xD69E, 0xD69E}, {0xD69F, 0xD69F, 0xD69F}, {0xD6A0, 0xD6A0, 0xD6A0}, {0xD6A1, 0xD6A1, 0xD6A1}, {0xD6A2, 0xD6A2, 0xD6A2}, {0xD6A3, 0xD6A3, 0xD6A3}, {0xD6A4, 0xD6A4, 0xD6A4}, {0xD6A5, 0xD6A5, 0xD6A5}, {0xD6A6, 0xD6A6, 0xD6A6}, {0xD6A7, 0xD6A7, 0xD6A7}, {0xD6A8, 0xD6A8, 0xD6A8}, {0xD6A9, 0xD6A9, 0xD6A9}, {0xD6AA, 0xD6AA, 0xD6AA}, {0xD6AB, 0xD6AB, 0xD6AB}, {0xD6AC, 0xD6AC, 0xD6AC}, {0xD6AD, 0xD6AD, 0xD6AD}, {0xD6AE, 0xD6AE, 0xD6AE}, {0xD6AF, 0xD6AF, 0xD6AF}, {0xD6B0, 0xD6B0, 0xD6B0}, {0xD6B1, 0xD6B1, 0xD6B1}, {0xD6B2, 0xD6B2, 0xD6B2}, {0xD6B3, 0xD6B3, 0xD6B3}, {0xD6B4, 0xD6B4, 0xD6B4}, {0xD6B5, 0xD6B5, 0xD6B5}, {0xD6B6, 0xD6B6, 0xD6B6}, {0xD6B7, 0xD6B7, 0xD6B7}, {0xD6B8, 0xD6B8, 0xD6B8}, {0xD6B9, 0xD6B9, 0xD6B9}, {0xD6BA, 0xD6BA, 0xD6BA}, {0xD6BB, 0xD6BB, 0xD6BB}, {0xD6BC, 0xD6BC, 0xD6BC}, {0xD6BD, 0xD6BD, 0xD6BD}, {0xD6BE, 0xD6BE, 0xD6BE}, {0xD6BF, 0xD6BF, 0xD6BF}, {0xD6C0, 0xD6C0, 0xD6C0}, {0xD6C1, 0xD6C1, 0xD6C1}, {0xD6C2, 0xD6C2, 0xD6C2}, {0xD6C3, 0xD6C3, 0xD6C3}, {0xD6C4, 0xD6C4, 0xD6C4}, {0xD6C5, 0xD6C5, 0xD6C5}, {0xD6C6, 0xD6C6, 0xD6C6}, {0xD6C7, 0xD6C7, 0xD6C7}, {0xD6C8, 0xD6C8, 0xD6C8}, {0xD6C9, 0xD6C9, 0xD6C9}, {0xD6CA, 0xD6CA, 0xD6CA}, {0xD6CB, 0xD6CB, 0xD6CB}, {0xD6CC, 0xD6CC, 0xD6CC}, {0xD6CD, 0xD6CD, 0xD6CD}, {0xD6CE, 0xD6CE, 0xD6CE}, {0xD6CF, 0xD6CF, 0xD6CF}, {0xD6D0, 0xD6D0, 0xD6D0}, {0xD6D1, 0xD6D1, 0xD6D1}, {0xD6D2, 0xD6D2, 0xD6D2}, {0xD6D3, 0xD6D3, 0xD6D3}, {0xD6D4, 0xD6D4, 0xD6D4}, {0xD6D5, 0xD6D5, 0xD6D5}, {0xD6D6, 0xD6D6, 0xD6D6}, {0xD6D7, 0xD6D7, 0xD6D7}, {0xD6D8, 0xD6D8, 0xD6D8}, {0xD6D9, 0xD6D9, 0xD6D9}, {0xD6DA, 0xD6DA, 0xD6DA}, {0xD6DB, 0xD6DB, 0xD6DB}, {0xD6DC, 0xD6DC, 0xD6DC}, {0xD6DD, 0xD6DD, 0xD6DD}, {0xD6DE, 0xD6DE, 0xD6DE}, {0xD6DF, 0xD6DF, 0xD6DF}, {0xD6E0, 0xD6E0, 0xD6E0}, {0xD6E1, 0xD6E1, 0xD6E1}, {0xD6E2, 0xD6E2, 0xD6E2}, {0xD6E3, 0xD6E3, 0xD6E3}, {0xD6E4, 0xD6E4, 0xD6E4}, {0xD6E5, 0xD6E5, 0xD6E5}, {0xD6E6, 0xD6E6, 0xD6E6}, {0xD6E7, 0xD6E7, 0xD6E7}, {0xD6E8, 0xD6E8, 0xD6E8}, {0xD6E9, 0xD6E9, 0xD6E9}, {0xD6EA, 0xD6EA, 0xD6EA}, {0xD6EB, 0xD6EB, 0xD6EB}, {0xD6EC, 0xD6EC, 0xD6EC}, {0xD6ED, 0xD6ED, 0xD6ED}, {0xD6EE, 0xD6EE, 0xD6EE}, {0xD6EF, 0xD6EF, 0xD6EF}, {0xD6F0, 0xD6F0, 0xD6F0}, {0xD6F1, 0xD6F1, 0xD6F1}, {0xD6F2, 0xD6F2, 0xD6F2}, {0xD6F3, 0xD6F3, 0xD6F3}, {0xD6F4, 0xD6F4, 0xD6F4}, {0xD6F5, 0xD6F5, 0xD6F5}, {0xD6F6, 0xD6F6, 0xD6F6}, {0xD6F7, 0xD6F7, 0xD6F7}, {0xD6F8, 0xD6F8, 0xD6F8}, {0xD6F9, 0xD6F9, 0xD6F9}, {0xD6FA, 0xD6FA, 0xD6FA}, {0xD6FB, 0xD6FB, 0xD6FB}, {0xD6FC, 0xD6FC, 0xD6FC}, {0xD6FD, 0xD6FD, 0xD6FD}, {0xD6FE, 0xD6FE, 0xD6FE}, {0xD6FF, 0xD6FF, 0xD6FF}, {0xD700, 0xD700, 0xD700}, {0xD701, 0xD701, 0xD701}, {0xD702, 0xD702, 0xD702}, {0xD703, 0xD703, 0xD703}, {0xD704, 0xD704, 0xD704}, {0xD705, 0xD705, 0xD705}, {0xD706, 0xD706, 0xD706}, {0xD707, 0xD707, 0xD707}, {0xD708, 0xD708, 0xD708}, {0xD709, 0xD709, 0xD709}, {0xD70A, 0xD70A, 0xD70A}, {0xD70B, 0xD70B, 0xD70B}, {0xD70C, 0xD70C, 0xD70C}, {0xD70D, 0xD70D, 0xD70D}, {0xD70E, 0xD70E, 0xD70E}, {0xD70F, 0xD70F, 0xD70F}, {0xD710, 0xD710, 0xD710}, {0xD711, 0xD711, 0xD711}, {0xD712, 0xD712, 0xD712}, {0xD713, 0xD713, 0xD713}, {0xD714, 0xD714, 0xD714}, {0xD715, 0xD715, 0xD715}, {0xD716, 0xD716, 0xD716}, {0xD717, 0xD717, 0xD717}, {0xD718, 0xD718, 0xD718}, {0xD719, 0xD719, 0xD719}, {0xD71A, 0xD71A, 0xD71A}, {0xD71B, 0xD71B, 0xD71B}, {0xD71C, 0xD71C, 0xD71C}, {0xD71D, 0xD71D, 0xD71D}, {0xD71E, 0xD71E, 0xD71E}, {0xD71F, 0xD71F, 0xD71F}, {0xD720, 0xD720, 0xD720}, {0xD721, 0xD721, 0xD721}, {0xD722, 0xD722, 0xD722}, {0xD723, 0xD723, 0xD723}, {0xD724, 0xD724, 0xD724}, {0xD725, 0xD725, 0xD725}, {0xD726, 0xD726, 0xD726}, {0xD727, 0xD727, 0xD727}, {0xD728, 0xD728, 0xD728}, {0xD729, 0xD729, 0xD729}, {0xD72A, 0xD72A, 0xD72A}, {0xD72B, 0xD72B, 0xD72B}, {0xD72C, 0xD72C, 0xD72C}, {0xD72D, 0xD72D, 0xD72D}, {0xD72E, 0xD72E, 0xD72E}, {0xD72F, 0xD72F, 0xD72F}, {0xD730, 0xD730, 0xD730}, {0xD731, 0xD731, 0xD731}, {0xD732, 0xD732, 0xD732}, {0xD733, 0xD733, 0xD733}, {0xD734, 0xD734, 0xD734}, {0xD735, 0xD735, 0xD735}, {0xD736, 0xD736, 0xD736}, {0xD737, 0xD737, 0xD737}, {0xD738, 0xD738, 0xD738}, {0xD739, 0xD739, 0xD739}, {0xD73A, 0xD73A, 0xD73A}, {0xD73B, 0xD73B, 0xD73B}, {0xD73C, 0xD73C, 0xD73C}, {0xD73D, 0xD73D, 0xD73D}, {0xD73E, 0xD73E, 0xD73E}, {0xD73F, 0xD73F, 0xD73F}, {0xD740, 0xD740, 0xD740}, {0xD741, 0xD741, 0xD741}, {0xD742, 0xD742, 0xD742}, {0xD743, 0xD743, 0xD743}, {0xD744, 0xD744, 0xD744}, {0xD745, 0xD745, 0xD745}, {0xD746, 0xD746, 0xD746}, {0xD747, 0xD747, 0xD747}, {0xD748, 0xD748, 0xD748}, {0xD749, 0xD749, 0xD749}, {0xD74A, 0xD74A, 0xD74A}, {0xD74B, 0xD74B, 0xD74B}, {0xD74C, 0xD74C, 0xD74C}, {0xD74D, 0xD74D, 0xD74D}, {0xD74E, 0xD74E, 0xD74E}, {0xD74F, 0xD74F, 0xD74F}, {0xD750, 0xD750, 0xD750}, {0xD751, 0xD751, 0xD751}, {0xD752, 0xD752, 0xD752}, {0xD753, 0xD753, 0xD753}, {0xD754, 0xD754, 0xD754}, {0xD755, 0xD755, 0xD755}, {0xD756, 0xD756, 0xD756}, {0xD757, 0xD757, 0xD757}, {0xD758, 0xD758, 0xD758}, {0xD759, 0xD759, 0xD759}, {0xD75A, 0xD75A, 0xD75A}, {0xD75B, 0xD75B, 0xD75B}, {0xD75C, 0xD75C, 0xD75C}, {0xD75D, 0xD75D, 0xD75D}, {0xD75E, 0xD75E, 0xD75E}, {0xD75F, 0xD75F, 0xD75F}, {0xD760, 0xD760, 0xD760}, {0xD761, 0xD761, 0xD761}, {0xD762, 0xD762, 0xD762}, {0xD763, 0xD763, 0xD763}, {0xD764, 0xD764, 0xD764}, {0xD765, 0xD765, 0xD765}, {0xD766, 0xD766, 0xD766}, {0xD767, 0xD767, 0xD767}, {0xD768, 0xD768, 0xD768}, {0xD769, 0xD769, 0xD769}, {0xD76A, 0xD76A, 0xD76A}, {0xD76B, 0xD76B, 0xD76B}, {0xD76C, 0xD76C, 0xD76C}, {0xD76D, 0xD76D, 0xD76D}, {0xD76E, 0xD76E, 0xD76E}, {0xD76F, 0xD76F, 0xD76F}, {0xD770, 0xD770, 0xD770}, {0xD771, 0xD771, 0xD771}, {0xD772, 0xD772, 0xD772}, {0xD773, 0xD773, 0xD773}, {0xD774, 0xD774, 0xD774}, {0xD775, 0xD775, 0xD775}, {0xD776, 0xD776, 0xD776}, {0xD777, 0xD777, 0xD777}, {0xD778, 0xD778, 0xD778}, {0xD779, 0xD779, 0xD779}, {0xD77A, 0xD77A, 0xD77A}, {0xD77B, 0xD77B, 0xD77B}, {0xD77C, 0xD77C, 0xD77C}, {0xD77D, 0xD77D, 0xD77D}, {0xD77E, 0xD77E, 0xD77E}, {0xD77F, 0xD77F, 0xD77F}, {0xD780, 0xD780, 0xD780}, {0xD781, 0xD781, 0xD781}, {0xD782, 0xD782, 0xD782}, {0xD783, 0xD783, 0xD783}, {0xD784, 0xD784, 0xD784}, {0xD785, 0xD785, 0xD785}, {0xD786, 0xD786, 0xD786}, {0xD787, 0xD787, 0xD787}, {0xD788, 0xD788, 0xD788}, {0xD789, 0xD789, 0xD789}, {0xD78A, 0xD78A, 0xD78A}, {0xD78B, 0xD78B, 0xD78B}, {0xD78C, 0xD78C, 0xD78C}, {0xD78D, 0xD78D, 0xD78D}, {0xD78E, 0xD78E, 0xD78E}, {0xD78F, 0xD78F, 0xD78F}, {0xD790, 0xD790, 0xD790}, {0xD791, 0xD791, 0xD791}, {0xD792, 0xD792, 0xD792}, {0xD793, 0xD793, 0xD793}, {0xD794, 0xD794, 0xD794}, {0xD795, 0xD795, 0xD795}, {0xD796, 0xD796, 0xD796}, {0xD797, 0xD797, 0xD797}, {0xD798, 0xD798, 0xD798}, {0xD799, 0xD799, 0xD799}, {0xD79A, 0xD79A, 0xD79A}, {0xD79B, 0xD79B, 0xD79B}, {0xD79C, 0xD79C, 0xD79C}, {0xD79D, 0xD79D, 0xD79D}, {0xD79E, 0xD79E, 0xD79E}, {0xD79F, 0xD79F, 0xD79F}, {0xD7A0, 0xD7A0, 0xD7A0}, {0xD7A1, 0xD7A1, 0xD7A1}, {0xD7A2, 0xD7A2, 0xD7A2}, {0xD7A3, 0xD7A3, 0xD7A3}, {0xF900, 0xF900, 0xF900}, {0xF901, 0xF901, 0xF901}, {0xF902, 0xF902, 0xF902}, {0xF903, 0xF903, 0xF903}, {0xF904, 0xF904, 0xF904}, {0xF905, 0xF905, 0xF905}, {0xF906, 0xF906, 0xF906}, {0xF907, 0xF907, 0xF907}, {0xF908, 0xF908, 0xF908}, {0xF909, 0xF909, 0xF909}, {0xF90A, 0xF90A, 0xF90A}, {0xF90B, 0xF90B, 0xF90B}, {0xF90C, 0xF90C, 0xF90C}, {0xF90D, 0xF90D, 0xF90D}, {0xF90E, 0xF90E, 0xF90E}, {0xF90F, 0xF90F, 0xF90F}, {0xF910, 0xF910, 0xF910}, {0xF911, 0xF911, 0xF911}, {0xF912, 0xF912, 0xF912}, {0xF913, 0xF913, 0xF913}, {0xF914, 0xF914, 0xF914}, {0xF915, 0xF915, 0xF915}, {0xF916, 0xF916, 0xF916}, {0xF917, 0xF917, 0xF917}, {0xF918, 0xF918, 0xF918}, {0xF919, 0xF919, 0xF919}, {0xF91A, 0xF91A, 0xF91A}, {0xF91B, 0xF91B, 0xF91B}, {0xF91C, 0xF91C, 0xF91C}, {0xF91D, 0xF91D, 0xF91D}, {0xF91E, 0xF91E, 0xF91E}, {0xF91F, 0xF91F, 0xF91F}, {0xF920, 0xF920, 0xF920}, {0xF921, 0xF921, 0xF921}, {0xF922, 0xF922, 0xF922}, {0xF923, 0xF923, 0xF923}, {0xF924, 0xF924, 0xF924}, {0xF925, 0xF925, 0xF925}, {0xF926, 0xF926, 0xF926}, {0xF927, 0xF927, 0xF927}, {0xF928, 0xF928, 0xF928}, {0xF929, 0xF929, 0xF929}, {0xF92A, 0xF92A, 0xF92A}, {0xF92B, 0xF92B, 0xF92B}, {0xF92C, 0xF92C, 0xF92C}, {0xF92D, 0xF92D, 0xF92D}, {0xF92E, 0xF92E, 0xF92E}, {0xF92F, 0xF92F, 0xF92F}, {0xF930, 0xF930, 0xF930}, {0xF931, 0xF931, 0xF931}, {0xF932, 0xF932, 0xF932}, {0xF933, 0xF933, 0xF933}, {0xF934, 0xF934, 0xF934}, {0xF935, 0xF935, 0xF935}, {0xF936, 0xF936, 0xF936}, {0xF937, 0xF937, 0xF937}, {0xF938, 0xF938, 0xF938}, {0xF939, 0xF939, 0xF939}, {0xF93A, 0xF93A, 0xF93A}, {0xF93B, 0xF93B, 0xF93B}, {0xF93C, 0xF93C, 0xF93C}, {0xF93D, 0xF93D, 0xF93D}, {0xF93E, 0xF93E, 0xF93E}, {0xF93F, 0xF93F, 0xF93F}, {0xF940, 0xF940, 0xF940}, {0xF941, 0xF941, 0xF941}, {0xF942, 0xF942, 0xF942}, {0xF943, 0xF943, 0xF943}, {0xF944, 0xF944, 0xF944}, {0xF945, 0xF945, 0xF945}, {0xF946, 0xF946, 0xF946}, {0xF947, 0xF947, 0xF947}, {0xF948, 0xF948, 0xF948}, {0xF949, 0xF949, 0xF949}, {0xF94A, 0xF94A, 0xF94A}, {0xF94B, 0xF94B, 0xF94B}, {0xF94C, 0xF94C, 0xF94C}, {0xF94D, 0xF94D, 0xF94D}, {0xF94E, 0xF94E, 0xF94E}, {0xF94F, 0xF94F, 0xF94F}, {0xF950, 0xF950, 0xF950}, {0xF951, 0xF951, 0xF951}, {0xF952, 0xF952, 0xF952}, {0xF953, 0xF953, 0xF953}, {0xF954, 0xF954, 0xF954}, {0xF955, 0xF955, 0xF955}, {0xF956, 0xF956, 0xF956}, {0xF957, 0xF957, 0xF957}, {0xF958, 0xF958, 0xF958}, {0xF959, 0xF959, 0xF959}, {0xF95A, 0xF95A, 0xF95A}, {0xF95B, 0xF95B, 0xF95B}, {0xF95C, 0xF95C, 0xF95C}, {0xF95D, 0xF95D, 0xF95D}, {0xF95E, 0xF95E, 0xF95E}, {0xF95F, 0xF95F, 0xF95F}, {0xF960, 0xF960, 0xF960}, {0xF961, 0xF961, 0xF961}, {0xF962, 0xF962, 0xF962}, {0xF963, 0xF963, 0xF963}, {0xF964, 0xF964, 0xF964}, {0xF965, 0xF965, 0xF965}, {0xF966, 0xF966, 0xF966}, {0xF967, 0xF967, 0xF967}, {0xF968, 0xF968, 0xF968}, {0xF969, 0xF969, 0xF969}, {0xF96A, 0xF96A, 0xF96A}, {0xF96B, 0xF96B, 0xF96B}, {0xF96C, 0xF96C, 0xF96C}, {0xF96D, 0xF96D, 0xF96D}, {0xF96E, 0xF96E, 0xF96E}, {0xF96F, 0xF96F, 0xF96F}, {0xF970, 0xF970, 0xF970}, {0xF971, 0xF971, 0xF971}, {0xF972, 0xF972, 0xF972}, {0xF973, 0xF973, 0xF973}, {0xF974, 0xF974, 0xF974}, {0xF975, 0xF975, 0xF975}, {0xF976, 0xF976, 0xF976}, {0xF977, 0xF977, 0xF977}, {0xF978, 0xF978, 0xF978}, {0xF979, 0xF979, 0xF979}, {0xF97A, 0xF97A, 0xF97A}, {0xF97B, 0xF97B, 0xF97B}, {0xF97C, 0xF97C, 0xF97C}, {0xF97D, 0xF97D, 0xF97D}, {0xF97E, 0xF97E, 0xF97E}, {0xF97F, 0xF97F, 0xF97F}, {0xF980, 0xF980, 0xF980}, {0xF981, 0xF981, 0xF981}, {0xF982, 0xF982, 0xF982}, {0xF983, 0xF983, 0xF983}, {0xF984, 0xF984, 0xF984}, {0xF985, 0xF985, 0xF985}, {0xF986, 0xF986, 0xF986}, {0xF987, 0xF987, 0xF987}, {0xF988, 0xF988, 0xF988}, {0xF989, 0xF989, 0xF989}, {0xF98A, 0xF98A, 0xF98A}, {0xF98B, 0xF98B, 0xF98B}, {0xF98C, 0xF98C, 0xF98C}, {0xF98D, 0xF98D, 0xF98D}, {0xF98E, 0xF98E, 0xF98E}, {0xF98F, 0xF98F, 0xF98F}, {0xF990, 0xF990, 0xF990}, {0xF991, 0xF991, 0xF991}, {0xF992, 0xF992, 0xF992}, {0xF993, 0xF993, 0xF993}, {0xF994, 0xF994, 0xF994}, {0xF995, 0xF995, 0xF995}, {0xF996, 0xF996, 0xF996}, {0xF997, 0xF997, 0xF997}, {0xF998, 0xF998, 0xF998}, {0xF999, 0xF999, 0xF999}, {0xF99A, 0xF99A, 0xF99A}, {0xF99B, 0xF99B, 0xF99B}, {0xF99C, 0xF99C, 0xF99C}, {0xF99D, 0xF99D, 0xF99D}, {0xF99E, 0xF99E, 0xF99E}, {0xF99F, 0xF99F, 0xF99F}, {0xF9A0, 0xF9A0, 0xF9A0}, {0xF9A1, 0xF9A1, 0xF9A1}, {0xF9A2, 0xF9A2, 0xF9A2}, {0xF9A3, 0xF9A3, 0xF9A3}, {0xF9A4, 0xF9A4, 0xF9A4}, {0xF9A5, 0xF9A5, 0xF9A5}, {0xF9A6, 0xF9A6, 0xF9A6}, {0xF9A7, 0xF9A7, 0xF9A7}, {0xF9A8, 0xF9A8, 0xF9A8}, {0xF9A9, 0xF9A9, 0xF9A9}, {0xF9AA, 0xF9AA, 0xF9AA}, {0xF9AB, 0xF9AB, 0xF9AB}, {0xF9AC, 0xF9AC, 0xF9AC}, {0xF9AD, 0xF9AD, 0xF9AD}, {0xF9AE, 0xF9AE, 0xF9AE}, {0xF9AF, 0xF9AF, 0xF9AF}, {0xF9B0, 0xF9B0, 0xF9B0}, {0xF9B1, 0xF9B1, 0xF9B1}, {0xF9B2, 0xF9B2, 0xF9B2}, {0xF9B3, 0xF9B3, 0xF9B3}, {0xF9B4, 0xF9B4, 0xF9B4}, {0xF9B5, 0xF9B5, 0xF9B5}, {0xF9B6, 0xF9B6, 0xF9B6}, {0xF9B7, 0xF9B7, 0xF9B7}, {0xF9B8, 0xF9B8, 0xF9B8}, {0xF9B9, 0xF9B9, 0xF9B9}, {0xF9BA, 0xF9BA, 0xF9BA}, {0xF9BB, 0xF9BB, 0xF9BB}, {0xF9BC, 0xF9BC, 0xF9BC}, {0xF9BD, 0xF9BD, 0xF9BD}, {0xF9BE, 0xF9BE, 0xF9BE}, {0xF9BF, 0xF9BF, 0xF9BF}, {0xF9C0, 0xF9C0, 0xF9C0}, {0xF9C1, 0xF9C1, 0xF9C1}, {0xF9C2, 0xF9C2, 0xF9C2}, {0xF9C3, 0xF9C3, 0xF9C3}, {0xF9C4, 0xF9C4, 0xF9C4}, {0xF9C5, 0xF9C5, 0xF9C5}, {0xF9C6, 0xF9C6, 0xF9C6}, {0xF9C7, 0xF9C7, 0xF9C7}, {0xF9C8, 0xF9C8, 0xF9C8}, {0xF9C9, 0xF9C9, 0xF9C9}, {0xF9CA, 0xF9CA, 0xF9CA}, {0xF9CB, 0xF9CB, 0xF9CB}, {0xF9CC, 0xF9CC, 0xF9CC}, {0xF9CD, 0xF9CD, 0xF9CD}, {0xF9CE, 0xF9CE, 0xF9CE}, {0xF9CF, 0xF9CF, 0xF9CF}, {0xF9D0, 0xF9D0, 0xF9D0}, {0xF9D1, 0xF9D1, 0xF9D1}, {0xF9D2, 0xF9D2, 0xF9D2}, {0xF9D3, 0xF9D3, 0xF9D3}, {0xF9D4, 0xF9D4, 0xF9D4}, {0xF9D5, 0xF9D5, 0xF9D5}, {0xF9D6, 0xF9D6, 0xF9D6}, {0xF9D7, 0xF9D7, 0xF9D7}, {0xF9D8, 0xF9D8, 0xF9D8}, {0xF9D9, 0xF9D9, 0xF9D9}, {0xF9DA, 0xF9DA, 0xF9DA}, {0xF9DB, 0xF9DB, 0xF9DB}, {0xF9DC, 0xF9DC, 0xF9DC}, {0xF9DD, 0xF9DD, 0xF9DD}, {0xF9DE, 0xF9DE, 0xF9DE}, {0xF9DF, 0xF9DF, 0xF9DF}, {0xF9E0, 0xF9E0, 0xF9E0}, {0xF9E1, 0xF9E1, 0xF9E1}, {0xF9E2, 0xF9E2, 0xF9E2}, {0xF9E3, 0xF9E3, 0xF9E3}, {0xF9E4, 0xF9E4, 0xF9E4}, {0xF9E5, 0xF9E5, 0xF9E5}, {0xF9E6, 0xF9E6, 0xF9E6}, {0xF9E7, 0xF9E7, 0xF9E7}, {0xF9E8, 0xF9E8, 0xF9E8}, {0xF9E9, 0xF9E9, 0xF9E9}, {0xF9EA, 0xF9EA, 0xF9EA}, {0xF9EB, 0xF9EB, 0xF9EB}, {0xF9EC, 0xF9EC, 0xF9EC}, {0xF9ED, 0xF9ED, 0xF9ED}, {0xF9EE, 0xF9EE, 0xF9EE}, {0xF9EF, 0xF9EF, 0xF9EF}, {0xF9F0, 0xF9F0, 0xF9F0}, {0xF9F1, 0xF9F1, 0xF9F1}, {0xF9F2, 0xF9F2, 0xF9F2}, {0xF9F3, 0xF9F3, 0xF9F3}, {0xF9F4, 0xF9F4, 0xF9F4}, {0xF9F5, 0xF9F5, 0xF9F5}, {0xF9F6, 0xF9F6, 0xF9F6}, {0xF9F7, 0xF9F7, 0xF9F7}, {0xF9F8, 0xF9F8, 0xF9F8}, {0xF9F9, 0xF9F9, 0xF9F9}, {0xF9FA, 0xF9FA, 0xF9FA}, {0xF9FB, 0xF9FB, 0xF9FB}, {0xF9FC, 0xF9FC, 0xF9FC}, {0xF9FD, 0xF9FD, 0xF9FD}, {0xF9FE, 0xF9FE, 0xF9FE}, {0xF9FF, 0xF9FF, 0xF9FF}, {0xFA00, 0xFA00, 0xFA00}, {0xFA01, 0xFA01, 0xFA01}, {0xFA02, 0xFA02, 0xFA02}, {0xFA03, 0xFA03, 0xFA03}, {0xFA04, 0xFA04, 0xFA04}, {0xFA05, 0xFA05, 0xFA05}, {0xFA06, 0xFA06, 0xFA06}, {0xFA07, 0xFA07, 0xFA07}, {0xFA08, 0xFA08, 0xFA08}, {0xFA09, 0xFA09, 0xFA09}, {0xFA0A, 0xFA0A, 0xFA0A}, {0xFA0B, 0xFA0B, 0xFA0B}, {0xFA0C, 0xFA0C, 0xFA0C}, {0xFA0D, 0xFA0D, 0xFA0D}, {0xFA0E, 0xFA0E, 0xFA0E}, {0xFA0F, 0xFA0F, 0xFA0F}, {0xFA10, 0xFA10, 0xFA10}, {0xFA11, 0xFA11, 0xFA11}, {0xFA12, 0xFA12, 0xFA12}, {0xFA13, 0xFA13, 0xFA13}, {0xFA14, 0xFA14, 0xFA14}, {0xFA15, 0xFA15, 0xFA15}, {0xFA16, 0xFA16, 0xFA16}, {0xFA17, 0xFA17, 0xFA17}, {0xFA18, 0xFA18, 0xFA18}, {0xFA19, 0xFA19, 0xFA19}, {0xFA1A, 0xFA1A, 0xFA1A}, {0xFA1B, 0xFA1B, 0xFA1B}, {0xFA1C, 0xFA1C, 0xFA1C}, {0xFA1D, 0xFA1D, 0xFA1D}, {0xFA1E, 0xFA1E, 0xFA1E}, {0xFA1F, 0xFA1F, 0xFA1F}, {0xFA20, 0xFA20, 0xFA20}, {0xFA21, 0xFA21, 0xFA21}, {0xFA22, 0xFA22, 0xFA22}, {0xFA23, 0xFA23, 0xFA23}, {0xFA24, 0xFA24, 0xFA24}, {0xFA25, 0xFA25, 0xFA25}, {0xFA26, 0xFA26, 0xFA26}, {0xFA27, 0xFA27, 0xFA27}, {0xFA28, 0xFA28, 0xFA28}, {0xFA29, 0xFA29, 0xFA29}, {0xFA2A, 0xFA2A, 0xFA2A}, {0xFA2B, 0xFA2B, 0xFA2B}, {0xFA2C, 0xFA2C, 0xFA2C}, {0xFA2D, 0xFA2D, 0xFA2D}, {0xFA30, 0xFA30, 0xFA30}, {0xFA31, 0xFA31, 0xFA31}, {0xFA32, 0xFA32, 0xFA32}, {0xFA33, 0xFA33, 0xFA33}, {0xFA34, 0xFA34, 0xFA34}, {0xFA35, 0xFA35, 0xFA35}, {0xFA36, 0xFA36, 0xFA36}, {0xFA37, 0xFA37, 0xFA37}, {0xFA38, 0xFA38, 0xFA38}, {0xFA39, 0xFA39, 0xFA39}, {0xFA3A, 0xFA3A, 0xFA3A}, {0xFA3B, 0xFA3B, 0xFA3B}, {0xFA3C, 0xFA3C, 0xFA3C}, {0xFA3D, 0xFA3D, 0xFA3D}, {0xFA3E, 0xFA3E, 0xFA3E}, {0xFA3F, 0xFA3F, 0xFA3F}, {0xFA40, 0xFA40, 0xFA40}, {0xFA41, 0xFA41, 0xFA41}, {0xFA42, 0xFA42, 0xFA42}, {0xFA43, 0xFA43, 0xFA43}, {0xFA44, 0xFA44, 0xFA44}, {0xFA45, 0xFA45, 0xFA45}, {0xFA46, 0xFA46, 0xFA46}, {0xFA47, 0xFA47, 0xFA47}, {0xFA48, 0xFA48, 0xFA48}, {0xFA49, 0xFA49, 0xFA49}, {0xFA4A, 0xFA4A, 0xFA4A}, {0xFA4B, 0xFA4B, 0xFA4B}, {0xFA4C, 0xFA4C, 0xFA4C}, {0xFA4D, 0xFA4D, 0xFA4D}, {0xFA4E, 0xFA4E, 0xFA4E}, {0xFA4F, 0xFA4F, 0xFA4F}, {0xFA50, 0xFA50, 0xFA50}, {0xFA51, 0xFA51, 0xFA51}, {0xFA52, 0xFA52, 0xFA52}, {0xFA53, 0xFA53, 0xFA53}, {0xFA54, 0xFA54, 0xFA54}, {0xFA55, 0xFA55, 0xFA55}, {0xFA56, 0xFA56, 0xFA56}, {0xFA57, 0xFA57, 0xFA57}, {0xFA58, 0xFA58, 0xFA58}, {0xFA59, 0xFA59, 0xFA59}, {0xFA5A, 0xFA5A, 0xFA5A}, {0xFA5B, 0xFA5B, 0xFA5B}, {0xFA5C, 0xFA5C, 0xFA5C}, {0xFA5D, 0xFA5D, 0xFA5D}, {0xFA5E, 0xFA5E, 0xFA5E}, {0xFA5F, 0xFA5F, 0xFA5F}, {0xFA60, 0xFA60, 0xFA60}, {0xFA61, 0xFA61, 0xFA61}, {0xFA62, 0xFA62, 0xFA62}, {0xFA63, 0xFA63, 0xFA63}, {0xFA64, 0xFA64, 0xFA64}, {0xFA65, 0xFA65, 0xFA65}, {0xFA66, 0xFA66, 0xFA66}, {0xFA67, 0xFA67, 0xFA67}, {0xFA68, 0xFA68, 0xFA68}, {0xFA69, 0xFA69, 0xFA69}, {0xFA6A, 0xFA6A, 0xFA6A}, {0xFA70, 0xFA70, 0xFA70}, {0xFA71, 0xFA71, 0xFA71}, {0xFA72, 0xFA72, 0xFA72}, {0xFA73, 0xFA73, 0xFA73}, {0xFA74, 0xFA74, 0xFA74}, {0xFA75, 0xFA75, 0xFA75}, {0xFA76, 0xFA76, 0xFA76}, {0xFA77, 0xFA77, 0xFA77}, {0xFA78, 0xFA78, 0xFA78}, {0xFA79, 0xFA79, 0xFA79}, {0xFA7A, 0xFA7A, 0xFA7A}, {0xFA7B, 0xFA7B, 0xFA7B}, {0xFA7C, 0xFA7C, 0xFA7C}, {0xFA7D, 0xFA7D, 0xFA7D}, {0xFA7E, 0xFA7E, 0xFA7E}, {0xFA7F, 0xFA7F, 0xFA7F}, {0xFA80, 0xFA80, 0xFA80}, {0xFA81, 0xFA81, 0xFA81}, {0xFA82, 0xFA82, 0xFA82}, {0xFA83, 0xFA83, 0xFA83}, {0xFA84, 0xFA84, 0xFA84}, {0xFA85, 0xFA85, 0xFA85}, {0xFA86, 0xFA86, 0xFA86}, {0xFA87, 0xFA87, 0xFA87}, {0xFA88, 0xFA88, 0xFA88}, {0xFA89, 0xFA89, 0xFA89}, {0xFA8A, 0xFA8A, 0xFA8A}, {0xFA8B, 0xFA8B, 0xFA8B}, {0xFA8C, 0xFA8C, 0xFA8C}, {0xFA8D, 0xFA8D, 0xFA8D}, {0xFA8E, 0xFA8E, 0xFA8E}, {0xFA8F, 0xFA8F, 0xFA8F}, {0xFA90, 0xFA90, 0xFA90}, {0xFA91, 0xFA91, 0xFA91}, {0xFA92, 0xFA92, 0xFA92}, {0xFA93, 0xFA93, 0xFA93}, {0xFA94, 0xFA94, 0xFA94}, {0xFA95, 0xFA95, 0xFA95}, {0xFA96, 0xFA96, 0xFA96}, {0xFA97, 0xFA97, 0xFA97}, {0xFA98, 0xFA98, 0xFA98}, {0xFA99, 0xFA99, 0xFA99}, {0xFA9A, 0xFA9A, 0xFA9A}, {0xFA9B, 0xFA9B, 0xFA9B}, {0xFA9C, 0xFA9C, 0xFA9C}, {0xFA9D, 0xFA9D, 0xFA9D}, {0xFA9E, 0xFA9E, 0xFA9E}, {0xFA9F, 0xFA9F, 0xFA9F}, {0xFAA0, 0xFAA0, 0xFAA0}, {0xFAA1, 0xFAA1, 0xFAA1}, {0xFAA2, 0xFAA2, 0xFAA2}, {0xFAA3, 0xFAA3, 0xFAA3}, {0xFAA4, 0xFAA4, 0xFAA4}, {0xFAA5, 0xFAA5, 0xFAA5}, {0xFAA6, 0xFAA6, 0xFAA6}, {0xFAA7, 0xFAA7, 0xFAA7}, {0xFAA8, 0xFAA8, 0xFAA8}, {0xFAA9, 0xFAA9, 0xFAA9}, {0xFAAA, 0xFAAA, 0xFAAA}, {0xFAAB, 0xFAAB, 0xFAAB}, {0xFAAC, 0xFAAC, 0xFAAC}, {0xFAAD, 0xFAAD, 0xFAAD}, {0xFAAE, 0xFAAE, 0xFAAE}, {0xFAAF, 0xFAAF, 0xFAAF}, {0xFAB0, 0xFAB0, 0xFAB0}, {0xFAB1, 0xFAB1, 0xFAB1}, {0xFAB2, 0xFAB2, 0xFAB2}, {0xFAB3, 0xFAB3, 0xFAB3}, {0xFAB4, 0xFAB4, 0xFAB4}, {0xFAB5, 0xFAB5, 0xFAB5}, {0xFAB6, 0xFAB6, 0xFAB6}, {0xFAB7, 0xFAB7, 0xFAB7}, {0xFAB8, 0xFAB8, 0xFAB8}, {0xFAB9, 0xFAB9, 0xFAB9}, {0xFABA, 0xFABA, 0xFABA}, {0xFABB, 0xFABB, 0xFABB}, {0xFABC, 0xFABC, 0xFABC}, {0xFABD, 0xFABD, 0xFABD}, {0xFABE, 0xFABE, 0xFABE}, {0xFABF, 0xFABF, 0xFABF}, {0xFAC0, 0xFAC0, 0xFAC0}, {0xFAC1, 0xFAC1, 0xFAC1}, {0xFAC2, 0xFAC2, 0xFAC2}, {0xFAC3, 0xFAC3, 0xFAC3}, {0xFAC4, 0xFAC4, 0xFAC4}, {0xFAC5, 0xFAC5, 0xFAC5}, {0xFAC6, 0xFAC6, 0xFAC6}, {0xFAC7, 0xFAC7, 0xFAC7}, {0xFAC8, 0xFAC8, 0xFAC8}, {0xFAC9, 0xFAC9, 0xFAC9}, {0xFACA, 0xFACA, 0xFACA}, {0xFACB, 0xFACB, 0xFACB}, {0xFACC, 0xFACC, 0xFACC}, {0xFACD, 0xFACD, 0xFACD}, {0xFACE, 0xFACE, 0xFACE}, {0xFACF, 0xFACF, 0xFACF}, {0xFAD0, 0xFAD0, 0xFAD0}, {0xFAD1, 0xFAD1, 0xFAD1}, {0xFAD2, 0xFAD2, 0xFAD2}, {0xFAD3, 0xFAD3, 0xFAD3}, {0xFAD4, 0xFAD4, 0xFAD4}, {0xFAD5, 0xFAD5, 0xFAD5}, {0xFAD6, 0xFAD6, 0xFAD6}, {0xFAD7, 0xFAD7, 0xFAD7}, {0xFAD8, 0xFAD8, 0xFAD8}, {0xFAD9, 0xFAD9, 0xFAD9}, {0xFB00, 0xFB00, 0xFB00}, {0xFB01, 0xFB01, 0xFB01}, {0xFB02, 0xFB02, 0xFB02}, {0xFB03, 0xFB03, 0xFB03}, {0xFB04, 0xFB04, 0xFB04}, {0xFB05, 0xFB05, 0xFB05}, {0xFB06, 0xFB06, 0xFB06}, {0xFB13, 0xFB13, 0xFB13}, {0xFB14, 0xFB14, 0xFB14}, {0xFB15, 0xFB15, 0xFB15}, {0xFB16, 0xFB16, 0xFB16}, {0xFB17, 0xFB17, 0xFB17}, {0xFB1D, 0xFB1D, 0xFB1D}, {0xFB1E, 0xFB1E, 0xFB1E}, {0xFB1F, 0xFB1F, 0xFB1F}, {0xFB20, 0xFB20, 0xFB20}, {0xFB21, 0xFB21, 0xFB21}, {0xFB22, 0xFB22, 0xFB22}, {0xFB23, 0xFB23, 0xFB23}, {0xFB24, 0xFB24, 0xFB24}, {0xFB25, 0xFB25, 0xFB25}, {0xFB26, 0xFB26, 0xFB26}, {0xFB27, 0xFB27, 0xFB27}, {0xFB28, 0xFB28, 0xFB28}, {0xFB2A, 0xFB2A, 0xFB2A}, {0xFB2B, 0xFB2B, 0xFB2B}, {0xFB2C, 0xFB2C, 0xFB2C}, {0xFB2D, 0xFB2D, 0xFB2D}, {0xFB2E, 0xFB2E, 0xFB2E}, {0xFB2F, 0xFB2F, 0xFB2F}, {0xFB30, 0xFB30, 0xFB30}, {0xFB31, 0xFB31, 0xFB31}, {0xFB32, 0xFB32, 0xFB32}, {0xFB33, 0xFB33, 0xFB33}, {0xFB34, 0xFB34, 0xFB34}, {0xFB35, 0xFB35, 0xFB35}, {0xFB36, 0xFB36, 0xFB36}, {0xFB38, 0xFB38, 0xFB38}, {0xFB39, 0xFB39, 0xFB39}, {0xFB3A, 0xFB3A, 0xFB3A}, {0xFB3B, 0xFB3B, 0xFB3B}, {0xFB3C, 0xFB3C, 0xFB3C}, {0xFB3E, 0xFB3E, 0xFB3E}, {0xFB40, 0xFB40, 0xFB40}, {0xFB41, 0xFB41, 0xFB41}, {0xFB43, 0xFB43, 0xFB43}, {0xFB44, 0xFB44, 0xFB44}, {0xFB46, 0xFB46, 0xFB46}, {0xFB47, 0xFB47, 0xFB47}, {0xFB48, 0xFB48, 0xFB48}, {0xFB49, 0xFB49, 0xFB49}, {0xFB4A, 0xFB4A, 0xFB4A}, {0xFB4B, 0xFB4B, 0xFB4B}, {0xFB4C, 0xFB4C, 0xFB4C}, {0xFB4D, 0xFB4D, 0xFB4D}, {0xFB4E, 0xFB4E, 0xFB4E}, {0xFB4F, 0xFB4F, 0xFB4F}, {0xFB50, 0xFB50, 0xFB50}, {0xFB51, 0xFB51, 0xFB51}, {0xFB52, 0xFB52, 0xFB52}, {0xFB53, 0xFB53, 0xFB53}, {0xFB54, 0xFB54, 0xFB54}, {0xFB55, 0xFB55, 0xFB55}, {0xFB56, 0xFB56, 0xFB56}, {0xFB57, 0xFB57, 0xFB57}, {0xFB58, 0xFB58, 0xFB58}, {0xFB59, 0xFB59, 0xFB59}, {0xFB5A, 0xFB5A, 0xFB5A}, {0xFB5B, 0xFB5B, 0xFB5B}, {0xFB5C, 0xFB5C, 0xFB5C}, {0xFB5D, 0xFB5D, 0xFB5D}, {0xFB5E, 0xFB5E, 0xFB5E}, {0xFB5F, 0xFB5F, 0xFB5F}, {0xFB60, 0xFB60, 0xFB60}, {0xFB61, 0xFB61, 0xFB61}, {0xFB62, 0xFB62, 0xFB62}, {0xFB63, 0xFB63, 0xFB63}, {0xFB64, 0xFB64, 0xFB64}, {0xFB65, 0xFB65, 0xFB65}, {0xFB66, 0xFB66, 0xFB66}, {0xFB67, 0xFB67, 0xFB67}, {0xFB68, 0xFB68, 0xFB68}, {0xFB69, 0xFB69, 0xFB69}, {0xFB6A, 0xFB6A, 0xFB6A}, {0xFB6B, 0xFB6B, 0xFB6B}, {0xFB6C, 0xFB6C, 0xFB6C}, {0xFB6D, 0xFB6D, 0xFB6D}, {0xFB6E, 0xFB6E, 0xFB6E}, {0xFB6F, 0xFB6F, 0xFB6F}, {0xFB70, 0xFB70, 0xFB70}, {0xFB71, 0xFB71, 0xFB71}, {0xFB72, 0xFB72, 0xFB72}, {0xFB73, 0xFB73, 0xFB73}, {0xFB74, 0xFB74, 0xFB74}, {0xFB75, 0xFB75, 0xFB75}, {0xFB76, 0xFB76, 0xFB76}, {0xFB77, 0xFB77, 0xFB77}, {0xFB78, 0xFB78, 0xFB78}, {0xFB79, 0xFB79, 0xFB79}, {0xFB7A, 0xFB7A, 0xFB7A}, {0xFB7B, 0xFB7B, 0xFB7B}, {0xFB7C, 0xFB7C, 0xFB7C}, {0xFB7D, 0xFB7D, 0xFB7D}, {0xFB7E, 0xFB7E, 0xFB7E}, {0xFB7F, 0xFB7F, 0xFB7F}, {0xFB80, 0xFB80, 0xFB80}, {0xFB81, 0xFB81, 0xFB81}, {0xFB82, 0xFB82, 0xFB82}, {0xFB83, 0xFB83, 0xFB83}, {0xFB84, 0xFB84, 0xFB84}, {0xFB85, 0xFB85, 0xFB85}, {0xFB86, 0xFB86, 0xFB86}, {0xFB87, 0xFB87, 0xFB87}, {0xFB88, 0xFB88, 0xFB88}, {0xFB89, 0xFB89, 0xFB89}, {0xFB8A, 0xFB8A, 0xFB8A}, {0xFB8B, 0xFB8B, 0xFB8B}, {0xFB8C, 0xFB8C, 0xFB8C}, {0xFB8D, 0xFB8D, 0xFB8D}, {0xFB8E, 0xFB8E, 0xFB8E}, {0xFB8F, 0xFB8F, 0xFB8F}, {0xFB90, 0xFB90, 0xFB90}, {0xFB91, 0xFB91, 0xFB91}, {0xFB92, 0xFB92, 0xFB92}, {0xFB93, 0xFB93, 0xFB93}, {0xFB94, 0xFB94, 0xFB94}, {0xFB95, 0xFB95, 0xFB95}, {0xFB96, 0xFB96, 0xFB96}, {0xFB97, 0xFB97, 0xFB97}, {0xFB98, 0xFB98, 0xFB98}, {0xFB99, 0xFB99, 0xFB99}, {0xFB9A, 0xFB9A, 0xFB9A}, {0xFB9B, 0xFB9B, 0xFB9B}, {0xFB9C, 0xFB9C, 0xFB9C}, {0xFB9D, 0xFB9D, 0xFB9D}, {0xFB9E, 0xFB9E, 0xFB9E}, {0xFB9F, 0xFB9F, 0xFB9F}, {0xFBA0, 0xFBA0, 0xFBA0}, {0xFBA1, 0xFBA1, 0xFBA1}, {0xFBA2, 0xFBA2, 0xFBA2}, {0xFBA3, 0xFBA3, 0xFBA3}, {0xFBA4, 0xFBA4, 0xFBA4}, {0xFBA5, 0xFBA5, 0xFBA5}, {0xFBA6, 0xFBA6, 0xFBA6}, {0xFBA7, 0xFBA7, 0xFBA7}, {0xFBA8, 0xFBA8, 0xFBA8}, {0xFBA9, 0xFBA9, 0xFBA9}, {0xFBAA, 0xFBAA, 0xFBAA}, {0xFBAB, 0xFBAB, 0xFBAB}, {0xFBAC, 0xFBAC, 0xFBAC}, {0xFBAD, 0xFBAD, 0xFBAD}, {0xFBAE, 0xFBAE, 0xFBAE}, {0xFBAF, 0xFBAF, 0xFBAF}, {0xFBB0, 0xFBB0, 0xFBB0}, {0xFBB1, 0xFBB1, 0xFBB1}, {0xFBD3, 0xFBD3, 0xFBD3}, {0xFBD4, 0xFBD4, 0xFBD4}, {0xFBD5, 0xFBD5, 0xFBD5}, {0xFBD6, 0xFBD6, 0xFBD6}, {0xFBD7, 0xFBD7, 0xFBD7}, {0xFBD8, 0xFBD8, 0xFBD8}, {0xFBD9, 0xFBD9, 0xFBD9}, {0xFBDA, 0xFBDA, 0xFBDA}, {0xFBDB, 0xFBDB, 0xFBDB}, {0xFBDC, 0xFBDC, 0xFBDC}, {0xFBDD, 0xFBDD, 0xFBDD}, {0xFBDE, 0xFBDE, 0xFBDE}, {0xFBDF, 0xFBDF, 0xFBDF}, {0xFBE0, 0xFBE0, 0xFBE0}, {0xFBE1, 0xFBE1, 0xFBE1}, {0xFBE2, 0xFBE2, 0xFBE2}, {0xFBE3, 0xFBE3, 0xFBE3}, {0xFBE4, 0xFBE4, 0xFBE4}, {0xFBE5, 0xFBE5, 0xFBE5}, {0xFBE6, 0xFBE6, 0xFBE6}, {0xFBE7, 0xFBE7, 0xFBE7}, {0xFBE8, 0xFBE8, 0xFBE8}, {0xFBE9, 0xFBE9, 0xFBE9}, {0xFBEA, 0xFBEA, 0xFBEA}, {0xFBEB, 0xFBEB, 0xFBEB}, {0xFBEC, 0xFBEC, 0xFBEC}, {0xFBED, 0xFBED, 0xFBED}, {0xFBEE, 0xFBEE, 0xFBEE}, {0xFBEF, 0xFBEF, 0xFBEF}, {0xFBF0, 0xFBF0, 0xFBF0}, {0xFBF1, 0xFBF1, 0xFBF1}, {0xFBF2, 0xFBF2, 0xFBF2}, {0xFBF3, 0xFBF3, 0xFBF3}, {0xFBF4, 0xFBF4, 0xFBF4}, {0xFBF5, 0xFBF5, 0xFBF5}, {0xFBF6, 0xFBF6, 0xFBF6}, {0xFBF7, 0xFBF7, 0xFBF7}, {0xFBF8, 0xFBF8, 0xFBF8}, {0xFBF9, 0xFBF9, 0xFBF9}, {0xFBFA, 0xFBFA, 0xFBFA}, {0xFBFB, 0xFBFB, 0xFBFB}, {0xFBFC, 0xFBFC, 0xFBFC}, {0xFBFD, 0xFBFD, 0xFBFD}, {0xFBFE, 0xFBFE, 0xFBFE}, {0xFBFF, 0xFBFF, 0xFBFF}, {0xFC00, 0xFC00, 0xFC00}, {0xFC01, 0xFC01, 0xFC01}, {0xFC02, 0xFC02, 0xFC02}, {0xFC03, 0xFC03, 0xFC03}, {0xFC04, 0xFC04, 0xFC04}, {0xFC05, 0xFC05, 0xFC05}, {0xFC06, 0xFC06, 0xFC06}, {0xFC07, 0xFC07, 0xFC07}, {0xFC08, 0xFC08, 0xFC08}, {0xFC09, 0xFC09, 0xFC09}, {0xFC0A, 0xFC0A, 0xFC0A}, {0xFC0B, 0xFC0B, 0xFC0B}, {0xFC0C, 0xFC0C, 0xFC0C}, {0xFC0D, 0xFC0D, 0xFC0D}, {0xFC0E, 0xFC0E, 0xFC0E}, {0xFC0F, 0xFC0F, 0xFC0F}, {0xFC10, 0xFC10, 0xFC10}, {0xFC11, 0xFC11, 0xFC11}, {0xFC12, 0xFC12, 0xFC12}, {0xFC13, 0xFC13, 0xFC13}, {0xFC14, 0xFC14, 0xFC14}, {0xFC15, 0xFC15, 0xFC15}, {0xFC16, 0xFC16, 0xFC16}, {0xFC17, 0xFC17, 0xFC17}, {0xFC18, 0xFC18, 0xFC18}, {0xFC19, 0xFC19, 0xFC19}, {0xFC1A, 0xFC1A, 0xFC1A}, {0xFC1B, 0xFC1B, 0xFC1B}, {0xFC1C, 0xFC1C, 0xFC1C}, {0xFC1D, 0xFC1D, 0xFC1D}, {0xFC1E, 0xFC1E, 0xFC1E}, {0xFC1F, 0xFC1F, 0xFC1F}, {0xFC20, 0xFC20, 0xFC20}, {0xFC21, 0xFC21, 0xFC21}, {0xFC22, 0xFC22, 0xFC22}, {0xFC23, 0xFC23, 0xFC23}, {0xFC24, 0xFC24, 0xFC24}, {0xFC25, 0xFC25, 0xFC25}, {0xFC26, 0xFC26, 0xFC26}, {0xFC27, 0xFC27, 0xFC27}, {0xFC28, 0xFC28, 0xFC28}, {0xFC29, 0xFC29, 0xFC29}, {0xFC2A, 0xFC2A, 0xFC2A}, {0xFC2B, 0xFC2B, 0xFC2B}, {0xFC2C, 0xFC2C, 0xFC2C}, {0xFC2D, 0xFC2D, 0xFC2D}, {0xFC2E, 0xFC2E, 0xFC2E}, {0xFC2F, 0xFC2F, 0xFC2F}, {0xFC30, 0xFC30, 0xFC30}, {0xFC31, 0xFC31, 0xFC31}, {0xFC32, 0xFC32, 0xFC32}, {0xFC33, 0xFC33, 0xFC33}, {0xFC34, 0xFC34, 0xFC34}, {0xFC35, 0xFC35, 0xFC35}, {0xFC36, 0xFC36, 0xFC36}, {0xFC37, 0xFC37, 0xFC37}, {0xFC38, 0xFC38, 0xFC38}, {0xFC39, 0xFC39, 0xFC39}, {0xFC3A, 0xFC3A, 0xFC3A}, {0xFC3B, 0xFC3B, 0xFC3B}, {0xFC3C, 0xFC3C, 0xFC3C}, {0xFC3D, 0xFC3D, 0xFC3D}, {0xFC3E, 0xFC3E, 0xFC3E}, {0xFC3F, 0xFC3F, 0xFC3F}, {0xFC40, 0xFC40, 0xFC40}, {0xFC41, 0xFC41, 0xFC41}, {0xFC42, 0xFC42, 0xFC42}, {0xFC43, 0xFC43, 0xFC43}, {0xFC44, 0xFC44, 0xFC44}, {0xFC45, 0xFC45, 0xFC45}, {0xFC46, 0xFC46, 0xFC46}, {0xFC47, 0xFC47, 0xFC47}, {0xFC48, 0xFC48, 0xFC48}, {0xFC49, 0xFC49, 0xFC49}, {0xFC4A, 0xFC4A, 0xFC4A}, {0xFC4B, 0xFC4B, 0xFC4B}, {0xFC4C, 0xFC4C, 0xFC4C}, {0xFC4D, 0xFC4D, 0xFC4D}, {0xFC4E, 0xFC4E, 0xFC4E}, {0xFC4F, 0xFC4F, 0xFC4F}, {0xFC50, 0xFC50, 0xFC50}, {0xFC51, 0xFC51, 0xFC51}, {0xFC52, 0xFC52, 0xFC52}, {0xFC53, 0xFC53, 0xFC53}, {0xFC54, 0xFC54, 0xFC54}, {0xFC55, 0xFC55, 0xFC55}, {0xFC56, 0xFC56, 0xFC56}, {0xFC57, 0xFC57, 0xFC57}, {0xFC58, 0xFC58, 0xFC58}, {0xFC59, 0xFC59, 0xFC59}, {0xFC5A, 0xFC5A, 0xFC5A}, {0xFC5B, 0xFC5B, 0xFC5B}, {0xFC5C, 0xFC5C, 0xFC5C}, {0xFC5D, 0xFC5D, 0xFC5D}, {0xFC5E, 0xFC5E, 0xFC5E}, {0xFC5F, 0xFC5F, 0xFC5F}, {0xFC60, 0xFC60, 0xFC60}, {0xFC61, 0xFC61, 0xFC61}, {0xFC62, 0xFC62, 0xFC62}, {0xFC63, 0xFC63, 0xFC63}, {0xFC64, 0xFC64, 0xFC64}, {0xFC65, 0xFC65, 0xFC65}, {0xFC66, 0xFC66, 0xFC66}, {0xFC67, 0xFC67, 0xFC67}, {0xFC68, 0xFC68, 0xFC68}, {0xFC69, 0xFC69, 0xFC69}, {0xFC6A, 0xFC6A, 0xFC6A}, {0xFC6B, 0xFC6B, 0xFC6B}, {0xFC6C, 0xFC6C, 0xFC6C}, {0xFC6D, 0xFC6D, 0xFC6D}, {0xFC6E, 0xFC6E, 0xFC6E}, {0xFC6F, 0xFC6F, 0xFC6F}, {0xFC70, 0xFC70, 0xFC70}, {0xFC71, 0xFC71, 0xFC71}, {0xFC72, 0xFC72, 0xFC72}, {0xFC73, 0xFC73, 0xFC73}, {0xFC74, 0xFC74, 0xFC74}, {0xFC75, 0xFC75, 0xFC75}, {0xFC76, 0xFC76, 0xFC76}, {0xFC77, 0xFC77, 0xFC77}, {0xFC78, 0xFC78, 0xFC78}, {0xFC79, 0xFC79, 0xFC79}, {0xFC7A, 0xFC7A, 0xFC7A}, {0xFC7B, 0xFC7B, 0xFC7B}, {0xFC7C, 0xFC7C, 0xFC7C}, {0xFC7D, 0xFC7D, 0xFC7D}, {0xFC7E, 0xFC7E, 0xFC7E}, {0xFC7F, 0xFC7F, 0xFC7F}, {0xFC80, 0xFC80, 0xFC80}, {0xFC81, 0xFC81, 0xFC81}, {0xFC82, 0xFC82, 0xFC82}, {0xFC83, 0xFC83, 0xFC83}, {0xFC84, 0xFC84, 0xFC84}, {0xFC85, 0xFC85, 0xFC85}, {0xFC86, 0xFC86, 0xFC86}, {0xFC87, 0xFC87, 0xFC87}, {0xFC88, 0xFC88, 0xFC88}, {0xFC89, 0xFC89, 0xFC89}, {0xFC8A, 0xFC8A, 0xFC8A}, {0xFC8B, 0xFC8B, 0xFC8B}, {0xFC8C, 0xFC8C, 0xFC8C}, {0xFC8D, 0xFC8D, 0xFC8D}, {0xFC8E, 0xFC8E, 0xFC8E}, {0xFC8F, 0xFC8F, 0xFC8F}, {0xFC90, 0xFC90, 0xFC90}, {0xFC91, 0xFC91, 0xFC91}, {0xFC92, 0xFC92, 0xFC92}, {0xFC93, 0xFC93, 0xFC93}, {0xFC94, 0xFC94, 0xFC94}, {0xFC95, 0xFC95, 0xFC95}, {0xFC96, 0xFC96, 0xFC96}, {0xFC97, 0xFC97, 0xFC97}, {0xFC98, 0xFC98, 0xFC98}, {0xFC99, 0xFC99, 0xFC99}, {0xFC9A, 0xFC9A, 0xFC9A}, {0xFC9B, 0xFC9B, 0xFC9B}, {0xFC9C, 0xFC9C, 0xFC9C}, {0xFC9D, 0xFC9D, 0xFC9D}, {0xFC9E, 0xFC9E, 0xFC9E}, {0xFC9F, 0xFC9F, 0xFC9F}, {0xFCA0, 0xFCA0, 0xFCA0}, {0xFCA1, 0xFCA1, 0xFCA1}, {0xFCA2, 0xFCA2, 0xFCA2}, {0xFCA3, 0xFCA3, 0xFCA3}, {0xFCA4, 0xFCA4, 0xFCA4}, {0xFCA5, 0xFCA5, 0xFCA5}, {0xFCA6, 0xFCA6, 0xFCA6}, {0xFCA7, 0xFCA7, 0xFCA7}, {0xFCA8, 0xFCA8, 0xFCA8}, {0xFCA9, 0xFCA9, 0xFCA9}, {0xFCAA, 0xFCAA, 0xFCAA}, {0xFCAB, 0xFCAB, 0xFCAB}, {0xFCAC, 0xFCAC, 0xFCAC}, {0xFCAD, 0xFCAD, 0xFCAD}, {0xFCAE, 0xFCAE, 0xFCAE}, {0xFCAF, 0xFCAF, 0xFCAF}, {0xFCB0, 0xFCB0, 0xFCB0}, {0xFCB1, 0xFCB1, 0xFCB1}, {0xFCB2, 0xFCB2, 0xFCB2}, {0xFCB3, 0xFCB3, 0xFCB3}, {0xFCB4, 0xFCB4, 0xFCB4}, {0xFCB5, 0xFCB5, 0xFCB5}, {0xFCB6, 0xFCB6, 0xFCB6}, {0xFCB7, 0xFCB7, 0xFCB7}, {0xFCB8, 0xFCB8, 0xFCB8}, {0xFCB9, 0xFCB9, 0xFCB9}, {0xFCBA, 0xFCBA, 0xFCBA}, {0xFCBB, 0xFCBB, 0xFCBB}, {0xFCBC, 0xFCBC, 0xFCBC}, {0xFCBD, 0xFCBD, 0xFCBD}, {0xFCBE, 0xFCBE, 0xFCBE}, {0xFCBF, 0xFCBF, 0xFCBF}, {0xFCC0, 0xFCC0, 0xFCC0}, {0xFCC1, 0xFCC1, 0xFCC1}, {0xFCC2, 0xFCC2, 0xFCC2}, {0xFCC3, 0xFCC3, 0xFCC3}, {0xFCC4, 0xFCC4, 0xFCC4}, {0xFCC5, 0xFCC5, 0xFCC5}, {0xFCC6, 0xFCC6, 0xFCC6}, {0xFCC7, 0xFCC7, 0xFCC7}, {0xFCC8, 0xFCC8, 0xFCC8}, {0xFCC9, 0xFCC9, 0xFCC9}, {0xFCCA, 0xFCCA, 0xFCCA}, {0xFCCB, 0xFCCB, 0xFCCB}, {0xFCCC, 0xFCCC, 0xFCCC}, {0xFCCD, 0xFCCD, 0xFCCD}, {0xFCCE, 0xFCCE, 0xFCCE}, {0xFCCF, 0xFCCF, 0xFCCF}, {0xFCD0, 0xFCD0, 0xFCD0}, {0xFCD1, 0xFCD1, 0xFCD1}, {0xFCD2, 0xFCD2, 0xFCD2}, {0xFCD3, 0xFCD3, 0xFCD3}, {0xFCD4, 0xFCD4, 0xFCD4}, {0xFCD5, 0xFCD5, 0xFCD5}, {0xFCD6, 0xFCD6, 0xFCD6}, {0xFCD7, 0xFCD7, 0xFCD7}, {0xFCD8, 0xFCD8, 0xFCD8}, {0xFCD9, 0xFCD9, 0xFCD9}, {0xFCDA, 0xFCDA, 0xFCDA}, {0xFCDB, 0xFCDB, 0xFCDB}, {0xFCDC, 0xFCDC, 0xFCDC}, {0xFCDD, 0xFCDD, 0xFCDD}, {0xFCDE, 0xFCDE, 0xFCDE}, {0xFCDF, 0xFCDF, 0xFCDF}, {0xFCE0, 0xFCE0, 0xFCE0}, {0xFCE1, 0xFCE1, 0xFCE1}, {0xFCE2, 0xFCE2, 0xFCE2}, {0xFCE3, 0xFCE3, 0xFCE3}, {0xFCE4, 0xFCE4, 0xFCE4}, {0xFCE5, 0xFCE5, 0xFCE5}, {0xFCE6, 0xFCE6, 0xFCE6}, {0xFCE7, 0xFCE7, 0xFCE7}, {0xFCE8, 0xFCE8, 0xFCE8}, {0xFCE9, 0xFCE9, 0xFCE9}, {0xFCEA, 0xFCEA, 0xFCEA}, {0xFCEB, 0xFCEB, 0xFCEB}, {0xFCEC, 0xFCEC, 0xFCEC}, {0xFCED, 0xFCED, 0xFCED}, {0xFCEE, 0xFCEE, 0xFCEE}, {0xFCEF, 0xFCEF, 0xFCEF}, {0xFCF0, 0xFCF0, 0xFCF0}, {0xFCF1, 0xFCF1, 0xFCF1}, {0xFCF2, 0xFCF2, 0xFCF2}, {0xFCF3, 0xFCF3, 0xFCF3}, {0xFCF4, 0xFCF4, 0xFCF4}, {0xFCF5, 0xFCF5, 0xFCF5}, {0xFCF6, 0xFCF6, 0xFCF6}, {0xFCF7, 0xFCF7, 0xFCF7}, {0xFCF8, 0xFCF8, 0xFCF8}, {0xFCF9, 0xFCF9, 0xFCF9}, {0xFCFA, 0xFCFA, 0xFCFA}, {0xFCFB, 0xFCFB, 0xFCFB}, {0xFCFC, 0xFCFC, 0xFCFC}, {0xFCFD, 0xFCFD, 0xFCFD}, {0xFCFE, 0xFCFE, 0xFCFE}, {0xFCFF, 0xFCFF, 0xFCFF}, {0xFD00, 0xFD00, 0xFD00}, {0xFD01, 0xFD01, 0xFD01}, {0xFD02, 0xFD02, 0xFD02}, {0xFD03, 0xFD03, 0xFD03}, {0xFD04, 0xFD04, 0xFD04}, {0xFD05, 0xFD05, 0xFD05}, {0xFD06, 0xFD06, 0xFD06}, {0xFD07, 0xFD07, 0xFD07}, {0xFD08, 0xFD08, 0xFD08}, {0xFD09, 0xFD09, 0xFD09}, {0xFD0A, 0xFD0A, 0xFD0A}, {0xFD0B, 0xFD0B, 0xFD0B}, {0xFD0C, 0xFD0C, 0xFD0C}, {0xFD0D, 0xFD0D, 0xFD0D}, {0xFD0E, 0xFD0E, 0xFD0E}, {0xFD0F, 0xFD0F, 0xFD0F}, {0xFD10, 0xFD10, 0xFD10}, {0xFD11, 0xFD11, 0xFD11}, {0xFD12, 0xFD12, 0xFD12}, {0xFD13, 0xFD13, 0xFD13}, {0xFD14, 0xFD14, 0xFD14}, {0xFD15, 0xFD15, 0xFD15}, {0xFD16, 0xFD16, 0xFD16}, {0xFD17, 0xFD17, 0xFD17}, {0xFD18, 0xFD18, 0xFD18}, {0xFD19, 0xFD19, 0xFD19}, {0xFD1A, 0xFD1A, 0xFD1A}, {0xFD1B, 0xFD1B, 0xFD1B}, {0xFD1C, 0xFD1C, 0xFD1C}, {0xFD1D, 0xFD1D, 0xFD1D}, {0xFD1E, 0xFD1E, 0xFD1E}, {0xFD1F, 0xFD1F, 0xFD1F}, {0xFD20, 0xFD20, 0xFD20}, {0xFD21, 0xFD21, 0xFD21}, {0xFD22, 0xFD22, 0xFD22}, {0xFD23, 0xFD23, 0xFD23}, {0xFD24, 0xFD24, 0xFD24}, {0xFD25, 0xFD25, 0xFD25}, {0xFD26, 0xFD26, 0xFD26}, {0xFD27, 0xFD27, 0xFD27}, {0xFD28, 0xFD28, 0xFD28}, {0xFD29, 0xFD29, 0xFD29}, {0xFD2A, 0xFD2A, 0xFD2A}, {0xFD2B, 0xFD2B, 0xFD2B}, {0xFD2C, 0xFD2C, 0xFD2C}, {0xFD2D, 0xFD2D, 0xFD2D}, {0xFD2E, 0xFD2E, 0xFD2E}, {0xFD2F, 0xFD2F, 0xFD2F}, {0xFD30, 0xFD30, 0xFD30}, {0xFD31, 0xFD31, 0xFD31}, {0xFD32, 0xFD32, 0xFD32}, {0xFD33, 0xFD33, 0xFD33}, {0xFD34, 0xFD34, 0xFD34}, {0xFD35, 0xFD35, 0xFD35}, {0xFD36, 0xFD36, 0xFD36}, {0xFD37, 0xFD37, 0xFD37}, {0xFD38, 0xFD38, 0xFD38}, {0xFD39, 0xFD39, 0xFD39}, {0xFD3A, 0xFD3A, 0xFD3A}, {0xFD3B, 0xFD3B, 0xFD3B}, {0xFD3C, 0xFD3C, 0xFD3C}, {0xFD3D, 0xFD3D, 0xFD3D}, {0xFD50, 0xFD50, 0xFD50}, {0xFD51, 0xFD51, 0xFD51}, {0xFD52, 0xFD52, 0xFD52}, {0xFD53, 0xFD53, 0xFD53}, {0xFD54, 0xFD54, 0xFD54}, {0xFD55, 0xFD55, 0xFD55}, {0xFD56, 0xFD56, 0xFD56}, {0xFD57, 0xFD57, 0xFD57}, {0xFD58, 0xFD58, 0xFD58}, {0xFD59, 0xFD59, 0xFD59}, {0xFD5A, 0xFD5A, 0xFD5A}, {0xFD5B, 0xFD5B, 0xFD5B}, {0xFD5C, 0xFD5C, 0xFD5C}, {0xFD5D, 0xFD5D, 0xFD5D}, {0xFD5E, 0xFD5E, 0xFD5E}, {0xFD5F, 0xFD5F, 0xFD5F}, {0xFD60, 0xFD60, 0xFD60}, {0xFD61, 0xFD61, 0xFD61}, {0xFD62, 0xFD62, 0xFD62}, {0xFD63, 0xFD63, 0xFD63}, {0xFD64, 0xFD64, 0xFD64}, {0xFD65, 0xFD65, 0xFD65}, {0xFD66, 0xFD66, 0xFD66}, {0xFD67, 0xFD67, 0xFD67}, {0xFD68, 0xFD68, 0xFD68}, {0xFD69, 0xFD69, 0xFD69}, {0xFD6A, 0xFD6A, 0xFD6A}, {0xFD6B, 0xFD6B, 0xFD6B}, {0xFD6C, 0xFD6C, 0xFD6C}, {0xFD6D, 0xFD6D, 0xFD6D}, {0xFD6E, 0xFD6E, 0xFD6E}, {0xFD6F, 0xFD6F, 0xFD6F}, {0xFD70, 0xFD70, 0xFD70}, {0xFD71, 0xFD71, 0xFD71}, {0xFD72, 0xFD72, 0xFD72}, {0xFD73, 0xFD73, 0xFD73}, {0xFD74, 0xFD74, 0xFD74}, {0xFD75, 0xFD75, 0xFD75}, {0xFD76, 0xFD76, 0xFD76}, {0xFD77, 0xFD77, 0xFD77}, {0xFD78, 0xFD78, 0xFD78}, {0xFD79, 0xFD79, 0xFD79}, {0xFD7A, 0xFD7A, 0xFD7A}, {0xFD7B, 0xFD7B, 0xFD7B}, {0xFD7C, 0xFD7C, 0xFD7C}, {0xFD7D, 0xFD7D, 0xFD7D}, {0xFD7E, 0xFD7E, 0xFD7E}, {0xFD7F, 0xFD7F, 0xFD7F}, {0xFD80, 0xFD80, 0xFD80}, {0xFD81, 0xFD81, 0xFD81}, {0xFD82, 0xFD82, 0xFD82}, {0xFD83, 0xFD83, 0xFD83}, {0xFD84, 0xFD84, 0xFD84}, {0xFD85, 0xFD85, 0xFD85}, {0xFD86, 0xFD86, 0xFD86}, {0xFD87, 0xFD87, 0xFD87}, {0xFD88, 0xFD88, 0xFD88}, {0xFD89, 0xFD89, 0xFD89}, {0xFD8A, 0xFD8A, 0xFD8A}, {0xFD8B, 0xFD8B, 0xFD8B}, {0xFD8C, 0xFD8C, 0xFD8C}, {0xFD8D, 0xFD8D, 0xFD8D}, {0xFD8E, 0xFD8E, 0xFD8E}, {0xFD8F, 0xFD8F, 0xFD8F}, {0xFD92, 0xFD92, 0xFD92}, {0xFD93, 0xFD93, 0xFD93}, {0xFD94, 0xFD94, 0xFD94}, {0xFD95, 0xFD95, 0xFD95}, {0xFD96, 0xFD96, 0xFD96}, {0xFD97, 0xFD97, 0xFD97}, {0xFD98, 0xFD98, 0xFD98}, {0xFD99, 0xFD99, 0xFD99}, {0xFD9A, 0xFD9A, 0xFD9A}, {0xFD9B, 0xFD9B, 0xFD9B}, {0xFD9C, 0xFD9C, 0xFD9C}, {0xFD9D, 0xFD9D, 0xFD9D}, {0xFD9E, 0xFD9E, 0xFD9E}, {0xFD9F, 0xFD9F, 0xFD9F}, {0xFDA0, 0xFDA0, 0xFDA0}, {0xFDA1, 0xFDA1, 0xFDA1}, {0xFDA2, 0xFDA2, 0xFDA2}, {0xFDA3, 0xFDA3, 0xFDA3}, {0xFDA4, 0xFDA4, 0xFDA4}, {0xFDA5, 0xFDA5, 0xFDA5}, {0xFDA6, 0xFDA6, 0xFDA6}, {0xFDA7, 0xFDA7, 0xFDA7}, {0xFDA8, 0xFDA8, 0xFDA8}, {0xFDA9, 0xFDA9, 0xFDA9}, {0xFDAA, 0xFDAA, 0xFDAA}, {0xFDAB, 0xFDAB, 0xFDAB}, {0xFDAC, 0xFDAC, 0xFDAC}, {0xFDAD, 0xFDAD, 0xFDAD}, {0xFDAE, 0xFDAE, 0xFDAE}, {0xFDAF, 0xFDAF, 0xFDAF}, {0xFDB0, 0xFDB0, 0xFDB0}, {0xFDB1, 0xFDB1, 0xFDB1}, {0xFDB2, 0xFDB2, 0xFDB2}, {0xFDB3, 0xFDB3, 0xFDB3}, {0xFDB4, 0xFDB4, 0xFDB4}, {0xFDB5, 0xFDB5, 0xFDB5}, {0xFDB6, 0xFDB6, 0xFDB6}, {0xFDB7, 0xFDB7, 0xFDB7}, {0xFDB8, 0xFDB8, 0xFDB8}, {0xFDB9, 0xFDB9, 0xFDB9}, {0xFDBA, 0xFDBA, 0xFDBA}, {0xFDBB, 0xFDBB, 0xFDBB}, {0xFDBC, 0xFDBC, 0xFDBC}, {0xFDBD, 0xFDBD, 0xFDBD}, {0xFDBE, 0xFDBE, 0xFDBE}, {0xFDBF, 0xFDBF, 0xFDBF}, {0xFDC0, 0xFDC0, 0xFDC0}, {0xFDC1, 0xFDC1, 0xFDC1}, {0xFDC2, 0xFDC2, 0xFDC2}, {0xFDC3, 0xFDC3, 0xFDC3}, {0xFDC4, 0xFDC4, 0xFDC4}, {0xFDC5, 0xFDC5, 0xFDC5}, {0xFDC6, 0xFDC6, 0xFDC6}, {0xFDC7, 0xFDC7, 0xFDC7}, {0xFDF0, 0xFDF0, 0xFDF0}, {0xFDF1, 0xFDF1, 0xFDF1}, {0xFDF2, 0xFDF2, 0xFDF2}, {0xFDF3, 0xFDF3, 0xFDF3}, {0xFDF4, 0xFDF4, 0xFDF4}, {0xFDF5, 0xFDF5, 0xFDF5}, {0xFDF6, 0xFDF6, 0xFDF6}, {0xFDF7, 0xFDF7, 0xFDF7}, {0xFDF8, 0xFDF8, 0xFDF8}, {0xFDF9, 0xFDF9, 0xFDF9}, {0xFDFA, 0xFDFA, 0xFDFA}, {0xFDFB, 0xFDFB, 0xFDFB}, {0xFE00, 0xFE00, 0xFE00}, {0xFE01, 0xFE01, 0xFE01}, {0xFE02, 0xFE02, 0xFE02}, {0xFE03, 0xFE03, 0xFE03}, {0xFE04, 0xFE04, 0xFE04}, {0xFE05, 0xFE05, 0xFE05}, {0xFE06, 0xFE06, 0xFE06}, {0xFE07, 0xFE07, 0xFE07}, {0xFE08, 0xFE08, 0xFE08}, {0xFE09, 0xFE09, 0xFE09}, {0xFE0A, 0xFE0A, 0xFE0A}, {0xFE0B, 0xFE0B, 0xFE0B}, {0xFE0C, 0xFE0C, 0xFE0C}, {0xFE0D, 0xFE0D, 0xFE0D}, {0xFE0E, 0xFE0E, 0xFE0E}, {0xFE0F, 0xFE0F, 0xFE0F}, {0xFE20, 0xFE20, 0xFE20}, {0xFE21, 0xFE21, 0xFE21}, {0xFE22, 0xFE22, 0xFE22}, {0xFE23, 0xFE23, 0xFE23}, {0xFE70, 0xFE70, 0xFE70}, {0xFE71, 0xFE71, 0xFE71}, {0xFE72, 0xFE72, 0xFE72}, {0xFE73, 0xFE73, 0xFE73}, {0xFE74, 0xFE74, 0xFE74}, {0xFE76, 0xFE76, 0xFE76}, {0xFE77, 0xFE77, 0xFE77}, {0xFE78, 0xFE78, 0xFE78}, {0xFE79, 0xFE79, 0xFE79}, {0xFE7A, 0xFE7A, 0xFE7A}, {0xFE7B, 0xFE7B, 0xFE7B}, {0xFE7C, 0xFE7C, 0xFE7C}, {0xFE7D, 0xFE7D, 0xFE7D}, {0xFE7E, 0xFE7E, 0xFE7E}, {0xFE7F, 0xFE7F, 0xFE7F}, {0xFE80, 0xFE80, 0xFE80}, {0xFE81, 0xFE81, 0xFE81}, {0xFE82, 0xFE82, 0xFE82}, {0xFE83, 0xFE83, 0xFE83}, {0xFE84, 0xFE84, 0xFE84}, {0xFE85, 0xFE85, 0xFE85}, {0xFE86, 0xFE86, 0xFE86}, {0xFE87, 0xFE87, 0xFE87}, {0xFE88, 0xFE88, 0xFE88}, {0xFE89, 0xFE89, 0xFE89}, {0xFE8A, 0xFE8A, 0xFE8A}, {0xFE8B, 0xFE8B, 0xFE8B}, {0xFE8C, 0xFE8C, 0xFE8C}, {0xFE8D, 0xFE8D, 0xFE8D}, {0xFE8E, 0xFE8E, 0xFE8E}, {0xFE8F, 0xFE8F, 0xFE8F}, {0xFE90, 0xFE90, 0xFE90}, {0xFE91, 0xFE91, 0xFE91}, {0xFE92, 0xFE92, 0xFE92}, {0xFE93, 0xFE93, 0xFE93}, {0xFE94, 0xFE94, 0xFE94}, {0xFE95, 0xFE95, 0xFE95}, {0xFE96, 0xFE96, 0xFE96}, {0xFE97, 0xFE97, 0xFE97}, {0xFE98, 0xFE98, 0xFE98}, {0xFE99, 0xFE99, 0xFE99}, {0xFE9A, 0xFE9A, 0xFE9A}, {0xFE9B, 0xFE9B, 0xFE9B}, {0xFE9C, 0xFE9C, 0xFE9C}, {0xFE9D, 0xFE9D, 0xFE9D}, {0xFE9E, 0xFE9E, 0xFE9E}, {0xFE9F, 0xFE9F, 0xFE9F}, {0xFEA0, 0xFEA0, 0xFEA0}, {0xFEA1, 0xFEA1, 0xFEA1}, {0xFEA2, 0xFEA2, 0xFEA2}, {0xFEA3, 0xFEA3, 0xFEA3}, {0xFEA4, 0xFEA4, 0xFEA4}, {0xFEA5, 0xFEA5, 0xFEA5}, {0xFEA6, 0xFEA6, 0xFEA6}, {0xFEA7, 0xFEA7, 0xFEA7}, {0xFEA8, 0xFEA8, 0xFEA8}, {0xFEA9, 0xFEA9, 0xFEA9}, {0xFEAA, 0xFEAA, 0xFEAA}, {0xFEAB, 0xFEAB, 0xFEAB}, {0xFEAC, 0xFEAC, 0xFEAC}, {0xFEAD, 0xFEAD, 0xFEAD}, {0xFEAE, 0xFEAE, 0xFEAE}, {0xFEAF, 0xFEAF, 0xFEAF}, {0xFEB0, 0xFEB0, 0xFEB0}, {0xFEB1, 0xFEB1, 0xFEB1}, {0xFEB2, 0xFEB2, 0xFEB2}, {0xFEB3, 0xFEB3, 0xFEB3}, {0xFEB4, 0xFEB4, 0xFEB4}, {0xFEB5, 0xFEB5, 0xFEB5}, {0xFEB6, 0xFEB6, 0xFEB6}, {0xFEB7, 0xFEB7, 0xFEB7}, {0xFEB8, 0xFEB8, 0xFEB8}, {0xFEB9, 0xFEB9, 0xFEB9}, {0xFEBA, 0xFEBA, 0xFEBA}, {0xFEBB, 0xFEBB, 0xFEBB}, {0xFEBC, 0xFEBC, 0xFEBC}, {0xFEBD, 0xFEBD, 0xFEBD}, {0xFEBE, 0xFEBE, 0xFEBE}, {0xFEBF, 0xFEBF, 0xFEBF}, {0xFEC0, 0xFEC0, 0xFEC0}, {0xFEC1, 0xFEC1, 0xFEC1}, {0xFEC2, 0xFEC2, 0xFEC2}, {0xFEC3, 0xFEC3, 0xFEC3}, {0xFEC4, 0xFEC4, 0xFEC4}, {0xFEC5, 0xFEC5, 0xFEC5}, {0xFEC6, 0xFEC6, 0xFEC6}, {0xFEC7, 0xFEC7, 0xFEC7}, {0xFEC8, 0xFEC8, 0xFEC8}, {0xFEC9, 0xFEC9, 0xFEC9}, {0xFECA, 0xFECA, 0xFECA}, {0xFECB, 0xFECB, 0xFECB}, {0xFECC, 0xFECC, 0xFECC}, {0xFECD, 0xFECD, 0xFECD}, {0xFECE, 0xFECE, 0xFECE}, {0xFECF, 0xFECF, 0xFECF}, {0xFED0, 0xFED0, 0xFED0}, {0xFED1, 0xFED1, 0xFED1}, {0xFED2, 0xFED2, 0xFED2}, {0xFED3, 0xFED3, 0xFED3}, {0xFED4, 0xFED4, 0xFED4}, {0xFED5, 0xFED5, 0xFED5}, {0xFED6, 0xFED6, 0xFED6}, {0xFED7, 0xFED7, 0xFED7}, {0xFED8, 0xFED8, 0xFED8}, {0xFED9, 0xFED9, 0xFED9}, {0xFEDA, 0xFEDA, 0xFEDA}, {0xFEDB, 0xFEDB, 0xFEDB}, {0xFEDC, 0xFEDC, 0xFEDC}, {0xFEDD, 0xFEDD, 0xFEDD}, {0xFEDE, 0xFEDE, 0xFEDE}, {0xFEDF, 0xFEDF, 0xFEDF}, {0xFEE0, 0xFEE0, 0xFEE0}, {0xFEE1, 0xFEE1, 0xFEE1}, {0xFEE2, 0xFEE2, 0xFEE2}, {0xFEE3, 0xFEE3, 0xFEE3}, {0xFEE4, 0xFEE4, 0xFEE4}, {0xFEE5, 0xFEE5, 0xFEE5}, {0xFEE6, 0xFEE6, 0xFEE6}, {0xFEE7, 0xFEE7, 0xFEE7}, {0xFEE8, 0xFEE8, 0xFEE8}, {0xFEE9, 0xFEE9, 0xFEE9}, {0xFEEA, 0xFEEA, 0xFEEA}, {0xFEEB, 0xFEEB, 0xFEEB}, {0xFEEC, 0xFEEC, 0xFEEC}, {0xFEED, 0xFEED, 0xFEED}, {0xFEEE, 0xFEEE, 0xFEEE}, {0xFEEF, 0xFEEF, 0xFEEF}, {0xFEF0, 0xFEF0, 0xFEF0}, {0xFEF1, 0xFEF1, 0xFEF1}, {0xFEF2, 0xFEF2, 0xFEF2}, {0xFEF3, 0xFEF3, 0xFEF3}, {0xFEF4, 0xFEF4, 0xFEF4}, {0xFEF5, 0xFEF5, 0xFEF5}, {0xFEF6, 0xFEF6, 0xFEF6}, {0xFEF7, 0xFEF7, 0xFEF7}, {0xFEF8, 0xFEF8, 0xFEF8}, {0xFEF9, 0xFEF9, 0xFEF9}, {0xFEFA, 0xFEFA, 0xFEFA}, {0xFEFB, 0xFEFB, 0xFEFB}, {0xFEFC, 0xFEFC, 0xFEFC}, {0xFF21, 0xFF21, 0xFF41}, {0xFF22, 0xFF22, 0xFF42}, {0xFF23, 0xFF23, 0xFF43}, {0xFF24, 0xFF24, 0xFF44}, {0xFF25, 0xFF25, 0xFF45}, {0xFF26, 0xFF26, 0xFF46}, {0xFF27, 0xFF27, 0xFF47}, {0xFF28, 0xFF28, 0xFF48}, {0xFF29, 0xFF29, 0xFF49}, {0xFF2A, 0xFF2A, 0xFF4A}, {0xFF2B, 0xFF2B, 0xFF4B}, {0xFF2C, 0xFF2C, 0xFF4C}, {0xFF2D, 0xFF2D, 0xFF4D}, {0xFF2E, 0xFF2E, 0xFF4E}, {0xFF2F, 0xFF2F, 0xFF4F}, {0xFF30, 0xFF30, 0xFF50}, {0xFF31, 0xFF31, 0xFF51}, {0xFF32, 0xFF32, 0xFF52}, {0xFF33, 0xFF33, 0xFF53}, {0xFF34, 0xFF34, 0xFF54}, {0xFF35, 0xFF35, 0xFF55}, {0xFF36, 0xFF36, 0xFF56}, {0xFF37, 0xFF37, 0xFF57}, {0xFF38, 0xFF38, 0xFF58}, {0xFF39, 0xFF39, 0xFF59}, {0xFF3A, 0xFF3A, 0xFF5A}, {0xFF41, 0xFF21, 0xFF41}, {0xFF42, 0xFF22, 0xFF42}, {0xFF43, 0xFF23, 0xFF43}, {0xFF44, 0xFF24, 0xFF44}, {0xFF45, 0xFF25, 0xFF45}, {0xFF46, 0xFF26, 0xFF46}, {0xFF47, 0xFF27, 0xFF47}, {0xFF48, 0xFF28, 0xFF48}, {0xFF49, 0xFF29, 0xFF49}, {0xFF4A, 0xFF2A, 0xFF4A}, {0xFF4B, 0xFF2B, 0xFF4B}, {0xFF4C, 0xFF2C, 0xFF4C}, {0xFF4D, 0xFF2D, 0xFF4D}, {0xFF4E, 0xFF2E, 0xFF4E}, {0xFF4F, 0xFF2F, 0xFF4F}, {0xFF50, 0xFF30, 0xFF50}, {0xFF51, 0xFF31, 0xFF51}, {0xFF52, 0xFF32, 0xFF52}, {0xFF53, 0xFF33, 0xFF53}, {0xFF54, 0xFF34, 0xFF54}, {0xFF55, 0xFF35, 0xFF55}, {0xFF56, 0xFF36, 0xFF56}, {0xFF57, 0xFF37, 0xFF57}, {0xFF58, 0xFF38, 0xFF58}, {0xFF59, 0xFF39, 0xFF59}, {0xFF5A, 0xFF3A, 0xFF5A}, {0xFF66, 0xFF66, 0xFF66}, {0xFF67, 0xFF67, 0xFF67}, {0xFF68, 0xFF68, 0xFF68}, {0xFF69, 0xFF69, 0xFF69}, {0xFF6A, 0xFF6A, 0xFF6A}, {0xFF6B, 0xFF6B, 0xFF6B}, {0xFF6C, 0xFF6C, 0xFF6C}, {0xFF6D, 0xFF6D, 0xFF6D}, {0xFF6E, 0xFF6E, 0xFF6E}, {0xFF6F, 0xFF6F, 0xFF6F}, {0xFF70, 0xFF70, 0xFF70}, {0xFF71, 0xFF71, 0xFF71}, {0xFF72, 0xFF72, 0xFF72}, {0xFF73, 0xFF73, 0xFF73}, {0xFF74, 0xFF74, 0xFF74}, {0xFF75, 0xFF75, 0xFF75}, {0xFF76, 0xFF76, 0xFF76}, {0xFF77, 0xFF77, 0xFF77}, {0xFF78, 0xFF78, 0xFF78}, {0xFF79, 0xFF79, 0xFF79}, {0xFF7A, 0xFF7A, 0xFF7A}, {0xFF7B, 0xFF7B, 0xFF7B}, {0xFF7C, 0xFF7C, 0xFF7C}, {0xFF7D, 0xFF7D, 0xFF7D}, {0xFF7E, 0xFF7E, 0xFF7E}, {0xFF7F, 0xFF7F, 0xFF7F}, {0xFF80, 0xFF80, 0xFF80}, {0xFF81, 0xFF81, 0xFF81}, {0xFF82, 0xFF82, 0xFF82}, {0xFF83, 0xFF83, 0xFF83}, {0xFF84, 0xFF84, 0xFF84}, {0xFF85, 0xFF85, 0xFF85}, {0xFF86, 0xFF86, 0xFF86}, {0xFF87, 0xFF87, 0xFF87}, {0xFF88, 0xFF88, 0xFF88}, {0xFF89, 0xFF89, 0xFF89}, {0xFF8A, 0xFF8A, 0xFF8A}, {0xFF8B, 0xFF8B, 0xFF8B}, {0xFF8C, 0xFF8C, 0xFF8C}, {0xFF8D, 0xFF8D, 0xFF8D}, {0xFF8E, 0xFF8E, 0xFF8E}, {0xFF8F, 0xFF8F, 0xFF8F}, {0xFF90, 0xFF90, 0xFF90}, {0xFF91, 0xFF91, 0xFF91}, {0xFF92, 0xFF92, 0xFF92}, {0xFF93, 0xFF93, 0xFF93}, {0xFF94, 0xFF94, 0xFF94}, {0xFF95, 0xFF95, 0xFF95}, {0xFF96, 0xFF96, 0xFF96}, {0xFF97, 0xFF97, 0xFF97}, {0xFF98, 0xFF98, 0xFF98}, {0xFF99, 0xFF99, 0xFF99}, {0xFF9A, 0xFF9A, 0xFF9A}, {0xFF9B, 0xFF9B, 0xFF9B}, {0xFF9C, 0xFF9C, 0xFF9C}, {0xFF9D, 0xFF9D, 0xFF9D}, {0xFF9E, 0xFF9E, 0xFF9E}, {0xFF9F, 0xFF9F, 0xFF9F}, {0xFFA0, 0xFFA0, 0xFFA0}, {0xFFA1, 0xFFA1, 0xFFA1}, {0xFFA2, 0xFFA2, 0xFFA2}, {0xFFA3, 0xFFA3, 0xFFA3}, {0xFFA4, 0xFFA4, 0xFFA4}, {0xFFA5, 0xFFA5, 0xFFA5}, {0xFFA6, 0xFFA6, 0xFFA6}, {0xFFA7, 0xFFA7, 0xFFA7}, {0xFFA8, 0xFFA8, 0xFFA8}, {0xFFA9, 0xFFA9, 0xFFA9}, {0xFFAA, 0xFFAA, 0xFFAA}, {0xFFAB, 0xFFAB, 0xFFAB}, {0xFFAC, 0xFFAC, 0xFFAC}, {0xFFAD, 0xFFAD, 0xFFAD}, {0xFFAE, 0xFFAE, 0xFFAE}, {0xFFAF, 0xFFAF, 0xFFAF}, {0xFFB0, 0xFFB0, 0xFFB0}, {0xFFB1, 0xFFB1, 0xFFB1}, {0xFFB2, 0xFFB2, 0xFFB2}, {0xFFB3, 0xFFB3, 0xFFB3}, {0xFFB4, 0xFFB4, 0xFFB4}, {0xFFB5, 0xFFB5, 0xFFB5}, {0xFFB6, 0xFFB6, 0xFFB6}, {0xFFB7, 0xFFB7, 0xFFB7}, {0xFFB8, 0xFFB8, 0xFFB8}, {0xFFB9, 0xFFB9, 0xFFB9}, {0xFFBA, 0xFFBA, 0xFFBA}, {0xFFBB, 0xFFBB, 0xFFBB}, {0xFFBC, 0xFFBC, 0xFFBC}, {0xFFBD, 0xFFBD, 0xFFBD}, {0xFFBE, 0xFFBE, 0xFFBE}, {0xFFC2, 0xFFC2, 0xFFC2}, {0xFFC3, 0xFFC3, 0xFFC3}, {0xFFC4, 0xFFC4, 0xFFC4}, {0xFFC5, 0xFFC5, 0xFFC5}, {0xFFC6, 0xFFC6, 0xFFC6}, {0xFFC7, 0xFFC7, 0xFFC7}, {0xFFCA, 0xFFCA, 0xFFCA}, {0xFFCB, 0xFFCB, 0xFFCB}, {0xFFCC, 0xFFCC, 0xFFCC}, {0xFFCD, 0xFFCD, 0xFFCD}, {0xFFCE, 0xFFCE, 0xFFCE}, {0xFFCF, 0xFFCF, 0xFFCF}, {0xFFD2, 0xFFD2, 0xFFD2}, {0xFFD3, 0xFFD3, 0xFFD3}, {0xFFD4, 0xFFD4, 0xFFD4}, {0xFFD5, 0xFFD5, 0xFFD5}, {0xFFD6, 0xFFD6, 0xFFD6}, {0xFFD7, 0xFFD7, 0xFFD7}, {0xFFDA, 0xFFDA, 0xFFDA}, {0xFFDB, 0xFFDB, 0xFFDB}, {0xFFDC, 0xFFDC, 0xFFDC}}; nuspell-5.1.7/external/hunspell/hunspell/w_char.hxx000066400000000000000000000050531511132717100225120ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef W_CHAR_HXX_ #define W_CHAR_HXX_ #include #ifndef GCC struct w_char { #else struct __attribute__((packed)) w_char { #endif unsigned char l; unsigned char h; friend bool operator<(const w_char a, const w_char b) { unsigned short a_idx = (a.h << 8) + a.l; unsigned short b_idx = (b.h << 8) + b.l; return a_idx < b_idx; } friend bool operator==(const w_char a, const w_char b) { return (((a).l == (b).l) && ((a).h == (b).h)); } friend bool operator!=(const w_char a, const w_char b) { return !(a == b);; } }; // two character arrays struct replentry { std::string pattern; std::string outstrings[4]; // med, ini, fin, isol }; #endif nuspell-5.1.7/external/hunspell/tools/000077500000000000000000000000001511132717100200215ustar00rootroot00000000000000nuspell-5.1.7/external/hunspell/tools/affixcompress000077500000000000000000000121531511132717100226220ustar00rootroot00000000000000#!/bin/sh # affix compressor utility for Hunspell # 2008 (c) László Németh, version 0.3 # usage: affixcompress sorted_word_list_file [max_affix_rules] case $# in 0) echo \ "affixcompress - compress a huge sorted word list to Hunspell format Usage: LC_ALL=C sort word_list >sorted_word_list affixcompress sorted_word_list [max_affix_rules] Default value of max_affix_rules = 5000 Note: output may need manually added affix parameters (SET character_encoding, TRY suggestion_characters etc., see man(4) hunspell)" exit 0;; esac MAXAFFIX=${2:-5000} # profiling #AWK="pgawk --profile" AWK="awk" if which gawk; then AWK="gawk" fi rm -f $1.aff $1.dic cat $1 | $AWK ' { # calculate frequent suffixes A[$1] = 1 len = length($1) if (len > 2) { # print $1, substr($1, 1, len - 1), substr($1, len, 1) >"/dev/stderr" B[substr($1, 1, len - 1)] = substr($1, len, 1); } for(i = 2; i < len; i++) { r = substr($1, 1, i) if (i == 2) { if (prev != r) { delete A delete B print "Deleted roots: ", prev > "/dev/stderr" A[$1] = 1 } prev = r } if (A[r]) { # print $1 ": " r " és "substr($1, i + 1, len - i + 1) >"/dev/stderr" sfx[substr($1, i + 1, len - i + 1)]++ } else if (B[r] && B[r] != substr($1, i + 1, 1)) { r2 = substr($1, i + 1, len - i + 1) sfy[r2,B[r]]++ } } } END { for (i in sfx) print i, 0, sfx[i] for (i in sfy) print i, sfy[i] } ' | tr '\034' ' ' >affixcompress0.tmp sort -rnk 3 affixcompress0.tmp | $AWK '$3 >= 1{print $0}' | head -$MAXAFFIX >affixcompress1.tmp cat affixcompress1.tmp | $AWK ' function potential_roots() { # potential roots with most frequent suffixes for(word in W) if (W[word]==1) { print word >"word" len = length(word); for(i = 2; i < len; i++) { root = substr(word, 1, i) suff = substr(word, i + 1, len - i + 1) if ((W[root]!="") && (sfxfr[suff] > 100)) C[root]++ if (sfz[suff]) { l = split(sfz[suff], a) for (k=1; k <= l; k++) if ((W[root a[k]]!="") && (sfyfr[root a[k]] > 100)) { C[root a[k]]++ } } } } # calculate roots for(word in W) if (W[word]==1) { print word >"word2" len = length(word); z = 0 # choose most frequent root (maybe the original word) max = C[word] maxword = word maxsuff = 0 for(i = 2; i < len; i++) { root = substr(word, 1, i) suff = substr(word, i + 1, len - i + 1) if ((sfx[suff] != "") && (C[root] > max)) { max = C[root] maxword = root maxsuff = sfx[suff] } if (sfz[suff] != "") { l = split(sfz[suff], a) for (k=1; k <= l; k++) if (C[root a[k]] > max) { max = C[root a[k]] maxword = root a[k] maxsuff = sfy[suff,a[k]] } } } if (max > 0) { if (maxsuff > 0) print maxword, maxsuff; else print maxword A[maxword]++ z=1 } else { for(i = 2; i < len; i++) { root = substr(word, 1, i) suff = substr(word, i + 1, len - i + 1) if ((A[root] > 0) && sfx[suff]!="") { print root, sfx[suff] z = 1 break } if (sfz[suff]) { l = split(sfz[suff], a) for (k=1; k <= l; k++) if (A[root a[k]]!="") { print root a[k], sfy[suff,a[k]] z = 1 break } } } } if (z == 0) { print word A[word]++ } } delete A delete C } FILENAME == "-" { if ($2 == 0) { sfx[$1] = NR sfxfr[$1] = $3 } else { sfy[$1,$2] = NR sfyfr[$1,$2] = $3 sfz[$1] = sfz[$1] " " $2 } maxsuf = NR next } { cap = substr($1, 1, 3) if (cap != prev) { potential_roots() delete W print "Deleted class:", prev > "/dev/stderr" } prev = cap W[$1] = 1 } END { potential_roots() # write out frequent suffixes out=FILENAME ".aff" print "FLAG num" >out for (i in sfx) if (sfx[i] > 0) { print "SFX", sfx[i], "Y 1" >out print "SFX", sfx[i], "0", i, "." >out } for (i in sfy) if (sfy[i] > 0) { print "SFX", sfy[i], "Y 1" >out split(i, c, "\034"); print "SFX", sfy[i], c[2], c[1], c[2] >out } } ' - $1 >affixcompress2.tmp sort -nk 2 affixcompress2.tmp >affixcompress3.tmp cat affixcompress3.tmp | $AWK -v out="$1.dic" ' { if (A[$1]=="") A[$1]=$2; else if ($2!="") A[$1] = A[$1] "," $2 } END { for (i in A) n++ print n >out for (i in A) { if (A[i]=="") print i else print i "/" A[i] } } ' | sort >>$1.dic nuspell-5.1.7/external/hunspell/tools/analyze.cxx000066400000000000000000000072441511132717100222170ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include "../hunspell/hunspell.hxx" #ifndef WIN32 using namespace std; #endif int main(int, char** argv) { /* first parse the command line options */ for (int i = 1; i < 3; ++i) if (!argv[i]) { fprintf(stderr, "correct syntax is:\nanalyze affix_file"); fprintf(stderr, " dictionary_file file_of_words_to_check\n"); fprintf(stderr, "use two words per line for morphological generation\n"); exit(1); } /* open the words to check list */ FILE* wtclst = fopen(argv[3], "r"); if (!wtclst) { fprintf(stderr, "Error - could not open file to check\n"); exit(1); } Hunspell* pMS = new Hunspell(argv[1], argv[2]); char buf[100]; while (fgets(buf, sizeof(buf), wtclst)) { buf[strcspn(buf, "\n")] = 0; if (*buf == '\0') continue; // morphgen demo char* s = strchr(buf, ' '); if (s) { *s = '\0'; std::vector result = pMS->generate(buf, s + 1); for (size_t i = 0; i < result.size(); ++i) { fprintf(stdout, "generate(%s, %s) = %s\n", buf, s + 1, result[i].c_str()); } if (result.empty()) fprintf(stdout, "generate(%s, %s) = NO DATA\n", buf, s + 1); } else { int dp = pMS->spell(std::string(buf)); fprintf(stdout, "> %s\n", buf); if (dp) { std::vector result = pMS->analyze(buf); for (size_t i = 0; i < result.size(); ++i) { fprintf(stdout, "analyze(%s) = %s\n", buf, result[i].c_str()); } result = pMS->stem(buf); for (size_t i = 0; i < result.size(); ++i) { fprintf(stdout, "stem(%s) = %s\n", buf, result[i].c_str()); } } else { fprintf(stdout, "Unknown word.\n"); } } } delete pMS; fclose(wtclst); return 0; } nuspell-5.1.7/external/hunspell/tools/chmorph.cxx000066400000000000000000000076071511132717100222170ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include "../hunspell/hunspell.hxx" #include "../parsers/textparser.hxx" #ifndef W32 using namespace std; #endif int main(int, char** argv) { FILE* f; /* first parse the command line options */ for (int i = 1; i < 6; i++) if (!argv[i]) { fprintf( stderr, "chmorph - change affixes by morphological analysis and generation\n" "correct syntax is:\nchmorph affix_file " "dictionary_file file_to_convert STRING1 STRING2\n" "STRINGS may be arbitrary parts of the morphological descriptions\n" "example: chmorph hu.aff hu.dic hu.txt SG_2 SG_3 " " (convert informal Hungarian second person texts to formal third " "person texts)\n"); exit(1); } /* open the words to check list */ f = fopen(argv[3], "r"); if (!f) { fprintf(stderr, "Error - could not open file to check\n"); exit(1); } Hunspell* pMS = new Hunspell(argv[1], argv[2]); TextParser* p = new TextParser( "qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"); char buf[MAXLNLEN]; while (fgets(buf, MAXLNLEN, f)) { p->put_line(buf); std::string next; while (p->next_token(next)) { std::vector pl = pMS->analyze(next); if (!pl.empty()) { int gen = 0; for (size_t i = 0; i < pl.size(); ++i) { const char* pos = strstr(pl[i].c_str(), argv[4]); if (pos) { std::string r(pl[i], pos - pl[i].c_str()); r.append(argv[5]); r.append(pos + strlen(argv[4])); pl[i] = r; gen = 1; } } if (gen) { std::vector pl2 = pMS->generate(next, pl); if (!pl2.empty()) { p->change_token(pl2[0].c_str()); // jump over the (possibly un)modified word (void)p->next_token(next); } } } } fprintf(stdout, "%s\n", p->get_line().c_str()); } delete p; fclose(f); return 0; } nuspell-5.1.7/external/hunspell/tools/example.cxx000066400000000000000000000064611511132717100222070ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include "../hunspell/hunspell.hxx" using namespace std; int main(int argc, char** argv) { /* first parse the command line options */ if (argc < 4) { fprintf(stderr, "example (now it works with more dictionary files):\n"); fprintf(stderr, "example affix_file dictionary_file(s) file_of_words_to_check\n"); exit(1); } /* open the words to check list */ std::ifstream wtclst(argv[argc - 1], std::ios_base::in); if (!wtclst.is_open()) { fprintf(stderr, "Error - could not open file of words to check\n"); exit(1); } Hunspell* pMS = new Hunspell(argv[1], argv[2]); // load extra dictionaries if (argc > 4) for (int k = 3; k < argc - 1; ++k) pMS->add_dic(argv[k]); std::string buf; while (std::getline(wtclst, buf)) { int dp = pMS->spell(buf); if (dp) { fprintf(stdout, "\"%s\" is okay\n", buf.c_str()); fprintf(stdout, "\n"); } else { fprintf(stdout, "\"%s\" is incorrect!\n", buf.c_str()); fprintf(stdout, " suggestions:\n"); std::vector wlst = pMS->suggest(buf.c_str()); for (size_t i = 0; i < wlst.size(); ++i) { fprintf(stdout, " ...\"%s\"\n", wlst[i].c_str()); } fprintf(stdout, "\n"); } // for the same of testing this code path // do an analysis here and throw away the results pMS->analyze(buf); } delete pMS; return 0; } nuspell-5.1.7/external/hunspell/tools/ispellaff2myspell000066400000000000000000000314511511132717100234050ustar00rootroot00000000000000#!/usr/bin/perl -w # -*- coding: iso-8859-1 -*- # $Id$ # # (C) 2002-2005 Agustin Martin Domingo # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 this program. If not, see . sub usage { print "ispellaff2myspell: A program to convert ispell affix tables to myspell format (C) 2002-2005 Agustin Martin Domingo License: GPL Usage: ispellaff2myspell [options] Options: --affixfile=s Affix file --bylocale Use current locale setup for upper/lowercase conversion --charset=s Use specified charset for upper/lowercase conversion (defaults to latin1) --debug Print debugging info --extraflags Allow some non alphabetic flags --lowercase=s Lowercase string --myheader=s Header file --printcomments Print commented lines in output --replacements=s Replacements file --split=i Split flags with more that i entries --uppercase=s Uppercase string --wordlist=s Still unused Currently allowed valued for charset are: latin1, latin2, latin3 This script does not create the dict file. Something like ( echo `cat mydict.words+ | wc -l`; cat mydict.words+ ) > mydict.dict should do the work, with mydict.words+ being the ispell munched wordlist "; exit; } sub debugprint { if ( $debug ){ print STDERR "@_"; } } sub shipoutflag{ my $flag_entries=scalar @flag_array; if ( $flag_entries != 0 ){ if ( $split ){ while ( @flag_array ){ my @flag_subarray=splice(@flag_array,0,$split); my $subflag_entries=scalar @flag_subarray; if ( scalar @flag_array ){ print "$myaffix $flagname $flagcombine $subflag_entries S\n"; } else { print "$myaffix $flagname $flagcombine $subflag_entries\n"; } print join("\n",@flag_subarray); print "\n\n"; } } else { print "$myaffix $flagname $flagcombine $flag_entries\n"; print join("\n",@flag_array); print "\n\n"; } } @flag_array=(); $flagname=''; $flagcombine=''; } sub mylc{ my $inputstring=shift; my $outputstring; if ( $bylocale ){ { use locale; $outputstring = lc $inputstring; } } else { if ( $charset eq "latin0" ){ $lowercase='a-z'; $uppercase='A-Z޼'; } elsif ( $charset eq "latin1" ){ $lowercase='a-z'; $uppercase='A-Z'; } elsif ( $charset eq "latin2" ){ $lowercase='a-z'; $uppercase='A-Z'; } elsif ( $charset eq "latin3" ){ $lowercase='a-z'; $uppercase='A-Z'; # } elsif ( $charset eq "other_charset" ){ # die "latin2 still unimplemented"; } else { if ( not $lowercase and not $uppercase ){ die "Unsupported charset [$charset] Explicitly use --lowercase=string and --uppercase=string options. Remember that both string must match exactly, but case changed. "; } } $outputstring=$inputstring; eval "\$outputstring=~tr/$uppercase/$lowercase/"; } return $outputstring; } sub validate_flag (){ my $flag = shift; if ($flag=~m/[a-zA-Z]+/){ return $flag; } elsif ( $hasextraflags ){ foreach ( keys %theextraflags ){ if ($flag =~ m/^$_/){ $flag =~ s/^$_//; return $flag; } } } return ''; } sub process_replacements{ my $file = shift; my @replaces = (); open (REPLACE,"< $file") || die "Error: Could not open replacements file: $file\n"; while (){ next unless m/^REP[\s\t]*\D.*/; next if m/^REP\s+[0-9]+/; s/\015\012//; s/\015//; chomp; push @replaces, $_; } close REPLACE; my $number = scalar @replaces; print "REP $number\n"; foreach ( @replaces ){ print $_ . "\n"; } } # ----------------------------------------------------------- # Now the progran start, after the functions are defined # ----------------------------------------------------------- use Getopt::Long; # Initializing option values $affixfile = ''; $bylocale = ''; $charset = ''; $debug = ''; $lowercase = ''; $myheader = ''; $printcomments = ''; $replacements = ''; $split = ''; $uppercase = ''; $wordlist = ''; $hasextraflags = ''; @flag_array = (); %theextraflags = (); # Initializing root values $rootremove = "0"; $rootname = ''; $addtoroot = ''; $comment = ''; # Initializing flag values $flagname = ''; $flagcombine = ''; $inflags = ''; GetOptions ('affixfile=s' => \$affixfile, 'bylocale' => \$bylocale, 'charset=s' => \$charset, 'debug' => \$debug, 'extraflags:s' => sub { $hasextraflags = 1; shift; $theflag = shift; $theextraflags{$theflag}++ if $theflag}, 'lowercase=s' => \$lowercase, 'myheader=s' => \$myheader, 'printcomments' => \$printcomments, 'replacements=s'=> \$replacements, 'split=i' => \$split, 'uppercase=s' => \$uppercase, 'wordlist=s' => \$wordlist) or usage; if ( not $affixfile ){ $affixfile=shift or usage; } if ( $charset and ( $lowercase or $uppercase )){ die "Error: charset and lowercase/uppercase options are incompatible. Use either charset or lowercase/uppercase options to specify the patterns " } elsif ( not $lowercase and not $uppercase and not $charset ){ $charset="latin1"; } if ( scalar(keys %theextraflags) == 0 && $hasextraflags ){ $theextraflags{"\\\\"}++; } debugprint "$affixfile $charset"; open (AFFIXFILE,"< $affixfile") || die "Error: Could not open affix file: $affixfile"; if ( $myheader ){ my $myspell_header=`cat $myheader`; print $myspell_header . "\n"; } while (){ chomp; if (/^\s*\#.*/){ debugprint "Ignoring line $.\n"; print "$_\n" if $printcomments; } elsif (/^\s*$/){ debugprint "Ignoring line $.\n"; } elsif (/^\s*prefixes/){ debugprint "Prefixes starting in line $.\n"; $affix="PFX"; } elsif (/^\s*suffixes/){ debugprint "Suffixes starting in line $.\n"; $affix="SFX"; } elsif (/^[\s\t]*flag.*/){ next if not $affix; # In case we are still in the preamble shipoutflag if $inflags; $inflags="yes"; s/^[\s\t]*flag[\s\t]*//; s/[\s\t]*:.*$//; debugprint "Found flag $_ in line $.\n"; if (/\*/){ s/[\*\s]//g; $flagcombine="Y"; debugprint "Flag renamed to $_ with combine=$flagcombine\n"; } else { $flagcombine="N"; } if ( $flagname = &validate_flag($_) ){ $myaffix = $affix; } else { $myaffix = "\# $affix"; $flagname = $_; print STDERR "Ignoring invalid flag $flagname in line $.\n"; } } elsif ( $affix and $inflags ) { ($rootname,@comments) = split('#',$_); $comment = '# ' . join('#',@comments); $rootname =~ s/\s*//g; $rootname = mylc $rootname; ($rootname,$addtoroot) = split('>',$rootname); if ( $addtoroot =~ s/^\-//g ){ ($rootremove,$addtoroot) = split(',',$addtoroot); $addtoroot = "0" unless $addtoroot; $addtoroot = "0" if ( $addtoroot eq "-"); } else { $rootremove = "0"; } $addtoroot =~ s/\\\-/\-/g; # prefix ANTI\- to anti- if ( $rootname eq '.' && $rootremove ne "0" ){ $rootname = $rootremove; } debugprint "$rootname, $addtoroot, $rootremove\n"; if ( $printcomments ){ $affix_line=sprintf("%s %s %-5s %-11s %-24s %s", $myaffix, $flagname, $rootremove, $addtoroot, $rootname, $comment); } else { $affix_line=sprintf("%s %s %-5s %-11s %s", $myaffix, $flagname, $rootremove, $addtoroot, $rootname); } $rootremove = "0"; $rootname = ''; $addtoroot = ''; $comment = ''; @comments = (); push @flag_array,$affix_line; debugprint "$affix_line\n"; } else { # } } shipoutflag; close AFFIXFILE; if ( $replacements ){ &process_replacements($replacements); } __END__ =head1 NAME B - A program to convert ispell affix tables to myspell format. =head1 SYNOPSIS ispellaff2myspell [options] --myheader your_header Options: --affixfile=s Affix file --bylocale Use current locale setup for upper/lowercase conversion --charset=s Use specified charset for upper/lowercase conversion (defaults to latin1) --debug Print debugging info --extraflags=s Allow some non alphabetic flags --lowercase=s Lowercase string --myheader=s Header file --printcomments Print commented lines in output --replacements=s Replacements file --split=i Split flags with more that i entries --uppercase=s Uppercase string =head1 DESCRIPTION B is a script that will convert ispell affix tables to myspell format in a more or less successful way. This script does not create the dict file. Something like ( echo `cat mydict.words+ | wc -l`; cat mydict.words+ ) > mydict.dict should do the work, with mydict.words+ being the munched wordlist =head1 OPTIONS =over 8 =item B<--affixfile=s> Affix file. You can put it directly in the command line. =item B<--bylocale> Use current locale setup for upper/lowercase conversion. Make sure that the selected locale match the dictionary one, or you might get into trouble. =item B<--charset=s> Use specified charset for upper/lowercase conversion (defaults to latin1). Currently allowed values for charset are: latin0, latin1, latin2, latin3. =item B<--debug> Print some debugging info. =item B<--extraflags:s> Allows some non alphabetic flags. When invoked with no value the supported flags are currently those corresponding to chars represented with the escape char B<\> as first char. B<\> will be stripped. When given with the flag prefix will allow that flag and strip the given prefix. Be careful when giving the prefix to properly escape chars, e.g. you will need B<-e "\\\\"> or B<-e '\\'> for flags like B<\[> to be stripped to B<[>. Otherwise you might even get errors. Use B<-e "^"> to allow all flags and pass them unmodified. You will need a call to -e for each flag type, e.g., B<-e "\\\\" -e "~\\\\"> (or B<-e '\\' -e '~\\'>). When a prefix is explicitely set, the default value (anything starting by B<\>) is disabled and you need to enable it explicitely as in previous example. =item B<--lowercase=s> Lowercase string. Manually set the string of lowercase chars. This requires B<--uppercase> having exactly that string but uppercase. =item B<--myheader=s> Header file. The myspell aff header. You need to write it manually. This can contain everything you want to be before the affix table =item B<--printcomments> Print commented lines in output. =item B<--replacements=file> Add a pre-defined replacements table taken from 'file' to the .aff file. Will skip lines not beginning with REP, and set the replacements number appropriately. =item B<--split=i> Split flags with more that i entries. This can be of interest for flags having a lot of entries. Will split the flag in chunks containing B entries. =item B<--uppercase=s> Uppercase string. Manually set the sring of uppercase chars. This requires B<--lowercase> having exactly that string but lowercase. =back If your encoding is currently unsupported you can send me a file with the two strings of lower and uppercase chars. Note that they must match exactly but case changed. It will look something like $lowercase='a-z'; $uppercase='A-Z'; =head1 SEE ALSO The OpenOffice.org Lingucomponent Project home page L and the document L that provides information about the basics of the myspell affix file format. You can also take a look at /usr/share/doc/libmyspell-dev/affix.readme.gz /usr/share/doc/libmyspell-dev/README.compoundwords /usr/share/doc/libmyspell-dev/README.replacetable in your Debian system. =head1 AUTHORS Agustin Martin =cut nuspell-5.1.7/external/hunspell/tools/makealias000077500000000000000000000050041511132717100216750ustar00rootroot00000000000000#!/bin/sh # makealias: make alias compressed dic and aff files # Usage: alias.sh dic aff (not alias.sh aff dic!) # Version: 2007-10-26 case $# in 0|1) echo 'makealias: make alias compressed dic and aff files Usage: makealias file.dic file.aff (not makefile file.aff file.dic!)' >/dev/stderr exit;; esac DIC=`basename $1 .dic` AFF=`basename $2 .aff` # FLAG type definition must be before alias definitions grep '^FLAG' $2 >"${AFF}_alias.aff" awk 'BEGIN{n=1;m=1} function cutslash(st) { if (split(st,t,"/") > 1) return t[1] return st } function ltrim(st) { sub(/^ +/,"",st) return st } FILENAME ~ /.dic$/ && $1 ~ "/[^ \t]" { split($1,t,"/") if(!a[t[2]]){ a[t[2]]=n b[n]=t[2] n++ } if (NF > 1) { $1 = "" if(!a2[$0]){ a2[$0]=m c[m]=$0 m++ } print t[1]"/"a[t[2]] "\t" a2[$0] } else { print t[1]"/"a[t[2]] } next } FILENAME ~ /.dic$/ && NF > 1 { x = $1 $1 = "" if(!a2[$0]){ a2[$0]=m c[m]=$0 m++ } print cutslash(x) "\t" a2[$0] next } FILENAME ~ /.dic$/ { print cutslash($1) } FILENAME ~ /.aff$/ && /^[PS]FX/ && ($4 ~ /\/[^ ]/) && NF > 4 { split($4,t,"/") if(!a[t[2]]){ a[t[2]]=n b[n]=t[2] n++ } begin = $1 " " $2 " " $3 " " (t[1]"/"a[t[2]]) " " $5 if ($6!="") ok = 1; else ok = 0; $1 = "" $2 = "" $3 = "" $4 = "" $5 = "" if(ok){ if(!a2[$0]){ a2[$0]=m c[m]=$0 m++ } print begin " " a2[$0] >>"/dev/stderr" } else print begin >>"/dev/stderr" next } FILENAME ~ /.aff$/ && /^[PS]FX/ && NF > 4 { begin = $1 " " $2 " " $3 " " cutslash($4) " " $5 if ($6!="") ok = 1; else ok = 0; $1 = "" $2 = "" $3 = "" $4 = "" $5 = "" if(ok) { if (!a2[$0]){ a2[$0]=m c[m]=$0 m++ } print begin " " a2[$0] >>"/dev/stderr" } else print begin >>"/dev/stderr" next } FILENAME ~ /.aff$/ { print $0 >>"/dev/stderr" } END{ if (n>1) { print "AF", n-1 >>"'${AFF}_alias.aff'" for(i=1;i>"'${AFF}_alias.aff'" } if (m>1) { print "AM", m-1 >>"'${AFF}_alias.aff'" for(i=1;i>"'${AFF}_alias.aff'" } }' $1 $2 >${DIC}_alias.dic 2>${AFF}_alias.$$ grep -v '^FLAG' ${AFF}_alias.$$ >>${AFF}_alias.aff echo "output: ${DIC}_alias.dic, ${AFF}_alias.aff" rm ${AFF}_alias.$$ nuspell-5.1.7/external/hunspell/tools/munch.cxx000066400000000000000000000544471511132717100216750ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* Munch a word list and generate a smaller root word list with affixes*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "munch.h" int main(int argc, char** argv) { int i, j, k, n; int rl, p, nwl; int al; FILE* wrdlst; FILE* afflst; char *nword, *wf, *af; char as[(MAX_PREFIXES + MAX_SUFFIXES)]; char* ap; struct hentry* ep; struct hentry* ep1; struct affent* pfxp; struct affent* sfxp; (void)argc; /* first parse the command line options */ /* arg1 - wordlist, arg2 - affix file */ if (argv[1]) { wf = mystrdup(argv[1]); } else { fprintf(stderr, "correct syntax is:\n"); fprintf(stderr, "munch word_list_file affix_file\n"); exit(1); } if (argv[2]) { af = mystrdup(argv[2]); } else { fprintf(stderr, "correct syntax is:\n"); fprintf(stderr, "munch word_list_file affix_file\n"); exit(1); } /* open the affix file */ afflst = fopen(af, "r"); if (!afflst) { fprintf(stderr, "Error - could not open affix description file\n"); exit(1); } /* step one is to parse the affix file building up the internal affix data structures */ numpfx = 0; numsfx = 0; if (parse_aff_file(afflst)) { fprintf(stderr, "Error - in affix file loading\n"); exit(1); } fclose(afflst); fprintf(stderr, "parsed in %d prefixes and %d suffixes\n", numpfx, numsfx); /* affix file is now parsed so create hash table of wordlist on the fly */ /* open the wordlist */ wrdlst = fopen(wf, "r"); if (!wrdlst) { fprintf(stderr, "Error - could not open word list file\n"); exit(1); } if (load_tables(wrdlst)) { fprintf(stderr, "Error building hash tables\n"); exit(1); } fclose(wrdlst); for (i = 0; i < tablesize; i++) { ep = &tableptr[i]; if (ep->word == NULL) continue; for (; ep != NULL; ep = ep->next) { numroots = 0; aff_chk(ep->word, strlen(ep->word)); if (numroots) { /* now there might be a number of combinations */ /* of prefixes and suffixes that might match this */ /* word. So how to choose? As a first shot look */ /* for the shortest remaining root word to */ /* to maximize the combinatorial power */ /* but be careful, do not REQUIRE a specific combination */ /* of a prefix and a suffix to generate the word since */ /* that violates the rule that the root word with just */ /* the prefix or just the suffix must also exist in the */ /* wordlist as well */ /* in fact because of the cross product issue, this not a */ /* simple choice since some combinations of previous */ /* prefixes and new suffixes may not be valid. */ /* The only way to know is to simply try them all */ rl = 1000; p = -1; for (j = 0; j < numroots; j++) { /* first collect the root word info and build up */ /* the potential new affix string */ nword = (roots[j].hashent)->word; nwl = strlen(nword); *as = '\0'; ap = as; if (roots[j].prefix) *ap++ = (roots[j].prefix)->achar; if (roots[j].suffix) *ap++ = (roots[j].suffix)->achar; if ((roots[j].hashent)->affstr) { strcpy(ap, (roots[j].hashent)->affstr); } else { *ap = '\0'; } al = strlen(as); /* now expand the potential affix string to generate */ /* all legal words and make sure they all exist in the */ /* word list */ numwords = 0; wlist[numwords].word = mystrdup(nword); wlist[numwords].pallow = 0; numwords++; n = 0; if (al) expand_rootword(nword, nwl, as); for (k = 0; k < numwords; k++) { if (lookup(wlist[k].word)) n++; free(wlist[k].word); wlist[k].word = NULL; wlist[k].pallow = 0; } /* if all exist in word list then okay */ if (n == numwords) { if (nwl < rl) { rl = nwl; p = j; } } } if (p != -1) { ep1 = roots[p].hashent; pfxp = roots[p].prefix; sfxp = roots[p].suffix; ep1->keep = 1; if (pfxp != NULL) add_affix_char(ep1, pfxp->achar); if (sfxp != NULL) add_affix_char(ep1, sfxp->achar); } else { ep->keep = 1; } } else { ep->keep = 1; } } } /* now output only the words to keep along with affixes info */ /* first count how many words that is */ k = 0; for (i = 0; i < tablesize; i++) { ep = &tableptr[i]; if (ep->word == NULL) continue; for (; ep != NULL; ep = ep->next) { if (ep->keep > 0) k++; } } fprintf(stdout, "%d\n", k); for (i = 0; i < tablesize; i++) { ep = &tableptr[i]; if (ep->word == NULL) continue; for (; ep != NULL; ep = ep->next) { if (ep->keep > 0) { if (ep->affstr != NULL) { fprintf(stdout, "%s/%s\n", ep->word, ep->affstr); } else { fprintf(stdout, "%s\n", ep->word); } } } } return 0; } int parse_aff_file(FILE* afflst) { int i, j; int numents = 0; char achar = '\0'; short ff = 0; struct affent* ptr = NULL; struct affent* nptr = NULL; char* line = (char*)malloc(MAX_LN_LEN); while (fgets(line, MAX_LN_LEN, afflst)) { mychomp(line); char ft = ' '; fprintf(stderr, "parsing line: %s\n", line); if (strncmp(line, "PFX", 3) == 0) ft = 'P'; if (strncmp(line, "SFX", 3) == 0) ft = 'S'; if (ft != ' ') { char* tp = line; char* piece; i = 0; ff = 0; while ((piece = mystrsep(&tp, ' '))) { if (*piece != '\0') { switch (i) { case 0: break; case 1: { achar = *piece; break; } case 2: { if (*piece == 'Y') ff = XPRODUCT; break; } case 3: { numents = atoi(piece); if ((numents <= 0) || ((std::numeric_limits::max() / sizeof(struct affent)) < static_cast(numents))) { fprintf(stderr, "Error: too many entries: %d\n", numents); numents = 0; } else { ptr = (struct affent*)malloc(numents * sizeof(struct affent)); ptr->achar = achar; ptr->xpflg = ff; fprintf(stderr, "parsing %c entries %d\n", achar, numents); } break; } default: break; } i++; } free(piece); } /* now parse all of the sub entries*/ nptr = ptr; for (j = 0; j < numents; j++) { if (!fgets(line, MAX_LN_LEN, afflst)) return 1; mychomp(line); tp = line; i = 0; while ((piece = mystrsep(&tp, ' '))) { if (*piece != '\0') { switch (i) { case 0: { if (nptr != ptr) { nptr->achar = ptr->achar; nptr->xpflg = ptr->xpflg; } break; } case 1: break; case 2: { nptr->strip = mystrdup(piece); nptr->stripl = strlen(nptr->strip); if (strcmp(nptr->strip, "0") == 0) { free(nptr->strip); nptr->strip = mystrdup(""); nptr->stripl = 0; } break; } case 3: { nptr->appnd = mystrdup(piece); nptr->appndl = strlen(nptr->appnd); if (strcmp(nptr->appnd, "0") == 0) { free(nptr->appnd); nptr->appnd = mystrdup(""); nptr->appndl = 0; } break; } case 4: { encodeit(nptr, piece); } fprintf(stderr, " affix: %s %d, strip: %s %d\n", nptr->appnd, nptr->appndl, nptr->strip, nptr->stripl); // no break default: break; } i++; } free(piece); } nptr++; } if (ft == 'P') { if (numpfx < MAX_PREFIXES) { ptable[numpfx].aep = ptr; ptable[numpfx].num = numents; fprintf(stderr, "ptable %d num is %d\n", numpfx, ptable[numpfx].num); numpfx++; } else { fprintf(stderr, "prefix buffer ptable is full\n"); } } else { if (numsfx < MAX_SUFFIXES) { stable[numsfx].aep = ptr; stable[numsfx].num = numents; fprintf(stderr, "stable %d num is %d\n", numsfx, stable[numsfx].num); numsfx++; } else { fprintf(stderr, "suffix buffer stable is full\n"); } } ptr = NULL; nptr = NULL; numents = 0; achar = '\0'; } } free(line); return 0; } void encodeit(struct affent* ptr, char* cs) { int nc; int neg; int grp; int n; int ec; int nm; int i, j, k; unsigned char mbr[MAX_WD_LEN]; /* now clear the conditions array */ for (i = 0; i < SET_SIZE; i++) ptr->conds[i] = (unsigned char)0; /* now parse the string to create the conds array */ nc = strlen(cs); neg = 0; /* complement indicator */ grp = 0; /* group indicator */ n = 0; /* number of conditions */ ec = 0; /* end condition indicator */ nm = 0; /* number of member in group */ i = 0; if (strcmp(cs, ".") == 0) { ptr->numconds = 0; return; } while (i < nc) { unsigned char c = *((unsigned char*)(cs + i)); if (c == '[') { grp = 1; c = 0; } if ((grp == 1) && (c == '^')) { neg = 1; c = 0; } if (c == ']') { ec = 1; c = 0; } if ((grp == 1) && (c != 0)) { *(mbr + nm) = c; nm++; c = 0; } if (c != 0) { ec = 1; } if (ec) { if (grp == 1) { if (neg == 0) { for (j = 0; j < nm; j++) { k = (unsigned int)mbr[j]; ptr->conds[k] = ptr->conds[k] | (1 << n); } } else { for (j = 0; j < SET_SIZE; j++) ptr->conds[j] = ptr->conds[j] | (1 << n); for (j = 0; j < nm; j++) { k = (unsigned int)mbr[j]; ptr->conds[k] = ptr->conds[k] & ~(1 << n); } } neg = 0; grp = 0; nm = 0; } else { /* not a group so just set the proper bit for this char */ /* but first handle special case of . inside condition */ if (c == '.') { /* wild card character so set them all */ for (j = 0; j < SET_SIZE; j++) ptr->conds[j] = ptr->conds[j] | (1 << n); } else { ptr->conds[(unsigned int)c] = ptr->conds[(unsigned int)c] | (1 << n); } } n++; ec = 0; } i++; } ptr->numconds = n; return; } /* search for a prefix */ void pfx_chk(const char* word, int len, struct affent* ep, int num) { struct affent* aent; int cond; struct hentry* hent; int i; for (aent = ep, i = num; i > 0; aent++, i--) { int tlen = len - aent->appndl; if (tlen > 0 && (aent->appndl == 0 || strncmp(aent->appnd, word, aent->appndl) == 0) && tlen + aent->stripl >= aent->numconds) { std::string tword(aent->strip); tword.append(word + aent->appndl); /* now go through the conds and make sure they all match */ unsigned char* cp = (unsigned char*)tword.c_str(); for (cond = 0; cond < aent->numconds; cond++) { if ((aent->conds[*cp++] & (1 << cond)) == 0) break; } if (cond >= aent->numconds) { if ((hent = lookup(tword.c_str())) != NULL) { if (numroots < MAX_ROOTS) { roots[numroots].hashent = hent; roots[numroots].prefix = aent; roots[numroots].suffix = NULL; numroots++; } } } } } } void suf_chk(const char* word, int len, struct affent* ep, int num, struct affent* pfxent, int cpflag) { struct affent* aent; int cond; struct hentry* hent; int i; for (aent = ep, i = num; i > 0; aent++, i--) { if ((cpflag & XPRODUCT) != 0 && (aent->xpflg & XPRODUCT) == 0) continue; int tlen = len - aent->appndl; if (tlen > 0 && (aent->appndl == 0 || strcmp(aent->appnd, (word + tlen)) == 0) && tlen + aent->stripl >= aent->numconds) { std::string tword(word); tword.resize(tlen); tword.append(aent->strip); unsigned char* cp = (unsigned char*)(tword.c_str() + tword.size()); for (cond = aent->numconds; --cond >= 0;) { if ((aent->conds[*--cp] & (1 << cond)) == 0) break; } if (cond < 0) { if ((hent = lookup(tword.c_str())) != NULL) { if (numroots < MAX_ROOTS) { roots[numroots].hashent = hent; roots[numroots].prefix = pfxent; roots[numroots].suffix = aent; numroots++; } } } } } } void aff_chk(const char* word, int len) { int i; int nh = 0; if (len < 4) return; for (i = 0; i < numpfx; i++) { pfx_chk(word, len, ptable[i].aep, ptable[i].num); } nh = numroots; if (nh > 0) { for (int j = 0; j < nh; j++) { if (roots[j].prefix->xpflg & XPRODUCT) { char* nword = mystrdup((roots[j].hashent)->word); int nwl = strlen(nword); for (i = 0; i < numsfx; i++) { suf_chk(nword, nwl, stable[i].aep, stable[i].num, roots[j].prefix, XPRODUCT); } free(nword); } } } for (i = 0; i < numsfx; i++) { suf_chk(word, len, stable[i].aep, stable[i].num, NULL, 0); } } /* lookup a root word in the hashtable */ struct hentry* lookup(const char* word) { struct hentry* dp; dp = &tableptr[hash(word)]; if (dp->word == NULL) return NULL; for (; dp != NULL; dp = dp->next) { if (strcmp(word, dp->word) == 0) return dp; } return NULL; } /* add a word to the hash table */ int add_word(char* word) { int i; struct hentry* dp; struct hentry* hp = (struct hentry*)malloc(sizeof(struct hentry)); hp->word = word; hp->affstr = NULL; hp->keep = 0; hp->next = NULL; i = hash(word); dp = &tableptr[i]; if (dp->word == NULL) { *dp = *hp; free(hp); } else { while (dp->next != NULL) dp = dp->next; dp->next = hp; } return 0; } /* load a word list and build a hash table on the fly */ int load_tables(FILE* wdlst) { char ts[MAX_LN_LEN]; int nExtra = 5; /* first read the first line of file to get hash table size */ if (!fgets(ts, MAX_LN_LEN - 1, wdlst)) return 2; mychomp(ts); tablesize = atoi(ts); if (tablesize <= 0 || (tablesize >= (std::numeric_limits::max() - 1 - nExtra) / (int)sizeof(struct hentry*))) { return 3; } tablesize += nExtra; if ((tablesize % 2) == 0) tablesize++; /* allocate the hash table */ tableptr = (struct hentry*)calloc(tablesize, sizeof(struct hentry)); if (!tableptr) return 3; /* loop thorugh all words on much list and add to hash * table and store away word and affix strings in tmpfile */ while (fgets(ts, MAX_LN_LEN - 1, wdlst)) { mychomp(ts); char* ap = mystrdup(ts); add_word(ap); } return 0; } /* the hash function is a simple load and rotate * algorithm borrowed */ int hash(const char* word) { int i; long hv = 0; for (i = 0; i < 4 && *word != 0; i++) hv = (hv << 8) | (*word++); while (*word != 0) { ROTATE(hv, ROTATE_LEN); hv ^= (*word++); } return (unsigned long)hv % tablesize; } void add_affix_char(struct hentry* ep, char ac) { int al; int i; char* tmp; if (ep->affstr == NULL) { ep->affstr = (char*)malloc(2); *(ep->affstr) = ac; *((ep->affstr) + 1) = '\0'; return; } al = strlen(ep->affstr); for (i = 0; i < al; i++) if (ac == (ep->affstr)[i]) return; tmp = (char*)calloc(al + 2, 1); memcpy(tmp, ep->affstr, (al + 1)); *(tmp + al) = ac; *(tmp + al + 1) = '\0'; free(ep->affstr); ep->affstr = tmp; return; } /* add a prefix to word */ void pfx_add(const char* word, int len, struct affent* ep, int num) { struct affent* aent; int cond; unsigned char* cp; int i; char* pp; char tword[MAX_WD_LEN]; for (aent = ep, i = num; i > 0; aent++, i--) { /* now make sure all conditions match */ if ((len > aent->stripl) && (len >= aent->numconds)) { cp = (unsigned char*)word; for (cond = 0; cond < aent->numconds; cond++) { if ((aent->conds[*cp++] & (1 << cond)) == 0) break; } if (cond >= aent->numconds) { /* we have a match so add prefix */ int tlen = 0; if (aent->appndl) { strncpy(tword, aent->appnd, MAX_WD_LEN - 1); tword[MAX_WD_LEN - 1] = '\0'; tlen += aent->appndl; } pp = tword + tlen; strcpy(pp, (word + aent->stripl)); if (numwords < MAX_WORDS) { wlist[numwords].word = mystrdup(tword); wlist[numwords].pallow = 0; numwords++; } } } } } /* add a suffix to a word */ void suf_add(const char* word, int len, struct affent* ep, int num) { struct affent* aent; int cond; unsigned char* cp; int i; char tword[MAX_WD_LEN]; char* pp; for (aent = ep, i = num; i > 0; aent++, i--) { /* if conditions hold on root word * then strip off strip string and add suffix */ if ((len > aent->stripl) && (len >= aent->numconds)) { cp = (unsigned char*)(word + len); for (cond = aent->numconds; --cond >= 0;) { if ((aent->conds[*--cp] & (1 << cond)) == 0) break; } if (cond < 0) { /* we have a matching condition */ int tlen = len; strncpy(tword, word, MAX_WD_LEN - 1); tword[MAX_WD_LEN - 1] = '\0'; if (aent->stripl) { tlen -= aent->stripl; } pp = (tword + tlen); if (aent->appndl) { strcpy(pp, aent->appnd); } else *pp = '\0'; if (numwords < MAX_WORDS) { wlist[numwords].word = mystrdup(tword); wlist[numwords].pallow = (aent->xpflg & XPRODUCT); numwords++; } } } } } int expand_rootword(const char* ts, int wl, const char* ap) { int i; int nh = 0; for (i = 0; i < numsfx; i++) { if (strchr(ap, (stable[i].aep)->achar)) { suf_add(ts, wl, stable[i].aep, stable[i].num); } } nh = numwords; if (nh > 1) { for (int j = 1; j < nh; j++) { if (wlist[j].pallow) { for (i = 0; i < numpfx; i++) { if (strchr(ap, (ptable[i].aep)->achar)) { if ((ptable[i].aep)->xpflg & XPRODUCT) { int nwl = strlen(wlist[j].word); pfx_add(wlist[j].word, nwl, ptable[i].aep, ptable[i].num); } } } } } } for (i = 0; i < numpfx; i++) { if (strchr(ap, (ptable[i].aep)->achar)) { pfx_add(ts, wl, ptable[i].aep, ptable[i].num); } } return 0; } /* strip strings into token based on single char delimiter * acts like strsep() but only uses a delim char and not * a delim string */ char* mystrsep(char** stringp, const char delim) { char* rv = NULL; char* mp = *stringp; int n = strlen(mp); if (n > 0) { char* dp = (char*)memchr(mp, (int)((unsigned char)delim), n); if (dp) { ptrdiff_t nc; *stringp = dp + 1; nc = dp - mp; rv = (char*)malloc(nc + 1); if (rv) { memcpy(rv, mp, nc); *(rv + nc) = '\0'; } } else { rv = (char*)malloc(n + 1); if (rv) { memcpy(rv, mp, n); *(rv + n) = '\0'; *stringp = mp + n; } } } return rv; } char* mystrdup(const char* s) { char* d = NULL; if (s) { int sl = strlen(s) + 1; d = (char*)malloc(sl); if (d) memcpy(d, s, sl); } return d; } void mychomp(char* s) { int k = strlen(s); if (k > 0) *(s + k - 1) = '\0'; if ((k > 1) && (*(s + k - 2) == '\r')) *(s + k - 2) = '\0'; } nuspell-5.1.7/external/hunspell/tools/munch.h000066400000000000000000000104701511132717100213060ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Hunspell, based on MySpell. * * The Initial Developers of the Original Code are * Kevin Hendricks (MySpell) and Németh László (Hunspell). * Portions created by the Initial Developers are Copyright (C) 2002-2005 * the Initial Developers. All Rights Reserved. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* munch header file */ #define MAX_LN_LEN 200 #define MAX_WD_LEN 200 #define MAX_PREFIXES 2048 #define MAX_SUFFIXES 2048 #define MAX_ROOTS 20 #define MAX_WORDS 5000 #define ROTATE_LEN 5 #define ROTATE(v, q) \ (v) = ((v) << (q)) | (((v) >> (32 - q)) & ((1 << (q)) - 1)); #define SET_SIZE 256 #define XPRODUCT (1 << 0) /* the affix table entry */ struct affent { char* appnd; char* strip; short appndl; short stripl; char achar; char xpflg; short numconds; char conds[SET_SIZE]; }; struct affixptr { struct affent* aep; int num; }; /* the prefix and suffix table */ int numpfx; /* Number of prefixes in table */ int numsfx; /* Number of suffixes in table */ /* the prefix table */ struct affixptr ptable[MAX_PREFIXES]; /* the suffix table */ struct affixptr stable[MAX_SUFFIXES]; /* data structure to store results of lookups */ struct matches { struct hentry* hashent; /* hash table entry */ struct affent* prefix; /* Prefix used, or NULL */ struct affent* suffix; /* Suffix used, or NULL */ }; int numroots; /* number of root words found */ struct matches roots[MAX_ROOTS]; /* list of root words found */ /* hashing stuff */ struct hentry { char* word; char* affstr; struct hentry* next; int keep; }; int tablesize; struct hentry* tableptr; /* unmunch stuff */ int numwords; /* number of words found */ struct dwords { char* word; int pallow; }; struct dwords wlist[MAX_WORDS]; /* list words found */ /* the routines */ int parse_aff_file(FILE* afflst); void encodeit(struct affent* ptr, char* cs); int load_tables(FILE* wrdlst); int hash(const char*); int add_word(char*); struct hentry* lookup(const char*); void aff_chk(const char* word, int len); void pfx_chk(const char* word, int len, struct affent* ep, int num); void suf_chk(const char* word, int len, struct affent* ep, int num, struct affent* pfxent, int cpflag); void add_affix_char(struct hentry* hent, char ac); int expand_rootword(const char*, int, const char*); void pfx_add(const char* word, int len, struct affent* ep, int num); void suf_add(const char* word, int len, struct affent* ep, int num); char* mystrsep(char** stringp, const char delim); char* mystrdup(const char* s); void mychomp(char* s); nuspell-5.1.7/external/hunspell/tools/unmunch.cxx000066400000000000000000000345671511132717100222410ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* Un-munch a root word list with affix tags * to recreate the original word list */ #include #include #include #include #include #include #include #include #include #include #include #include #include "unmunch.h" int main(int argc, char** argv) { int i; int al; FILE* wrdlst; FILE* afflst; char *wf, *af; char ts[MAX_LN_LEN]; (void)argc; /* first parse the command line options */ /* arg1 - munched wordlist, arg2 - affix file */ if (argv[1]) { wf = mystrdup(argv[1]); } else { fprintf(stderr, "correct syntax is:\n"); fprintf(stderr, "unmunch dic_file affix_file\n"); exit(1); } if (argv[2]) { af = mystrdup(argv[2]); } else { fprintf(stderr, "correct syntax is:\n"); fprintf(stderr, "unmunch dic_file affix_file\n"); exit(1); } /* open the affix file */ afflst = fopen(af, "r"); if (!afflst) { fprintf(stderr, "Error - could not open affix description file\n"); exit(1); } /* step one is to parse the affix file building up the internal affix data structures */ numpfx = 0; numsfx = 0; fullstrip = 0; if (parse_aff_file(afflst)) { fprintf(stderr, "Error - in affix file loading\n"); exit(1); } fclose(afflst); fprintf(stderr, "parsed in %d prefixes and %d suffixes\n", numpfx, numsfx); /* affix file is now parsed so create hash table of wordlist on the fly */ /* open the wordlist */ wrdlst = fopen(wf, "r"); if (!wrdlst) { fprintf(stderr, "Error - could not open word list file\n"); exit(1); } /* skip over the hash table size */ if (!fgets(ts, MAX_LN_LEN - 1, wrdlst)) { fclose(wrdlst); return 2; } mychomp(ts); while (fgets(ts, MAX_LN_LEN - 1, wrdlst)) { mychomp(ts); /* split each line into word and affix char strings */ char* ap = strchr(ts, '/'); if (ap) { *ap = '\0'; ap++; al = strlen(ap); } else { al = 0; ap = NULL; } int wl = strlen(ts); numwords = 0; wlist[numwords].word = mystrdup(ts); wlist[numwords].pallow = 0; numwords++; if (al) expand_rootword(ts, wl, ap); for (i = 0; i < numwords; i++) { fprintf(stdout, "%s\n", wlist[i].word); free(wlist[i].word); wlist[i].word = NULL; wlist[i].pallow = 0; } } fclose(wrdlst); return 0; } int parse_aff_file(FILE* afflst) { int i, j; int numents = 0; char achar = '\0'; short ff = 0; struct affent* ptr = NULL; struct affent* nptr = NULL; char* line = (char*)malloc(MAX_LN_LEN); while (fgets(line, MAX_LN_LEN, afflst)) { mychomp(line); char ft = ' '; fprintf(stderr, "parsing line: %s\n", line); if (strncmp(line, "FULLSTRIP", 9) == 0) fullstrip = 1; if (strncmp(line, "PFX", 3) == 0) ft = 'P'; if (strncmp(line, "SFX", 3) == 0) ft = 'S'; if (ft != ' ') { char* tp = line; char* piece; ff = 0; i = 0; while ((piece = mystrsep(&tp, ' '))) { if (*piece != '\0') { switch (i) { case 0: break; case 1: { achar = *piece; break; } case 2: { if (*piece == 'Y') ff = XPRODUCT; break; } case 3: { numents = atoi(piece); if ((numents <= 0) || ((std::numeric_limits::max() / sizeof(struct affent)) < static_cast(numents))) { fprintf(stderr, "Error: too many entries: %d\n", numents); numents = 0; } else { ptr = (struct affent*)malloc(numents * sizeof(struct affent)); ptr->achar = achar; ptr->xpflg = ff; fprintf(stderr, "parsing %c entries %d\n", achar, numents); } break; } default: break; } i++; } free(piece); } /* now parse all of the sub entries*/ nptr = ptr; for (j = 0; j < numents; j++) { if (!fgets(line, MAX_LN_LEN, afflst)) return 1; mychomp(line); tp = line; i = 0; while ((piece = mystrsep(&tp, ' '))) { if (*piece != '\0') { switch (i) { case 0: { if (nptr != ptr) { nptr->achar = ptr->achar; nptr->xpflg = ptr->xpflg; } break; } case 1: break; case 2: { nptr->strip = mystrdup(piece); nptr->stripl = strlen(nptr->strip); if (strcmp(nptr->strip, "0") == 0) { free(nptr->strip); nptr->strip = mystrdup(""); nptr->stripl = 0; } break; } case 3: { nptr->appnd = mystrdup(piece); nptr->appndl = strlen(nptr->appnd); if (strcmp(nptr->appnd, "0") == 0) { free(nptr->appnd); nptr->appnd = mystrdup(""); nptr->appndl = 0; } if (strchr(nptr->appnd, '/')) { char* addseparator = (char*)realloc(nptr->appnd, nptr->appndl + 2); if (addseparator) { nptr->appndl++; addseparator[nptr->appndl - 1] = '|'; addseparator[nptr->appndl] = '\0'; nptr->appnd = addseparator; } } break; } case 4: { encodeit(nptr, piece); } fprintf(stderr, " affix: %s %d, strip: %s %d\n", nptr->appnd, nptr->appndl, nptr->strip, nptr->stripl); // no break default: break; } i++; } free(piece); } nptr++; } if (ptr) { if (ft == 'P') { ptable[numpfx].aep = ptr; ptable[numpfx].num = numents; fprintf(stderr, "ptable %d num is %d flag %c\n", numpfx, ptable[numpfx].num, ptr->achar); numpfx++; } else if (ft == 'S') { stable[numsfx].aep = ptr; stable[numsfx].num = numents; fprintf(stderr, "stable %d num is %d flag %c\n", numsfx, stable[numsfx].num, ptr->achar); numsfx++; } ptr = NULL; } nptr = NULL; numents = 0; achar = '\0'; } } free(line); return 0; } void encodeit(struct affent* ptr, char* cs) { int nc; int neg; int grp; int n; int ec; int nm; int i, j, k; unsigned char mbr[MAX_WD_LEN]; /* now clear the conditions array */ for (i = 0; i < SET_SIZE; i++) ptr->conds[i] = (unsigned char)0; /* now parse the string to create the conds array */ nc = strlen(cs); neg = 0; /* complement indicator */ grp = 0; /* group indicator */ n = 0; /* number of conditions */ ec = 0; /* end condition indicator */ nm = 0; /* number of member in group */ i = 0; if (strcmp(cs, ".") == 0) { ptr->numconds = 0; return; } while (i < nc) { unsigned char c = *((unsigned char*)(cs + i)); if (c == '[') { grp = 1; c = 0; } if ((grp == 1) && (c == '^')) { neg = 1; c = 0; } if (c == ']') { ec = 1; c = 0; } if ((grp == 1) && (c != 0)) { *(mbr + nm) = c; nm++; c = 0; } if (c != 0) { ec = 1; } if (ec) { if (grp == 1) { if (neg == 0) { for (j = 0; j < nm; j++) { k = (unsigned int)mbr[j]; ptr->conds[k] = ptr->conds[k] | (1 << n); } } else { for (j = 0; j < SET_SIZE; j++) ptr->conds[j] = ptr->conds[j] | (1 << n); for (j = 0; j < nm; j++) { k = (unsigned int)mbr[j]; ptr->conds[k] = ptr->conds[k] & ~(1 << n); } } neg = 0; grp = 0; nm = 0; } else { /* not a group so just set the proper bit for this char */ /* but first handle special case of . inside condition */ if (c == '.') { /* wild card character so set them all */ for (j = 0; j < SET_SIZE; j++) ptr->conds[j] = ptr->conds[j] | (1 << n); } else { ptr->conds[(unsigned int)c] = ptr->conds[(unsigned int)c] | (1 << n); } } n++; ec = 0; } i++; } ptr->numconds = n; return; } /* add a prefix to word */ void pfx_add(const char* word, int len, struct affent* ep, int num) { struct affent* aent; int cond; unsigned char* cp; int i; for (aent = ep, i = num; i > 0; aent++, i--) { /* now make sure all conditions match */ if ((len + fullstrip > aent->stripl) && (len >= aent->numconds) && ((aent->stripl == 0) || (strncmp(aent->strip, word, aent->stripl) == 0))) { cp = (unsigned char*)word; for (cond = 0; cond < aent->numconds; cond++) { if ((aent->conds[*cp++] & (1 << cond)) == 0) break; } if (cond >= aent->numconds) { std::string tword; /* we have a match so add prefix */ if (aent->appndl) { tword.append(aent->appnd); } tword.append(word + aent->stripl); if (numwords < MAX_WORDS) { wlist[numwords].word = mystrdup(tword.c_str()); wlist[numwords].pallow = 0; numwords++; } } } } } /* add a suffix to a word */ void suf_add(const char* word, int len, struct affent* ep, int num) { struct affent* aent; int cond; unsigned char* cp; int i; for (aent = ep, i = num; i > 0; aent++, i--) { /* if conditions hold on root word * then strip off strip string and add suffix */ if ((len + fullstrip > aent->stripl) && (len >= aent->numconds) && ((aent->stripl == 0) || (strcmp(aent->strip, word + len - aent->stripl) == 0))) { cp = (unsigned char*)(word + len); for (cond = aent->numconds; --cond >= 0;) { if ((aent->conds[*--cp] & (1 << cond)) == 0) break; } if (cond < 0) { /* we have a matching condition */ std::string tword(word); tword.resize(len - aent->stripl); tword.append(aent->appnd); if (numwords < MAX_WORDS) { wlist[numwords].word = mystrdup(tword.c_str()); wlist[numwords].pallow = (aent->xpflg & XPRODUCT); numwords++; } } } } } int expand_rootword(const char* ts, int wl, const char* ap) { int i; int nh = 0; for (i = 0; i < numsfx; i++) { if (strchr(ap, (stable[i].aep)->achar)) { suf_add(ts, wl, stable[i].aep, stable[i].num); } } nh = numwords; if (nh > 1) { for (int j = 1; j < nh; j++) { if (wlist[j].pallow) { for (i = 0; i < numpfx; i++) { if (strchr(ap, (ptable[i].aep)->achar)) { if ((ptable[i].aep)->xpflg & XPRODUCT) { int nwl = strlen(wlist[j].word); pfx_add(wlist[j].word, nwl, ptable[i].aep, ptable[i].num); } } } } } } for (i = 0; i < numpfx; i++) { if (strchr(ap, (ptable[i].aep)->achar)) { pfx_add(ts, wl, ptable[i].aep, ptable[i].num); } } return 0; } /* strip strings into token based on single char delimiter * acts like strsep() but only uses a delim char and not * a delim string */ char* mystrsep(char** stringp, const char delim) { char* rv = NULL; char* mp = *stringp; int n = strlen(mp); if (n > 0) { char* dp = (char*)memchr(mp, (int)((unsigned char)delim), n); if (dp) { ptrdiff_t nc; *stringp = dp + 1; nc = dp - mp; rv = (char*)malloc(nc + 1); if (rv) { memcpy(rv, mp, nc); *(rv + nc) = '\0'; } } else { rv = (char*)malloc(n + 1); if (rv) { memcpy(rv, mp, n); *(rv + n) = '\0'; *stringp = mp + n; } } } return rv; } char* mystrdup(const char* s) { char* d = NULL; if (s) { int sl = strlen(s) + 1; d = (char*)malloc(sl); if (d) memcpy(d, s, sl); } return d; } void mychomp(char* s) { int k = strlen(s); if ((k > 0) && (*(s + k - 1) == '\n')) *(s + k - 1) = '\0'; if ((k > 1) && (*(s + k - 2) == '\r')) *(s + k - 2) = '\0'; } nuspell-5.1.7/external/hunspell/tools/unmunch.h000066400000000000000000000063021511132717100216500ustar00rootroot00000000000000/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * Copyright (C) 2002-2017 Németh László * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks. * * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* unmunch header file */ #define MAX_LN_LEN 200 #define MAX_WD_LEN 200 #define MAX_PREFIXES 256 #define MAX_SUFFIXES 256 #define MAX_WORDS 500000 #define ROTATE_LEN 5 #define ROTATE(v, q) \ (v) = ((v) << (q)) | (((v) >> (32 - q)) & ((1 << (q)) - 1)); #define SET_SIZE 256 #define XPRODUCT (1 << 0) /* the affix table entry */ struct affent { char* appnd; char* strip; short appndl; short stripl; char achar; char xpflg; short numconds; char conds[SET_SIZE]; }; struct affixptr { struct affent* aep; int num; }; /* the prefix and suffix table */ int numpfx; /* Number of prefixes in table */ int numsfx; /* Number of suffixes in table */ /* the prefix table */ struct affixptr ptable[MAX_PREFIXES]; /* the suffix table */ struct affixptr stable[MAX_SUFFIXES]; int fullstrip; int numwords; /* number of words found */ struct dwords { char* word; int pallow; }; struct dwords wlist[MAX_WORDS]; /* list words found */ /* the routines */ int parse_aff_file(FILE* afflst); void encodeit(struct affent* ptr, char* cs); int expand_rootword(const char*, int, const char*); void pfx_add(const char* word, int len, struct affent* ep, int num); void suf_add(const char* word, int len, struct affent* ep, int num); char* mystrsep(char** stringp, const char delim); char* mystrdup(const char* s); void mychomp(char* s); nuspell-5.1.7/external/hunspell/tools/wordforms000077500000000000000000000024671511132717100220020ustar00rootroot00000000000000#!/bin/sh case $# in 0|1|2) echo "Usage: wordforms [-s | -p] dictionary.aff dictionary.dic word -s: print only suffixed forms -p: print only prefixed forms "; exit 1;; esac fx=0 case $1 in -s) fx=1; shift;; -p) fx=2; shift;; esac test -h /tmp/wordforms.aff && rm /tmp/wordforms.aff ln -s $PWD/$1 /tmp/wordforms.aff # prepared dic only with the query word echo 1 >/tmp/wordforms.dic grep "^$3/" $2 >>/tmp/wordforms.dic echo $3 | awk -v "fx=$fx" ' fx!=2 && FILENAME!="-" && /^SFX/ && NF > 4{split($4,a,"/");clen=($3=="0") ? 0 : length($3);sfx[a[1],clen]=a[1];sfxc[a[1],clen]=clen;next} fx!=1 && FILENAME!="-" && /^PFX/ && NF > 4{split($4,a,"/");clen=($3=="0") ? 0 : length($3);pfx[a[1],clen]=a[1];pfxc[a[1],clen]=clen;next} FILENAME=="-"{ wlen=length($1) if (fx==0 || fx==2) { for (j in pfx) {if (wlen<=pfxc[j]) continue; print (pfx[j]=="0" ? "" : pfx[j]) substr($1, pfxc[j]+1)} } if (fx==0 || fx==1) { for(i in sfx){clen=sfxc[i];if (wlen<=clen) continue; print substr($1, 1, wlen-clen) (sfx[i]=="0" ? "": sfx[i]) } } if (fx==0) { for (j in pfx) {if (wlen<=pfxc[j]) continue; for(i in sfx){clen=sfxc[i];if (wlen<=clen || wlen <= (clen + pfxc[j]))continue; print (pfx[j]=="0" ? "" : pfx[j]) substr($1, pfxc[j]+1, wlen-clen-pfxc[j]) (sfx[i]=="0" ? "": sfx[i]) }} } } ' /tmp/wordforms.aff - | hunspell -d /tmp/wordforms -G -l nuspell-5.1.7/external/hunspell/tools/wordlist2hunspell000066400000000000000000000031601511132717100234500ustar00rootroot00000000000000#!/bin/sh # # (C) 2008 Caolán McNamara # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 this program. If not, see . # This creates a LANG_TERRITORY .aff & .dic from a wordlist. # It is only a simple wordlist spellchecking dictionary output, no # knowledge of language rules can be extrapolated to shrink the # wordlist or provide .aff rules for extending wordstems if [ $# -lt 2 ]; then echo "Usage: wordlist2hunspell wordlist_file locale" echo "e.g. wordlist2hunspell breton.words br_FR to create br_FR.dic and br_FR.aff in cwd" exit 1 fi export LANG=$2.utf8 echo "# A basic .aff for a raw wordlist, created through wordlist2hunspell" > $2.aff echo SET UTF-8 >> $2.aff #see https://bugzilla.redhat.com/show_bug.cgi?id=462184 for the "C" hacks echo TRY `sed 's/./&\n/g' $1 | sed '/^$/d' | LC_ALL=C sort -n | LC_ALL=C uniq -c | LC_ALL=C sort -rn | tr -s ' ' | cut -d ' ' -f 3 | tr -d '\n'` >> $2.aff cat $1 | sed '/^$/d' | wc -l > $2.dic LC_ALL=C sort $1 | sed '/^$/d' >> $2.dic echo Basic $2.dic and $2.aff created nuspell-5.1.7/nuspell.pc.in000066400000000000000000000004671511132717100156270ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: @PROJECT_DESCRIPTION@ URL: @PROJECT_HOMEPAGE_URL@ Version: @PROJECT_VERSION@ Libs: -L${libdir} -lnuspell Requires: icu-uc Cflags: -I${includedir} nuspell-5.1.7/src/000077500000000000000000000000001511132717100137745ustar00rootroot00000000000000nuspell-5.1.7/src/nuspell/000077500000000000000000000000001511132717100154565ustar00rootroot00000000000000nuspell-5.1.7/src/nuspell/CMakeLists.txt000066400000000000000000000026431511132717100202230ustar00rootroot00000000000000add_library(nuspell defines.hxx aff_data.cxx aff_data.hxx checker.cxx checker.hxx suggester.cxx suggester.hxx dictionary.cxx dictionary.hxx finder.cxx finder.hxx unicode.hxx utils.cxx utils.hxx structures.hxx) add_library(Nuspell::nuspell ALIAS nuspell) include(GenerateExportHeader) generate_export_header(nuspell) set(nuspell_headers aff_data.hxx checker.hxx suggester.hxx dictionary.hxx finder.hxx structures.hxx unicode.hxx defines.hxx ${CMAKE_CURRENT_BINARY_DIR}/nuspell_export.h) set_target_properties(nuspell PROPERTIES PUBLIC_HEADER "${nuspell_headers}" VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} CXX_VISIBILITY_PRESET hidden) target_compile_features(nuspell PUBLIC cxx_std_17) target_include_directories(nuspell PUBLIC $ INTERFACE $ $) target_link_libraries(nuspell PUBLIC ICU::uc ICU::data) if (subproject) return() endif() install(TARGETS nuspell EXPORT NuspellTargets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/nuspell) install(EXPORT NuspellTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nuspell NAMESPACE Nuspell::) nuspell-5.1.7/src/nuspell/aff_data.cxx000066400000000000000000000670251511132717100177410ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include "aff_data.hxx" #include "utils.hxx" #include #include #include #include #include using namespace std; /** * @brief Library main namespace */ namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE auto Encoding::normalize_name() -> void { to_upper_ascii(name); if (name == "UTF8") name = "UTF-8"; else if (name.compare(0, 10, "MICROSOFT-") == 0) name.erase(0, 10); } namespace { void reset_failbit_istream(std::istream& in) { in.clear(in.rdstate() & ~in.failbit); } enum class Parsing_Error_Code { NO_FLAGS_AFTER_SLASH_WARNING = -16, NONUTF8_FLAGS_ABOVE_127_WARNING, ARRAY_COMMAND_EXTRA_ENTRIES_WARNING, MULTIPLE_ENTRIES_WARNING, NO_ERROR = 0, ISTREAM_READING_ERROR, INVALID_ENCODING_IDENTIFIER, ENCODING_CONVERSION_ERROR, INVALID_FLAG_TYPE, INVALID_LANG_IDENTIFIER, MISSING_FLAGS, UNPAIRED_LONG_FLAG, INVALID_NUMERIC_FLAG, // FLAGS_ARE_UTF8_BUT_FILE_NOT, INVALID_UTF8, FLAG_ABOVE_65535, INVALID_NUMERIC_ALIAS, AFX_CROSS_CHAR_INVALID, AFX_CONDITION_INVALID_FORMAT, COMPOUND_RULE_INVALID_FORMAT, ARRAY_COMMAND_NO_COUNT }; auto decode_flags(string_view s, Flag_Type t, const Encoding& enc, u16string& out) -> Parsing_Error_Code { using Err = Parsing_Error_Code; using Ft = Flag_Type; auto warn = Err(); out.clear(); if (s.empty()) return Err::MISSING_FLAGS; switch (t) { case Ft::SINGLE_CHAR: if (enc.is_utf8() && !is_all_ascii(s)) { warn = Err::NONUTF8_FLAGS_ABOVE_127_WARNING; // This warning will be triggered in Hungarian. // Version 1 passed this, it just read a single byte // even if the stream utf-8. Hungarian dictionary // exploited this bug/feature, resulting it's file to be // mixed utf-8 and latin2. In v2 this will eventually // work, with a warning. } latin1_to_ucs2(s, out); break; case Ft::DOUBLE_CHAR: { if (enc.is_utf8() && !is_all_ascii(s)) warn = Err::NONUTF8_FLAGS_ABOVE_127_WARNING; if (s.size() % 2 == 1) return Err::UNPAIRED_LONG_FLAG; auto i = s.begin(); auto e = s.end(); for (; i != e; i += 2) { unsigned char c1 = *i; unsigned char c2 = *(i + 1); out.push_back((c1 << 8) | c2); } break; } case Ft::NUMBER: for (auto p = begin_ptr(s);;) { uint16_t flag; auto fc = from_chars(p, end_ptr(s), flag); if (fc.ec == errc::invalid_argument) return Err::INVALID_NUMERIC_FLAG; if (fc.ec == errc::result_out_of_range) return Err::FLAG_ABOVE_65535; out.push_back(flag); if (fc.ptr == end_ptr(s) || *fc.ptr != ',') break; p = fc.ptr + 1; } break; case Ft::UTF8: { // if (!enc.is_utf8()) // return Err::FLAGS_ARE_UTF8_BUT_FILE_NOT; auto ok = utf8_to_16(s, out); if (!ok) { out.clear(); return Err::INVALID_UTF8; } if (!is_all_bmp(out)) { out.clear(); return Err::FLAG_ABOVE_65535; } break; } } return warn; } auto decode_flags_possible_alias(string_view s, Flag_Type t, const Encoding& enc, const vector& flag_aliases, u16string& out) -> Parsing_Error_Code { if (flag_aliases.empty()) return decode_flags(s, t, enc, out); out.clear(); size_t i; auto fc = from_chars(begin_ptr(s), end_ptr(s), i); if (fc.ec == errc::invalid_argument || fc.ec == errc::result_out_of_range) return Parsing_Error_Code::INVALID_NUMERIC_ALIAS; if (0 < i && i <= flag_aliases.size()) { out = flag_aliases[i - 1]; return {}; } return Parsing_Error_Code::INVALID_NUMERIC_ALIAS; } auto get_parsing_error_message(Parsing_Error_Code err) { using Err = Parsing_Error_Code; switch (err) { case Err::NO_FLAGS_AFTER_SLASH_WARNING: return "Nuspell warning: no flags after slash."; case Err::NONUTF8_FLAGS_ABOVE_127_WARNING: return "Nuspell warning: bytes above 127 in flags in UTF-8 " "file are treated as lone bytes for backward " "compatibility. That means if in the flags you have " "ONE character above ASCII, it may be interpreted as " "2, 3, or 4 flags. Please update dictionary and affix " "files to use FLAG UTF-8 and make the file valid " "UTF-8 if it is not already."; case Err::ARRAY_COMMAND_EXTRA_ENTRIES_WARNING: return "Nuspell warning: extra entries of array command."; case Err::MULTIPLE_ENTRIES_WARNING: return "Nuspell warning: multiple entries the same command."; case Err::NO_ERROR: return ""; case Err::ISTREAM_READING_ERROR: return "Nuspell error: problem reading number or string from " "istream."; case Err::INVALID_ENCODING_IDENTIFIER: return "Nuspell error: Invalid identifier of encoding."; case Err::ENCODING_CONVERSION_ERROR: return "Nuspell error: encoding conversion error."; case Err::INVALID_FLAG_TYPE: return "Nuspell error: invalid identifier for the type of the " "flags."; case Err::INVALID_LANG_IDENTIFIER: return "Nuspell error: invalid language code."; case Err::MISSING_FLAGS: return "Nuspell error: missing flags."; case Err::UNPAIRED_LONG_FLAG: return "Nuspell error: the number of chars in string of long " "flags is odd, should be even."; case Err::INVALID_NUMERIC_FLAG: return "Nuspell error: invalid numerical flag."; // case Err::FLAGS_ARE_UTF8_BUT_FILE_NOT: // return "Nuspell error: flags are UTF-8 but file is not\n"; case Err::INVALID_UTF8: return "Nuspell error: Invalid UTF-8 in flags"; case Err::FLAG_ABOVE_65535: return "Nuspell error: Flag above 65535 in line"; case Err::INVALID_NUMERIC_ALIAS: return "Nuspell error: Flag alias is invalid."; case Err::AFX_CROSS_CHAR_INVALID: return "Nuspell error: Invalid cross char in affix entry. It " "must be Y or N."; case Err::AFX_CONDITION_INVALID_FORMAT: return "Nuspell error: Affix condition is invalid."; case Err::COMPOUND_RULE_INVALID_FORMAT: return "Nuspell error: Compound rule is in invalid format."; case Err::ARRAY_COMMAND_NO_COUNT: return "Nuspell error: The first line of array command (series " "of similar commands) has no count. Ignoring all of " "them."; } return "Unknown error"; } auto decode_compound_rule(string_view s, Flag_Type t, const Encoding& enc, u16string& out) -> Parsing_Error_Code { using Ft = Flag_Type; using Err = Parsing_Error_Code; switch (t) { case Ft::SINGLE_CHAR: case Ft::UTF8: return decode_flags(s, t, enc, out); break; case Ft::DOUBLE_CHAR: out.clear(); if (s.empty()) return Err::MISSING_FLAGS; for (size_t i = 0;;) { if (s.size() - i < 4) return Err::COMPOUND_RULE_INVALID_FORMAT; if (s[i] != '(' || s[i + 3] != ')') return Err::COMPOUND_RULE_INVALID_FORMAT; auto c1 = s[i + 1]; auto c2 = s[i + 2]; out.push_back((c1 << 8) | c2); i += 4; if (i == s.size()) break; if (s[i] == '?' || s[i] == '*') { out.push_back(s[i]); i += 1; } } break; case Ft::NUMBER: out.clear(); if (s.empty()) return Err::MISSING_FLAGS; for (auto p = begin_ptr(s); p != end_ptr(s);) { if (*p != '(') return Err::COMPOUND_RULE_INVALID_FORMAT; ++p; uint16_t flag; auto fc = from_chars(p, end_ptr(s), flag); if (fc.ec == errc::invalid_argument) return Err::INVALID_NUMERIC_FLAG; if (fc.ec == errc::result_out_of_range) return Err::FLAG_ABOVE_65535; p = fc.ptr; if (p == end_ptr(s) || *p != ')') return Err::COMPOUND_RULE_INVALID_FORMAT; out.push_back(flag); ++p; if (p == end_ptr(s)) break; if (*p == '?' || *p == '*') { out.push_back(*p); ++p; } } break; } return {}; } auto strip_utf8_bom(std::istream& in) -> void { if (!in.good()) return; auto bom = string(3, '\0'); in.read(bom.data(), 3); if (in && bom == "\xEF\xBB\xBF") return; if (in.bad()) return; reset_failbit_istream(in); for (auto i = size_t(in.gcount()); i-- != 0;) in.putback(bom[i]); } struct Compound_Rule_Ref_Wrapper { std::u16string& rule; }; auto wrap_compound_rule(std::u16string& r) -> Compound_Rule_Ref_Wrapper { return {r}; } class Aff_Line_Parser { std::string str_buf; std::u16string flag_buffer; const Aff_Data* aff_data = nullptr; Encoding_Converter cvt; using Err = Parsing_Error_Code; public: Parsing_Error_Code err = {}; Aff_Line_Parser() = default; Aff_Line_Parser(Aff_Data& a) : aff_data(&a), cvt(a.encoding.value_or_default()) { } auto& parse(istream& in, Encoding& enc) { in >> str_buf; if (in.fail()) { err = Err::ISTREAM_READING_ERROR; return in; } enc = str_buf; cvt = Encoding_Converter(enc.value_or_default()); if (!cvt.valid()) { err = Err::INVALID_ENCODING_IDENTIFIER; in.setstate(in.failbit); } return in; } auto& parse(istream& in, std::string& str) { in >> str_buf; if (in.fail()) { // str_buf is unmodified on fail err = Err::ISTREAM_READING_ERROR; return in; } auto ok = cvt.to_utf8(str_buf, str); if (!ok) { err = Err::INVALID_ENCODING_IDENTIFIER; in.setstate(in.failbit); } return in; } auto& parse(istream& in, Flag_Type& flag_type) { using Ft = Flag_Type; flag_type = {}; in >> str_buf; if (in.fail()) { err = Err::ISTREAM_READING_ERROR; return in; } to_upper_ascii(str_buf); if (str_buf == "LONG") flag_type = Ft::DOUBLE_CHAR; else if (str_buf == "NUM") flag_type = Ft::NUMBER; else if (str_buf == "UTF-8") flag_type = Ft::UTF8; else { err = Err::INVALID_FLAG_TYPE; in.setstate(in.failbit); } return in; } auto& parse(istream& in, icu::Locale& loc) { in >> str_buf; if (in.fail()) { err = Err::ISTREAM_READING_ERROR; return in; } loc = icu::Locale(str_buf.c_str()); if (loc.isBogus()) { err = Err::INVALID_LANG_IDENTIFIER; in.setstate(in.failbit); } return in; } private: auto& parse_flags(istream& in, std::u16string& flags) { in >> str_buf; if (in.fail()) { err = Err::ISTREAM_READING_ERROR; return in; } err = decode_flags(str_buf, aff_data->flag_type, aff_data->encoding, flags); if (static_cast(err) > 0) in.setstate(in.failbit); return in; } public: auto& parse(istream& in, char16_t& flag) { flag = 0; parse_flags(in, flag_buffer); if (in) flag = flag_buffer[0]; return in; } auto& parse(istream& in, Flag_Set& flags) { parse_flags(in, flag_buffer); if (in) flags = flag_buffer; return in; } auto& parse_word_slash_flags(istream& in, string& word, Flag_Set& flags) { in >> str_buf; if (in.fail()) { err = Err::ISTREAM_READING_ERROR; return in; } // err = {}; auto slash_pos = str_buf.find('/'); if (slash_pos != str_buf.npos) { auto flag_str = str_buf.substr(slash_pos + 1); // temporary str_buf.erase(slash_pos); err = decode_flags_possible_alias( flag_str, aff_data->flag_type, aff_data->encoding, aff_data->flag_aliases, flag_buffer); if (err == Err::MISSING_FLAGS) err = Err::NO_FLAGS_AFTER_SLASH_WARNING; flags = flag_buffer; } if (static_cast(err) > 0) { in.setstate(in.failbit); return in; } auto ok = cvt.to_utf8(str_buf, word); if (!ok) { err = Err::ENCODING_CONVERSION_ERROR; in.setstate(in.failbit); } return in; } auto parse_word_slash_single_flag(istream& in, string& word, char16_t& flag) -> istream& { in >> str_buf; if (in.fail()) { err = Err::ISTREAM_READING_ERROR; return in; } // err = {}; auto slash_pos = str_buf.find('/'); if (slash_pos != str_buf.npos) { auto flag_str = str_buf.substr(slash_pos + 1); // temporary str_buf.erase(slash_pos); err = decode_flags(flag_str, aff_data->flag_type, aff_data->encoding, flag_buffer); if (!flag_buffer.empty()) flag = flag_buffer[0]; } if (static_cast(err) > 0) { in.setstate(in.failbit); return in; } auto ok = cvt.to_utf8(str_buf, word); if (!ok) { err = Err::ENCODING_CONVERSION_ERROR; in.setstate(in.failbit); } return in; } auto& parse_compound_rule(istream& in, u16string& out) { in >> str_buf; if (in.fail()) { err = Err::ISTREAM_READING_ERROR; return in; } err = decode_compound_rule(str_buf, aff_data->flag_type, aff_data->encoding, out); if (static_cast(err) > 0) in.setstate(in.failbit); return in; } auto& parse(istream& in, pair& out) { parse(in, out.first); parse(in, out.second); return in; } auto& parse(istream& in, Condition& x) { auto str = string(); parse(in, str); if (in.fail()) return in; try { x = std::move(str); } catch (const Condition_Exception& ex) { err = Parsing_Error_Code::AFX_CONDITION_INVALID_FORMAT; in.setstate(in.failbit); } return in; } auto& parse(istream& in, Compound_Rule_Ref_Wrapper x) { return parse_compound_rule(in, x.rule); } auto& parse(istream& in, string& word, Flag_Set& flags) { return parse_word_slash_flags(in, word, flags); } auto& parse(istream& in, string& word, char16_t& flag) { return parse_word_slash_single_flag(in, word, flag); } auto& parse(istream& in, Compound_Pattern& p) { auto first_word_end = string(); auto second_word_begin = string(); p.match_first_only_unaffixed_or_zero_affixed = false; parse(in, first_word_end, p.first_word_flag); parse(in, second_word_begin, p.second_word_flag); if (in.fail()) return in; if (first_word_end == "0") { first_word_end.clear(); p.match_first_only_unaffixed_or_zero_affixed = true; } p.begin_end_chars = {first_word_end, second_word_begin}; parse(in, p.replacement); // optional if (in.fail() && in.eof() && !in.bad()) { err = {}; reset_failbit_istream(in); p.replacement.clear(); } return in; } }; template auto parse_vector_of_T(istream& in, Aff_Line_Parser& p, const string& command, unordered_map& counts, vector& vec, Func modifier_wrapper = Func()) -> void { auto dat = counts.find(command); if (dat == counts.end()) { // first line auto& cnt = counts[command]; // cnt == 0 size_t a; in >> a; if (in) cnt = a; else { // cnt aka counts[command] remains 0. p.err = Parsing_Error_Code::ARRAY_COMMAND_NO_COUNT; in.setstate(in.failbit); } } else if (dat->second != 0) { dat->second--; auto& elem = vec.emplace_back(); p.parse(in, modifier_wrapper(elem)); } else { p.err = Parsing_Error_Code::ARRAY_COMMAND_EXTRA_ENTRIES_WARNING; } } template auto parse_affix(istream& in, Aff_Line_Parser& p, string& command, vector& vec, unordered_map>& cmd_affix) -> void { using Err = Parsing_Error_Code; char16_t f; p.parse(in, f); if (in.fail()) return; command.append(reinterpret_cast(&f), sizeof(f)); auto dat = cmd_affix.find(command); // note: the current affix parser does not allow the same flag // to be used once with cross product and again without // one flag is tied to one cross product value if (dat == cmd_affix.end()) { char cross_char; // 'Y' or 'N' size_t cnt; auto& cross_and_cnt = cmd_affix[command]; // == false, 0 in >> cross_char >> cnt; if (in.fail()) { p.err = Parsing_Error_Code::ISTREAM_READING_ERROR; return; } if (cross_char != 'Y' && cross_char != 'N') { p.err = Err::AFX_CROSS_CHAR_INVALID; in.setstate(in.failbit); return; } bool cross = cross_char == 'Y'; cross_and_cnt = {cross, cnt}; } else if (dat->second.second) { dat->second.second--; auto& elem = vec.emplace_back(); elem.flag = f; elem.cross_product = dat->second.first; p.parse(in, elem.stripping); if (elem.stripping == "0") elem.stripping.clear(); p.parse(in, elem.appending, elem.cont_flags); if (elem.appending == "0") elem.appending.clear(); if (in.fail()) return; p.parse(in, elem.condition); // optional if (in.fail() && in.eof() && !in.bad()) { elem.condition = "."; p.err = {}; reset_failbit_istream(in); } // in >> elem.morphological_fields; } else { p.err = Parsing_Error_Code::ARRAY_COMMAND_EXTRA_ENTRIES_WARNING; } } } // namespace auto Aff_Data::parse_aff(istream& in, ostream& err_msg) -> bool { auto prefixes = vector(); auto suffixes = vector(); auto break_patterns = vector(); auto break_exists = false; auto input_conversion = vector>(); auto output_conversion = vector>(); // auto morphological_aliases = vector>(); auto rules = vector(); auto replacements = vector>(); auto map_related_chars = vector(); auto phonetic_replacements = vector>(); max_compound_suggestions = 3; max_ngram_suggestions = 4; max_diff_factor = 5; flag_type = Flag_Type::SINGLE_CHAR; unordered_map command_strings = { {"IGNORE", &ignored_chars}, {"KEY", &keyboard_closeness}, {"TRY", &try_chars}}; unordered_map command_bools = { {"COMPLEXPREFIXES", &complex_prefixes}, {"ONLYMAXDIFF", &only_max_diff}, {"NOSPLITSUGS", &no_split_suggestions}, {"SUGSWITHDOTS", &suggest_with_dots}, {"FORBIDWARN", &forbid_warn}, {"COMPOUNDMORESUFFIXES", &compound_more_suffixes}, {"CHECKCOMPOUNDDUP", &compound_check_duplicate}, {"CHECKCOMPOUNDREP", &compound_check_rep}, {"CHECKCOMPOUNDCASE", &compound_check_case}, {"CHECKCOMPOUNDTRIPLE", &compound_check_triple}, {"SIMPLIFIEDTRIPLE", &compound_simplified_triple}, {"SYLLABLENUM", &compound_syllable_num}, {"FULLSTRIP", &fullstrip}, {"CHECKSHARPS", &checksharps}}; unordered_map command_shorts = { {"MAXCPDSUGS", &max_compound_suggestions}, {"MAXNGRAMSUGS", &max_ngram_suggestions}, {"MAXDIFF", &max_diff_factor}, {"COMPOUNDMIN", &compound_min_length}, {"COMPOUNDWORDMAX", &compound_max_word_count}}; unordered_map>*> command_vec_pair = {{"REP", &replacements}, {"PHONE", &phonetic_replacements}, {"ICONV", &input_conversion}, {"OCONV", &output_conversion}}; unordered_map command_flag = { {"NOSUGGEST", &nosuggest_flag}, {"WARN", &warn_flag}, {"COMPOUNDFLAG", &compound_flag}, {"COMPOUNDBEGIN", &compound_begin_flag}, {"COMPOUNDEND", &compound_last_flag}, {"COMPOUNDMIDDLE", &compound_middle_flag}, {"ONLYINCOMPOUND", &compound_onlyin_flag}, {"COMPOUNDPERMITFLAG", &compound_permit_flag}, {"COMPOUNDFORBIDFLAG", &compound_forbid_flag}, {"COMPOUNDROOT", &compound_root_flag}, {"FORCEUCASE", &compound_force_uppercase}, {"CIRCUMFIX", &circumfix_flag}, {"FORBIDDENWORD", &forbiddenword_flag}, {"KEEPCASE", &keepcase_flag}, {"NEEDAFFIX", &need_affix_flag}, {"SUBSTANDARD", &substandard_flag}}; // keeps count for each array-command auto cmd_with_vec_cnt = unordered_map(); auto cmd_affix = unordered_map>(); auto line = string(); auto command = string(); auto line_num = size_t(0); auto ss = istringstream(); auto p = Aff_Line_Parser(*this); auto error_happened = false; // while parsing, the streams must have plain ascii locale without // any special number separator otherwise istream >> int might fail // due to thousands separator. // "C" locale can be used assuming it is US-ASCII in.imbue(locale::classic()); ss.imbue(locale::classic()); strip_utf8_bom(in); while (getline(in, line)) { line_num++; ss.str(line); ss.clear(); p.err = {}; ss >> ws; if (ss.eof() || ss.peek() == '#') continue; // skip comment or empty lines ss >> command; to_upper_ascii(command); if (command == "SFX") { parse_affix(ss, p, command, suffixes, cmd_affix); } else if (command == "PFX") { parse_affix(ss, p, command, prefixes, cmd_affix); } else if (command_strings.count(command)) { auto& str = *command_strings[command]; if (str.empty()) p.parse(ss, str); else p.err = Parsing_Error_Code:: MULTIPLE_ENTRIES_WARNING; } else if (command_bools.count(command)) { *command_bools[command] = true; } else if (command_shorts.count(command)) { auto ptr = command_shorts[command]; ss >> *ptr; if (ptr == &compound_min_length && *ptr == 0) compound_min_length = 1; if (ptr == &max_diff_factor && max_diff_factor > 10) max_diff_factor = 5; } else if (command_flag.count(command)) { p.parse(ss, *command_flag[command]); } else if (command == "MAP") { parse_vector_of_T(ss, p, command, cmd_with_vec_cnt, map_related_chars); } else if (command_vec_pair.count(command)) { auto& vec = *command_vec_pair[command]; parse_vector_of_T(ss, p, command, cmd_with_vec_cnt, vec); } else if (command == "SET") { if (encoding.empty()) p.parse(ss, encoding); else p.err = Parsing_Error_Code:: MULTIPLE_ENTRIES_WARNING; } else if (command == "FLAG") { p.parse(ss, flag_type); } else if (command == "LANG") { p.parse(ss, icu_locale); } else if (command == "AF") { parse_vector_of_T(ss, p, command, cmd_with_vec_cnt, flag_aliases); } else if (command == "AM") { // parse_vector_of_T(ss, command, cmd_with_vec_cnt, // morphological_aliases); } else if (command == "BREAK") { parse_vector_of_T(ss, p, command, cmd_with_vec_cnt, break_patterns); break_exists = true; } else if (command == "CHECKCOMPOUNDPATTERN") { parse_vector_of_T(ss, p, command, cmd_with_vec_cnt, compound_patterns); } else if (command == "COMPOUNDRULE") { parse_vector_of_T(ss, p, command, cmd_with_vec_cnt, rules, wrap_compound_rule); } else if (command == "COMPOUNDSYLLABLE") { ss >> compound_syllable_max; p.parse(ss, compound_syllable_vowels); } else if (command == "WORDCHARS") { p.parse(ss, wordchars); } if (ss.fail()) { assert(static_cast(p.err) > 0); error_happened = true; err_msg << "Nuspell error: could not parse affix file. " << line_num << ": " << line << '\n' << get_parsing_error_message(p.err) << endl; } else if (p.err != Parsing_Error_Code::NO_ERROR) { assert(static_cast(p.err) < 0); err_msg << "Nuspell warning: while parsing affix file. " << line_num << ": " << line << '\n' << get_parsing_error_message(p.err) << endl; } } // default BREAK definition if (!break_exists) { break_patterns = {"-", "^-", "-$"}; } for (auto& r : replacements) { auto& s = r.second; replace_ascii_char(s, '_', ' '); } // now fill data structures from temporary data compound_rules = std::move(rules); similarities.assign(begin(map_related_chars), end(map_related_chars)); break_table = std::move(break_patterns); input_substr_replacer = std::move(input_conversion); output_substr_replacer = std::move(output_conversion); this->replacements = std::move(replacements); // phonetic_table = std::move(phonetic_replacements); for (auto& x : prefixes) { erase_chars(x.appending, ignored_chars); } for (auto& x : suffixes) { erase_chars(x.appending, ignored_chars); } this->prefixes = std::move(prefixes); this->suffixes = std::move(suffixes); return in.eof() && !error_happened; // true for success } auto Aff_Data::parse_dic(istream& in, ostream& err_msg) -> bool { size_t line_number = 1; size_t approximate_size; string line; string word; string flags_str; u16string flags; string u8word; auto enc_conv = Encoding_Converter(encoding.value_or_default()); auto success = true; // locale must be without thousands separator. auto& ctype = use_facet>(locale::classic()); in.imbue(locale::classic()); strip_utf8_bom(in); in >> approximate_size; if (in.fail()) { err_msg << "Nuspell error: while parsing first line of .dic " "file. There is no number." << endl; return false; } words.reserve(approximate_size); getline(in, line); while (getline(in, line)) { line_number++; word.clear(); flags_str.clear(); flags.clear(); if (!empty(line) && line.back() == '\r') line.pop_back(); auto end_word_pos = line.npos; for (size_t i = 0; i != size(line); ++i) { switch (line[i]) { case '/': if (i == 0) continue; if (line[i - 1] == '\\') { --i; line.erase(i, 1); } else { end_word_pos = i; } break; case '\t': end_word_pos = i; break; case ' ': { auto p = ctype.scan_not( ctype.space, &line[i + 1], end_ptr(line)); size_t k = p - begin_ptr(line); if (k == size(line) || (size(line) - k >= 3 && line[k + 2] == ':' && ctype.is(ctype.lower, line[k]) && ctype.is(ctype.lower, line[k + 1]))) end_word_pos = i; break; } } if (end_word_pos != line.npos) break; } word.assign(line, 0, end_word_pos); if (end_word_pos != line.npos && line[end_word_pos] == '/') { // slash found, word until slash auto slash_pos = end_word_pos; auto ptr = ctype.scan_is(ctype.space, &line[slash_pos], end_ptr(line)); auto end_flags_pos = ptr - begin_ptr(line); flags_str.assign(line, slash_pos + 1, end_flags_pos - (slash_pos + 1)); auto err = decode_flags_possible_alias( flags_str, flag_type, encoding, flag_aliases, flags); if (err == Parsing_Error_Code::MISSING_FLAGS || (/* bug in eu.dic that we fix here. Remove this once fixed there. */ err == Parsing_Error_Code::INVALID_NUMERIC_FLAG && flags_str == "None")) err = Parsing_Error_Code:: NO_FLAGS_AFTER_SLASH_WARNING; if (static_cast(err) > 0) { err_msg << "Nuspell error: while parsing " ".dic file. " << line_number << ": " << line << '\n' << get_parsing_error_message(err) << endl; success = false; continue; } else if (static_cast(err) < 0) { err_msg << "Nuspell warning: while parsing " ".dic file. " << line_number << ": " << line << '\n' << get_parsing_error_message(err) << endl; } } if (empty(word)) continue; auto ok = enc_conv.to_utf8(word, u8word); if (!ok) continue; erase_chars(u8word, ignored_chars); auto casing = classify_casing(u8word); auto inserted = words.emplace(u8word, flags); switch (casing) { case Casing::ALL_CAPITAL: if (flags.empty()) break; [[fallthrough]]; case Casing::PASCAL: case Casing::CAMEL: { // This if is needed for the test allcaps2.dic. // Maybe it can be solved better by not checking the // forbiddenword_flag, but by keeping the hidden // homonym last in the multimap among the same-key // entries. if (inserted->second.contains(forbiddenword_flag)) break; to_title(u8word, icu_locale, u8word); flags += HIDDEN_HOMONYM_FLAG; words.emplace(u8word, flags); break; } default: break; } } return in.eof() && success; // success if we reached eof } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell nuspell-5.1.7/src/nuspell/aff_data.hxx000066400000000000000000000116751511132717100177460ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #ifndef NUSPELL_AFF_DATA_HXX #define NUSPELL_AFF_DATA_HXX #include "nuspell_export.h" #include "structures.hxx" #include #include namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE class Encoding { std::string name; NUSPELL_EXPORT auto normalize_name() -> void; public: enum Enc_Type { SINGLEBYTE = false, UTF8 = true }; Encoding() = default; explicit Encoding(const std::string& e) : name(e) { normalize_name(); } explicit Encoding(std::string&& e) : name(std::move(e)) { normalize_name(); } explicit Encoding(const char* e) : name(e) { normalize_name(); } auto& operator=(const std::string& e) { name = e; normalize_name(); return *this; } auto& operator=(std::string&& e) { name = std::move(e); normalize_name(); return *this; } auto& operator=(const char* e) { name = e; normalize_name(); return *this; } auto empty() const { return name.empty(); } auto& value() const { return name; } auto is_utf8() const { return name == "UTF-8"; } auto value_or_default() const -> std::string { if (name.empty()) return "ISO8859-1"; else return name; } operator Enc_Type() const { return is_utf8() ? UTF8 : SINGLEBYTE; } }; enum class Flag_Type { SINGLE_CHAR, DOUBLE_CHAR, NUMBER, UTF8 }; /** * @internal * @brief Map between words and word_flags. * * Flags are stored as part of the container. Maybe for the future flags should * be stored elsewhere (flag aliases) and this should store pointers. * * Does not store morphological data as is low priority feature and is out of * scope. */ using Word_List = Hash_Multimap; struct Aff_Data { static constexpr char16_t HIDDEN_HOMONYM_FLAG = -1; static constexpr size_t MAX_SUGGESTIONS = 16; // spell checking options Word_List words = {}; Prefix_Table prefixes = {}; Suffix_Table suffixes = {}; bool complex_prefixes = {}; bool fullstrip = {}; bool checksharps = {}; bool forbid_warn = {}; char16_t compound_onlyin_flag = {}; char16_t circumfix_flag = {}; char16_t forbiddenword_flag = {}; char16_t keepcase_flag = {}; char16_t need_affix_flag = {}; char16_t warn_flag = {}; // compounding options char16_t compound_flag = {}; char16_t compound_begin_flag = {}; char16_t compound_last_flag = {}; char16_t compound_middle_flag = {}; Compound_Rule_Table compound_rules = {}; // spell checking options Break_Table break_table = {}; Substr_Replacer input_substr_replacer = {}; std::string ignored_chars = {}; icu::Locale icu_locale = {}; Substr_Replacer output_substr_replacer = {}; // suggestion options Replacement_Table replacements = {}; std::vector similarities = {}; std::string keyboard_closeness = {}; std::string try_chars = {}; // Phonetic_Table phonetic_table = {}; char16_t nosuggest_flag = {}; char16_t substandard_flag = {}; unsigned short max_compound_suggestions = {}; unsigned short max_ngram_suggestions = {}; unsigned short max_diff_factor = {}; bool only_max_diff = {}; bool no_split_suggestions = {}; bool suggest_with_dots = {}; // compounding options unsigned short compound_min_length = {}; unsigned short compound_max_word_count = {}; char16_t compound_permit_flag = {}; char16_t compound_forbid_flag = {}; char16_t compound_root_flag = {}; char16_t compound_force_uppercase = {}; bool compound_more_suffixes = {}; bool compound_check_duplicate = {}; bool compound_check_rep = {}; bool compound_check_case = {}; bool compound_check_triple = {}; bool compound_simplified_triple = {}; bool compound_syllable_num = {}; unsigned short compound_syllable_max = {}; std::string compound_syllable_vowels = {}; std::vector compound_patterns = {}; // data members used only while parsing Flag_Type flag_type = {}; Encoding encoding = {}; std::vector flag_aliases = {}; std::string wordchars = {}; // deprecated? auto parse_aff(std::istream& in, std::ostream& err_msg) -> bool; auto parse_dic(std::istream& in, std::ostream& err_msg) -> bool; auto parse_aff_dic(std::istream& aff, std::istream& dic, std::ostream& err_msg) { if (parse_aff(aff, err_msg)) return parse_dic(dic, err_msg); return false; } }; NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell #endif // NUSPELL_AFF_DATA_HXX nuspell-5.1.7/src/nuspell/checker.cxx000066400000000000000000001601401511132717100176100ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include "checker.hxx" #include "utils.hxx" #include using namespace std; namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE template class At_Scope_Exit { L& lambda; public: At_Scope_Exit(L& action) : lambda(action) {} ~At_Scope_Exit() { lambda(); } }; #define CONCAT_IMPL(x, y) x##y #define MACRO_CONCAT(x, y) CONCAT_IMPL(x, y) #define ASE_INTERNAL1(lname, aname, ...) \ auto lname = [&]() { __VA_ARGS__; }; \ At_Scope_Exit aname(lname) #define ASE_INTERNAL2(ctr, ...) \ ASE_INTERNAL1(MACRO_CONCAT(Auto_func_, ctr), \ MACRO_CONCAT(Auto_instance_, ctr), __VA_ARGS__) #define AT_SCOPE_EXIT(...) ASE_INTERNAL2(__COUNTER__, __VA_ARGS__) auto Checker::spell_priv(string& s) const -> bool { // do input conversion (iconv) input_substr_replacer.replace(s); // trimming whitespace should be part of tokenization, not here if (s.empty()) return true; bool abbreviation = s.back() == '.'; if (abbreviation) { // trim trailing periods auto i = s.find_last_not_of('.'); // if i == npos, i + 1 == 0, so no need for extra if. s.erase(i + 1); if (s.empty()) { // TODO add back removed periods return true; } } // accept number if (is_number(s)) return true; erase_chars(s, ignored_chars); // handle break patterns auto copy = s; auto ret = spell_break(s); assert(s == copy); if (!ret && abbreviation) { s += '.'; ret = spell_break(s); } return ret; } auto Checker::spell_break(std::string& s, size_t depth) const -> bool { // check spelling according to case auto res = spell_casing(s); if (res) { // handle forbidden words if (res->contains(forbiddenword_flag)) { return false; } if (forbid_warn && res->contains(warn_flag)) { return false; } return true; } if (depth == 9) return false; // handle break pattern at start of a word for (auto& pat : break_table.start_word_breaks()) { if (begins_with(s, pat)) { auto substr = s.substr(pat.size()); auto res = spell_break(substr, depth + 1); if (res) return res; } } // handle break pattern at end of a word for (auto& pat : break_table.end_word_breaks()) { if (ends_with(s, pat)) { auto substr = s.substr(0, s.size() - pat.size()); auto res = spell_break(substr, depth + 1); if (res) return res; } } // handle break pattern in middle of a word for (auto& pat : break_table.middle_word_breaks()) { auto i = s.find(pat); if (i > 0 && i < s.size() - pat.size()) { auto part1 = s.substr(0, i); auto part2 = s.substr(i + pat.size()); auto res1 = spell_break(part1, depth + 1); if (!res1) continue; auto res2 = spell_break(part2, depth + 1); if (res2) return res2; } } return false; } auto Checker::spell_casing(std::string& s) const -> const Flag_Set* { auto casing_type = classify_casing(s); const Flag_Set* res = nullptr; switch (casing_type) { case Casing::SMALL: case Casing::CAMEL: case Casing::PASCAL: res = check_word(s); break; case Casing::ALL_CAPITAL: res = spell_casing_upper(s); break; case Casing::INIT_CAPITAL: res = spell_casing_title(s); break; } return res; } auto Checker::spell_casing_upper(std::string& s) const -> const Flag_Set* { auto& loc = icu_locale; auto res = check_word(s, ALLOW_BAD_FORCEUCASE); if (res) return res; // handle prefixes separated by apostrophe for Catalan, French and // Italian, e.g. SANT'ELIA -> Sant'+Elia auto apos = s.find('\''); if (apos != s.npos && apos != s.size() - 1) { // apostophe is at beginning of word or dividing the word auto part1 = s.substr(0, apos + 1); auto part2 = s.substr(apos + 1); to_lower(part1, loc, part1); to_title(part2, loc, part2); auto t = part1 + part2; res = check_word(t, ALLOW_BAD_FORCEUCASE); if (res) return res; to_title(part1, loc, part1); t = part1 + part2; res = check_word(t, ALLOW_BAD_FORCEUCASE); if (res) return res; } auto s2 = string(); // handle sharp s for German if (checksharps && s.find("SS") != s.npos) { to_lower(s, loc, s2); res = spell_sharps(s2); if (res) return res; to_title(s, loc, s2); res = spell_sharps(s2); if (res) return res; } to_title(s, loc, s2); res = check_word(s2, ALLOW_BAD_FORCEUCASE); if (res && !res->contains(keepcase_flag)) return res; to_lower(s, loc, s2); res = check_word(s2, ALLOW_BAD_FORCEUCASE); if (res && !res->contains(keepcase_flag)) return res; return nullptr; } auto Checker::spell_casing_title(std::string& s) const -> const Flag_Set* { auto& loc = icu_locale; // check title case auto res = check_word(s, ALLOW_BAD_FORCEUCASE, SKIP_HIDDEN_HOMONYM); if (res) return res; auto s2 = string(); to_lower(s, loc, s2); res = check_word(s2, ALLOW_BAD_FORCEUCASE); // with CHECKSHARPS, ß is allowed too in KEEPCASE words with title case if (res && res->contains(keepcase_flag) && !(checksharps && (s2.find("ß") != s.npos))) { res = nullptr; } return res; } /** * @internal * @brief Checks german word with double SS * * Checks recursively spelling starting on a word in title or lower case which * originate from a word in upper case containing the letters 'SS'. The * technique used is use recursion for checking all variations with repetitions * of minimal one replacement of 'ss' with sharp s 'ß'. Maximum recursion depth * is limited with a hardcoded value. * * @param base string to check spelling for where zero or more occurrences of * 'ss' have been replaced by sharp s 'ß'. * @param pos position in the string to start next find and replacement. * @param n counter for the recursion depth. * @param rep counter for the number of replacements done. * @return The flags of the corresponding dictionary word. */ auto Checker::spell_sharps(std::string& base, size_t pos, size_t n, size_t rep) const -> const Flag_Set* { const size_t MAX_SHARPS = 5; pos = base.find("ss", pos); if (pos != base.npos && n < MAX_SHARPS) { base.replace(pos, 2, "ß"); auto res = spell_sharps(base, pos + 1, n + 1, rep + 1); base.replace(pos, 2, "ss"); if (res) return res; res = spell_sharps(base, pos + 2, n + 1, rep); if (res) return res; } else if (rep > 0) { return check_word(base, ALLOW_BAD_FORCEUCASE); } return nullptr; } auto Checker::check_word(std::string& s, Forceucase allow_bad_forceucase, Hidden_Homonym skip_hidden_homonym) const -> const Flag_Set* { auto ret1 = check_simple_word(s, skip_hidden_homonym); if (ret1) return ret1; auto ret2 = check_compound(s, allow_bad_forceucase); if (ret2) return &ret2->second; return nullptr; } auto Checker::check_simple_word(std::string& s, Hidden_Homonym skip_hidden_homonym) const -> const Flag_Set* { for (auto& we : Subrange(words.equal_range(s))) { auto& word_flags = we.second; if (word_flags.contains(need_affix_flag)) continue; if (word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; return &word_flags; } { auto ret3 = strip_suffix_only(s, skip_hidden_homonym); if (ret3) return &ret3->second; } { auto ret2 = strip_prefix_only(s, skip_hidden_homonym); if (ret2) return &ret2->second; } { auto ret4 = strip_prefix_then_suffix_commutative( s, skip_hidden_homonym); if (ret4) return &ret4->second; } if (!complex_prefixes) { auto ret6 = strip_suffix_then_suffix(s, skip_hidden_homonym); if (ret6) return &ret6->second; auto ret7 = strip_prefix_then_2_suffixes(s, skip_hidden_homonym); if (ret7) return &ret7->second; auto ret8 = strip_suffix_prefix_suffix(s, skip_hidden_homonym); if (ret8) return &ret8->second; // this is slow and unused so comment // auto ret9 = strip_2_suffixes_then_prefix(s, // skip_hidden_homonym); if (ret9) // return &ret9->second; } else { auto ret6 = strip_prefix_then_prefix(s, skip_hidden_homonym); if (ret6) return &ret6->second; auto ret7 = strip_suffix_then_2_prefixes(s, skip_hidden_homonym); if (ret7) return &ret7->second; auto ret8 = strip_prefix_suffix_prefix(s, skip_hidden_homonym); if (ret8) return &ret8->second; // this is slow and unused so comment // auto ret9 = strip_2_prefixes_then_suffix(s, // skip_hidden_homonym); if (ret9) // return &ret9->second; } return nullptr; } template class To_Root_Unroot_RAII { private: string& word; const AffixT& affix; public: To_Root_Unroot_RAII(string& w, const AffixT& a) : word(w), affix(a) { affix.to_root(word); } ~To_Root_Unroot_RAII() { affix.to_derived(word); } }; template auto Checker::is_valid_inside_compound(const Flag_Set& flags) const { if (m == AT_COMPOUND_BEGIN && !flags.contains(compound_flag) && !flags.contains(compound_begin_flag)) return false; if (m == AT_COMPOUND_MIDDLE && !flags.contains(compound_flag) && !flags.contains(compound_middle_flag)) return false; if (m == AT_COMPOUND_END && !flags.contains(compound_flag) && !flags.contains(compound_last_flag)) return false; return true; } /** * @internal * @brief strip_prefix_only * @param s derived word with affixes * @return if found, root word + prefix */ template auto Checker::strip_prefix_only(std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { auto& dic = words; for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& e = *it; if (outer_affix_NOT_valid(e)) continue; if (is_circumfix(e)) continue; To_Root_Unroot_RAII xxx(word, e); if (!e.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(word_flags, e)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check if (!is_valid_inside_compound(word_flags) && !is_valid_inside_compound(e.cont_flags)) continue; return {word_entry, e}; } } return {}; } /** * @internal * @brief strip_suffix_only * @param s derived word with affixes * @return if found, root word + suffix */ template auto Checker::strip_suffix_only(std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { auto& dic = words; for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& e = *it; if (outer_affix_NOT_valid(e)) continue; if (e.appending.size() != 0 && m == AT_COMPOUND_END && e.cont_flags.contains(compound_onlyin_flag)) continue; if (is_circumfix(e)) continue; To_Root_Unroot_RAII xxx(word, e); if (!e.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(word_flags, e)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check if (!is_valid_inside_compound(word_flags) && !is_valid_inside_compound(e.cont_flags)) continue; return {word_entry, e}; } } return {}; } /** * @internal * @brief strip_prefix_then_suffix * * This accepts a derived word that was formed first by adding * suffix then prefix to the root. The stripping is in reverse. * * @param s derived word with affixes * @return if found, root word + suffix + prefix */ template auto Checker::strip_prefix_then_suffix(std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& pe = *it; if (pe.cross_product == false) continue; if (outer_affix_NOT_valid(pe)) continue; To_Root_Unroot_RAII xxx(word, pe); if (!pe.check_condition(word)) continue; auto ret = strip_pfx_then_sfx_2(pe, word, skip_hidden_homonym); if (ret) return ret; } return {}; } template auto Checker::strip_pfx_then_sfx_2(const Prefix& pe, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { auto& dic = words; for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& se = *it; if (se.cross_product == false) continue; if (affix_NOT_valid(se)) continue; if (is_circumfix(pe) != is_circumfix(se)) continue; To_Root_Unroot_RAII xxx(word, se); if (!se.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(se, pe) && !cross_valid_inner_outer(word_flags, pe)) continue; if (!cross_valid_inner_outer(word_flags, se)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check if (!is_valid_inside_compound(word_flags) && !is_valid_inside_compound(se.cont_flags) && !is_valid_inside_compound(pe.cont_flags)) continue; return {word_entry, se, pe}; } } return {}; } /** * @internal * @brief strip_suffix_then_prefix * * This accepts a derived word that was formed first by adding * prefix then suffix to the root. The stripping is in reverse. * * @param s derived word with prefix and suffix * @return if found, root word + prefix + suffix */ template auto Checker::strip_suffix_then_prefix(std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& se = *it; if (se.cross_product == false) continue; if (outer_affix_NOT_valid(se)) continue; To_Root_Unroot_RAII xxx(word, se); if (!se.check_condition(word)) continue; auto ret = strip_sfx_then_pfx_2(se, word, skip_hidden_homonym); if (ret) return ret; } return {}; } template auto Checker::strip_sfx_then_pfx_2(const Suffix& se, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { auto& dic = words; for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& pe = *it; if (pe.cross_product == false) continue; if (affix_NOT_valid(pe)) continue; if (is_circumfix(pe) != is_circumfix(se)) continue; To_Root_Unroot_RAII xxx(word, pe); if (!pe.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(pe, se) && !cross_valid_inner_outer(word_flags, se)) continue; if (!cross_valid_inner_outer(word_flags, pe)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check if (!is_valid_inside_compound(word_flags) && !is_valid_inside_compound(se.cont_flags) && !is_valid_inside_compound(pe.cont_flags)) continue; return {word_entry, pe, se}; } } return {}; } template auto Checker::strip_prefix_then_suffix_commutative( std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& pe = *it; if (pe.cross_product == false) continue; if (affix_NOT_valid(pe)) continue; To_Root_Unroot_RAII xxx(word, pe); if (!pe.check_condition(word)) continue; auto ret = strip_pfx_then_sfx_comm_2(pe, word, skip_hidden_homonym); if (ret) return ret; } return {}; } template auto Checker::strip_pfx_then_sfx_comm_2( const Prefix& pe, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { auto& dic = words; auto has_needaffix_pe = pe.cont_flags.contains(need_affix_flag); auto is_circumfix_pe = is_circumfix(pe); for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& se = *it; if (se.cross_product == false) continue; if (affix_NOT_valid(se)) continue; auto has_needaffix_se = se.cont_flags.contains(need_affix_flag); if (has_needaffix_pe && has_needaffix_se) continue; if (is_circumfix_pe != is_circumfix(se)) continue; To_Root_Unroot_RAII xxx(word, se); if (!se.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; auto valid_cross_pe_outer = !has_needaffix_pe && cross_valid_inner_outer(word_flags, se) && (cross_valid_inner_outer(se, pe) || cross_valid_inner_outer(word_flags, pe)); auto valid_cross_se_outer = !has_needaffix_se && cross_valid_inner_outer(word_flags, pe) && (cross_valid_inner_outer(pe, se) || cross_valid_inner_outer(word_flags, se)); if (!valid_cross_pe_outer && !valid_cross_se_outer) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check if (!is_valid_inside_compound(word_flags) && !is_valid_inside_compound(se.cont_flags) && !is_valid_inside_compound(pe.cont_flags)) continue; return {word_entry, se, pe}; } } return {}; } template auto Checker::strip_suffix_then_suffix(std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { // The following check is purely for performance, it does not change // correctness. if (!suffixes.has_continuation_flags()) return {}; for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& se1 = *it; // The following check is purely for performance, it does not // change correctness. if (!suffixes.has_continuation_flag(se1.flag)) continue; if (outer_affix_NOT_valid(se1)) continue; if (is_circumfix(se1)) continue; To_Root_Unroot_RAII xxx(word, se1); if (!se1.check_condition(word)) continue; auto ret = strip_sfx_then_sfx_2(se1, word, skip_hidden_homonym); if (ret) return ret; } return {}; } template auto Checker::strip_sfx_then_sfx_2(const Suffix& se1, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { auto& dic = words; for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& se2 = *it; if (!cross_valid_inner_outer(se2, se1)) continue; if (affix_NOT_valid(se2)) continue; if (is_circumfix(se2)) continue; To_Root_Unroot_RAII xxx(word, se2); if (!se2.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(word_flags, se2)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check here if needed return {word_entry, se2, se1}; } } return {}; } template auto Checker::strip_prefix_then_prefix(std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { // The following check is purely for performance, it does not change // correctness. if (!prefixes.has_continuation_flags()) return {}; for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& pe1 = *it; // The following check is purely for performance, it does not // change correctness. if (!prefixes.has_continuation_flag(pe1.flag)) continue; if (outer_affix_NOT_valid(pe1)) continue; if (is_circumfix(pe1)) continue; To_Root_Unroot_RAII xxx(word, pe1); if (!pe1.check_condition(word)) continue; auto ret = strip_pfx_then_pfx_2(pe1, word, skip_hidden_homonym); if (ret) return ret; } return {}; } template auto Checker::strip_pfx_then_pfx_2(const Prefix& pe1, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result { auto& dic = words; for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& pe2 = *it; if (!cross_valid_inner_outer(pe2, pe1)) continue; if (affix_NOT_valid(pe2)) continue; if (is_circumfix(pe2)) continue; To_Root_Unroot_RAII xxx(word, pe2); if (!pe2.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(word_flags, pe2)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check here if needed return {word_entry, pe2, pe1}; } } return {}; } template auto Checker::strip_prefix_then_2_suffixes( std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { // The following check is purely for performance, it does not change // correctness. if (!suffixes.has_continuation_flags()) return {}; for (auto i1 = prefixes.iterate_prefixes_of(word); i1; ++i1) { auto& pe1 = *i1; if (pe1.cross_product == false) continue; if (outer_affix_NOT_valid(pe1)) continue; To_Root_Unroot_RAII xxx(word, pe1); if (!pe1.check_condition(word)) continue; for (auto i2 = suffixes.iterate_suffixes_of(word); i2; ++i2) { auto& se1 = *i2; // The following check is purely for performance, it // does not change correctness. if (!suffixes.has_continuation_flag(se1.flag)) continue; if (se1.cross_product == false) continue; if (affix_NOT_valid(se1)) continue; if (is_circumfix(pe1) != is_circumfix(se1)) continue; To_Root_Unroot_RAII yyy(word, se1); if (!se1.check_condition(word)) continue; auto ret = strip_pfx_2_sfx_3( pe1, se1, word, skip_hidden_homonym); if (ret) return ret; } } return {}; } template auto Checker::strip_pfx_2_sfx_3(const Prefix& pe1, const Suffix& se1, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { auto& dic = words; for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& se2 = *it; if (!cross_valid_inner_outer(se2, se1)) continue; if (affix_NOT_valid(se2)) continue; if (is_circumfix(se2)) continue; To_Root_Unroot_RAII xxx(word, se2); if (!se2.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(se1, pe1) && !cross_valid_inner_outer(word_flags, pe1)) continue; if (!cross_valid_inner_outer(word_flags, se2)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check here if needed return {word_entry}; } } return {}; } template auto Checker::strip_suffix_prefix_suffix( std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { // The following check is purely for performance, it does not change // correctness. if (!suffixes.has_continuation_flags() && !prefixes.has_continuation_flags()) return {}; for (auto i1 = suffixes.iterate_suffixes_of(word); i1; ++i1) { auto& se1 = *i1; // The following check is purely for performance, it // does not change correctness. if (!suffixes.has_continuation_flag(se1.flag) && !prefixes.has_continuation_flag(se1.flag)) continue; if (se1.cross_product == false) continue; if (outer_affix_NOT_valid(se1)) continue; To_Root_Unroot_RAII xxx(word, se1); if (!se1.check_condition(word)) continue; for (auto i2 = prefixes.iterate_prefixes_of(word); i2; ++i2) { auto& pe1 = *i2; if (pe1.cross_product == false) continue; if (affix_NOT_valid(pe1)) continue; To_Root_Unroot_RAII yyy(word, pe1); if (!pe1.check_condition(word)) continue; auto ret = strip_s_p_s_3( se1, pe1, word, skip_hidden_homonym); if (ret) return ret; } } return {}; } template auto Checker::strip_s_p_s_3(const Suffix& se1, const Prefix& pe1, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { auto& dic = words; for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& se2 = *it; if (se2.cross_product == false) continue; if (!cross_valid_inner_outer(se2, se1) && !cross_valid_inner_outer(pe1, se1)) continue; if (affix_NOT_valid(se2)) continue; auto circ1ok = (is_circumfix(pe1) == is_circumfix(se1)) && !is_circumfix(se2); auto circ2ok = (is_circumfix(pe1) == is_circumfix(se2)) && !is_circumfix(se1); if (!circ1ok && !circ2ok) continue; To_Root_Unroot_RAII xxx(word, se2); if (!se2.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(se2, pe1) && !cross_valid_inner_outer(word_flags, pe1)) continue; if (!cross_valid_inner_outer(word_flags, se2)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check here if needed return {word_entry}; } } return {}; } template auto Checker::strip_2_suffixes_then_prefix( std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { // The following check is purely for performance, it does not change // correctness. if (!suffixes.has_continuation_flags() && !prefixes.has_continuation_flags()) return {}; for (auto i1 = suffixes.iterate_suffixes_of(word); i1; ++i1) { auto& se1 = *i1; // The following check is purely for performance, it // does not change correctness. if (!suffixes.has_continuation_flag(se1.flag) && !prefixes.has_continuation_flag(se1.flag)) continue; if (outer_affix_NOT_valid(se1)) continue; if (is_circumfix(se1)) continue; To_Root_Unroot_RAII xxx(word, se1); if (!se1.check_condition(word)) continue; for (auto i2 = suffixes.iterate_suffixes_of(word); i2; ++i2) { auto& se2 = *i2; if (se2.cross_product == false) continue; if (affix_NOT_valid(se2)) continue; To_Root_Unroot_RAII yyy(word, se2); if (!se2.check_condition(word)) continue; auto ret = strip_2_sfx_pfx_3( se1, se2, word, skip_hidden_homonym); if (ret) return ret; } } return {}; } template auto Checker::strip_2_sfx_pfx_3(const Suffix& se1, const Suffix& se2, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { auto& dic = words; for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& pe1 = *it; if (pe1.cross_product == false) continue; if (!cross_valid_inner_outer(se2, se1) && !cross_valid_inner_outer(pe1, se1)) continue; if (affix_NOT_valid(pe1)) continue; if (is_circumfix(se2) != is_circumfix(pe1)) continue; To_Root_Unroot_RAII xxx(word, pe1); if (!pe1.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(pe1, se2) && !cross_valid_inner_outer(word_flags, se2)) continue; if (!cross_valid_inner_outer(word_flags, pe1)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; // needflag check here if needed return {word_entry}; } } return {}; } template auto Checker::strip_suffix_then_2_prefixes( std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { // The following check is purely for performance, it does not change // correctness. if (!prefixes.has_continuation_flags()) return {}; for (auto i1 = suffixes.iterate_suffixes_of(word); i1; ++i1) { auto& se1 = *i1; if (se1.cross_product == false) continue; if (outer_affix_NOT_valid(se1)) continue; To_Root_Unroot_RAII xxx(word, se1); if (!se1.check_condition(word)) continue; for (auto i2 = prefixes.iterate_prefixes_of(word); i2; ++i2) { auto& pe1 = *i2; // The following check is purely for performance, it // does not change correctness. if (!prefixes.has_continuation_flag(pe1.flag)) continue; if (pe1.cross_product == false) continue; if (affix_NOT_valid(pe1)) continue; if (is_circumfix(se1) != is_circumfix(pe1)) continue; To_Root_Unroot_RAII yyy(word, pe1); if (!pe1.check_condition(word)) continue; auto ret = strip_sfx_2_pfx_3( se1, pe1, word, skip_hidden_homonym); if (ret) return ret; } } return {}; } template auto Checker::strip_sfx_2_pfx_3(const Suffix& se1, const Prefix& pe1, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { auto& dic = words; for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& pe2 = *it; if (!cross_valid_inner_outer(pe2, pe1)) continue; if (affix_NOT_valid(pe2)) continue; if (is_circumfix(pe2)) continue; To_Root_Unroot_RAII xxx(word, pe2); if (!pe2.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(pe1, se1) && !cross_valid_inner_outer(word_flags, se1)) continue; if (!cross_valid_inner_outer(word_flags, pe2)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; return {word_entry}; } } return {}; } template auto Checker::strip_prefix_suffix_prefix( std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { // The following check is purely for performance, it does not change // correctness. if (!prefixes.has_continuation_flags() && !suffixes.has_continuation_flags()) return {}; for (auto i1 = prefixes.iterate_prefixes_of(word); i1; ++i1) { auto& pe1 = *i1; // The following check is purely for performance, it // does not change correctness. if (!prefixes.has_continuation_flag(pe1.flag) && !suffixes.has_continuation_flag(pe1.flag)) continue; if (pe1.cross_product == false) continue; if (outer_affix_NOT_valid(pe1)) continue; To_Root_Unroot_RAII xxx(word, pe1); if (!pe1.check_condition(word)) continue; for (auto i2 = suffixes.iterate_suffixes_of(word); i2; ++i2) { auto& se1 = *i2; if (se1.cross_product == false) continue; if (affix_NOT_valid(se1)) continue; To_Root_Unroot_RAII yyy(word, se1); if (!se1.check_condition(word)) continue; auto ret = strip_p_s_p_3( pe1, se1, word, skip_hidden_homonym); if (ret) return ret; } } return {}; } template auto Checker::strip_p_s_p_3(const Prefix& pe1, const Suffix& se1, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { auto& dic = words; for (auto it = prefixes.iterate_prefixes_of(word); it; ++it) { auto& pe2 = *it; if (pe2.cross_product == false) continue; if (!cross_valid_inner_outer(pe2, pe1) && !cross_valid_inner_outer(se1, pe1)) continue; if (affix_NOT_valid(pe2)) continue; auto circ1ok = (is_circumfix(se1) == is_circumfix(pe1)) && !is_circumfix(pe2); auto circ2ok = (is_circumfix(se1) == is_circumfix(pe2)) && !is_circumfix(pe1); if (!circ1ok && !circ2ok) continue; To_Root_Unroot_RAII xxx(word, pe2); if (!pe2.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(pe2, se1) && !cross_valid_inner_outer(word_flags, se1)) continue; if (!cross_valid_inner_outer(word_flags, pe2)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; return {word_entry}; } } return {}; } template auto Checker::strip_2_prefixes_then_suffix( std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { // The following check is purely for performance, it does not change // correctness. if (!prefixes.has_continuation_flags() && !suffixes.has_continuation_flags()) return {}; for (auto i1 = prefixes.iterate_prefixes_of(word); i1; ++i1) { auto& pe1 = *i1; // The following check is purely for performance, it // does not change correctness. if (!prefixes.has_continuation_flag(pe1.flag) && !suffixes.has_continuation_flag(pe1.flag)) continue; if (outer_affix_NOT_valid(pe1)) continue; if (is_circumfix(pe1)) continue; To_Root_Unroot_RAII xxx(word, pe1); if (!pe1.check_condition(word)) continue; for (auto i2 = prefixes.iterate_prefixes_of(word); i2; ++i2) { auto& pe2 = *i2; if (pe2.cross_product == false) continue; if (affix_NOT_valid(pe2)) continue; To_Root_Unroot_RAII yyy(word, pe2); if (!pe2.check_condition(word)) continue; auto ret = strip_2_pfx_sfx_3( pe1, pe2, word, skip_hidden_homonym); if (ret) return ret; } } return {}; } template auto Checker::strip_2_pfx_sfx_3(const Prefix& pe1, const Prefix& pe2, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<> { auto& dic = words; for (auto it = suffixes.iterate_suffixes_of(word); it; ++it) { auto& se1 = *it; if (se1.cross_product == false) continue; if (!cross_valid_inner_outer(pe2, pe1) && !cross_valid_inner_outer(se1, pe1)) continue; if (affix_NOT_valid(se1)) continue; if (is_circumfix(pe2) != is_circumfix(se1)) continue; To_Root_Unroot_RAII xxx(word, se1); if (!se1.check_condition(word)) continue; for (auto& word_entry : Subrange(dic.equal_range(word))) { auto& word_flags = word_entry.second; if (!cross_valid_inner_outer(se1, pe2) && !cross_valid_inner_outer(word_flags, pe2)) continue; if (!cross_valid_inner_outer(word_flags, se1)) continue; // badflag check if (m == FULL_WORD && word_flags.contains(compound_onlyin_flag)) continue; if (skip_hidden_homonym && word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; return {word_entry}; } } return {}; } auto match_compound_pattern(const Compound_Pattern& p, string_view word, size_t i, Compounding_Result first, Compounding_Result second) { if (i < p.begin_end_chars.idx()) return false; if (word.compare(i - p.begin_end_chars.idx(), p.begin_end_chars.str().size(), p.begin_end_chars.str()) != 0) return false; if (p.first_word_flag != 0 && !first->second.contains(p.first_word_flag)) return false; if (p.second_word_flag != 0 && !second->second.contains(p.second_word_flag)) return false; if (p.match_first_only_unaffixed_or_zero_affixed && first.affixed_and_modified) return false; return true; } auto is_compound_forbidden_by_patterns(const vector& patterns, string_view word, size_t i, Compounding_Result first, Compounding_Result second) { return any_of(begin(patterns), end(patterns), [&](auto& p) { return match_compound_pattern(p, word, i, first, second); }); } auto Checker::check_compound(std::string& word, Forceucase allow_bad_forceucase) const -> Compounding_Result { auto part = string(); if (compound_flag || compound_begin_flag || compound_middle_flag || compound_last_flag) { auto ret = check_compound(word, 0, 0, part, allow_bad_forceucase); if (ret) return ret; } if (!compound_rules.empty()) { auto words_data = vector(); return check_compound_with_rules(word, words_data, 0, part, allow_bad_forceucase); } return {}; } template auto Checker::check_compound(std::string& word, size_t start_pos, size_t num_part, std::string& part, Forceucase allow_bad_forceucase) const -> Compounding_Result { size_t min_num_cp = 3; if (compound_min_length != 0) min_num_cp = compound_min_length; auto i = start_pos; for (size_t num_cp = 0; num_cp != min_num_cp; ++num_cp) { if (i == size(word)) return {}; valid_u8_advance_index(word, i); } auto last_i = size(word); for (size_t num_cp = 0; num_cp != min_num_cp; ++num_cp) { if (last_i < i) return {}; valid_u8_reverse_index(word, last_i); } for (; i <= last_i; valid_u8_advance_index(word, i)) { auto part1_entry = check_compound_classic( word, start_pos, i, num_part, part, allow_bad_forceucase); if (part1_entry) return part1_entry; part1_entry = check_compound_with_pattern_replacements( word, start_pos, i, num_part, part, allow_bad_forceucase); if (part1_entry) return part1_entry; } return {}; } auto are_three_code_points_equal(string_view word, size_t i) -> bool { auto cp = valid_u8_next_cp(word, i); auto prev_cp = valid_u8_prev_cp(word, i); if (prev_cp.cp == cp.cp) { if (cp.end_i != size(word)) { auto next_cp = valid_u8_next_cp(word, cp.end_i); if (cp.cp == next_cp.cp) return true; } if (prev_cp.begin_i != 0) { auto prev2_cp = valid_u8_prev_cp(word, prev_cp.begin_i); if (prev2_cp.cp == cp.cp) return true; } } return false; } template auto Checker::check_compound_classic(std::string& word, size_t start_pos, size_t i, size_t num_part, std::string& part, Forceucase allow_bad_forceucase) const -> Compounding_Result { auto old_num_part = num_part; part.assign(word, start_pos, i - start_pos); auto part1_entry = check_word_in_compound(part); if (!part1_entry) return {}; if (part1_entry->second.contains(forbiddenword_flag)) return {}; if (compound_check_triple) { if (are_three_code_points_equal(word, i)) return {}; } if (compound_check_case && has_uppercase_at_compound_word_boundary(word, i)) return {}; num_part += part1_entry.num_words_modifier; num_part += compound_root_flag && part1_entry->second.contains(compound_root_flag); part.assign(word, i, word.npos); auto part2_entry = check_word_in_compound(part); if (!part2_entry) goto try_recursive; if (part2_entry->second.contains(forbiddenword_flag)) goto try_recursive; if (is_compound_forbidden_by_patterns(compound_patterns, word, i, part1_entry, part2_entry)) goto try_recursive; if (compound_check_duplicate && part1_entry == part2_entry) goto try_recursive; if (compound_check_rep) { part.assign(word, start_pos); if (is_rep_similar(part)) goto try_recursive; } if (compound_force_uppercase && !allow_bad_forceucase && part2_entry->second.contains(compound_force_uppercase)) goto try_recursive; old_num_part = num_part; num_part += part2_entry.num_words_modifier; num_part += compound_root_flag && part2_entry->second.contains(compound_root_flag); if (compound_max_word_count != 0 && num_part + 1 >= compound_max_word_count) { if (compound_syllable_vowels.empty()) // is not Hungarian return {}; // end search here, num_part can only go up // else, language is Hungarian auto num_syllable = count_syllables(word); num_syllable += part2_entry.num_syllable_modifier; if (num_syllable > compound_syllable_max) { num_part = old_num_part; goto try_recursive; } } return part1_entry; try_recursive: part2_entry = check_compound( word, i, num_part + 1, part, allow_bad_forceucase); if (!part2_entry) goto try_simplified_triple; if (is_compound_forbidden_by_patterns(compound_patterns, word, i, part1_entry, part2_entry)) goto try_simplified_triple; // if (compound_check_duplicate && part1_entry == part2_entry) // goto try_simplified_triple; if (compound_check_rep) { part.assign(word, start_pos); if (is_rep_similar(part)) goto try_simplified_triple; auto& p2word = part2_entry->first; if (word.compare(i, p2word.size(), p2word) == 0) { // part.assign(word, start_pos, // i - start_pos + p2word.size()); // The erase() is equivaled as the assign above. part.erase(i - start_pos + p2word.size()); if (is_rep_similar(part)) goto try_simplified_triple; } } return part1_entry; try_simplified_triple: if (!compound_simplified_triple) return {}; auto prev_cp = valid_u8_prev_cp(word, i); if (prev_cp.begin_i == 0) return {}; auto prev2_cp = valid_u8_prev_cp(word, prev_cp.begin_i); if (prev_cp.cp != prev2_cp.cp) return {}; auto const enc_cp = U8_Encoded_CP(prev_cp.cp); word.insert(i, enc_cp); AT_SCOPE_EXIT(word.erase(i, size(enc_cp))); part.assign(word, i, word.npos); part2_entry = check_word_in_compound(part); if (!part2_entry) goto try_simplified_triple_recursive; if (part2_entry->second.contains(forbiddenword_flag)) goto try_simplified_triple_recursive; if (is_compound_forbidden_by_patterns(compound_patterns, word, i, part1_entry, part2_entry)) goto try_simplified_triple_recursive; if (compound_check_duplicate && part1_entry == part2_entry) goto try_simplified_triple_recursive; if (compound_check_rep) { part.assign(word, start_pos); // The added char above should not be checked for rep // similarity, instead check the original word. part.erase(i - start_pos, size(enc_cp)); if (is_rep_similar(part)) goto try_simplified_triple_recursive; } if (compound_force_uppercase && !allow_bad_forceucase && part2_entry->second.contains(compound_force_uppercase)) goto try_simplified_triple_recursive; if (compound_max_word_count != 0 && num_part + 1 >= compound_max_word_count) return {}; return part1_entry; try_simplified_triple_recursive: part2_entry = check_compound( word, i, num_part + 1, part, allow_bad_forceucase); if (!part2_entry) return {}; if (is_compound_forbidden_by_patterns(compound_patterns, word, i, part1_entry, part2_entry)) return {}; // if (compound_check_duplicate && part1_entry == part2_entry) // return {}; if (compound_check_rep) { part.assign(word, start_pos); part.erase(i - start_pos, size(enc_cp)); // for the added CP if (is_rep_similar(part)) return {}; auto& p2word = part2_entry->first; if (word.compare(i, p2word.size(), p2word) == 0) { part.assign(word, start_pos, i - start_pos + p2word.size()); part.erase(i - start_pos, size(enc_cp)); // for the added CP if (is_rep_similar(part)) return {}; } } return part1_entry; } template auto Checker::check_compound_with_pattern_replacements( std::string& word, size_t start_pos, size_t i, size_t num_part, std::string& part, Forceucase allow_bad_forceucase) const -> Compounding_Result { for (auto& p : compound_patterns) { if (p.replacement.empty()) continue; if (word.compare(i, p.replacement.size(), p.replacement) != 0) continue; // at this point p.replacement is substring in word word.replace(i, p.replacement.size(), p.begin_end_chars.str()); i += p.begin_end_chars.idx(); AT_SCOPE_EXIT({ i -= p.begin_end_chars.idx(); word.replace(i, p.begin_end_chars.str().size(), p.replacement); }); part.assign(word, start_pos, i - start_pos); auto part1_entry = check_word_in_compound(part); if (!part1_entry) continue; if (part1_entry->second.contains(forbiddenword_flag)) continue; if (p.first_word_flag != 0 && !part1_entry->second.contains(p.first_word_flag)) continue; if (compound_check_triple) { if (are_three_code_points_equal(word, i)) continue; } part.assign(word, i, word.npos); auto part2_entry = check_word_in_compound(part); if (!part2_entry) goto try_recursive; if (part2_entry->second.contains(forbiddenword_flag)) goto try_recursive; if (p.second_word_flag != 0 && !part2_entry->second.contains(p.second_word_flag)) goto try_recursive; if (compound_check_duplicate && part1_entry == part2_entry) goto try_recursive; if (compound_check_rep) { part.assign(word, start_pos); part.replace(i - start_pos - p.begin_end_chars.idx(), p.begin_end_chars.str().size(), p.replacement); if (is_rep_similar(part)) goto try_recursive; } if (compound_force_uppercase && !allow_bad_forceucase && part2_entry->second.contains(compound_force_uppercase)) goto try_recursive; if (compound_max_word_count != 0 && num_part + 1 >= compound_max_word_count) return {}; return part1_entry; try_recursive: part2_entry = check_compound( word, i, num_part + 1, part, allow_bad_forceucase); if (!part2_entry) goto try_simplified_triple; if (p.second_word_flag != 0 && !part2_entry->second.contains(p.second_word_flag)) goto try_simplified_triple; // if (compound_check_duplicate && part1_entry == part2_entry) // goto try_simplified_triple; if (compound_check_rep) { part.assign(word, start_pos); part.replace(i - start_pos - p.begin_end_chars.idx(), p.begin_end_chars.str().size(), p.replacement); if (is_rep_similar(part)) goto try_simplified_triple; auto& p2word = part2_entry->first; if (word.compare(i, p2word.size(), p2word) == 0) { part.assign(word, start_pos, i - start_pos + p2word.size()); if (is_rep_similar(part)) goto try_simplified_triple; } } return part1_entry; try_simplified_triple: // TODO: check code points, not units if (!compound_simplified_triple) continue; auto prev_cp = valid_u8_prev_cp(word, i); if (prev_cp.begin_i == 0) continue; auto prev2_cp = valid_u8_prev_cp(word, prev_cp.begin_i); if (prev_cp.cp != prev2_cp.cp) continue; auto const enc_cp = U8_Encoded_CP(prev_cp.cp); word.insert(i, enc_cp); AT_SCOPE_EXIT(word.erase(i, size(enc_cp))); part.assign(word, i, word.npos); part2_entry = check_word_in_compound(part); if (!part2_entry) goto try_simplified_triple_recursive; if (part2_entry->second.contains(forbiddenword_flag)) goto try_simplified_triple_recursive; if (p.second_word_flag != 0 && !part2_entry->second.contains(p.second_word_flag)) goto try_simplified_triple_recursive; if (compound_check_duplicate && part1_entry == part2_entry) goto try_simplified_triple_recursive; if (compound_check_rep) { part.assign(word, start_pos); part.erase(i - start_pos, size(enc_cp)); // for the added char part.replace(i - start_pos - p.begin_end_chars.idx(), p.begin_end_chars.str().size(), p.replacement); if (is_rep_similar(part)) goto try_simplified_triple_recursive; } if (compound_force_uppercase && !allow_bad_forceucase && part2_entry->second.contains(compound_force_uppercase)) goto try_simplified_triple_recursive; if (compound_max_word_count != 0 && num_part + 1 >= compound_max_word_count) return {}; return part1_entry; try_simplified_triple_recursive: part2_entry = check_compound( word, i, num_part + 1, part, allow_bad_forceucase); if (!part2_entry) continue; if (p.second_word_flag != 0 && !part2_entry->second.contains(p.second_word_flag)) continue; // if (compound_check_duplicate && part1_entry == part2_entry) // continue; if (compound_check_rep) { part.assign(word, start_pos); part.erase(i - start_pos, size(enc_cp)); // for the added char part.replace(i - start_pos - p.begin_end_chars.idx(), p.begin_end_chars.str().size(), p.replacement); if (is_rep_similar(part)) continue; auto& p2word = part2_entry->first; if (word.compare(i, p2word.size(), p2word) == 0) { part.assign(word, start_pos, i - start_pos + p2word.size()); part.erase(i - start_pos, size(enc_cp)); // for the added char if (is_rep_similar(part)) continue; } } return part1_entry; } return {}; } template auto is_modiying_affix(const AffixT& a) { return !a.stripping.empty() || !a.appending.empty(); } template auto Checker::check_word_in_compound(std::string& word) const -> Compounding_Result { auto cpd_flag = char16_t(); if (m == AT_COMPOUND_BEGIN) cpd_flag = compound_begin_flag; else if (m == AT_COMPOUND_MIDDLE) cpd_flag = compound_middle_flag; else if (m == AT_COMPOUND_END) cpd_flag = compound_last_flag; auto range = words.equal_range(word); for (auto& we : Subrange(range)) { auto& word_flags = we.second; if (word_flags.contains(need_affix_flag)) continue; if (!word_flags.contains(compound_flag) && !word_flags.contains(cpd_flag)) continue; if (word_flags.contains(HIDDEN_HOMONYM_FLAG)) continue; auto num_syllable_mod = calc_syllable_modifier(we); return {&we, 0, num_syllable_mod}; } auto x2 = strip_suffix_only(word, SKIP_HIDDEN_HOMONYM); if (x2) { auto num_syllable_mod = calc_syllable_modifier(*x2, *x2.a); return {x2, 0, num_syllable_mod, is_modiying_affix(*x2.a)}; } auto x1 = strip_prefix_only(word, SKIP_HIDDEN_HOMONYM); if (x1) { auto num_words_mod = calc_num_words_modifier(*x1.a); return {x1, num_words_mod, 0, is_modiying_affix(*x1.a)}; } auto x3 = strip_prefix_then_suffix_commutative(word, SKIP_HIDDEN_HOMONYM); if (x3) { auto num_words_mod = calc_num_words_modifier(*x3.b); auto num_syllable_mod = calc_syllable_modifier(*x3, *x3.a); return {x3, num_words_mod, num_syllable_mod, is_modiying_affix(*x3.a) || is_modiying_affix(*x3.b)}; } return {}; } auto Checker::calc_num_words_modifier(const Prefix& pfx) const -> unsigned char { if (compound_syllable_vowels.empty()) return 0; auto c = count_syllables(pfx.appending); return c > 1; } template auto Checker::calc_syllable_modifier(Word_List::const_reference we) const -> signed char { auto subtract_syllable = m == AT_COMPOUND_END && !compound_syllable_vowels.empty() && we.second.contains('I') && !we.second.contains('J'); return 0 - subtract_syllable; } template auto Checker::calc_syllable_modifier(Word_List::const_reference we, const Suffix& sfx) const -> signed char { if (m != AT_COMPOUND_END) return 0; if (compound_syllable_vowels.empty()) return 0; auto& appnd = sfx.appending; signed char num_syllable_mod = 0 - count_syllables(appnd); auto sfx_extra = !appnd.empty() && appnd.back() == 'i'; if (sfx_extra && appnd.size() > 1) { auto c = appnd[appnd.size() - 2]; sfx_extra = c != 'y' && c != 't'; } num_syllable_mod -= sfx_extra; if (compound_syllable_num) { switch (sfx.flag) { case 'c': num_syllable_mod += 2; break; case 'J': num_syllable_mod += 1; break; case 'I': num_syllable_mod += we.second.contains('J'); break; } } return num_syllable_mod; } auto Checker::count_syllables(std::string_view word) const -> size_t { return count_appereances_of(word, compound_syllable_vowels); } auto Checker::check_compound_with_rules( std::string& word, std::vector& words_data, size_t start_pos, std::string& part, Forceucase allow_bad_forceucase) const -> Compounding_Result { size_t min_num_cp = 3; if (compound_min_length != 0) min_num_cp = compound_min_length; auto i = start_pos; for (size_t num_cp = 0; num_cp != min_num_cp; ++num_cp) { if (i == size(word)) return {}; valid_u8_advance_index(word, i); } auto last_i = size(word); for (size_t num_cp = 0; num_cp != min_num_cp; ++num_cp) { if (last_i < i) return {}; valid_u8_reverse_index(word, last_i); } for (; i <= last_i; valid_u8_advance_index(word, i)) { part.assign(word, start_pos, i - start_pos); auto part1_entry = Word_List::const_pointer(); auto range = words.equal_range(part); for (auto& we : Subrange(range)) { auto& word_flags = we.second; if (word_flags.contains(need_affix_flag)) continue; if (!compound_rules.has_any_of_flags(word_flags)) continue; part1_entry = &we; break; } if (!part1_entry) continue; words_data.push_back(&part1_entry->second); AT_SCOPE_EXIT(words_data.pop_back()); part.assign(word, i, word.npos); auto part2_entry = Word_List::const_pointer(); range = words.equal_range(part); for (auto& we : Subrange(range)) { auto& word_flags = we.second; if (word_flags.contains(need_affix_flag)) continue; if (!compound_rules.has_any_of_flags(word_flags)) continue; part2_entry = &we; break; } if (!part2_entry) goto try_recursive; { words_data.push_back(&part2_entry->second); AT_SCOPE_EXIT(words_data.pop_back()); auto m = compound_rules.match_any_rule(words_data); if (!m) goto try_recursive; if (compound_force_uppercase && !allow_bad_forceucase && part2_entry->second.contains( compound_force_uppercase)) goto try_recursive; return {part1_entry}; } try_recursive: part2_entry = check_compound_with_rules( word, words_data, i, part, allow_bad_forceucase); if (part2_entry) return {part2_entry}; } return {}; } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell nuspell-5.1.7/src/nuspell/checker.hxx000066400000000000000000000267111511132717100176220ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #ifndef NUSPELL_CHECKER_HXX #define NUSPELL_CHECKER_HXX #include "aff_data.hxx" namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE enum Affixing_Mode { FULL_WORD, AT_COMPOUND_BEGIN, AT_COMPOUND_END, AT_COMPOUND_MIDDLE }; struct Affixing_Result_Base { Word_List::const_pointer root_word = {}; operator Word_List::const_pointer() const { return root_word; } auto& operator*() const { return *root_word; } auto operator->() const { return root_word; } }; template struct Affixing_Result : Affixing_Result_Base { const T1* a = {}; const T2* b = {}; Affixing_Result() = default; Affixing_Result(Word_List::const_reference r, const T1& a, const T2& b) : Affixing_Result_Base{&r}, a{&a}, b{&b} { } }; template struct Affixing_Result : Affixing_Result_Base { const T1* a = {}; Affixing_Result() = default; Affixing_Result(Word_List::const_reference r, const T1& a) : Affixing_Result_Base{&r}, a{&a} { } }; template <> struct Affixing_Result : Affixing_Result_Base { Affixing_Result() = default; Affixing_Result(Word_List::const_reference r) : Affixing_Result_Base{&r} { } }; struct Compounding_Result { Word_List::const_pointer word_entry = {}; unsigned char num_words_modifier = {}; signed char num_syllable_modifier = {}; bool affixed_and_modified = {}; /**< non-zero affix */ operator Word_List::const_pointer() const { return word_entry; } auto& operator*() const { return *word_entry; } auto operator->() const { return word_entry; } }; struct Checker : public Aff_Data { enum Forceucase : bool { FORBID_BAD_FORCEUCASE = false, ALLOW_BAD_FORCEUCASE = true }; enum Hidden_Homonym : bool { ACCEPT_HIDDEN_HOMONYM = false, SKIP_HIDDEN_HOMONYM = true }; auto spell_priv(std::string& s) const -> bool; auto spell_break(std::string& s, size_t depth = 0) const -> bool; auto spell_casing(std::string& s) const -> const Flag_Set*; auto spell_casing_upper(std::string& s) const -> const Flag_Set*; auto spell_casing_title(std::string& s) const -> const Flag_Set*; auto spell_sharps(std::string& base, size_t n_pos = 0, size_t n = 0, size_t rep = 0) const -> const Flag_Set*; auto check_word(std::string& s, Forceucase allow_bad_forceucase = {}, Hidden_Homonym skip_hidden_homonym = {}) const -> const Flag_Set*; auto check_simple_word(std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const -> const Flag_Set*; template auto affix_NOT_valid(const Prefix& a) const; template auto affix_NOT_valid(const Suffix& a) const; template auto outer_affix_NOT_valid(const AffixT& a) const; template auto is_circumfix(const AffixT& a) const; template auto is_valid_inside_compound(const Flag_Set& flags) const; template auto strip_prefix_only(std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result; template auto strip_suffix_only(std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result; template auto strip_prefix_then_suffix(std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result; template auto strip_pfx_then_sfx_2(const Prefix& pe, std::string& s, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result; template auto strip_suffix_then_prefix(std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result; template auto strip_sfx_then_pfx_2(const Suffix& se, std::string& s, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result; template auto strip_prefix_then_suffix_commutative( std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result; template auto strip_pfx_then_sfx_comm_2(const Prefix& pe, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result; template auto strip_suffix_then_suffix(std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result; template auto strip_sfx_then_sfx_2(const Suffix& se1, std::string& s, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result; template auto strip_prefix_then_prefix(std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result; template auto strip_pfx_then_pfx_2(const Prefix& pe1, std::string& s, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result; template auto strip_prefix_then_2_suffixes( std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result<>; template auto strip_pfx_2_sfx_3(const Prefix& pe1, const Suffix& se1, std::string& s, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<>; template auto strip_suffix_prefix_suffix( std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result<>; template auto strip_s_p_s_3(const Suffix& se1, const Prefix& pe1, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<>; template auto strip_2_suffixes_then_prefix( std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result<>; template auto strip_2_sfx_pfx_3(const Suffix& se1, const Suffix& se2, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<>; template auto strip_suffix_then_2_prefixes( std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result<>; template auto strip_sfx_2_pfx_3(const Suffix& se1, const Prefix& pe1, std::string& s, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<>; template auto strip_prefix_suffix_prefix( std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result<>; template auto strip_p_s_p_3(const Prefix& pe1, const Suffix& se1, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<>; template auto strip_2_prefixes_then_suffix( std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const -> Affixing_Result<>; template auto strip_2_pfx_sfx_3(const Prefix& pe1, const Prefix& pe2, std::string& word, Hidden_Homonym skip_hidden_homonym) const -> Affixing_Result<>; auto check_compound(std::string& word, Forceucase allow_bad_forceucase) const -> Compounding_Result; template auto check_compound(std::string& word, size_t start_pos, size_t num_part, std::string& part, Forceucase allow_bad_forceucase) const -> Compounding_Result; template auto check_compound_classic(std::string& word, size_t start_pos, size_t i, size_t num_part, std::string& part, Forceucase allow_bad_forceucase) const -> Compounding_Result; template auto check_compound_with_pattern_replacements( std::string& word, size_t start_pos, size_t i, size_t num_part, std::string& part, Forceucase allow_bad_forceucase) const -> Compounding_Result; template auto check_word_in_compound(std::string& s) const -> Compounding_Result; auto calc_num_words_modifier(const Prefix& pfx) const -> unsigned char; template auto calc_syllable_modifier(Word_List::const_reference we) const -> signed char; template auto calc_syllable_modifier(Word_List::const_reference we, const Suffix& sfx) const -> signed char; auto count_syllables(std::string_view word) const -> size_t; auto check_compound_with_rules(std::string& word, std::vector& words_data, size_t start_pos, std::string& part, Forceucase allow_bad_forceucase) const -> Compounding_Result; auto is_rep_similar(std::string& word) const -> bool; }; template auto Checker::affix_NOT_valid(const Prefix& e) const { if (m == FULL_WORD && e.cont_flags.contains(compound_onlyin_flag)) return true; if (m == AT_COMPOUND_END && !e.cont_flags.contains(compound_permit_flag)) return true; if (m != FULL_WORD && e.cont_flags.contains(compound_forbid_flag)) return true; return false; } template auto Checker::affix_NOT_valid(const Suffix& e) const { if (m == FULL_WORD && e.cont_flags.contains(compound_onlyin_flag)) return true; if (m == AT_COMPOUND_BEGIN && !e.cont_flags.contains(compound_permit_flag)) return true; if (m != FULL_WORD && e.cont_flags.contains(compound_forbid_flag)) return true; return false; } template auto Checker::outer_affix_NOT_valid(const AffixT& e) const { if (affix_NOT_valid(e)) return true; if (e.cont_flags.contains(need_affix_flag)) return true; return false; } template auto Checker::is_circumfix(const AffixT& a) const { return a.cont_flags.contains(circumfix_flag); } template auto cross_valid_inner_outer(const AffixInner& inner, const AffixOuter& outer) { return inner.cont_flags.contains(outer.flag); } template auto cross_valid_inner_outer(const Flag_Set& word_flags, const Affix& afx) { return word_flags.contains(afx.flag); } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell #endif // NUSPELL_CHECKER_HXX nuspell-5.1.7/src/nuspell/defines.hxx000066400000000000000000000016341511132717100176300ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #ifndef NUSPELL_DEFINES_HXX #define NUSPELL_DEFINES_HXX #define NUSPELL_BEGIN_INLINE_NAMESPACE inline namespace v5 { #define NUSPELL_END_INLINE_NAMESPACE } #endif // NUSPELL_DEFINES_HXX nuspell-5.1.7/src/nuspell/dictionary.cxx000066400000000000000000000121151511132717100203470ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include "dictionary.hxx" #include "utils.hxx" #include #include /** * @mainpage * * You should be looking at: * * - Class nuspell::Dictionary * - Exception class nuspell::Dictionary_Loading_Error * - Auxiliary free functions for locating dictionaries on a file-system, see * finder.hxx */ using namespace std; namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE Dictionary::Dictionary(std::istream& aff, std::istream& dic) { load_aff_dic(aff, dic); } Dictionary::Dictionary() = default; /** * @brief Load the dictionary from opened files as iostreams * @pre Before calling this the dictionary object must be empty e.g * default-constructed or assigned with another empty object. * @param aff The iostream of the .aff file * @param dic The iostream of the .dic file * @throws Dictionary_Loading_Error on error */ auto Dictionary::load_aff_dic(std::istream& aff, std::istream& dic) -> void { auto err_msg = ostringstream(); if (!parse_aff_dic(aff, dic, err_msg)) throw Dictionary_Loading_Error(std::move(err_msg).str()); } static auto open_aff_dic(const filesystem::path& aff_path) -> pair { auto aff_file = ifstream(aff_path); if (aff_file.fail()) { auto err = "Aff file " + aff_path.string() + " not found."; throw Dictionary_Loading_Error(err); } auto dic_path = aff_path; dic_path.replace_extension(".dic"); auto dic_file = ifstream(dic_path); if (dic_file.fail()) { auto err = "Dic file " + dic_path.string() + " not found."; throw Dictionary_Loading_Error(err); } return {std::move(aff_file), std::move(dic_file)}; } /** * @brief Load the dictionary from file on filesystem * @pre Before calling this the dictionary object must be empty e.g * default-constructed or assigned with another empty object. * @param aff_path path to .aff file. The path of .dic is inffered from this. * @throws Dictionary_Loading_Error on error */ auto Dictionary::load_aff_dic(const std::filesystem::path& aff_path) -> void { auto [aff, dic] = open_aff_dic(aff_path); load_aff_dic(aff, dic); } auto Dictionary::load_aff_dic_internal(const std::filesystem::path& aff_path, std::ostream& err_msg) -> void { auto [aff, dic] = open_aff_dic(aff_path); if (!parse_aff_dic(aff, dic, err_msg)) throw Dictionary_Loading_Error("Parsing error."); } /** * @brief Create a dictionary from opened files as iostreams * * Prefer using load_from_path(). Use this if you have a specific use case, * like when .aff and .dic are in-memory buffers istringstream. * * @deprecated Use new non-static member function * load_aff_dic(std::istream&,std::istream&). * @param aff The iostream of the .aff file * @param dic The iostream of the .dic file * @return Dictionary object * @throws Dictionary_Loading_Error on error */ auto Dictionary::load_from_aff_dic(std::istream& aff, std::istream& dic) -> Dictionary { auto d = Dictionary(); d.load_aff_dic(aff, dic); return d; } /** * @brief Create a dictionary from files * @deprecated Use new non-static member function * load_aff_dic(const std::filesystem::path&). Note that the new function takes * path **WITH .aff extension**. * @param file_path_without_extension path *without* extensions (without .dic or * .aff) * @return Dictionary object * @throws Dictionary_Loading_Error on error */ auto Dictionary::load_from_path(const std::string& file_path_without_extension) -> Dictionary { auto d = Dictionary(); d.load_aff_dic(file_path_without_extension + ".aff"); return d; } /** * @brief Checks if a given word is correct * @param word any word * @return true if correct, false otherwise */ auto Dictionary::spell(std::string_view word) const -> bool { auto ok_enc = validate_utf8(word); if (unlikely(word.size() > 360)) return false; if (unlikely(!ok_enc)) return false; auto word_buf = string(word); return spell_priv(word_buf); } /** * @brief Suggests correct words for a given incorrect word * @param[in] word incorrect word * @param[out] out this object will be populated with the suggestions */ auto Dictionary::suggest(std::string_view word, std::vector& out) const -> void { out.clear(); auto ok_enc = validate_utf8(word); if (unlikely(word.size() > 360)) return; if (unlikely(!ok_enc)) return; suggest_priv(word, out); } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell nuspell-5.1.7/src/nuspell/dictionary.hxx000066400000000000000000000041461511132717100203610ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ /** * @file * @brief Dictionary spelling. */ #ifndef NUSPELL_DICTIONARY_HXX #define NUSPELL_DICTIONARY_HXX #include "suggester.hxx" #include namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE /** * @brief The only important public exception */ class Dictionary_Loading_Error : public std::runtime_error { public: using std::runtime_error::runtime_error; }; /** * @brief The only important public class */ class NUSPELL_EXPORT Dictionary : private Suggester { [[deprecated]] Dictionary(std::istream& aff, std::istream& dic); public: Dictionary(); auto load_aff_dic(std::istream& aff, std::istream& dic) -> void; auto load_aff_dic(const std::filesystem::path& aff_path) -> void; /** * @internal * @brief Do not use, only for Nuspell's CLI tool */ auto load_aff_dic_internal(const std::filesystem::path& aff_path, std::ostream& err_msg) -> void; [[deprecated]] auto static load_from_aff_dic(std::istream& aff, std::istream& dic) -> Dictionary; [[deprecated]] auto static load_from_path( const std::string& file_path_without_extension) -> Dictionary; auto spell(std::string_view word) const -> bool; auto suggest(std::string_view word, std::vector& out) const -> void; }; NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell #endif // NUSPELL_DICTIONARY_HXX nuspell-5.1.7/src/nuspell/finder.cxx000066400000000000000000000303101511132717100174460ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include "finder.hxx" #include "utils.hxx" #include #include #include #if __has_include() #include // defines _POSIX_VERSION #endif #if _WIN32 #ifndef NOMINMAX #define NOMINMAX #endif #define WIN32_LEAN_AND_MEAN #include #endif using namespace std; namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE using fs_path = std::filesystem::path; using std::filesystem::directory_entry; using std::filesystem::directory_iterator; using std::filesystem::filesystem_error; template static auto& split_to_paths(basic_string_view s, CharT sep, vector& out) { for (size_t i1 = 0;;) { auto i2 = s.find(sep, i1); out.emplace_back(s.substr(i1, i2 - i1)); if (i2 == s.npos) break; i1 = i2 + 1; } return out; } /** * @brief Append the paths of the default directories to be searched for * dictionaries. * @param[out] paths vector that receives the directory paths */ auto append_default_dir_paths(vector& paths) -> void { #ifdef _WIN32 const auto PATHSEP = L';'; auto dicpath = _wgetenv(L"DICPATH"); #else const auto PATHSEP = ':'; auto dicpath = getenv("DICPATH"); #endif if (dicpath && *dicpath) split_to_paths(basic_string_view(dicpath), PATHSEP, paths); #ifdef _POSIX_VERSION auto xdg_data_home = getenv("XDG_DATA_HOME"); if (xdg_data_home && *xdg_data_home) paths.push_back(fs_path(xdg_data_home) / "hunspell"); else if (auto home = getenv("HOME")) paths.push_back(fs_path(home) / ".local/share/hunspell"); auto xdg_data_dirs = getenv("XDG_DATA_DIRS"); if (xdg_data_dirs && *xdg_data_dirs) { auto data_dirs = string_view(xdg_data_dirs); auto i = size(paths); split_to_paths(data_dirs, PATHSEP, paths); for (; i != size(paths); ++i) paths[i] /= "hunspell"; i = size(paths); split_to_paths(data_dirs, PATHSEP, paths); for (; i != size(paths); ++i) paths[i] /= "myspell"; } else { paths.push_back("/usr/local/share/hunspell"); paths.push_back("/usr/share/hunspell"); paths.push_back("/usr/local/share/myspell"); paths.push_back("/usr/share/myspell"); } #if defined(__APPLE__) && defined(__MACH__) if (auto home = getenv("HOME")) paths.push_back(fs_path(home) / "Library/Spelling"); #endif #endif #if _WIN32 for (auto& e : {L"LOCALAPPDATA", L"PROGRAMDATA"}) { auto p = _wgetenv(e); if (p) paths.push_back(fs_path(p) / L"hunspell"); } #endif } static auto append_lo_global(const fs_path& p, vector& paths) -> void { for (auto& de : directory_iterator(p)) { if (!de.is_directory()) continue; if (!begins_with(de.path().filename().string(), "dict-")) continue; paths.push_back(de); } } static auto append_lo_user(const directory_entry& de1, vector& paths) -> void { for (auto& de2 : directory_iterator(de1)) { try { if (!de2.is_directory()) continue; if (de2.path().extension() != ".oxt") continue; for (auto& de3 : directory_iterator(de2)) { if (de3.is_directory() && begins_with(de3.path().filename().string(), "dict")) { paths.push_back(de3); } else if (de3.is_regular_file() && de3.path().extension() == ".aff") { paths.push_back(de2); break; } } } catch (const filesystem_error&) { } } } /** * @brief Append the paths of the LibreOffice's directories to be searched for * dictionaries. * * @warning This function shall not be called from LibreOffice or modules that * may end up being used by LibreOffice. It is mainly intended to be used by * the CLI tool. * * @param[out] paths vector that receives the directory paths */ auto append_libreoffice_dir_paths(vector& paths) -> void { using namespace filesystem; auto p1 = path(); // add LibreOffice global paths try { #if _WIN32 auto lo_dir = wstring(MAX_PATH - 1, '*'); // size in bytes including the zero terminator DWORD lo_dir_sz = (size(lo_dir) + 1) * sizeof(wchar_t); auto subkey = L"SOFTWARE\\LibreOffice\\UNO\\InstallPath"; auto regerr = RegGetValueW(HKEY_LOCAL_MACHINE, subkey, nullptr, RRF_RT_REG_SZ, nullptr, data(lo_dir), &lo_dir_sz); lo_dir.resize(lo_dir_sz / sizeof(wchar_t) - 1); if (regerr == ERROR_MORE_DATA) { regerr = RegGetValueW(HKEY_LOCAL_MACHINE, subkey, nullptr, RRF_RT_REG_SZ, nullptr, data(lo_dir), &lo_dir_sz); } if (regerr == ERROR_SUCCESS) { p1 = lo_dir; p1.replace_filename("share\\extensions"); append_lo_global(p1, paths); } #elif defined(__APPLE__) && defined(__MACH__) p1 = "/Applications/LibreOffice.app/Contents/Resources/" "extensions"; append_lo_global(p1, paths); #elif _POSIX_VERSION p1 = "/opt"; for (auto& de1 : directory_iterator(p1)) { try { if (!de1.is_directory()) continue; if (!begins_with(de1.path().filename().string(), "libreoffice ")) continue; append_lo_global( de1.path() / "share/extensions", paths); } catch (const filesystem_error&) { } } #endif } catch (const filesystem_error&) { } // add LibreOffice user paths p1.clear(); try { #if _WIN32 auto appdata = _wgetenv(L"APPDATA"); if (!appdata) return; p1 = appdata; #elif _POSIX_VERSION auto home = getenv("HOME"); if (!home) return; p1 = home; #if defined(__APPLE__) && defined(__MACH__) p1 /= "Library/Application Support"; #else p1 /= ".config"; #endif #else return; #endif p1 /= "libreoffice/4/user/uno_packages/cache/uno_packages"; p1.make_preferred(); for (auto& de1 : directory_iterator(p1)) { try { if (de1.is_directory()) append_lo_user(de1, paths); } catch (const filesystem_error&) { } } } catch (const filesystem_error&) { } } /** * @brief Search the directories for only one dictionary * * This function is more efficient than search_dirs_for_dicts() because it * does not iterate whole directories, it only checks the existence of .dic and * .aff files. Useful for some CLI tools. GUI apps generally need a list of all * dictionaries. * * @param[in] dir_paths list of directories * @param[in] dict_name_stem dictionary name, filename without extension (stem) * @return path to the .aff file of the dictionary or empty object if not found */ auto search_dirs_for_one_dict(const vector& dir_paths, const fs_path& dict_name_stem) -> fs_path { using std::filesystem::is_regular_file; auto fp = fs_path(); for (auto& dir : dir_paths) { fp = dir; fp /= dict_name_stem; fp += ".dic"; if (is_regular_file(fp)) { fp.replace_extension(".aff"); if (is_regular_file(fp)) return fp; } } fp.clear(); return fp; } static auto search_dir_for_dicts(const fs_path& dir_path, vector& dict_list) -> void try { using namespace filesystem; auto dics = set(); for (auto& entry : directory_iterator(dir_path)) { if (!entry.is_regular_file()) continue; auto& fp = entry.path(); auto ext = fp.extension(); if (ext == ".dic" || ext == ".aff") { auto [it, inserted] = dics.insert(fp.stem()); if (!inserted) // already existed dict_list.emplace_back(fp).replace_extension( ".aff"); } } } catch (const filesystem_error&) { } /** * @brief Search the directories for dictionaries. * * This function searches the directories for files that represent dictionaries * and for each found dictionary it appends the path of the .aff file to @p * dict_list. One dictionary consts of two files, .aff and .dic, and both need * to exist, but only the .aff is added. * * @param[in] dir_paths list of paths to directories * @param[out] dict_list vector that receives the paths of the found * dictionaries */ auto search_dirs_for_dicts(const vector& dir_paths, vector& dict_list) -> void { for (auto& p : dir_paths) search_dir_for_dicts(p, dict_list); } /** * @brief Search the default directories for dictionaries. * * This is just a convenience that call two other functions. * @see append_default_dir_paths() * @see search_dirs_for_dicts() * @return vector with the paths of the .aff files of the found dictionaries */ auto search_default_dirs_for_dicts() -> vector { auto dir_paths = vector(); auto dict_list = vector(); append_default_dir_paths(dir_paths); search_dirs_for_dicts(dir_paths, dict_list); return dict_list; } auto append_default_dir_paths(std::vector& paths) -> void { auto out = vector(); append_default_dir_paths(out); transform(begin(out), end(out), back_inserter(paths), [](const fs_path& p) { return p.string(); }); } auto append_libreoffice_dir_paths(std::vector& paths) -> void { auto out = vector(); append_libreoffice_dir_paths(out); transform(begin(out), end(out), back_inserter(paths), [](const fs_path& p) { return p.string(); }); } static auto new_to_old_dict_list(vector& new_aff_paths, vector>& dict_list) -> void { transform(begin(new_aff_paths), end(new_aff_paths), back_inserter(dict_list), [](const fs_path& p) { return pair{p.stem().string(), fs_path(p).replace_extension().string()}; }); } auto search_dir_for_dicts(const string& dir_path, vector>& dict_list) -> void { auto new_dict_list = vector(); search_dir_for_dicts(dir_path, new_dict_list); new_to_old_dict_list(new_dict_list, dict_list); } auto search_dirs_for_dicts(const std::vector& dir_paths, std::vector>& dict_list) -> void { auto new_dict_list = vector(); for (auto& p : dir_paths) search_dir_for_dicts(p, new_dict_list); new_to_old_dict_list(new_dict_list, dict_list); } auto search_default_dirs_for_dicts( std::vector>& dict_list) -> void { auto new_dir_paths = vector(); auto new_dict_list = vector(); append_default_dir_paths(new_dir_paths); search_dirs_for_dicts(new_dir_paths, new_dict_list); new_to_old_dict_list(new_dict_list, dict_list); } auto find_dictionary( const std::vector>& dict_list, const std::string& dict_name) -> std::vector>::const_iterator { return find_if(begin(dict_list), end(dict_list), [&](auto& e) { return e.first == dict_name; }); } Dict_Finder_For_CLI_Tool::Dict_Finder_For_CLI_Tool() {} auto Dict_Finder_For_CLI_Tool::get_dictionary_path(const std::string&) const -> std::string { return {}; } Dict_Finder_For_CLI_Tool_2::Dict_Finder_For_CLI_Tool_2() { append_default_dir_paths(dir_paths); append_libreoffice_dir_paths(dir_paths); dir_paths.push_back("."); } /** * @internal * @brief Gets the dictionary path. * * If @p dict is a path that contains slash, the function returns the input * argument as is, otherwise searches the found dictionaries by their name * (stem) and returns their path. * * @param dict name (stem, filename without extension) or path with slash and * with .aff extension. * @return the path to dictionary or empty if does not exists. */ auto Dict_Finder_For_CLI_Tool_2::get_dictionary_path(const fs_path& dict) const -> fs_path { if (dict.has_stem() && distance(begin(dict), end(dict)) == 1) return search_dirs_for_one_dict(dir_paths, dict); return dict; } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell nuspell-5.1.7/src/nuspell/finder.hxx000066400000000000000000000073671511132717100174730ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ /** * @file * @brief Finding dictionaries. */ #ifndef NUSPELL_FINDER_HXX #define NUSPELL_FINDER_HXX #include "defines.hxx" #include "nuspell_export.h" #include #include #include #include #ifdef _MSC_VER #define NUSPELL_MSVC_PRAGMA_WARNING(x) __pragma(warning(x)) #else #define NUSPELL_MSVC_PRAGMA_WARNING(x) #endif NUSPELL_MSVC_PRAGMA_WARNING(push) NUSPELL_MSVC_PRAGMA_WARNING(disable : 4251) namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE NUSPELL_EXPORT auto append_default_dir_paths(std::vector& paths) -> void; NUSPELL_EXPORT auto append_libreoffice_dir_paths(std::vector& paths) -> void; NUSPELL_EXPORT auto search_dirs_for_one_dict(const std::vector& dir_paths, const std::filesystem::path& dict_name_stem) -> std::filesystem::path; NUSPELL_EXPORT auto search_dirs_for_dicts(const std::vector& dir_paths, std::vector& dict_list) -> void; NUSPELL_EXPORT auto search_default_dirs_for_dicts() -> std::vector; NUSPELL_DEPRECATED_EXPORT auto append_default_dir_paths(std::vector& paths) -> void; NUSPELL_DEPRECATED_EXPORT auto append_libreoffice_dir_paths(std::vector& paths) -> void; NUSPELL_DEPRECATED_EXPORT auto search_dir_for_dicts( const std::string& dir_path, std::vector>& dict_list) -> void; NUSPELL_DEPRECATED_EXPORT auto search_dirs_for_dicts( const std::vector& dir_paths, std::vector>& dict_list) -> void; NUSPELL_DEPRECATED_EXPORT auto search_default_dirs_for_dicts( std::vector>& dict_list) -> void; NUSPELL_DEPRECATED_EXPORT auto find_dictionary( const std::vector>& dict_list, const std::string& dict_name) -> std::vector>::const_iterator; /** * @internal * @brief Don't use this except from Nuspell CLI tool. * * There are no promises of the API. */ class NUSPELL_DEPRECATED_EXPORT Dict_Finder_For_CLI_Tool { std::vector dir_paths; std::vector> dict_multimap; public: Dict_Finder_For_CLI_Tool(); auto& get_dir_paths() const { return dir_paths; } auto& get_dictionaries() const { return dict_multimap; } auto get_dictionary_path(const std::string& dict) const -> std::string; }; /** * @internal * @brief Don't use this except from Nuspell CLI tool. * * There are no promises of the API. */ class NUSPELL_EXPORT Dict_Finder_For_CLI_Tool_2 { std::vector dir_paths; public: Dict_Finder_For_CLI_Tool_2(); auto& get_dir_paths() const { return dir_paths; } auto get_dictionary_path(const std::filesystem::path& dict) const -> std::filesystem::path; }; NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell NUSPELL_MSVC_PRAGMA_WARNING(pop) #endif // NUSPELL_FINDER_HXX nuspell-5.1.7/src/nuspell/structures.hxx000066400000000000000000001311051511132717100204330ustar00rootroot00000000000000/* Copyright 2018-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #ifndef NUSPELL_STRUCTURES_HXX #define NUSPELL_STRUCTURES_HXX #include "unicode.hxx" #include #include #include #include #include #include #include #include #include #include #include namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE template class Subrange { using Iter_Category = typename std::iterator_traits::iterator_category; It a = {}; It b = {}; public: Subrange() = default; Subrange(std::pair p) : a(p.first), b(p.second) {} Subrange(It first, It last) : a(first), b(last) {} template Subrange(Range& r) : a(r.begin()), b(r.end()) { } auto begin() const -> It { return a; } auto end() const -> It { return b; } }; // CTAD template Subrange(const Range& r) -> Subrange; template Subrange(Range& r) -> Subrange; /** * @internal * @brief Class that represents set of characters. * * Use this instead of std::set or std::set. * Internally it is implemented with ordered string. */ template class String_Set { private: std::basic_string d; auto sort_uniq() -> void { auto first = begin(); auto last = end(); using t = traits_type; sort(first, last, t::lt); d.erase(unique(first, last, t::eq), last); } struct Char_Traits_Less_Than { auto operator()(CharT a, CharT b) const noexcept { return traits_type::lt(a, b); } }; public: using Str = std::basic_string; using traits_type = typename Str::traits_type; using key_type = typename Str::value_type; using key_compare = Char_Traits_Less_Than; using value_type = typename Str::value_type; using value_compare = key_compare; using allocator_type = typename Str::allocator_type; using pointer = typename Str::pointer; using const_pointer = typename Str::const_pointer; using reference = typename Str::reference; using const_reference = typename Str::const_reference; using size_type = typename Str::size_type; using difference_type = typename Str::difference_type; using iterator = typename Str::iterator; using const_iterator = typename Str::const_iterator; using reverse_iterator = typename Str::reverse_iterator; using const_reverse_iterator = typename Str::const_reverse_iterator; String_Set() = default; explicit String_Set(const Str& s) : d(s) { sort_uniq(); } explicit String_Set(Str&& s) : d(move(s)) { sort_uniq(); } explicit String_Set(const CharT* s) : d(s) { sort_uniq(); } template String_Set(InputIterator first, InputIterator last) : d(first, last) { sort_uniq(); } String_Set(std::initializer_list il) : d(il) { sort_uniq(); } auto& operator=(const Str& s) { d = s; sort_uniq(); return *this; } auto& operator=(Str&& s) { d = move(s); sort_uniq(); return *this; } auto& operator=(std::initializer_list il) { d = il; sort_uniq(); return *this; } auto& operator=(const CharT* s) { d = s; sort_uniq(); return *this; } // non standard underlying storage access: auto data() const noexcept -> const_pointer { return d.data(); } operator const Str&() const noexcept { return d; } auto& str() const noexcept { return d; } // iterators: iterator begin() noexcept { return d.begin(); } const_iterator begin() const noexcept { return d.begin(); } iterator end() noexcept { return d.end(); } const_iterator end() const noexcept { return d.end(); } reverse_iterator rbegin() noexcept { return d.rbegin(); } const_reverse_iterator rbegin() const noexcept { return d.rbegin(); } reverse_iterator rend() noexcept { return d.rend(); } const_reverse_iterator rend() const noexcept { return d.rend(); } const_iterator cbegin() const noexcept { return d.cbegin(); } const_iterator cend() const noexcept { return d.cend(); } const_reverse_iterator crbegin() const noexcept { return d.crbegin(); } const_reverse_iterator crend() const noexcept { return d.crend(); } // capacity: bool empty() const noexcept { return d.empty(); } size_type size() const noexcept { return d.size(); } size_type max_size() const noexcept { return d.max_size(); } // modifiers: std::pair insert(value_type x) { auto it = lower_bound(x); if (it != end() && *it == x) { return {it, false}; } auto ret = d.insert(it, x); return {ret, true}; } iterator insert(iterator hint, value_type x) { if (hint == end() || traits_type::lt(x, *hint)) { if (hint == begin() || traits_type::lt(*(hint - 1), x)) { return d.insert(hint, x); } } return insert(x).first; } // iterator insert(const_iterator hint, value_type&& x); template void insert(InputIterator first, InputIterator last) { d.insert(end(), first, last); sort_uniq(); } void insert(std::initializer_list il) { d.insert(end(), il); sort_uniq(); } template std::pair emplace(Args&&... args) { return insert(CharT(args...)); } template iterator emplace_hint(iterator hint, Args&&... args) { return insert(hint, CharT(args...)); } iterator erase(iterator position) { return d.erase(position); } size_type erase(key_type x) { auto i = d.find(x); if (i != d.npos) { d.erase(i, 1); return true; } return false; } iterator erase(iterator first, iterator last) { return d.erase(first, last); } void swap(String_Set& s) { d.swap(s.d); } void clear() noexcept { d.clear(); } // non standard modifiers: auto insert(const Str& s) -> void { d += s; sort_uniq(); } auto& operator+=(const Str& s) { insert(s); return *this; } // observers: key_compare key_comp() const { return Char_Traits_Less_Than(); } value_compare value_comp() const { return key_comp(); } // set operations: private: auto lookup(key_type x) const { auto i = d.find(x); if (i == d.npos) i = d.size(); return i; } public: iterator find(key_type x) { return begin() + lookup(x); } const_iterator find(key_type x) const { return begin() + lookup(x); } size_type count(key_type x) const { return d.find(x) != d.npos; } iterator lower_bound(key_type x) { return std::lower_bound(begin(), end(), x, traits_type::lt); } const_iterator lower_bound(key_type x) const { return std::lower_bound(begin(), end(), x, traits_type::lt); } iterator upper_bound(key_type x) { return std::upper_bound(begin(), end(), x, traits_type::lt); } const_iterator upper_bound(key_type x) const { return std::upper_bound(begin(), end(), x, traits_type::lt); } std::pair equal_range(key_type x) { return std::equal_range(begin(), end(), x, traits_type::lt); } std::pair equal_range(key_type x) const { return std::equal_range(begin(), end(), x, traits_type::lt); } // non standard set operations: bool contains(key_type x) const { return count(x); } // compare bool operator<(const String_Set& rhs) const { return d < rhs.d; } bool operator<=(const String_Set& rhs) const { return d <= rhs.d; } bool operator==(const String_Set& rhs) const { return d == rhs.d; } bool operator!=(const String_Set& rhs) const { return d != rhs.d; } bool operator>=(const String_Set& rhs) const { return d >= rhs.d; } bool operator>(const String_Set& rhs) const { return d > rhs.d; } }; template auto swap(String_Set& a, String_Set& b) { a.swap(b); } using Flag_Set = String_Set; class Substr_Replacer { public: using Str = std::string; using Str_View = std::string_view; using Pair_Str = std::pair; using Table_Pairs = std::vector; private: Table_Pairs table; auto sort_uniq() -> void; auto find_match(Str_View s) const; public: Substr_Replacer() = default; explicit Substr_Replacer(const Table_Pairs& v) : table(v) { sort_uniq(); } explicit Substr_Replacer(Table_Pairs&& v) : table(std::move(v)) { sort_uniq(); } auto& operator=(const Table_Pairs& v) { table = v; sort_uniq(); return *this; } auto& operator=(Table_Pairs&& v) { table = std::move(v); sort_uniq(); return *this; } auto replace(Str& s) const -> Str&; auto replace_copy(Str s) const -> Str { replace(s); return s; } }; auto inline Substr_Replacer::sort_uniq() -> void { auto first = begin(table); auto last = end(table); sort(first, last, [](auto& a, auto& b) { return a.first < b.first; }); auto it = unique(first, last, [](auto& a, auto& b) { return a.first == b.first; }); table.erase(it, last); // remove empty key "" if (!table.empty() && table.front().first.empty()) table.erase(begin(table)); } auto inline Substr_Replacer::find_match(Str_View s) const { auto& t = table; struct Comparer_Str_Rep { auto static cmp_prefix_of(const Str& p, Str_View of) { return p.compare(0, p.npos, of.data(), std::min(p.size(), of.size())); } auto operator()(const Pair_Str& a, Str_View b) { return cmp_prefix_of(a.first, b) < 0; } auto operator()(Str_View a, const Pair_Str& b) { return cmp_prefix_of(b.first, a) > 0; } auto static eq(const Pair_Str& a, Str_View b) { return cmp_prefix_of(a.first, b) == 0; } }; Comparer_Str_Rep csr; auto it = begin(t); auto last_match = end(t); for (;;) { auto it2 = upper_bound(it, end(t), s, csr); if (it2 == it) { // not found, s is smaller that the range break; } --it2; if (csr.eq(*it2, s)) { // Match found. Try another search maybe for // longer. last_match = it2; it = ++it2; } else { // not found, s is greater that the range break; } } return last_match; } auto inline Substr_Replacer::replace(Str& s) const -> Str& { if (table.empty()) return s; for (size_t i = 0; i < s.size(); /*no increment here*/) { auto substr = Str_View(&s[i], s.size() - i); auto it = find_match(substr); if (it != end(table)) { auto& match = *it; // match found. match.first is the found string, // match.second is the replacement. s.replace(i, match.first.size(), match.second); i += match.second.size(); continue; } ++i; } return s; } class Break_Table { public: using Str = std::string; using Table_Str = std::vector; using iterator = typename Table_Str::iterator; using const_iterator = typename Table_Str::const_iterator; private: Table_Str table; size_t start_word_breaks_last_idx = 0; size_t end_word_breaks_last_idx = 0; auto order_entries() -> void; public: Break_Table() = default; explicit Break_Table(const Table_Str& v) : table(v) { order_entries(); } explicit Break_Table(Table_Str&& v) : table(std::move(v)) { order_entries(); } auto& operator=(const Table_Str& v) { table = v; order_entries(); return *this; } auto& operator=(Table_Str&& v) { table = std::move(v); order_entries(); return *this; } auto start_word_breaks() const -> Subrange { return {begin(table), begin(table) + start_word_breaks_last_idx}; } auto end_word_breaks() const -> Subrange { return {begin(table) + start_word_breaks_last_idx, begin(table) + end_word_breaks_last_idx}; } auto middle_word_breaks() const -> Subrange { return {begin(table) + end_word_breaks_last_idx, end(table)}; } }; auto inline Break_Table::order_entries() -> void { auto it = remove_if(begin(table), end(table), [](auto& s) { return s.empty() || (s.size() == 1 && (s[0] == '^' || s[0] == '$')); }); table.erase(it, end(table)); auto is_start_word_break = [=](auto& x) { return x[0] == '^'; }; auto is_end_word_break = [=](auto& x) { return x.back() == '$'; }; auto start_word_breaks_last = partition(begin(table), end(table), is_start_word_break); start_word_breaks_last_idx = start_word_breaks_last - begin(table); for_each(begin(table), start_word_breaks_last, [](auto& e) { e.erase(0, 1); }); auto end_word_breaks_last = partition(start_word_breaks_last, end(table), is_end_word_break); end_word_breaks_last_idx = end_word_breaks_last - begin(table); for_each(start_word_breaks_last, end_word_breaks_last, [](auto& e) { e.pop_back(); }); } struct identity { template constexpr auto operator()(T&& t) const noexcept -> T&& { return std::forward(t); } }; template class Hash_Multimap { using bucket_type = std::forward_list>; static constexpr float max_load_fact = 7.0 / 8.0; std::vector data; size_t sz = 0; size_t max_load_factor_capacity = 0; public: using key_type = Key; using mapped_type = T; using value_type = std::pair; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using hasher = std::hash; using reference = value_type&; using const_reference = const value_type&; using pointer = typename bucket_type::pointer; using const_pointer = typename bucket_type::const_pointer; using local_iterator = typename bucket_type::iterator; using local_const_iterator = typename bucket_type::const_iterator; Hash_Multimap() = default; auto size() const noexcept { return sz; } auto empty() const noexcept { return size() == 0; } auto rehash(size_t count) { if (empty()) { size_t capacity = 16; while (capacity <= count) capacity <<= 1; data.resize(capacity); max_load_factor_capacity = std::ceil(capacity * max_load_fact); return; } if (count < size() / max_load_fact) count = size() / max_load_fact; auto n = Hash_Multimap(); n.rehash(count); for (auto& b : data) { for (auto& x : b) { n.insert(std::move(x)); } } data.swap(n.data); sz = n.sz; max_load_factor_capacity = n.max_load_factor_capacity; } auto reserve(size_t count) -> void { rehash(std::ceil(count / max_load_fact)); } private: auto prepare_for_insert(const key_type& key) -> std::pair { auto hash = hasher(); if (sz == max_load_factor_capacity) { reserve(sz + 1); } auto h = hash(key); auto h_mod = h & (data.size() - 1); auto& bucket = data[h_mod]; auto prev = bucket.before_begin(); auto curr = begin(bucket); // find first entry with same key for (; curr != end(bucket); prev = curr++) { if (curr->first == key) break; } // find last entry with same key for (; curr != end(bucket); prev = curr++) { if (curr->first != key) break; } ++sz; return {bucket, prev}; } public: auto insert(value_type&& value) { auto& key = value.first; auto [bucket, it] = prepare_for_insert(key); return bucket.insert_after(it, move(value)); } template auto emplace(Args&&... a) { auto node = bucket_type(); auto& val = node.emplace_front(std::forward(a)...); auto& key = val.first; auto [bucket, it] = prepare_for_insert(key); bucket.splice_after(it, node, node.before_begin()); return next(it); } auto equal_range(const key_type& key) const -> std::pair { auto hash = hasher(); if (data.empty()) return {}; auto h = hash(key); auto h_mod = h & (data.size() - 1); auto& bucket = data[h_mod]; auto eq_key = [&](auto& x) { return key == x.first; }; auto first = std::find_if(begin(bucket), end(bucket), eq_key); if (first == end(bucket)) return {first, first}; // ret empty auto last = std::find_if_not(next(first), end(bucket), eq_key); return {first, last}; } auto bucket_count() const -> size_type { return data.size(); } auto bucket_data(size_type i) const { return Subrange(data[i]); } }; struct Condition_Exception : public std::runtime_error { using std::runtime_error::runtime_error; }; /** * @internal * @brief Minimal regex used as the condition in affix entries. */ class Condition { using Str = std::string; using Str_View = std::string_view; Str cond; size_t num_cp = 0; auto construct() -> void; public: Condition() = default; explicit Condition(const Str& condition) : cond(condition) { construct(); } explicit Condition(Str&& condition) : cond(std::move(condition)) { construct(); } explicit Condition(const char* condition) : cond(condition) { construct(); } auto& operator=(const Str& condition) { cond = condition; num_cp = 0; construct(); return *this; } auto& operator=(Str&& condition) { cond = std::move(condition); num_cp = 0; construct(); return *this; } auto& operator=(const char* condition) { cond = condition; num_cp = 0; construct(); return *this; } auto& str() const { return cond; } auto match_prefix(Str_View s) const -> bool; auto match_suffix(Str_View s) const { auto cp_cnt = size_t(0); auto i = size(s); for (; cp_cnt != num_cp && i != 0; ++cp_cnt) { valid_u8_reverse_index(s, i); } if (cp_cnt != num_cp) return false; return match_prefix(s.substr(i)); } }; auto inline Condition::construct() -> void { for (size_t i = 0; i != size(cond);) { size_t j = cond.find_first_of("[].", i); if (j == cond.npos) j = size(cond); while (i != j) { valid_u8_advance_index(cond, i); ++num_cp; } if (i == size(cond)) break; if (cond[i] == '.') { ++num_cp; ++i; continue; } else if (cond[i] == ']') { auto what = "closing bracket has no matching opening bracket"; throw Condition_Exception(what); } else if (cond[i] == '[') { ++i; if (i == size(cond)) { auto what = "opening bracket has no matching " "closing bracket"; throw Condition_Exception(what); } if (cond[i] == '^') ++i; j = cond.find(']', i); if (j == i) { auto what = "empty bracket expression"; throw Condition_Exception(what); } if (j == cond.npos) { auto what = "opening bracket has no matching " "closing bracket"; throw Condition_Exception(what); } ++num_cp; i = j + 1; } } } auto inline Condition::match_prefix(Str_View s) const -> bool { if (size(s) < num_cp) return false; auto s_i = size_t(0); auto cond_i = size_t(0); for (; s_i != size(s) && cond_i != size(cond); ++cond_i) { auto s_cu = s[s_i]; auto cond_cu = cond[cond_i]; switch (cond_cu) { default: if (s_cu != cond_cu) return false; ++s_i; break; case '.': valid_u8_advance_index(s, s_i); break; case '[': ++cond_i; cond_cu = cond[cond_i]; if (cond_cu == '^') ++cond_i; char32_t str_cp; valid_u8_advance_cp(s, s_i, str_cp); auto found = false; while (cond[cond_i] != ']') { char32_t cond_cp; valid_u8_advance_cp(cond, cond_i, cond_cp); if (str_cp == cond_cp) found = true; } if (cond_cu != '^' && !found) return false; if (cond_cu == '^' && found) return false; break; } } return cond_i == size(cond); } struct Prefix { using Str = std::string; char16_t flag = 0; bool cross_product = false; Str stripping; Str appending; Flag_Set cont_flags; Condition condition; auto to_root(Str& word) const -> Str& { return word.replace(0, appending.size(), stripping); } auto to_root_copy(Str word) const -> Str { to_root(word); return word; } auto to_derived(Str& word) const -> Str& { return word.replace(0, stripping.size(), appending); } auto to_derived_copy(Str word) const -> Str { to_derived(word); return word; } auto check_condition(const Str& word) const -> bool { return condition.match_prefix(word); } }; struct Suffix { using Str = std::string; char16_t flag = 0; bool cross_product = false; Str stripping; Str appending; Flag_Set cont_flags; Condition condition; auto to_root(Str& word) const -> Str& { return word.replace(word.size() - appending.size(), appending.size(), stripping); } auto to_root_copy(Str word) const -> Str { to_root(word); return word; } auto to_derived(Str& word) const -> Str& { return word.replace(word.size() - stripping.size(), stripping.size(), appending); } auto to_derived_copy(Str word) const -> Str { to_derived(word); return word; } auto check_condition(const Str& word) const -> bool { return condition.match_suffix(word); } }; template class Prefix_Multiset { public: using Value_Type = T; using Key_Type = std::remove_reference_t()( std::declval()))>; using Char_Type = typename Key_Type::value_type; using Traits = typename Key_Type::traits_type; using Vector_Type = std::vector; using Iterator = typename Vector_Type::const_iterator; private: struct Ebo_Key_Extr : public Key_Extr {}; struct Ebo_Key_Transf : public Key_Transform {}; struct Ebo : public Ebo_Key_Extr, Ebo_Key_Transf { Vector_Type table; } ebo; std::basic_string first_letter; std::vector prefix_idx_with_first_letter; auto key_extractor() const -> const Ebo_Key_Extr& { return ebo; } auto key_transformator() const -> const Ebo_Key_Transf& { return ebo; } auto& get_table() { return ebo.table; } auto& get_table() const { return ebo.table; } auto sort() { auto& extract_key = key_extractor(); auto& transform_key = key_transformator(); auto& table = get_table(); std::sort(begin(table), end(table), [&](T& a, T& b) { auto&& key_a = transform_key(extract_key(a)); auto&& key_b = transform_key(extract_key(b)); return key_a < key_b; }); first_letter.clear(); prefix_idx_with_first_letter.clear(); auto first = begin(table); auto last = end(table); auto it = std::find_if_not(first, last, [=](const T& x) { auto&& k = transform_key(extract_key(x)); return k.empty(); }); while (it != last) { auto&& k1 = transform_key(extract_key(*it)); first_letter.push_back(k1[0]); prefix_idx_with_first_letter.push_back(it - first); it = std::upper_bound( it, last, k1[0], Comparator{0, extract_key, transform_key}); } if (!prefix_idx_with_first_letter.empty()) prefix_idx_with_first_letter.push_back(last - first); } struct Comparator { size_t i; Key_Extr extract_key; Key_Transform transform_key; auto operator()(const T& a, Char_Type b) const { auto&& key_a = transform_key(extract_key(a)); return Traits::lt(key_a[i], b); } auto operator()(Char_Type a, const T& b) const { auto&& key_b = transform_key(extract_key(b)); return Traits::lt(a, key_b[i]); } }; public: Prefix_Multiset() = default; explicit Prefix_Multiset(Key_Extr ke, Key_Transform kt = {}) : ebo{{ke}, {kt}, {}} { } explicit Prefix_Multiset(const Vector_Type& v, Key_Extr ke = {}, Key_Transform kt = {}) : ebo{{ke}, {kt}, v} { sort(); } explicit Prefix_Multiset(Vector_Type&& v, Key_Extr ke = {}, Key_Transform kt = {}) : ebo{{ke}, {kt}, std::move(v)} { sort(); } Prefix_Multiset(std::initializer_list list, Key_Extr ke = {}, Key_Transform kt = {}) : ebo{{ke}, {kt}, list} { sort(); } auto& operator=(const Vector_Type& v) { get_table() = v; sort(); return *this; } auto& operator=(Vector_Type&& v) { get_table() = std::move(v); sort(); return *this; } auto& operator=(std::initializer_list list) { get_table() = list; sort(); return *this; } auto& data() const { return get_table(); } template auto for_each_prefixes_of(const Key_Type& word, Func func) const; template auto copy_all_prefixes_of(const Key_Type& word, OutIter o) const { for_each_prefixes_of(word, [&](const T& x) { *o++ = x; }); return o; } class Iter_Prefixes_Of { const Prefix_Multiset* set = {}; Iterator it = {}; Iterator last = {}; const Key_Type* search_key = {}; size_t len = {}; bool valid = false; auto advance() -> void; public: using iterator_category = std::input_iterator_tag; using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; using reference = const T&; using pointer = const T*; Iter_Prefixes_Of() = default; Iter_Prefixes_Of(const Prefix_Multiset& set, const Key_Type& word) : set(&set), it(set.get_table().begin()), last(set.get_table().end()), search_key(&word), valid(true) { advance(); } Iter_Prefixes_Of(const Prefix_Multiset&, Key_Type&&) = delete; Iter_Prefixes_Of(Prefix_Multiset&&, const Key_Type&) = delete; Iter_Prefixes_Of(Prefix_Multiset&&, Key_Type&&) = delete; auto& operator++() { ++it; advance(); return *this; } auto& operator++(int) { auto old = *this; ++*this; return old; } auto& operator*() const { return *it; } auto operator->() const { return &*it; } auto operator==(const Iter_Prefixes_Of& other) const { return valid == other.valid; } auto operator!=(const Iter_Prefixes_Of& other) const { return valid != other.valid; } operator bool() const { return valid; } auto begin() const { return *this; } auto end() const { return Iter_Prefixes_Of(); } }; auto iterate_prefixes_of(const Key_Type& word) const { return Iter_Prefixes_Of(*this, word); } auto iterate_prefixes_of(Key_Type&& word) const = delete; }; template auto Prefix_Multiset::Iter_Prefixes_Of::advance() -> void { auto& extract_key = set->key_extractor(); auto& transform_key = set->key_transformator(); auto& table = set->get_table(); if (len == 0) { if (it != last) { if (transform_key(extract_key(*it)).empty()) return; if (transform_key(*search_key).empty()) { valid = false; return; } auto& first_letter = set->first_letter; auto& prefix_idx_with_first_letter = set->prefix_idx_with_first_letter; auto idx = first_letter.find(transform_key(*search_key)[0]); if (idx == first_letter.npos) { valid = false; return; } auto first = table.begin(); it = first + prefix_idx_with_first_letter[idx]; last = first + prefix_idx_with_first_letter[idx + 1]; ++len; } else { valid = false; return; } } for (;; ++len) { if (it != last) { if (transform_key(extract_key(*it)).size() == len) return; if (len == transform_key(*search_key).size()) { valid = false; break; } } else { valid = false; break; } tie(it, last) = equal_range(it, last, transform_key(*search_key)[len], Comparator{len, extract_key, transform_key}); } } template template auto Prefix_Multiset::for_each_prefixes_of( const Key_Type& word, Func func) const { auto& extract_key = key_extractor(); auto& transform_key = key_transformator(); auto& table = get_table(); auto first = begin(table); auto last = end(table); auto it = first; for (; it != last; ++it) { auto&& k = transform_key(extract_key(*it)); if (k.empty()) func(*it); else break; } if (it == last) return; if (transform_key(word).empty()) return; auto idx = first_letter.find(transform_key(word)[0]); if (idx == first_letter.npos) return; first = begin(table) + prefix_idx_with_first_letter[idx]; last = begin(table) + prefix_idx_with_first_letter[idx + 1]; for (size_t len = 1;; ++len) { it = first; for (; it != last && transform_key(extract_key(*it)).size() == len; ++it) { func(*it); } if (it == last) break; if (len == transform_key(word).size()) break; tie(first, last) = equal_range(it, last, transform_key(word)[len], Comparator{len, extract_key, transform_key}); } } template class Reversed_String_View { public: using Str = std::basic_string; using traits_type = typename Str::traits_type; using value_type = typename Str::value_type; using size_type = typename Str::size_type; using const_iterator = typename Str::const_reverse_iterator; private: const_iterator first = {}; size_type sz = {}; public: Reversed_String_View() = default; explicit Reversed_String_View(const Str& s) : first(s.rbegin()), sz(s.size()) { } Reversed_String_View(Str&& s) = delete; auto& operator[](size_type i) const { return first[i]; } auto size() const { return sz; } auto empty() const { return sz == 0; } auto begin() const { return first; } auto end() const { return first + sz; } auto operator<(Reversed_String_View other) const { return lexicographical_compare(begin(), end(), other.begin(), other.end(), traits_type::lt); } }; template struct String_Reverser { auto operator()(const std::basic_string& x) const { return Reversed_String_View(x); } // auto operator()(T&& x) const = delete; }; template struct Extractor_Of_Appending_From_Affix { auto& operator()(const AffixT& a) const { return a.appending; } }; template using Suffix_Multiset = Prefix_Multiset< T, Key_Extr, String_Reverser::Char_Type>>; class Prefix_Table { using Prefix_Multiset_Type = Prefix_Multiset>; using Key_Type = typename Prefix_Multiset_Type::Key_Type; using Vector_Type = typename Prefix_Multiset_Type::Vector_Type; Prefix_Multiset_Type table; Flag_Set all_cont_flags; auto populate() { for (auto& x : table.data()) all_cont_flags += x.cont_flags; } public: Prefix_Table() = default; explicit Prefix_Table(const Vector_Type& t) : table(t) { populate(); } explicit Prefix_Table(Vector_Type&& t) : table(std::move(t)) { populate(); } auto& operator=(const Vector_Type& t) { table = t; populate(); return *this; } auto& operator=(Vector_Type&& t) { table = std::move(t); populate(); return *this; } auto begin() const { return table.data().begin(); } auto end() const { return table.data().end(); } auto size() const { return table.data().size(); } auto has_continuation_flags() const { return all_cont_flags.size() != 0; } auto has_continuation_flag(char16_t flag) const { return all_cont_flags.contains(flag); } auto iterate_prefixes_of(const Key_Type& word) const { return table.iterate_prefixes_of(word); } auto iterate_prefixes_of(Key_Type&& word) const = delete; }; class Suffix_Table { using Suffix_Multiset_Type = Suffix_Multiset>; using Key_Type = typename Suffix_Multiset_Type::Key_Type; using Vector_Type = typename Suffix_Multiset_Type::Vector_Type; Suffix_Multiset_Type table; Flag_Set all_cont_flags; auto populate() { for (auto& x : table.data()) all_cont_flags += x.cont_flags; } public: Suffix_Table() = default; explicit Suffix_Table(const Vector_Type& t) : table(t) { populate(); } explicit Suffix_Table(Vector_Type&& t) : table(std::move(t)) { populate(); } auto& operator=(const Vector_Type& t) { table = t; populate(); return *this; } auto& operator=(Vector_Type&& t) { table = std::move(t); populate(); return *this; } auto begin() const { return table.data().begin(); } auto end() const { return table.data().end(); } auto size() const { return table.data().size(); } auto has_continuation_flags() const { return all_cont_flags.size() != 0; } auto has_continuation_flag(char16_t flag) const { return all_cont_flags.contains(flag); } auto iterate_suffixes_of(const Key_Type& word) const { return table.iterate_prefixes_of(word); } auto iterate_suffixes_of(Key_Type&& word) const = delete; }; /** * @internal * @brief A pair of strings concatenated into one string. */ class String_Pair { using Str = std::string; using Str_View = std::string_view; size_t i = 0; Str s; public: String_Pair() = default; template explicit String_Pair(Str1&& str, size_t i) : i(i), s(std::forward(str)) { if (i > s.size()) throw std::out_of_range("word split is too long"); } template , Str>::value && std::is_same, Str>::value>> String_Pair(Str1&& first, Str2&& second) : i(first.size()) /* must be init before s, before we move from first */ , s(std::forward(first) + std::forward(second)) { } auto first() const { return Str_View(s).substr(0, i); } auto second() const { return Str_View(s).substr(i); } auto first(Str_View x) { s.replace(0, i, x); i = x.size(); } auto second(Str_View x) { s.replace(i, s.npos, x); } auto& str() const { return s; } auto idx() const { return i; } }; struct Compound_Pattern { String_Pair begin_end_chars; std::string replacement; char16_t first_word_flag = 0; char16_t second_word_flag = 0; bool match_first_only_unaffixed_or_zero_affixed = false; }; class Compound_Rule_Table { std::vector rules; Flag_Set all_flags; auto fill_all_flags() -> void; public: Compound_Rule_Table() = default; explicit Compound_Rule_Table(const std::vector& tbl) : rules(tbl) { fill_all_flags(); } explicit Compound_Rule_Table(std::vector&& tbl) : rules(std::move(tbl)) { fill_all_flags(); } auto& operator=(const std::vector& tbl) { rules = tbl; fill_all_flags(); return *this; } auto& operator=(std::vector&& tbl) { rules = std::move(tbl); fill_all_flags(); return *this; } auto empty() const { return rules.empty(); } auto has_any_of_flags(const Flag_Set& f) const -> bool; auto match_any_rule(const std::vector& data) const -> bool; }; auto inline Compound_Rule_Table::fill_all_flags() -> void { for (auto& f : rules) { all_flags += f; } all_flags.erase(u'?'); all_flags.erase(u'*'); } auto inline Compound_Rule_Table::has_any_of_flags(const Flag_Set& f) const -> bool { using std::begin; using std::end; struct Out_Iter_One_Bool { bool* value = nullptr; auto& operator++() { return *this; } auto& operator++(int) { return *this; } auto& operator*() { return *this; } auto& operator=(char16_t) { *value = true; return *this; } }; auto has_intersection = false; auto out_it = Out_Iter_One_Bool{&has_intersection}; std::set_intersection(begin(all_flags), end(all_flags), begin(f), end(f), out_it); return has_intersection; } template > auto match_simple_regex(DataIter data_first, DataIter data_last, PatternIter pat_first, PatternIter pat_last, FuncEq eq = FuncEq()) { auto s = std::stack>(); s.emplace(data_first, pat_first); auto data_it = DataIter(); auto pat_it = PatternIter(); while (!s.empty()) { std::tie(data_it, pat_it) = s.top(); s.pop(); if (pat_it == pat_last) { if (data_it == data_last) return true; else return false; } auto node_type = *pat_it; if (pat_it + 1 == pat_last) node_type = 0; else node_type = *(pat_it + 1); switch (node_type) { case '?': s.emplace(data_it, pat_it + 2); if (data_it != data_last && eq(*data_it, *pat_it)) s.emplace(data_it + 1, pat_it + 2); break; case '*': s.emplace(data_it, pat_it + 2); if (data_it != data_last && eq(*data_it, *pat_it)) s.emplace(data_it + 1, pat_it); break; default: if (data_it != data_last && eq(*data_it, *pat_it)) s.emplace(data_it + 1, pat_it + 1); break; } } return false; } template > auto match_simple_regex(const DataRange& data, const PatternRange& pattern, FuncEq eq = FuncEq()) { using namespace std; return match_simple_regex(begin(data), end(data), begin(pattern), end(pattern), eq); } auto inline match_compund_rule(const std::vector& words_data, const std::u16string& pattern) { return match_simple_regex( words_data, pattern, [](const Flag_Set* d, char16_t p) { return d->contains(p); }); } auto inline Compound_Rule_Table::match_any_rule( const std::vector& data) const -> bool { return any_of(begin(rules), end(rules), [&](const std::u16string& p) { return match_compund_rule(data, p); }); } using List_Strings = std::vector; class Replacement_Table { public: using Str = std::string; using Table_Str = std::vector>; using iterator = typename Table_Str::iterator; using const_iterator = typename Table_Str::const_iterator; private: Table_Str table; size_t whole_word_reps_last_idx = 0; size_t start_word_reps_last_idx = 0; size_t end_word_reps_last_idx = 0; auto order_entries() -> void; public: Replacement_Table() = default; explicit Replacement_Table(const Table_Str& v) : table(v) { order_entries(); } explicit Replacement_Table(Table_Str&& v) : table(std::move(v)) { order_entries(); } auto& operator=(const Table_Str& v) { table = v; order_entries(); return *this; } auto& operator=(Table_Str&& v) { table = std::move(v); order_entries(); return *this; } auto whole_word_replacements() const -> Subrange { return {begin(table), begin(table) + whole_word_reps_last_idx}; } auto start_word_replacements() const -> Subrange { return {begin(table) + whole_word_reps_last_idx, begin(table) + start_word_reps_last_idx}; } auto end_word_replacements() const -> Subrange { return {begin(table) + start_word_reps_last_idx, begin(table) + end_word_reps_last_idx}; } auto any_place_replacements() const -> Subrange { return {begin(table) + end_word_reps_last_idx, end(table)}; } }; auto inline Replacement_Table::order_entries() -> void { auto it = remove_if(begin(table), end(table), [](auto& p) { auto& s = p.first; return s.empty() || (s.size() == 1 && (s[0] == '^' || s[0] == '$')); }); table.erase(it, end(table)); auto is_start_word_pat = [=](auto& x) { return x.first[0] == '^'; }; auto is_end_word_pat = [=](auto& x) { return x.first.back() == '$'; }; auto start_word_reps_last = partition(begin(table), end(table), is_start_word_pat); start_word_reps_last_idx = start_word_reps_last - begin(table); for_each(begin(table), start_word_reps_last, [](auto& e) { e.first.erase(0, 1); }); auto whole_word_reps_last = partition(begin(table), start_word_reps_last, is_end_word_pat); whole_word_reps_last_idx = whole_word_reps_last - begin(table); for_each(begin(table), whole_word_reps_last, [](auto& e) { e.first.pop_back(); }); auto end_word_reps_last = partition(start_word_reps_last, end(table), is_end_word_pat); end_word_reps_last_idx = end_word_reps_last - begin(table); for_each(start_word_reps_last, end_word_reps_last, [](auto& e) { e.first.pop_back(); }); } struct Similarity_Group { using Str = std::string; Str chars; std::vector strings; auto parse(const Str& s) -> void; Similarity_Group() = default; explicit Similarity_Group(const Str& s) { parse(s); } auto& operator=(const Str& s) { parse(s); return *this; } }; auto inline Similarity_Group::parse(const Str& s) -> void { auto i = size_t(0); for (;;) { auto j = s.find('(', i); chars.append(s, i, j - i); if (j == s.npos) break; i = j + 1; j = s.find(')', i); if (j == s.npos) break; auto len = j - i; if (len == 1) chars += s[i]; else if (len > 1) strings.push_back(s.substr(i, len)); i = j + 1; } } class Phonetic_Table { using Char_Type = char; // not aware of unicode using Str = std::string; using Pair_Str = std::pair; struct Phonet_Match_Result { size_t count_matched = 0; size_t go_back_before_replace = 0; size_t priority = 5; bool go_back_after_replace = false; bool treat_next_as_begin = false; operator bool() { return count_matched; } }; std::vector> table; auto order() -> void; auto static match(const Str& data, size_t i, const Str& pattern, bool at_begin) -> Phonet_Match_Result; public: Phonetic_Table() = default; explicit Phonetic_Table(const std::vector& v) : table(v) { order(); } explicit Phonetic_Table(std::vector&& v) : table(std::move(v)) { order(); } auto& operator=(const std::vector& v) { table = v; order(); return *this; } auto& operator=(std::vector&& v) { table = std::move(v); order(); return *this; } auto replace(Str& word) const -> bool; }; auto inline Phonetic_Table::order() -> void { stable_sort(begin(table), end(table), [](auto& pair1, auto& pair2) { if (pair2.first.empty()) return false; if (pair1.first.empty()) return true; return pair1.first[0] < pair2.first[0]; }); auto it = find_if_not(begin(table), end(table), [](auto& p) { return p.first.empty(); }); table.erase(begin(table), it); for (auto& r : table) { if (r.second == "_") r.second.clear(); } } auto inline Phonetic_Table::match(const Str& data, size_t i, const Str& pattern, bool at_begin) -> Phonet_Match_Result { auto ret = Phonet_Match_Result(); auto j = pattern.find_first_of("(<-0123456789^$"); if (j == pattern.npos) j = pattern.size(); if (data.compare(i, j, pattern, 0, j) == 0) ret.count_matched = j; else return {}; if (j == pattern.size()) return ret; if (pattern[j] == '(') { auto k = pattern.find(')', j); if (k == pattern.npos) return {}; // bad rule auto x = std::char_traits::find( &pattern[j + 1], k - (j + 1), data[i + j]); if (!x) return {}; j = k + 1; ret.count_matched += 1; } if (j == pattern.size()) return ret; if (pattern[j] == '<') { ret.go_back_after_replace = true; ++j; } auto k = pattern.find_first_not_of('-', j); if (k == pattern.npos) { k = pattern.size(); ret.go_back_before_replace = k - j; if (ret.go_back_before_replace >= ret.count_matched) return {}; // bad rule return ret; } else { ret.go_back_before_replace = k - j; if (ret.go_back_before_replace >= ret.count_matched) return {}; // bad rule } j = k; if (pattern[j] >= '0' && pattern[j] <= '9') { ret.priority = pattern[j] - '0'; ++j; } if (j == pattern.size()) return ret; if (pattern[j] == '^') { if (!at_begin) return {}; ++j; } if (j == pattern.size()) return ret; if (pattern[j] == '^') { ret.treat_next_as_begin = true; ++j; } if (j == pattern.size()) return ret; if (pattern[j] != '$') return {}; // bad rule, no other char is allowed at this point if (i + ret.count_matched == data.size()) return ret; return {}; } auto inline Phonetic_Table::replace(Str& word) const -> bool { struct Cmp { auto operator()(Char_Type c, const Pair_Str& s) { return c < s.first[0]; } auto operator()(const Pair_Str& s, Char_Type c) { return s.first[0] < c; } }; if (table.empty()) return false; auto ret = false; auto treat_next_as_begin = true; size_t count_go_backs_after_replace = 0; // avoid infinite loop for (size_t i = 0; i != word.size(); ++i) { auto rules = equal_range(begin(table), end(table), word[i], Cmp()); for (auto& r : Subrange(rules)) { auto rule = &r; auto m1 = match(word, i, r.first, treat_next_as_begin); if (!m1) continue; if (!m1.go_back_before_replace) { auto j = i + m1.count_matched - 1; auto rules2 = equal_range( begin(table), end(table), word[j], Cmp()); for (auto& r2 : Subrange(rules2)) { auto m2 = match(word, j, r2.first, false); if (m2 && m2.priority >= m1.priority) { i = j; rule = &r2; m1 = m2; break; } } } word.replace( i, m1.count_matched - m1.go_back_before_replace, rule->second); treat_next_as_begin = m1.treat_next_as_begin; if (m1.go_back_after_replace && count_go_backs_after_replace < 100) { count_go_backs_after_replace++; } else { i += rule->second.size(); } --i; ret = true; break; } } return ret; } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell #endif // NUSPELL_STRUCTURES_HXX nuspell-5.1.7/src/nuspell/suggester.cxx000066400000000000000000001003051511132717100202110ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include "suggester.hxx" #include "utils.hxx" #include using namespace std; namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE auto static insert_sug_first(const string& word, List_Strings& out) { out.insert(begin(out), word); } auto& operator|=(Suggester::High_Quality_Sugs& lhs, Suggester::High_Quality_Sugs rhs) { lhs = Suggester::High_Quality_Sugs(lhs || rhs); return lhs; } auto Suggester::suggest_priv(string_view input_word, List_Strings& out) const -> void { if (empty(input_word)) return; auto word = string(input_word); input_substr_replacer.replace(word); auto abbreviation = word.back() == '.'; if (abbreviation) { // trim trailing periods auto i = word.find_last_not_of('.'); // if i == npos, i + 1 == 0, so no need for extra if. word.erase(i + 1); if (word.empty()) return; } auto buffer = string(); auto casing = classify_casing(word); auto hq_sugs = High_Quality_Sugs(); switch (casing) { case Casing::SMALL: if (compound_force_uppercase && check_compound(word, ALLOW_BAD_FORCEUCASE)) { to_title(word, icu_locale, buffer); out.push_back(buffer); return; } hq_sugs |= suggest_low(word, out); break; case Casing::INIT_CAPITAL: hq_sugs |= suggest_low(word, out); to_lower(word, icu_locale, buffer); hq_sugs |= suggest_low(buffer, out); break; case Casing::CAMEL: case Casing::PASCAL: { hq_sugs |= suggest_low(word, out); auto dot_idx = word.find('.'); if (dot_idx != word.npos) { auto after_dot = string_view(word).substr(dot_idx + 1); auto casing_after_dot = classify_casing(after_dot); if (casing_after_dot == Casing::INIT_CAPITAL) { word.insert(dot_idx + 1, 1, ' '); insert_sug_first(word, out); word.erase(dot_idx + 1, 1); } } if (casing == Casing::PASCAL) { buffer = word; to_lower_char_at(buffer, 0, icu_locale); if (spell_priv(buffer)) insert_sug_first(buffer, out); hq_sugs |= suggest_low(buffer, out); } to_lower(word, icu_locale, buffer); if (spell_priv(buffer)) insert_sug_first(buffer, out); hq_sugs |= suggest_low(buffer, out); if (casing == Casing::PASCAL) { to_title(word, icu_locale, buffer); if (spell_priv(buffer)) insert_sug_first(buffer, out); hq_sugs |= suggest_low(buffer, out); } for (auto it = begin(out); it != end(out); ++it) { auto& sug = *it; auto space_idx = sug.find(' '); if (space_idx == sug.npos) continue; auto i = space_idx + 1; auto len = sug.size() - i; if (len > word.size()) continue; if (sug.compare(i, len, word, word.size() - len) == 0) continue; to_title_char_at(sug, i, icu_locale); rotate(begin(out), it, it + 1); } break; } case Casing::ALL_CAPITAL: to_lower(word, icu_locale, buffer); if (keepcase_flag != 0 && spell_priv(buffer)) insert_sug_first(buffer, out); hq_sugs |= suggest_low(buffer, out); to_title(word, icu_locale, buffer); hq_sugs |= suggest_low(buffer, out); for (auto& sug : out) to_upper(sug, icu_locale, sug); break; } if (!hq_sugs && max_ngram_suggestions != 0) { if (casing == Casing::SMALL) buffer = word; else to_lower(word, icu_locale, buffer); auto old_size = out.size(); ngram_suggest(buffer, out); if (casing == Casing::ALL_CAPITAL) { for (auto i = old_size; i != out.size(); ++i) to_upper(out[i], icu_locale, out[i]); } } auto has_dash = word.find('-') != word.npos; auto has_dash_sug = has_dash && any_of(begin(out), end(out), [](const string& s) { return s.find('-') != s.npos; }); if (has_dash && !has_dash_sug) { auto sugs_tmp = List_Strings(); auto i = size_t(); for (;;) { auto j = word.find('-', i); buffer.assign(word, i, j - i); if (!spell_priv(buffer)) { suggest_priv(buffer, sugs_tmp); for (auto& t : sugs_tmp) { buffer = word; buffer.replace(i, j - i, t); auto flg = check_word(buffer); if (!flg || !flg->contains(forbiddenword_flag)) out.push_back(buffer); } } if (j == word.npos) break; i = j + 1; } } if (casing == Casing::INIT_CAPITAL || casing == Casing::PASCAL) { for (auto& sug : out) to_title_char_at(sug, 0, icu_locale); } // Suggest with dots can go here but nobody uses it so no point in // implementing it. if ((casing == Casing::INIT_CAPITAL || casing == Casing::ALL_CAPITAL) && (keepcase_flag != 0 || forbiddenword_flag != 0)) { auto is_ok = [&](string& s) { if (s.find(' ') != s.npos) return true; if (spell_priv(s)) return true; to_lower(s, icu_locale, s); if (spell_priv(s)) return true; to_title(s, icu_locale, s); return spell_priv(s); }; auto it = begin(out); auto last = end(out); // Below is remove_if(it, last, is_not_ok); // We don't use remove_if because is_ok modifies // the argument. for (; it != last; ++it) if (!is_ok(*it)) break; if (it != last) { for (auto it2 = it + 1; it2 != last; ++it2) if (is_ok(*it2)) *it++ = std::move(*it2); out.erase(it, last); } } { auto it = begin(out); auto last = end(out); for (; it != last; ++it) last = remove(it + 1, last, *it); out.erase(last, end(out)); } for (auto& sug : out) output_substr_replacer.replace(sug); } auto Suggester::suggest_low(std::string& word, List_Strings& out) const -> High_Quality_Sugs { auto old_size = out.size(); uppercase_suggest(word, out); rep_suggest(word, out); map_suggest(word, out); auto high_quality_sugs = old_size != out.size() || // If the word is already correct, set high_quality_sugs as true, // which then disables the expensive ngram sugs and makes the // benchmarks happy. In Hunspell, its map_suggest() adds the word as // suggestion if it's already correct and achieves the same. (!empty(similarities) && check_word(word, FORBID_BAD_FORCEUCASE, SKIP_HIDDEN_HOMONYM)); adjacent_swap_suggest(word, out); distant_swap_suggest(word, out); keyboard_suggest(word, out); extra_char_suggest(word, out); forgotten_char_suggest(word, out); move_char_suggest(word, out); bad_char_suggest(word, out); doubled_two_chars_suggest(word, out); two_words_suggest(word, out); return High_Quality_Sugs(high_quality_sugs); } auto Suggester::add_sug_if_correct(std::string& word, List_Strings& out) const -> bool { auto res = check_word(word, FORBID_BAD_FORCEUCASE, SKIP_HIDDEN_HOMONYM); if (!res) return false; if (res->contains(forbiddenword_flag)) return false; if (forbid_warn && res->contains(warn_flag)) return false; out.push_back(word); return true; } auto Suggester::uppercase_suggest(const std::string& word, List_Strings& out) const -> void { auto upp = to_upper(word, icu_locale); add_sug_if_correct(upp, out); } auto Suggester::rep_suggest(std::string& word, List_Strings& out) const -> void { auto& reps = replacements; for (auto& r : reps.whole_word_replacements()) { auto& from = r.first; auto& to = r.second; if (word == from) { word = to; try_rep_suggestion(word, out); word = from; } } for (auto& r : reps.start_word_replacements()) { auto& from = r.first; auto& to = r.second; if (begins_with(word, from)) { word.replace(0, from.size(), to); try_rep_suggestion(word, out); word.replace(0, to.size(), from); } } for (auto& r : reps.end_word_replacements()) { auto& from = r.first; auto& to = r.second; if (ends_with(word, from)) { auto pos = word.size() - from.size(); word.replace(pos, word.npos, to); try_rep_suggestion(word, out); word.replace(pos, word.npos, from); } } for (auto& r : reps.any_place_replacements()) { auto& from = r.first; auto& to = r.second; for (auto i = word.find(from); i != word.npos; i = word.find(from, i + 1)) { word.replace(i, from.size(), to); try_rep_suggestion(word, out); word.replace(i, to.size(), from); } } } auto Suggester::try_rep_suggestion(std::string& word, List_Strings& out) const -> void { if (add_sug_if_correct(word, out)) return; auto i = size_t(0); auto j = word.find(' '); if (j == word.npos) return; auto part = string(); for (; j != word.npos; i = j + 1, j = word.find(' ', i)) { part.assign(word, i, j - i); if (!check_word(part, FORBID_BAD_FORCEUCASE, SKIP_HIDDEN_HOMONYM)) return; } out.push_back(word); } auto Checker::is_rep_similar(std::string& word) const -> bool { auto& reps = replacements; for (auto& r : reps.whole_word_replacements()) { auto& from = r.first; auto& to = r.second; if (word == from) { word = to; auto ret = check_simple_word(word, SKIP_HIDDEN_HOMONYM); word = from; if (ret) return true; } } for (auto& r : reps.start_word_replacements()) { auto& from = r.first; auto& to = r.second; if (begins_with(word, from)) { word.replace(0, from.size(), to); auto ret = check_simple_word(word, SKIP_HIDDEN_HOMONYM); word.replace(0, to.size(), from); if (ret) return true; } } for (auto& r : reps.end_word_replacements()) { auto& from = r.first; auto& to = r.second; if (ends_with(word, from)) { auto pos = word.size() - from.size(); word.replace(pos, word.npos, to); auto ret = check_simple_word(word, SKIP_HIDDEN_HOMONYM); word.replace(pos, word.npos, from); if (ret) return true; } } for (auto& r : reps.any_place_replacements()) { auto& from = r.first; auto& to = r.second; for (auto i = word.find(from); i != word.npos; i = word.find(from, i + 1)) { word.replace(i, from.size(), to); auto ret = check_simple_word(word, SKIP_HIDDEN_HOMONYM); word.replace(i, to.size(), from); if (ret) return true; } } return false; } auto Suggester::max_attempts_for_long_alogs(string_view word) const -> size_t { unsigned long long p = size(prefixes) / 20; unsigned long long s = size(suffixes) / 20; auto cost = 1 + p + s + p * s; if (!complex_prefixes) cost += s * s + 2 * p * s * s; else cost += p * p + 2 * s * p * p; cost = clamp(cost, 250'000ull, 25'000'000'000ull); auto ret = 25'000'000'000 / cost; if (compound_flag || compound_begin_flag || compound_last_flag || compound_middle_flag) ret /= size(word); return ret; } auto Suggester::map_suggest(std::string& word, List_Strings& out) const -> void { auto remaining_attempts = max_attempts_for_long_alogs(word); map_suggest(word, out, 0, remaining_attempts); } auto Suggester::map_suggest(std::string& word, List_Strings& out, size_t i, size_t& remaining_attempts) const -> void { for (size_t next_i = i; i != size(word); i = next_i) { valid_u8_advance_index(word, next_i); auto word_cp = U8_Encoded_CP(word, {i, next_i}); for (auto& e : similarities) { auto j = e.chars.find(word_cp); if (j == word.npos) goto try_find_strings; for (size_t k = 0, next_k = 0; k != size(e.chars); k = next_k) { valid_u8_advance_index(e.chars, next_k); if (k == j) continue; if (remaining_attempts == 0) return; --remaining_attempts; auto rep_cp = string_view(&e.chars[k], next_k - k); word.replace(i, size(word_cp), rep_cp); add_sug_if_correct(word, out); map_suggest(word, out, i + size(rep_cp), remaining_attempts); word.replace(i, size(rep_cp), word_cp); } for (auto& r : e.strings) { if (remaining_attempts == 0) return; --remaining_attempts; word.replace(i, size(word_cp), r); add_sug_if_correct(word, out); map_suggest(word, out, i + size(r), remaining_attempts); word.replace(i, size(r), word_cp); } try_find_strings: for (auto& f : e.strings) { if (word.compare(i, size(f), f) != 0) continue; for (size_t k = 0, next_k = 0; k != size(e.chars); k = next_k) { if (remaining_attempts == 0) return; --remaining_attempts; valid_u8_advance_index(e.chars, next_k); auto rep_cp = string_view(&e.chars[k], next_k - k); word.replace(i, size(f), rep_cp); add_sug_if_correct(word, out); map_suggest(word, out, i + size(rep_cp), remaining_attempts); word.replace(i, size(rep_cp), f); } for (auto& r : e.strings) { if (f == r) continue; if (remaining_attempts == 0) return; --remaining_attempts; word.replace(i, size(f), r); add_sug_if_correct(word, out); map_suggest(word, out, i + size(r), remaining_attempts); word.replace(i, size(r), f); } } } } } auto Suggester::adjacent_swap_suggest(std::string& word, List_Strings& out) const -> void { if (word.empty()) return; auto i1 = size_t(0); auto i2 = valid_u8_next_index(word, i1); for (size_t i3 = i2; i3 != size(word); i1 = i2, i2 = i3) { valid_u8_advance_index(word, i3); i2 = u8_swap_adjacent_cp(word, i1, i2, i3); add_sug_if_correct(word, out); i2 = u8_swap_adjacent_cp(word, i1, i2, i3); } i1 = 0; i2 = valid_u8_next_index(word, i1); if (i2 == size(word)) return; auto i3 = valid_u8_next_index(word, i2); if (i3 == size(word)) return; auto i4 = valid_u8_next_index(word, i3); if (i4 == size(word)) return; auto i5 = valid_u8_next_index(word, i4); if (i5 == size(word)) { // word has 4 CPs i2 = u8_swap_adjacent_cp(word, i1, i2, i3); i4 = u8_swap_adjacent_cp(word, i3, i4, i5); add_sug_if_correct(word, out); i2 = u8_swap_adjacent_cp(word, i1, i2, i3); i4 = u8_swap_adjacent_cp(word, i3, i4, i5); return; } auto i6 = valid_u8_next_index(word, i5); if (i6 == size(word)) { // word has 5 CPs i2 = u8_swap_adjacent_cp(word, i1, i2, i3); i5 = u8_swap_adjacent_cp(word, i4, i5, i6); add_sug_if_correct(word, out); i2 = u8_swap_adjacent_cp(word, i1, i2, i3); // revert first two i3 = u8_swap_adjacent_cp(word, i2, i3, i4); add_sug_if_correct(word, out); i3 = u8_swap_adjacent_cp(word, i2, i3, i4); i5 = u8_swap_adjacent_cp(word, i4, i5, i6); } } auto Suggester::distant_swap_suggest(std::string& word, List_Strings& out) const -> void { if (empty(word)) return; auto remaining_attempts = max_attempts_for_long_alogs(word); auto i1 = size_t(0); auto i2 = valid_u8_next_index(word, i1); for (auto i3 = i2; i3 != size(word); i1 = i2, i2 = i3) { valid_u8_advance_index(word, i3); for (size_t j = i3, j2 = i3; j != size(word); j = j2) { valid_u8_advance_index(word, j2); if (remaining_attempts == 0) return; --remaining_attempts; auto [new_i2, new_j] = u8_swap_cp(word, {i1, i2}, {j, j2}); add_sug_if_correct(word, out); u8_swap_cp(word, {i1, new_i2}, {new_j, j2}); } } } auto Suggester::keyboard_suggest(std::string& word, List_Strings& out) const -> void { auto& kb = keyboard_closeness; for (size_t j = 0, next_j = 0; j != size(word); j = next_j) { char32_t c; valid_u8_advance_cp(word, next_j, c); auto enc_cp = U8_Encoded_CP(word, {j, next_j}); auto upp_c = char32_t(u_toupper(c)); if (upp_c != c) { auto enc_upp_c = U8_Encoded_CP(upp_c); word.replace(j, size(enc_cp), enc_upp_c); add_sug_if_correct(word, out); word.replace(j, size(enc_upp_c), enc_cp); } for (auto i = kb.find(enc_cp); i != kb.npos; i = kb.find(enc_cp, i + size(enc_cp))) { if (i != 0 && kb[i - 1] != '|') { auto prev_i = valid_u8_prev_index(kb, i); auto kb_c = U8_Encoded_CP(kb, {prev_i, i}); word.replace(j, size(enc_cp), kb_c); add_sug_if_correct(word, out); word.replace(j, size(kb_c), enc_cp); } auto next_i = i + size(enc_cp); if (next_i != size(kb) && kb[next_i] != '|') { auto next2_i = valid_u8_next_index(kb, next_i); auto kb_c = U8_Encoded_CP(kb, {next_i, next2_i}); word.replace(j, size(enc_cp), kb_c); add_sug_if_correct(word, out); word.replace(j, size(kb_c), enc_cp); } } } } auto Suggester::extra_char_suggest(std::string& word, List_Strings& out) const -> void { for (size_t i = 0, next_i = 0; i != size(word); i = next_i) { valid_u8_advance_index(word, next_i); auto cp = U8_Encoded_CP(word, {i, next_i}); word.erase(i, size(cp)); add_sug_if_correct(word, out); word.insert(i, cp); } } auto Suggester::forgotten_char_suggest(std::string& word, List_Strings& out) const -> void { auto remaining_attempts = max_attempts_for_long_alogs(word); for (size_t t = 0, next_t = 0; t != size(try_chars); t = next_t) { valid_u8_advance_index(try_chars, next_t); auto cp = string_view(&try_chars[t], next_t - t); for (size_t i = 0;; valid_u8_advance_index(word, i)) { if (remaining_attempts == 0) return; --remaining_attempts; word.insert(i, cp); add_sug_if_correct(word, out); word.erase(i, size(cp)); if (i == size(word)) break; } } } auto Suggester::move_char_suggest(std::string& word, List_Strings& out) const -> void { if (empty(word)) return; auto remaining_attempts = max_attempts_for_long_alogs(word); auto i1 = size_t(0); auto i2 = valid_u8_next_index(word, i1); for (auto i3 = i2; i3 != size(word); i1 = i2, i2 = i3) { valid_u8_advance_index(word, i3); auto new_i2 = u8_swap_adjacent_cp(word, i1, i2, i3); for (auto j1 = new_i2, j2 = i3, j3 = i3; j3 != size(word); j1 = j2, j2 = j3) { valid_u8_advance_index(word, j3); if (remaining_attempts == 0) { // revert word to initial value rotate(begin(word) + i1, begin(word) + j1, begin(word) + j2); return; } --remaining_attempts; j2 = u8_swap_adjacent_cp(word, j1, j2, j3); add_sug_if_correct(word, out); } // revert word to initial value rotate(begin(word) + i1, end(word) - (i2 - i1), end(word)); } auto i3 = size(word); i2 = valid_u8_prev_index(word, i3); for (i1 = i2; i1 != 0; i3 = i2, i2 = i1) { valid_u8_reverse_index(word, i1); auto new_i2 = u8_swap_adjacent_cp(word, i1, i2, i3); for (auto j3 = new_i2, j2 = i1, j1 = i1; j1 != 0; j3 = j2, j2 = j1) { valid_u8_reverse_index(word, j1); if (remaining_attempts == 0) { // revert word rotate(begin(word) + j2, begin(word) + j3, begin(word) + i3); return; } --remaining_attempts; j2 = u8_swap_adjacent_cp(word, j1, j2, j3); add_sug_if_correct(word, out); } // revert word rotate(begin(word), begin(word) + (i3 - i2), begin(word) + i3); } } auto Suggester::bad_char_suggest(std::string& word, List_Strings& out) const -> void { auto remaining_attempts = max_attempts_for_long_alogs(word); for (size_t t = 0, next_t = 0; t != size(try_chars); t = next_t) { char32_t t_cp; valid_u8_advance_cp(try_chars, next_t, t_cp); auto t_enc_cp = string_view(&try_chars[t], next_t - t); for (size_t i = 0, next_i = 0; i != size(word); i = next_i) { char32_t w_cp; valid_u8_advance_cp(word, next_i, w_cp); auto w_enc_cp = U8_Encoded_CP(word, {i, next_i}); if (t_cp == w_cp) continue; if (remaining_attempts == 0) return; --remaining_attempts; word.replace(i, size(w_enc_cp), t_enc_cp); add_sug_if_correct(word, out); word.replace(i, size(t_enc_cp), w_enc_cp); } } } auto Suggester::doubled_two_chars_suggest(std::string& word, List_Strings& out) const -> void { char32_t cp[5]; size_t i[5]; size_t j = 0; size_t num_cp = 0; for (; j != size(word) && num_cp != 4; ++num_cp) { i[num_cp] = j; valid_u8_advance_cp(word, j, cp[num_cp]); } if (num_cp != 4) // Not really needed. Makes static analysis happy. return; while (j != size(word)) { i[4] = j; valid_u8_advance_cp(word, j, cp[4]); if (cp[0] == cp[2] && cp[1] == cp[3] && cp[0] == cp[4]) { word.erase(i[3], j - i[3]); add_sug_if_correct(word, out); word.insert(i[3], word, i[1], i[3] - i[1]); } copy(begin(i) + 1, end(i), begin(i)); copy(begin(cp) + 1, end(cp), begin(cp)); } } auto Suggester::two_words_suggest(const std::string& word, List_Strings& out) const -> void { if (empty(word)) return; auto w1_num_cp = size_t(0); auto word1 = string(); auto word2 = string(); for (size_t i = 0, next_i = 0;; i = next_i, ++w1_num_cp) { valid_u8_advance_index(word, next_i); if (next_i == size(word)) break; word1.append(word, i, next_i - i); // TODO: maybe switch to check_word() auto w1 = check_simple_word(word1, SKIP_HIDDEN_HOMONYM); if (!w1) continue; word2.assign(word, next_i); auto w2 = check_simple_word(word2, SKIP_HIDDEN_HOMONYM); if (!w2) continue; word1 += ' '; word1 += word2; if (find(begin(out), end(out), word1) == end(out)) out.push_back(word1); auto w2_more_than_1_cp = valid_u8_next_index(word2, 0) != size(word2); if (w1_num_cp > 1 && w2_more_than_1_cp && !empty(try_chars) && (try_chars.find('a') != try_chars.npos || try_chars.find('-') != try_chars.npos)) { word1[next_i] = '-'; if (find(begin(out), end(out), word1) == end(out)) out.push_back(word1); } word1.erase(next_i); } } namespace { auto ngram_similarity_low_level(size_t n, u32string_view a, u32string_view b) -> ptrdiff_t { auto score = ptrdiff_t(0); n = min(n, a.size()); for (size_t k = 1; k != n + 1; ++k) { auto k_score = ptrdiff_t(0); for (size_t i = 0; i != a.size() - k + 1; ++i) { auto kgram = a.substr(i, k); auto find = b.find(kgram); if (find != b.npos) ++k_score; } score += k_score; if (k_score < 2) break; } return score; } auto ngram_similarity_weighted_low_level(size_t n, u32string_view a, u32string_view b) -> ptrdiff_t { auto score = ptrdiff_t(0); n = min(n, a.size()); for (size_t k = 1; k != n + 1; ++k) { auto k_score = ptrdiff_t(0); for (size_t i = 0; i != a.size() - k + 1; ++i) { auto kgram = a.substr(i, k); auto find = b.find(kgram); if (find != b.npos) { ++k_score; } else { --k_score; if (i == 0 || i == a.size() - k) --k_score; } } score += k_score; } return score; } auto ngram_similarity_longer_worse(size_t n, u32string_view a, u32string_view b) -> ptrdiff_t { if (b.empty()) return 0; auto score = ngram_similarity_low_level(n, a, b); auto d = ptrdiff_t(b.size() - a.size()) - 2; if (d > 0) score -= d; return score; } auto ngram_similarity_any_mismatch(size_t n, u32string_view a, u32string_view b) -> ptrdiff_t { if (b.empty()) return 0; auto score = ngram_similarity_low_level(n, a, b); auto d = abs(ptrdiff_t(b.size() - a.size())) - 2; if (d > 0) score -= d; return score; } auto ngram_similarity_any_mismatch_weighted(size_t n, u32string_view a, u32string_view b) -> ptrdiff_t { if (b.empty()) return 0; auto score = ngram_similarity_weighted_low_level(n, a, b); auto d = abs(ptrdiff_t(b.size() - a.size())) - 2; if (d > 0) score -= d; return score; } auto left_common_substring_length(u32string_view a, u32string_view b) -> ptrdiff_t { if (a.empty() || b.empty()) return 0; if (a[0] != b[0] && UChar32(a[0]) != u_tolower(b[0])) return 0; auto it = std::mismatch(begin(a) + 1, end(a), begin(b) + 1, end(b)); return it.first - begin(a); } auto longest_common_subsequence_length(u32string_view a, u32string_view b, vector& state_buffer) -> ptrdiff_t { state_buffer.assign(b.size(), 0); auto row1_prev = size_t(0); for (size_t i = 0; i != a.size(); ++i) { row1_prev = size_t(0); auto row2_prev = size_t(0); for (size_t j = 0; j != b.size(); ++j) { auto row1_current = state_buffer[j]; auto& row2_current = state_buffer[j]; if (a[i] == b[j]) row2_current = row1_prev + 1; else row2_current = max(row1_current, row2_prev); row1_prev = row1_current; row2_prev = row2_current; } row1_prev = row2_prev; } return ptrdiff_t(row1_prev); } struct Count_Eq_Chars_At_Same_Pos_Result { ptrdiff_t num; bool is_swap; }; auto count_eq_chars_at_same_pos(u32string_view a, u32string_view b) -> Count_Eq_Chars_At_Same_Pos_Result { auto n = min(a.size(), b.size()); auto count = size_t(); for (size_t i = 0; i != n; ++i) { if (a[i] == b[i]) ++count; } auto is_swap = false; if (a.size() == b.size() && n - count == 2) { auto miss1 = mismatch(begin(a), end(a), begin(b)); auto miss2 = mismatch(miss1.first + 1, end(a), miss1.second + 1); is_swap = *miss1.first == *miss2.second && *miss1.second == *miss2.first; } return {ptrdiff_t(count), is_swap}; } struct Word_Entry_And_Score { Word_List::const_pointer word_entry = {}; ptrdiff_t score = {}; [[maybe_unused]] auto operator<(const Word_Entry_And_Score& rhs) const { return score > rhs.score; // Greater than } }; struct Word_And_Score { u32string word = {}; ptrdiff_t score = {}; [[maybe_unused]] auto operator<(const Word_And_Score& rhs) const { return score > rhs.score; // Greater than } }; } // namespace auto Suggester::ngram_suggest(const std::string& word_u8, List_Strings& out) const -> void { auto const wrong_word = valid_utf8_to_32(word_u8); auto wide_buf = u32string(); auto roots = vector(); auto dict_word = u32string(); for (size_t bucket = 0; bucket != words.bucket_count(); ++bucket) { for (auto& word_entry : words.bucket_data(bucket)) { auto& [dict_word_u8, flags] = word_entry; if (flags.contains(forbiddenword_flag) || flags.contains(HIDDEN_HOMONYM_FLAG) || flags.contains(nosuggest_flag) || flags.contains(compound_onlyin_flag)) continue; valid_utf8_to_32(dict_word_u8, dict_word); auto score = left_common_substring_length(wrong_word, dict_word); auto& lower_dict_word = wide_buf; to_lower(dict_word, icu_locale, lower_dict_word); score += ngram_similarity_longer_worse(3, wrong_word, lower_dict_word); if (roots.size() != 100) { roots.push_back({&word_entry, score}); push_heap(begin(roots), end(roots)); } else if (score > roots.front().score) { pop_heap(begin(roots), end(roots)); roots.back() = {&word_entry, score}; push_heap(begin(roots), end(roots)); } } } auto threshold = ptrdiff_t(); for (auto k : {1u, 2u, 3u}) { auto& mangled_wrong_word = wide_buf; mangled_wrong_word = wrong_word; for (size_t i = k; i < mangled_wrong_word.size(); i += 4) mangled_wrong_word[i] = '*'; threshold += ngram_similarity_any_mismatch( wrong_word.size(), wrong_word, mangled_wrong_word); } threshold /= 3; auto expanded_list = List_Strings(); auto expanded_cross_afx = vector(); auto expanded_word = u32string(); auto guess_words = vector(); for (auto& root : roots) { expand_root_word_for_ngram(*root.word_entry, word_u8, expanded_list, expanded_cross_afx); for (auto& expanded_word_u8 : expanded_list) { valid_utf8_to_32(expanded_word_u8, expanded_word); auto score = left_common_substring_length( wrong_word, expanded_word); auto& lower_expanded_word = wide_buf; to_lower(expanded_word, icu_locale, lower_expanded_word); score += ngram_similarity_any_mismatch( wrong_word.size(), wrong_word, lower_expanded_word); if (score < threshold) continue; if (guess_words.size() != 200) { guess_words.push_back( {std::move(expanded_word), score}); push_heap(begin(guess_words), end(guess_words)); } else if (score > guess_words.front().score) { pop_heap(begin(guess_words), end(guess_words)); guess_words.back() = {std::move(expanded_word), score}; push_heap(begin(guess_words), end(guess_words)); } } } sort_heap(begin(guess_words), end(guess_words)); // is this needed? auto lcs_state = vector(); for (auto& [guess_word, score] : guess_words) { auto& lower_guess_word = wide_buf; to_lower(guess_word, icu_locale, lower_guess_word); auto lcs = longest_common_subsequence_length( wrong_word, lower_guess_word, lcs_state); if (wrong_word.size() == lower_guess_word.size() && wrong_word.size() == size_t(lcs)) { score += 2000; break; } auto ngram2 = ngram_similarity_any_mismatch_weighted( 2, wrong_word, lower_guess_word); ngram2 += ngram_similarity_any_mismatch_weighted( 2, lower_guess_word, wrong_word); auto ngram4 = ngram_similarity_any_mismatch(4, wrong_word, lower_guess_word); auto left_common = left_common_substring_length(wrong_word, lower_guess_word); auto num_eq_chars_same_pos = count_eq_chars_at_same_pos(wrong_word, lower_guess_word); score = 2 * lcs; score -= abs(ptrdiff_t(wrong_word.size() - lower_guess_word.size())); score += left_common + ngram2 + ngram4; if (num_eq_chars_same_pos.num != 0) score += 1; if (num_eq_chars_same_pos.is_swap) score += 10; if (5 * ngram2 < ptrdiff_t(wrong_word.size() + lower_guess_word.size()) * (10 - max_diff_factor)) score -= 1000; } sort(begin(guess_words), end(guess_words)); auto more_selective = !guess_words.empty() && guess_words.front().score > 1000; auto old_num_sugs = out.size(); auto max_sug = min(MAX_SUGGESTIONS, old_num_sugs + max_ngram_suggestions); for (auto& [guess_word, score] : guess_words) { if (out.size() == max_sug) break; if (more_selective && score <= 1000) break; if (score < -100 && (old_num_sugs != out.size() || only_max_diff)) break; auto guess_word_u8 = utf32_to_utf8(guess_word); if (any_of(begin(out), end(out), [&g = guess_word_u8](auto& sug) { return g.find(sug) != g.npos; })) { if (score < -100) break; else continue; } out.push_back(std::move(guess_word_u8)); } } auto Suggester::expand_root_word_for_ngram( Word_List::const_reference root_entry, std::string_view wrong, List_Strings& expanded_list, std::vector& cross_affix) const -> void { expanded_list.clear(); cross_affix.clear(); auto& [root, flags] = root_entry; if (!flags.contains(need_affix_flag)) { expanded_list.push_back(root); cross_affix.push_back(false); } if (flags.empty()) return; for (auto& suffix : suffixes) { if (!cross_valid_inner_outer(flags, suffix)) continue; if (outer_affix_NOT_valid(suffix)) continue; if (is_circumfix(suffix)) continue; // TODO Suffixes marked with needaffix or circumfix should not // be just skipped as we can later add prefix. This is not // handled in hunspell, too. if (!ends_with(root, suffix.stripping)) continue; if (!suffix.check_condition(root)) continue; if (!suffix.appending.empty() && !ends_with(wrong, suffix.appending)) continue; auto expanded = suffix.to_derived_copy(root); expanded_list.push_back(std::move(expanded)); cross_affix.push_back(suffix.cross_product); } for (size_t i = 0, n = expanded_list.size(); i != n; ++i) { if (!cross_affix[i]) continue; for (auto& prefix : prefixes) { auto& root_sfx = expanded_list[i]; if (!cross_valid_inner_outer(flags, prefix)) continue; if (outer_affix_NOT_valid(prefix)) continue; if (is_circumfix(prefix)) continue; if (!begins_with(root_sfx, prefix.stripping)) continue; if (!prefix.check_condition(root_sfx)) continue; if (!prefix.appending.empty() && !begins_with(wrong, prefix.appending)) continue; auto expanded = prefix.to_derived_copy(root_sfx); expanded_list.push_back(std::move(expanded)); } } for (auto& prefix : prefixes) { if (!cross_valid_inner_outer(flags, prefix)) continue; if (outer_affix_NOT_valid(prefix)) continue; if (is_circumfix(prefix)) continue; if (!begins_with(root, prefix.stripping)) continue; if (!prefix.check_condition(root)) continue; if (!prefix.appending.empty() && !begins_with(wrong, prefix.appending)) continue; auto expanded = prefix.to_derived_copy(root); expanded_list.push_back(std::move(expanded)); } } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell nuspell-5.1.7/src/nuspell/suggester.hxx000066400000000000000000000057551511132717100202330ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #ifndef NUSPELL_SUGGESTER_HXX #define NUSPELL_SUGGESTER_HXX #include "checker.hxx" namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE struct NUSPELL_EXPORT Suggester : public Checker { enum High_Quality_Sugs : bool { ALL_LOW_QUALITY_SUGS = false, HAS_HIGH_QUALITY_SUGS = true }; auto suggest_priv(std::string_view input_word, List_Strings& out) const -> void; auto suggest_low(std::string& word, List_Strings& out) const -> High_Quality_Sugs; auto add_sug_if_correct(std::string& word, List_Strings& out) const -> bool; auto uppercase_suggest(const std::string& word, List_Strings& out) const -> void; auto rep_suggest(std::string& word, List_Strings& out) const -> void; auto try_rep_suggestion(std::string& word, List_Strings& out) const -> void; auto max_attempts_for_long_alogs(std::string_view word) const -> size_t; auto map_suggest(std::string& word, List_Strings& out) const -> void; auto map_suggest(std::string& word, List_Strings& out, size_t i, size_t& remaining_attempts) const -> void; auto adjacent_swap_suggest(std::string& word, List_Strings& out) const -> void; auto distant_swap_suggest(std::string& word, List_Strings& out) const -> void; auto keyboard_suggest(std::string& word, List_Strings& out) const -> void; auto extra_char_suggest(std::string& word, List_Strings& out) const -> void; auto forgotten_char_suggest(std::string& word, List_Strings& out) const -> void; auto move_char_suggest(std::string& word, List_Strings& out) const -> void; auto bad_char_suggest(std::string& word, List_Strings& out) const -> void; auto doubled_two_chars_suggest(std::string& word, List_Strings& out) const -> void; auto two_words_suggest(const std::string& word, List_Strings& out) const -> void; auto ngram_suggest(const std::string& word_u8, List_Strings& out) const -> void; auto expand_root_word_for_ngram(Word_List::const_reference root, std::string_view wrong, List_Strings& expanded_list, std::vector& cross_affix) const -> void; }; NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell #endif // NUSPELL_SUGGESTER_HXX nuspell-5.1.7/src/nuspell/unicode.hxx000066400000000000000000000204111511132717100176330ustar00rootroot00000000000000/* Copyright 2021-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #ifndef NUSPELL_UNICODE_HXX #define NUSPELL_UNICODE_HXX #include "defines.hxx" #include #include #include #include namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE // UTF-8, work on malformed inline constexpr auto u8_max_cp_length = U8_MAX_LENGTH; auto inline u8_is_cp_error(int32_t cp) -> bool { return cp < 0; } template auto u8_advance_cp(const Range& str, size_t& i, int32_t& cp) -> void { using std::size, std::data; #if U_ICU_VERSION_MAJOR_NUM <= 60 auto s_ptr = data(str); int32_t idx = i; int32_t len = size(str); U8_NEXT(s_ptr, idx, len, cp); i = idx; #else auto len = size(str); U8_NEXT(str, i, len, cp); #endif } template auto u8_advance_index(const Range& str, size_t& i) -> void { using std::size; auto len = size(str); U8_FWD_1(str, i, len); } template auto u8_reverse_cp(const Range& str, size_t& i, int32_t& cp) -> void { using std::size, std::data; auto ptr = data(str); int32_t idx = i; U8_PREV(ptr, 0, idx, cp); i = idx; } template auto u8_reverse_index(const Range& str, size_t& i) -> void { using std::size, std::data; auto ptr = data(str); int32_t idx = i; U8_BACK_1(ptr, 0, idx); i = idx; } template auto u8_write_cp_and_advance(Range& buf, size_t& i, int32_t cp, bool& error) -> void { using std::size, std::data; #if U_ICU_VERSION_MAJOR_NUM <= 60 auto ptr = data(buf); int32_t idx = i; int32_t len = size(buf); U8_APPEND(buf, idx, len, cp, error); i = idx; #else auto len = size(buf); U8_APPEND(buf, i, len, cp, error); #endif } // UTF-8, valid template auto valid_u8_advance_cp(const Range& str, size_t& i, char32_t& cp) -> void { U8_NEXT_UNSAFE(str, i, cp); } template auto valid_u8_advance_index(const Range& str, size_t& i) -> void { U8_FWD_1_UNSAFE(str, i); } template auto valid_u8_reverse_cp(const Range& str, size_t& i, char32_t& cp) -> void { U8_PREV_UNSAFE(str, i, cp); } template auto valid_u8_reverse_index(const Range& str, size_t& i) -> void { U8_BACK_1_UNSAFE(str, i); } template auto valid_u8_write_cp_and_advance(Range& buf, size_t& i, char32_t cp) -> void { U8_APPEND_UNSAFE(buf, i, cp); } // UTF-16, work on malformed inline constexpr auto u16_max_cp_length = U16_MAX_LENGTH; auto inline u16_is_cp_error(int32_t cp) -> bool { return U_IS_SURROGATE(cp); } template auto u16_advance_cp(const Range& str, size_t& i, int32_t& cp) -> void { using std::size; auto len = size(str); U16_NEXT(str, i, len, cp); } template auto u16_advance_index(const Range& str, size_t& i) -> void { using std::size; auto len = size(str); U16_FWD_1(str, i, len); } template auto u16_reverse_cp(const Range& str, size_t& i, int32_t& cp) -> void { U16_PREV(str, 0, i, cp); } template auto u16_reverse_index(const Range& str, size_t& i) -> void { U16_BACK_1(str, 0, i); } template auto u16_write_cp_and_advance(Range& buf, size_t& i, int32_t cp, bool& error) -> void { using std::size; auto len = size(buf); U16_APPEND(buf, i, len, cp, error); } // UTF-16, valid template auto valid_u16_advance_cp(const Range& str, size_t& i, char32_t& cp) -> void { U16_NEXT_UNSAFE(str, i, cp); } template auto valid_u16_advance_index(const Range& str, size_t& i) -> void { U16_FWD_1_UNSAFE(str, i); } template auto valid_u16_reverse_cp(const Range& str, size_t& i, char32_t& cp) -> void { U16_PREV_UNSAFE(str, i, cp); } template auto valid_u16_reverse_index(const Range& str, size_t& i) -> void { U16_BACK_1_UNSAFE(str, i); } template auto valid_u16_write_cp_and_advance(Range& buf, size_t& i, char32_t cp) -> void { U16_APPEND_UNSAFE(buf, i, cp); } // higher level funcs struct U8_CP_Pos { size_t begin_i = 0; size_t end_i = begin_i; }; class U8_Encoded_CP { char d[u8_max_cp_length]; int sz; public: explicit U8_Encoded_CP(std::string_view str, U8_CP_Pos pos) : sz(pos.end_i - pos.begin_i) { auto i = sz; auto j = pos.end_i; auto max_len = 4; do { d[--i] = str[--j]; } while (i && --max_len); } U8_Encoded_CP(char32_t cp) { size_t z = 0; valid_u8_write_cp_and_advance(d, z, cp); sz = z; } auto size() const noexcept -> size_t { return sz; } auto data() const noexcept -> const char* { return d; } operator std::string_view() const noexcept { return std::string_view(data(), size()); } auto copy_to(std::string& str, size_t j) const { auto i = sz; j += sz; auto max_len = 4; do { str[--j] = d[--i]; } while (i && --max_len); } }; auto inline u8_swap_adjacent_cp(std::string& str, size_t i1, size_t i2, size_t i3) -> size_t { auto cp1 = U8_Encoded_CP(str, {i1, i2}); auto cp2 = U8_Encoded_CP(str, {i2, i3}); auto new_i2 = i1 + std::size(cp2); cp1.copy_to(str, new_i2); cp2.copy_to(str, i1); return new_i2; } auto inline u8_swap_cp(std::string& str, U8_CP_Pos pos1, U8_CP_Pos pos2) -> std::pair { using std::size; auto cp1 = U8_Encoded_CP(str, pos1); auto cp2 = U8_Encoded_CP(str, pos2); auto new_p1_end_i = pos1.begin_i + size(cp2); auto new_p2_begin_i = pos2.end_i - size(cp1); std::char_traits::move(&str[new_p1_end_i], &str[pos1.end_i], pos2.begin_i - pos1.end_i); cp2.copy_to(str, pos1.begin_i); cp1.copy_to(str, new_p2_begin_i); return {new_p1_end_i, new_p2_begin_i}; } // below go func without out-parametars // UTF-8, can be malformed, no out-parametars struct Idx_And_Next_CP { size_t end_i; int32_t cp; }; struct Idx_And_Prev_CP { size_t begin_i; int32_t cp; }; struct Write_CP_Idx_and_Error { size_t end_i; bool error; }; template [[nodiscard]] auto u8_next_cp(const Range& str, size_t i) -> Idx_And_Next_CP { int32_t cp; u8_advance_cp(str, i, cp); return {i, cp}; } template [[nodiscard]] auto u8_next_index(const Range& str, size_t i) -> size_t { u8_advance_index(str, i); return i; } template [[nodiscard]] auto u8_prev_cp(const Range& str, size_t i) -> Idx_And_Prev_CP { int32_t cp; u8_reverse_cp(str, i, cp); return {i, cp}; } template [[nodiscard]] auto u8_prev_index(const Range& str, size_t i) -> size_t { u8_reverse_index(str, i); return i; } template [[nodiscard]] auto u8_write_cp(Range& buf, size_t i, int32_t cp) -> Write_CP_Idx_and_Error { bool err; u8_write_cp_and_advance(buf, i, cp, err); return {i, err}; } // UTF-8, valid, no out-parametars struct Idx_And_Next_CP_Valid { size_t end_i; char32_t cp; }; struct Idx_And_Prev_CP_Valid { size_t begin_i; char32_t cp; }; template [[nodiscard]] auto valid_u8_next_cp(const Range& str, size_t i) -> Idx_And_Next_CP_Valid { char32_t cp; valid_u8_advance_cp(str, i, cp); return {i, cp}; } template [[nodiscard]] auto valid_u8_next_index(const Range& str, size_t i) -> size_t { valid_u8_advance_index(str, i); return i; } template [[nodiscard]] auto valid_u8_prev_cp(const Range& str, size_t i) -> Idx_And_Prev_CP_Valid { char32_t cp; valid_u8_reverse_cp(str, i, cp); return {i, cp}; } template [[nodiscard]] auto valid_u8_prev_index(const Range& str, size_t i) -> size_t { valid_u8_reverse_index(str, i); return i; } template [[nodiscard]] auto valid_u8_write_cp(Range& buf, size_t i, int32_t cp) -> size_t { valid_u8_write_cp_and_advance(buf, i, cp); return i; } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell #endif // NUSPELL_UNICODE_HXX nuspell-5.1.7/src/nuspell/utils.cxx000066400000000000000000000240521511132717100173450ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include "utils.hxx" #include "unicode.hxx" #include #include #include #include #include #include #include #if ' ' != 32 || '.' != 46 || 'A' != 65 || 'Z' != 90 || 'a' != 97 || 'z' != 122 #error "Basic execution character set is not ASCII" #endif using namespace std; namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE /** * @internal * @brief Splits string on set of single char separators. * * Consecutive separators are treated as separate and will emit empty strings. * * @deprecated TODO delete this on new major version. it was exported internal * symbol, but now it isn't used internally. it was exported for unit_test. * @param s string to split. * @param sep separator(s) to split on. * @param out vector where separated strings are appended. * @return @p out. */ auto split_on_any_of(std::string_view, const char*, std::vector& out) -> std::vector& { return out; } auto utf32_to_utf8(std::u32string_view in, std::string& out) -> void { out.clear(); for (size_t i = 0; i != size(in); ++i) { auto cp = in[i]; auto enc_cp = U8_Encoded_CP(cp); out += enc_cp; } } auto utf32_to_utf8(std::u32string_view in) -> std::string { auto out = string(); utf32_to_utf8(in, out); return out; } auto valid_utf8_to_32(std::string_view in, std::u32string& out) -> void { out.clear(); for (size_t i = 0; i != size(in);) { char32_t cp; valid_u8_advance_cp(in, i, cp); out.push_back(cp); } } auto valid_utf8_to_32(std::string_view in) -> std::u32string { auto out = u32string(); valid_utf8_to_32(in, out); return out; } auto utf8_to_16(std::string_view in) -> std::u16string { auto out = u16string(); utf8_to_16(in, out); return out; } bool utf8_to_16(std::string_view in, std::u16string& out) { int32_t len; auto err = U_ZERO_ERROR; u_strFromUTF8(data(out), size(out), &len, data(in), size(in), &err); out.resize(len); if (err == U_BUFFER_OVERFLOW_ERROR) { err = U_ZERO_ERROR; u_strFromUTF8(data(out), size(out), &len, data(in), size(in), &err); } if (U_SUCCESS(err)) return true; out.clear(); return false; } bool validate_utf8(string_view s) { auto err = U_ZERO_ERROR; u_strFromUTF8(nullptr, 0, nullptr, data(s), size(s), &err); if (err == U_INVALID_CHAR_FOUND) return false; return err == U_BUFFER_OVERFLOW_ERROR || U_SUCCESS(err); } auto static is_ascii(char c) -> bool { return static_cast(c) <= 127; } auto is_all_ascii(std::string_view s) -> bool { return all_of(begin(s), end(s), is_ascii); } auto static widen_latin1(char c) -> char16_t { return static_cast(c); } auto latin1_to_ucs2(std::string_view s) -> std::u16string { u16string ret; latin1_to_ucs2(s, ret); return ret; } auto latin1_to_ucs2(std::string_view s, std::u16string& out) -> void { out.resize(s.size()); transform(begin(s), end(s), begin(out), widen_latin1); } auto static is_surrogate_pair(char16_t c) -> bool { return 0xD800 <= c && c <= 0xDFFF; } auto is_all_bmp(std::u16string_view s) -> bool { return none_of(begin(s), end(s), is_surrogate_pair); } auto to_upper_ascii(std::string& s) -> void { auto& char_type = use_facet>(locale::classic()); char_type.toupper(begin_ptr(s), end_ptr(s)); } auto static utf32_to_icu(u32string_view in) -> icu::UnicodeString { static_assert(sizeof(UChar32) == sizeof(char32_t)); return icu::UnicodeString::fromUTF32( reinterpret_cast(in.data()), in.size()); } auto static icu_to_utf32(const icu::UnicodeString& in, std::u32string& out) -> bool { out.resize(in.length()); auto err = U_ZERO_ERROR; auto len = in.toUTF32(reinterpret_cast(out.data()), out.size(), err); if (U_SUCCESS(err)) { out.erase(len); return true; } out.clear(); return false; } auto to_upper(std::string_view in, const icu::Locale& loc) -> std::string { auto out = std::string(); to_upper(in, loc, out); return out; } auto to_title(std::string_view in, const icu::Locale& loc) -> std::string { auto out = std::string(); to_title(in, loc, out); return out; } auto to_lower(std::string_view in, const icu::Locale& loc) -> std::string { auto out = std::string(); to_lower(in, loc, out); return out; } auto to_upper(string_view in, const icu::Locale& loc, string& out) -> void { auto sp = icu::StringPiece(data(in), size(in)); auto us = icu::UnicodeString::fromUTF8(sp); us.toUpper(loc); out.clear(); us.toUTF8String(out); } auto to_title(string_view in, const icu::Locale& loc, string& out) -> void { auto sp = icu::StringPiece(data(in), size(in)); auto us = icu::UnicodeString::fromUTF8(sp); us.toTitle(nullptr, loc, U_TITLECASE_WHOLE_STRING); out.clear(); us.toUTF8String(out); } auto to_lower(u32string_view in, const icu::Locale& loc, u32string& out) -> void { auto us = utf32_to_icu(in); us.toLower(loc); icu_to_utf32(us, out); } auto to_lower(string_view in, const icu::Locale& loc, string& out) -> void { auto sp = icu::StringPiece(data(in), size(in)); auto us = icu::UnicodeString::fromUTF8(sp); us.toLower(loc); out.clear(); us.toUTF8String(out); } auto to_lower_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void { auto cp = valid_u8_next_cp(s, i); auto us = icu::UnicodeString(UChar32(cp.cp)); us.toLower(loc); auto u8_low = string(); us.toUTF8String(u8_low); s.replace(i, cp.end_i - i, u8_low); } auto to_title_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void { auto cp = valid_u8_next_cp(s, i); auto us = icu::UnicodeString(UChar32(cp.cp)); us.toTitle(nullptr, loc, U_TITLECASE_WHOLE_STRING); auto u8_title = string(); us.toUTF8String(u8_title); s.replace(i, cp.end_i - i, u8_title); } /** * @internal * @brief Determines casing (capitalization) type for a word. * * Casing is sometimes referred to as capitalization. * * @param s word. * @return The casing type. */ auto classify_casing(string_view s) -> Casing { size_t upper = 0; size_t lower = 0; for (size_t i = 0; i != size(s);) { char32_t c; valid_u8_advance_cp(s, i, c); if (u_isupper(c)) upper++; else if (u_islower(c)) lower++; // else neutral } if (upper == 0) // all lowercase, maybe with some neutral return Casing::SMALL; // most common case auto first_cp = valid_u8_next_cp(s, 0); auto first_capital = u_isupper(first_cp.cp); if (first_capital && upper == 1) return Casing::INIT_CAPITAL; // second most common if (lower == 0) return Casing::ALL_CAPITAL; if (first_capital) return Casing::PASCAL; else return Casing::CAMEL; } /** * @internal * @brief Check if word[i] or word[i-1] are uppercase * * Check if the two chars are alphabetic and at least one of them is in * uppercase. * * @return true if at least one is uppercase, false otherwise. */ auto has_uppercase_at_compound_word_boundary(string_view word, size_t i) -> bool { auto cp = valid_u8_next_cp(word, i); auto cp_prev = valid_u8_prev_cp(word, i); if (u_isupper(cp.cp)) { if (u_isalpha(cp_prev.cp)) return true; } else if (u_isupper(cp_prev.cp) && u_isalpha(cp.cp)) return true; return false; } Encoding_Converter::Encoding_Converter(const char* enc) { auto err = UErrorCode(); cnv = ucnv_open(enc, &err); } Encoding_Converter::~Encoding_Converter() { if (cnv) ucnv_close(cnv); } auto Encoding_Converter::to_utf8(string_view in, string& out) -> bool { if (ucnv_getType(cnv) == UCNV_UTF8) { if (validate_utf8(in)) { out = in; return true; } else { out.clear(); return false; } } auto err = U_ZERO_ERROR; auto len = ucnv_toAlgorithmic(UCNV_UTF8, cnv, out.data(), out.size(), in.data(), in.size(), &err); out.resize(len); if (err == U_BUFFER_OVERFLOW_ERROR) { err = U_ZERO_ERROR; ucnv_toAlgorithmic(UCNV_UTF8, cnv, out.data(), out.size(), in.data(), in.size(), &err); } return U_SUCCESS(err); } auto replace_ascii_char(string& s, char from, char to) -> void { for (auto i = s.find(from); i != s.npos; i = s.find(from, i + 1)) { s[i] = to; } } auto erase_chars(string& s, string_view erase_chars) -> void { if (erase_chars.empty()) return; for (size_t i = 0, next_i = 0; i != size(s); i = next_i) { valid_u8_advance_index(s, next_i); auto enc_cp = string_view(&s[i], next_i - i); if (erase_chars.find(enc_cp) != erase_chars.npos) { s.erase(i, next_i - i); next_i = i; } } return; } /** * @internal * @brief Tests if word is a number. * * Allow numbers with dot ".", dash "-" or comma "," between the digits, but * forbids double separators such as "..", "--" and ".,". */ auto is_number(string_view s) -> bool { if (s.empty()) return false; auto it = begin(s); if (s[0] == '-') ++it; while (it != end(s)) { auto next = std::find_if( it, end(s), [](auto c) { return c < '0' || c > '9'; }); if (next == it) return false; if (next == end(s)) return true; it = next; auto c = *it; if (c == '.' || c == ',' || c == '-') ++it; else return false; } return false; } auto count_appereances_of(string_view haystack, string_view needles) -> size_t { auto ret = size_t(0); for (size_t i = 0, next_i = 0; i != size(haystack); i = next_i) { valid_u8_advance_index(haystack, next_i); auto enc_cp = string_view(&haystack[i], next_i - i); ret += needles.find(enc_cp) != needles.npos; } return ret; } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell nuspell-5.1.7/src/nuspell/utils.hxx000066400000000000000000000125361511132717100173560ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #ifndef NUSPELL_UTILS_HXX #define NUSPELL_UTILS_HXX #include "defines.hxx" #include "nuspell_export.h" #include #include #include #include #ifdef __GNUC__ #define likely(expr) __builtin_expect(!!(expr), 1) #define unlikely(expr) __builtin_expect(!!(expr), 0) #else #define likely(expr) (expr) #define unlikely(expr) (expr) #endif struct UConverter; // unicode/ucnv.h namespace nuspell { NUSPELL_BEGIN_INLINE_NAMESPACE NUSPELL_DEPRECATED_EXPORT auto split_on_any_of(std::string_view s, const char* sep, std::vector& out) -> std::vector&; NUSPELL_EXPORT auto utf32_to_utf8(std::u32string_view in, std::string& out) -> void; NUSPELL_EXPORT auto utf32_to_utf8(std::u32string_view in) -> std::string; auto valid_utf8_to_32(std::string_view in, std::u32string& out) -> void; auto valid_utf8_to_32(std::string_view in) -> std::u32string; auto utf8_to_16(std::string_view in) -> std::u16string; auto utf8_to_16(std::string_view in, std::u16string& out) -> bool; auto validate_utf8(std::string_view s) -> bool; NUSPELL_EXPORT auto is_all_ascii(std::string_view s) -> bool; NUSPELL_EXPORT auto latin1_to_ucs2(std::string_view s) -> std::u16string; auto latin1_to_ucs2(std::string_view s, std::u16string& out) -> void; NUSPELL_EXPORT auto is_all_bmp(std::u16string_view s) -> bool; auto to_upper_ascii(std::string& s) -> void; [[nodiscard]] NUSPELL_EXPORT auto to_upper(std::string_view in, const icu::Locale& loc) -> std::string; [[nodiscard]] NUSPELL_EXPORT auto to_title(std::string_view in, const icu::Locale& loc) -> std::string; [[nodiscard]] NUSPELL_EXPORT auto to_lower(std::string_view in, const icu::Locale& loc) -> std::string; auto to_upper(std::string_view in, const icu::Locale& loc, std::string& out) -> void; auto to_title(std::string_view in, const icu::Locale& loc, std::string& out) -> void; auto to_lower(std::u32string_view in, const icu::Locale& loc, std::u32string& out) -> void; auto to_lower(std::string_view in, const icu::Locale& loc, std::string& out) -> void; auto to_lower_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void; auto to_title_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void; /** * @internal * @brief Enum that identifies the casing type of a word. * * Neutral characters like numbers are ignored, so "abc" and "abc123abc" are * both classified as small. */ enum class Casing : char { SMALL, INIT_CAPITAL, ALL_CAPITAL, CAMEL /**< @internal camelCase i.e. mixed case with first small */, PASCAL /**< @internal PascalCase i.e. mixed case with first capital */ }; NUSPELL_EXPORT auto classify_casing(std::string_view s) -> Casing; auto has_uppercase_at_compound_word_boundary(std::string_view word, size_t i) -> bool; class Encoding_Converter { UConverter* cnv = nullptr; public: Encoding_Converter() = default; explicit Encoding_Converter(const char* enc); explicit Encoding_Converter(const std::string& enc) : Encoding_Converter(enc.c_str()) { } ~Encoding_Converter(); Encoding_Converter(const Encoding_Converter& other) = delete; Encoding_Converter(Encoding_Converter&& other) noexcept { cnv = other.cnv; cnv = nullptr; } auto operator=(const Encoding_Converter& other) -> Encoding_Converter& = delete; auto operator=(Encoding_Converter&& other) noexcept -> Encoding_Converter& { std::swap(cnv, other.cnv); return *this; } auto to_utf8(std::string_view in, std::string& out) -> bool; auto valid() -> bool { return cnv != nullptr; } }; auto replace_ascii_char(std::string& s, char from, char to) -> void; auto erase_chars(std::string& s, std::string_view erase_chars) -> void; NUSPELL_EXPORT auto is_number(std::string_view s) -> bool; auto count_appereances_of(std::string_view haystack, std::string_view needles) -> size_t; auto inline begins_with(std::string_view haystack, std::string_view needle) -> bool { return haystack.compare(0, needle.size(), needle) == 0; } auto inline ends_with(std::string_view haystack, std::string_view needle) -> bool { return haystack.size() >= needle.size() && haystack.compare(haystack.size() - needle.size(), needle.size(), needle) == 0; } template auto begin_ptr(T& x) { return x.data(); } template auto end_ptr(T& x) { return x.data() + x.size(); } NUSPELL_END_INLINE_NAMESPACE } // namespace nuspell #endif // NUSPELL_UTILS_HXX nuspell-5.1.7/src/tools/000077500000000000000000000000001511132717100151345ustar00rootroot00000000000000nuspell-5.1.7/src/tools/CMakeLists.txt000066400000000000000000000016221511132717100176750ustar00rootroot00000000000000add_executable(nuspell-exe nuspell.cxx) set_target_properties(nuspell-exe PROPERTIES RUNTIME_OUTPUT_NAME nuspell) target_compile_definitions(nuspell-exe PRIVATE PROJECT_VERSION=\"${PROJECT_VERSION}\") target_link_libraries(nuspell-exe PRIVATE Nuspell::nuspell) if (MSVC) target_include_directories(nuspell-exe PRIVATE ${GETOPT_INCLUDE_DIR}) target_link_libraries(nuspell-exe PRIVATE ${GETOPT_LIBRARY}) endif() if (BUILD_SHARED_LIBS AND WIN32) # This should be PRE_LINK (or PRE_BUILD), so Vcpkg's POST_BUILD # step (see VCPKG_APPLOCAL_DEPS) that copies dll can pick up nuspell.dll # inside the folder ../tools and copy its transitive dependencies. add_custom_command(TARGET nuspell-exe PRE_LINK COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $) endif() if (NOT subproject) install(TARGETS nuspell-exe DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() nuspell-5.1.7/src/tools/nuspell.cxx000066400000000000000000000417221511132717100173500ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include #include #include #include #include #include #include #include #include #include #if __has_include() #include // defines _POSIX_VERSION #endif #ifdef _POSIX_VERSION #include #endif #ifdef _WIN32 #include #ifndef NOMINMAX #define NOMINMAX #endif #define WIN32_LEAN_AND_MEAN #include #endif // manually define if not supplied by the build system #ifndef PROJECT_VERSION #define PROJECT_VERSION "unknown.version" #endif using namespace std; using nuspell::Dictionary, nuspell::Dictionary_Loading_Error, nuspell::Dict_Finder_For_CLI_Tool_2; namespace { enum Mode { NORMAL, HELP, VERSION, LIST_DICTS }; auto print_help(const char* program_name) -> void { auto p = string_view(program_name); auto& o = cout; o << "Usage:\n" << p << " [-d dict_NAME] [OPTION]... [FILE...]\n" << p << " -D|--help|--version\n" << R"( Check spelling of each FILE. If no FILE is specified, check standard input. The text in the input is first segmented into words with an algorithm that recognizes punctuation and then each word is checked. -d, --dictionary=di_CT use di_CT dictionary, only one is supported -D, --list-dictionaries print search paths and available dictionaries --encoding=enc set both input and output encoding --input-encoding=enc input encoding, default is active locale --output-encoding=enc output encoding, default is active locale --help print this help --version print version number A dictionary consists of two files with extensions .dic and .aff. The -d option accepts either dictionary name without filename extension, usually a language tag, or a path (with slash) to the .aff file including the filename extension. When just a name is given, it will be searched among the list of dictionaries in the default directories (see option -D). When a path to .aff is given, only the dictionary under the path is considered. When -d is not present, the CLI tools tries to load a dictionary using the language tag from the active locale. Returns error if the argument syntax is invalid, if the dictionary can not be loaded or if some input file can not be opened. Otherwise, spell checking has occurred and returns success. The following environment variables can have effect: DICTIONARY - same as -d, DICPATH - additional directory path to search for dictionaries. Example: )" << " " << p << " -d en_US file.txt\n" << " " << p << " -d ../../subdir/di_CT.aff\n" << R"( Bug reports: Full documentation: Home page: )"; } auto ver_str = "nuspell " PROJECT_VERSION R"( Copyright 2016-2024 Dimitrij Mijoski License LGPLv3+: GNU LGPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Dimitrij Mijoski. )"; auto print_version() -> void { cout << ver_str; } auto list_dictionaries(const Dict_Finder_For_CLI_Tool_2& f) -> void { if (empty(f.get_dir_paths())) { cout << "No search paths available" << '\n'; } else { cout << "Search paths:" << '\n'; for (auto& p : f.get_dir_paths()) { cout << p.string() << '\n'; } } auto dicts = vector(); nuspell::search_dirs_for_dicts(f.get_dir_paths(), dicts); if (empty(dicts)) { cout << "No dictionaries available\n"; } else { stable_sort(begin(dicts), end(dicts)); cout << "Available dictionaries:\n"; for (auto& d : dicts) { cout << left << setw(15) << d.stem().string() << ' ' << d.string() << '\n'; } } } auto from_utf8(string_view source, string& dest, UConverter* ucnv, UErrorCode& uerr) { dest.resize(dest.capacity()); auto len = ucnv_fromAlgorithmic(ucnv, UCNV_UTF8, dest.data(), dest.size(), source.data(), source.size(), &uerr); dest.resize(len); if (uerr == U_BUFFER_OVERFLOW_ERROR) { uerr = U_ZERO_ERROR; ucnv_fromAlgorithmic(ucnv, UCNV_UTF8, dest.data(), dest.size(), source.data(), source.size(), &uerr); } } auto to_unicode_string(string_view source, icu::UnicodeString& dest, UConverter* ucnv, UErrorCode& uerr) { auto buf = dest.getBuffer(-1); auto len = ucnv_toUChars(ucnv, buf, dest.getCapacity(), source.data(), source.size(), &uerr); if (uerr == U_BUFFER_OVERFLOW_ERROR) { uerr = U_ZERO_ERROR; dest.releaseBuffer(0); buf = dest.getBuffer(len); if (!buf) throw bad_alloc(); len = ucnv_toUChars(ucnv, buf, dest.getCapacity(), source.data(), source.size(), &uerr); } dest.releaseBuffer(len); } auto process_word_utf8_output_enc(const Dictionary& dic, string_view word, vector& suggestions, ostream& out) { auto correct = dic.spell(word); if (correct) { out << "* OK\n"; return; } dic.suggest(word, suggestions); if (suggestions.empty()) { out << "# Wrong: " << word << ". No suggestions.\n"; return; } out << "& Wrong: " << word << ". How about: "; out << suggestions[0]; for_each(begin(suggestions) + 1, end(suggestions), [&](auto& sug) { out << ", " << sug; }); out << '\n'; } auto process_word_any_output_enc(const Dictionary& dic, string_view u8word, vector& suggestions, ostream& out, UConverter* out_cnv, UErrorCode& uerr) { auto correct = dic.spell(u8word); if (correct) { out << "* OK\n"; return; } dic.suggest(u8word, suggestions); auto encoded_out = string(); from_utf8(u8word, encoded_out, out_cnv, uerr); if (suggestions.empty()) { out << "# Wrong: " << encoded_out << ". No suggestions.\n"; return; } out << "& Wrong: " << encoded_out << ". How about: "; from_utf8(suggestions[0], encoded_out, out_cnv, uerr); out << encoded_out; for_each(begin(suggestions) + 1, end(suggestions), [&](const string& u8sug) { out << ", "; from_utf8(u8sug, encoded_out, out_cnv, uerr); out << encoded_out; }); out << '\n'; } auto is_word_break(int32_t typ) { return (UBRK_WORD_NUMBER <= typ && typ < UBRK_WORD_NUMBER_LIMIT) || (UBRK_WORD_LETTER <= typ && typ < UBRK_WORD_LETTER_LIMIT) || (UBRK_WORD_KANA <= typ && typ < UBRK_WORD_KANA_LIMIT) || (UBRK_WORD_IDEO <= typ && typ < UBRK_WORD_IDEO_LIMIT); } auto process_line_utf8_input_enc(const Dictionary& dic, const string& line, UText* utext, icu::BreakIterator* ubrkiter, vector& suggestions, ostream& out, UConverter* out_cnv, UErrorCode& uerr) { utext_openUTF8(utext, line.data(), line.size(), &uerr); ubrkiter->setText(utext, uerr); auto is_utf8_out = ucnv_getType(out_cnv) == UCNV_UTF8; for (auto i = ubrkiter->first(), prev = 0; i != ubrkiter->DONE; prev = i, i = ubrkiter->next()) { auto typ = ubrkiter->getRuleStatus(); if (is_word_break(typ)) { auto word = string_view(line).substr(prev, i - prev); if (is_utf8_out) process_word_utf8_output_enc(dic, word, suggestions, out); else process_word_any_output_enc( dic, word, suggestions, out, out_cnv, uerr); } } assert(U_SUCCESS(uerr)); } auto process_line_any_input_enc(const Dictionary& dic, const string& line, icu::UnicodeString& uline, UConverter* in_cnv, icu::BreakIterator* ubrkiter, UErrorCode& uerr, string& u8word, vector& suggestions, ostream& out, UConverter* out_cnv) { to_unicode_string(line, uline, in_cnv, uerr); ubrkiter->setText(uline); /* size_t orig_prev = 0, orig_i = 0; auto src = line.c_str(); auto src_end = src + line.size(); */ auto is_utf8_out = ucnv_getType(out_cnv) == UCNV_UTF8; ucnv_resetToUnicode(in_cnv); for (auto i = ubrkiter->first(), prev = 0; i != ubrkiter->DONE; prev = i, i = ubrkiter->next() /*, orig_prev = orig_i*/) { /* for (auto j = prev; j != i; ++j) { auto cp = ucnv_getNextUChar(in_cnv, &src, src_end, &uerr); // U_IS_SURROGATE(uline[j]) or // U_IS_LEAD(uline[j]) can work too j += !U_IS_BMP(cp); } orig_i = distance(line.c_str(), src); */ auto typ = ubrkiter->getRuleStatus(); if (is_word_break(typ)) { auto uword = uline.tempSubStringBetween(prev, i); u8word.clear(); uword.toUTF8String(u8word); /* auto enc_word = string_view(line).substr( orig_prev, orig_i - orig_prev); */ if (is_utf8_out) process_word_utf8_output_enc(dic, u8word, suggestions, out); else process_word_any_output_enc(dic, u8word, suggestions, out, out_cnv, uerr); } } assert(U_SUCCESS(uerr)); } auto process_text(const Dictionary& dic, istream& in, UConverter* in_cnv, ostream& out, UConverter* out_cnv, UErrorCode& uerr) { auto line = string(); auto suggestions = vector(); auto wrong_words = vector(); // TODO: try to use Locale constructed from dictionary name. auto ubrkiter = unique_ptr( icu::BreakIterator::createWordInstance(icu::Locale(), uerr)); auto utext = icu::LocalUTextPointer( utext_openUTF8(nullptr, line.data(), line.size(), &uerr)); auto uline = icu::UnicodeString(); auto u8word = string(); auto is_utf8 = ucnv_getType(in_cnv) == UCNV_UTF8; if (&in == &cin) out << "Enter some text: "; while (getline(in, line)) { wrong_words.clear(); if (is_utf8) process_line_utf8_input_enc(dic, line, utext.getAlias(), ubrkiter.get(), suggestions, out, out_cnv, uerr); else process_line_any_input_enc(dic, line, uline, in_cnv, ubrkiter.get(), uerr, u8word, suggestions, out, out_cnv); out << '\n'; // In NORMAL mode put empty line for each input // line. } } } // namespace int main(int argc, char* argv[]) { auto mode_int = int(Mode::NORMAL); auto program_name = "nuspell"; auto dictionary = string(); auto input_enc = string(); auto output_enc = string(); if (argc > 0 && argv[0]) program_name = argv[0]; ios_base::sync_with_stdio(false); auto optstring = "d:D"; option longopts[] = { {"help", no_argument, &mode_int, Mode::HELP}, {"version", no_argument, &mode_int, Mode::VERSION}, {"list-dictionaries", no_argument, &mode_int, Mode::LIST_DICTS}, {"dictionary", required_argument, nullptr, 'd'}, {"encoding", required_argument, nullptr, 'e'}, {"input-encoding", required_argument, nullptr, 'i'}, {"output-encoding", required_argument, nullptr, 'o'}, {}}; int longindex; int c; while ((c = getopt_long(argc, argv, optstring, longopts, &longindex)) != -1) { switch (c) { case 0: // check longopts[longindex] if needed break; case 'd': dictionary = optarg; break; case 'D': mode_int = Mode::LIST_DICTS; break; case 'e': input_enc = optarg; output_enc = optarg; break; case 'i': input_enc = optarg; break; case 'o': output_enc = optarg; break; case '?': return EXIT_FAILURE; } } auto mode = static_cast(mode_int); if (mode == Mode::VERSION) { print_version(); return 0; } else if (mode == Mode::HELP) { print_help(program_name); return 0; } auto f = Dict_Finder_For_CLI_Tool_2(); if (mode == Mode::LIST_DICTS) { list_dictionaries(f); return 0; } char* loc_str = nullptr; #if _WIN32 loc_str = setlocale(LC_CTYPE, nullptr); // will return "C" /* On Windows, the console is a buggy thing. If the default C locale is active, then the encoding of the strings gotten from C or C++ stdio (fgets, scanf, cin) is GetConsoleCP(). Stdout accessed via standard functions (printf, cout) expects encoding of GetConsoleOutputCP() which is the same as GetConsoleCP() unless manually changed. By default both are the active OEM encoding, unless changed with the command chcp, or by calling the Set functions. If we call setlocale(LC_CTYPE, ""), or let's say setlocale(LC_CTYPE, ".1251"), then stdin will still return in the encoding GetConsoleCP(), but stdout functions like printf now will expect a different encoding, the one set via setlocale. Because of this mess don't change locale with setlocale on Windows. When stdin or stout are redirected from/to file or another terminal like the one in MSYS2, they are read/written as-is. Then we will assume UTF-8 encoding. */ #else loc_str = setlocale(LC_CTYPE, ""); if (!loc_str) { clog << "WARNING: Can not set to system locale, fall back to " "\"C\".\n"; loc_str = setlocale(LC_CTYPE, nullptr); // will return "C" } #endif #if _POSIX_VERSION auto enc_str = nl_langinfo(CODESET); if (input_enc.empty()) input_enc = enc_str; if (output_enc.empty()) output_enc = enc_str; #elif _WIN32 if (optind == argc && _isatty(_fileno(stdin))) input_enc = "cp" + to_string(GetConsoleCP()); else if (input_enc.empty()) input_enc = "UTF-8"; if (_isatty(_fileno(stdout))) output_enc = "cp" + to_string(GetConsoleOutputCP()); else if (output_enc.empty()) output_enc = "UTF-8"; #endif auto loc_str_sv = string_view(loc_str); clog << "INFO: Locale LC_CTYPE=" << loc_str_sv << ", Input encoding=" << input_enc << ", Output encoding=" << output_enc << endl; if (dictionary.empty()) { auto denv = getenv("DICTIONARY"); if (denv) dictionary = denv; } if (dictionary.empty()) { // infer dictionary from locale auto idx = min(loc_str_sv.find('.'), loc_str_sv.find('@')); dictionary = loc_str_sv.substr(0, idx); } if (dictionary.empty()) { clog << "ERROR: No dictionary provided and can not infer from " "OS locale\n"; return EXIT_FAILURE; } auto filename = f.get_dictionary_path(dictionary); if (filename.empty()) { clog << "ERROR: Dictionary " << dictionary << " not found\n"; return EXIT_FAILURE; } clog << "INFO: Pointed dictionary " << filename.string() << endl; auto dic = Dictionary(); try { dic.load_aff_dic_internal(filename, clog); } catch (const Dictionary_Loading_Error& e) { clog << "ERROR: " << e.what() << '\n'; return EXIT_FAILURE; } // ICU reports all types of errors, logic errors and runtime errors // using this enum. We should not check for logic errors, they should // not happened. Optionally, only assert that they are not there can be // used. We should check for runtime errors. // The encoding conversion is a common case where runtime error can // happen, but by default ICU uses Unicode replacement character on // errors and reports success. This can be changed, but there is no need // for that. auto uerr = U_ZERO_ERROR; auto inp_enc_cstr = input_enc.c_str(); if (input_enc.empty()) { inp_enc_cstr = nullptr; clog << "WARNING: using default ICU encoding converter for IO" << endl; } auto in_ucnv = icu::LocalUConverterPointer(ucnv_open(inp_enc_cstr, &uerr)); if (U_FAILURE(uerr)) { clog << "ERROR: Invalid encoding " << input_enc << ".\n"; return EXIT_FAILURE; } auto out_ucnv_smart_ptr = icu::LocalUConverterPointer(); auto out_ucnv = in_ucnv.getAlias(); // often output_enc is same as input if (output_enc != input_enc) { auto output_enc_cstr = output_enc.c_str(); if (output_enc.empty()) { output_enc_cstr = nullptr; clog << "WARNING: using default ICU encoding converter " "for IO" << endl; } out_ucnv = ucnv_open(output_enc_cstr, &uerr); out_ucnv_smart_ptr.adoptInstead(out_ucnv); if (U_FAILURE(uerr)) { clog << "ERROR: Invalid encoding " << output_enc << ".\n"; return EXIT_FAILURE; } } if (optind == argc) { process_text(dic, cin, in_ucnv.getAlias(), cout, out_ucnv, uerr); } else { for (; optind != argc; ++optind) { auto file_name = argv[optind]; ifstream in(file_name); if (!in.is_open()) { clog << "ERROR: Can't open " << file_name << '\n'; return EXIT_FAILURE; } process_text(dic, in, in_ucnv.getAlias(), cout, out_ucnv, uerr); } } } nuspell-5.1.7/tests/000077500000000000000000000000001511132717100143475ustar00rootroot00000000000000nuspell-5.1.7/tests/CMakeLists.txt000066400000000000000000000024011511132717100171040ustar00rootroot00000000000000add_executable(unit_test unit_test.cxx) target_link_libraries(unit_test PRIVATE nuspell Catch2::Catch2WithMain) if (MSVC) target_compile_options(unit_test PRIVATE "/utf-8") # Consider doing this for all the other targets by setting this flag # globally for MSVC. ATM we use unicode string literals only here. endif() add_executable(legacy_test legacy_test.cxx) target_link_libraries(legacy_test PRIVATE nuspell) add_executable(verify verify.cxx) target_link_libraries(verify PRIVATE nuspell hunspell) if (MSVC) target_include_directories(verify PRIVATE ${GETOPT_INCLUDE_DIR}) target_link_libraries(verify PRIVATE ${GETOPT_LIBRARY}) endif() if (BUILD_SHARED_LIBS AND WIN32) add_custom_command(TARGET verify PRE_LINK COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ $) endif() add_test(NAME unit_test COMMAND unit_test) file(GLOB v1tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/v1cmdline "v1cmdline/*.dic" "v1cmdline/*.sug") foreach(t ${v1tests}) add_test( NAME ${t} COMMAND legacy_test ${CMAKE_CURRENT_SOURCE_DIR}/v1cmdline/${t}) endforeach() set_tests_properties( base_utf.dic nepali.dic checksharps.sug checksharpsutf.sug nosuggest.sug phone.sug utf8_nonbmp.sug PROPERTIES WILL_FAIL TRUE) nuspell-5.1.7/tests/List_of_common_misspellings.txt000066400000000000000000002413221511132717100226540ustar00rootroot00000000000000# source: http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines # released under the Creative Commons Attribution-Share-Alike License 3.0 # http://creativecommons.org/licenses/by-sa/3.0/ abandonned abandoned aberation aberration abilties abilities abilty ability abondon abandon abondoned abandoned abondoning abandoning abondons abandons aborigene aborigine abortificant abortifacient abreviated abbreviated abreviation abbreviation abritrary arbitrary absense absence absolutly absolutely absorbsion absorption absorbtion absorption abundacies abundances abundancies abundances abundunt abundant abutts abuts acadamy academy acadmic academic accademic academic accademy academy acccused accused accelleration acceleration accension accession, ascension acceptence acceptance acceptible acceptable accessable accessible accidentaly accidentally accidently accidentally acclimitization acclimatization acommodate accommodate accomadate accommodate accomadated accommodated accomadates accommodates accomadating accommodating accomadation accommodation accomadations accommodations accomdate accommodate accomodate accommodate accomodated accommodated accomodates accommodates accomodating accommodating accomodation accommodation accomodations accommodations accompanyed accompanied accordeon accordion accordian accordion accoring according accoustic acoustic accquainted acquainted accross across accussed accused acedemic academic acheive achieve acheived achieved acheivement achievement acheivements achievements acheives achieves acheiving achieving acheivment achievement acheivments achievements achievment achievement achievments achievements achive achieve, archive achived achieved, archived achivement achievement achivements achievements acknowldeged acknowledged acknowledgeing acknowledging ackward awkward, backward acomplish accomplish acomplished accomplished acomplishment accomplishment acomplishments accomplishments acording according acordingly accordingly acquaintence acquaintance acquaintences acquaintances acquiantence acquaintance acquiantences acquaintances acquited acquitted activites activities activly actively actualy actually acuracy accuracy acused accused acustom accustom acustommed accustomed adavanced advanced adbandon abandon additinally additionally additionaly additionally addmission admission addopt adopt addopted adopted addoptive adoptive addres address, adders addresable addressable addresed addressed addresing addressing addressess addresses addtion addition addtional additional adecuate adequate adhearing adhering adherance adherence admendment amendment admininistrative administrative adminstered administered adminstrate administrate adminstration administration adminstrative administrative adminstrator administrator admissability admissibility admissable admissible admited admitted admitedly admittedly adn and adolecent adolescent adquire acquire adquired acquired adquires acquires adquiring acquiring adres address adresable addressable adresing addressing adress address adressable addressable adressed addressed adressing addressing, dressing adventrous adventurous advertisment advertisement advertisments advertisements advesary adversary adviced advised aeriel aerial aeriels aerials afair affair afficianados aficionados afficionado aficionado afficionados aficionados affilate affiliate affilliate affiliate affort afford, effort aforememtioned aforementioned againnst against agains against agaisnt against aganist against aggaravates aggravates aggreed agreed aggreement agreement aggregious egregious aggresive aggressive agian again agianst against agin again agina again, angina aginst against agravate aggravate agre agree agred agreed agreeement agreement agreemnt agreement agregate aggregate agregates aggregates agreing agreeing agression aggression agressive aggressive agressively aggressively agressor aggressor agricuture agriculture agrieved aggrieved ahev have ahppen happen ahve have aicraft aircraft aiport airport airbourne airborne aircaft aircraft aircrafts aircraft airporta airports airrcraft aircraft aisian asian albiet albeit alchohol alcohol alchoholic alcoholic alchol alcohol alcholic alcoholic alcohal alcohol alcoholical alcoholic aledge allege aledged alleged aledges alleges alege allege aleged alleged alegience allegiance algebraical algebraic algorhitms algorithms algoritm algorithm algoritms algorithms alientating alienating alledge allege alledged alleged alledgedly allegedly alledges alleges allegedely allegedly allegedy allegedly allegely allegedly allegence allegiance allegience allegiance allign align alligned aligned alliviate alleviate allopone allophone allopones allophones allready already allthough although alltime all-time alltogether altogether almsot almost alochol alcohol alomst almost alot a lot, allot alotted allotted alowed allowed alowing allowing alreayd already alse else alsot also alternitives alternatives altho although althought although altough although alusion allusion, illusion alwasy always alwyas always amalgomated amalgamated amatuer amateur amature armature, amateur amendmant amendment amerliorate ameliorate amke make amking making ammend amend ammended amended ammendment amendment ammendments amendments ammount amount ammused amused amoung among amoungst amongst amung among analagous analogous analitic analytic analogeous analogous anarchim anarchism anarchistm anarchism anbd and ancestory ancestry ancilliary ancillary androgenous androgynous androgeny androgyny anihilation annihilation aniversary anniversary annoint anoint annointed anointed annointing anointing annoints anoints annouced announced annualy annually annuled annulled anohter another anomolies anomalies anomolous anomalous anomoly anomaly anonimity anonymity anounced announced ansalisation nasalisation ansalization nasalization ansestors ancestors antartic antarctic anthromorphization anthropomorphization anual annual, anal anulled annulled anwsered answered anyhwere anywhere anyother any other anytying anything aparent apparent aparment apartment apenines apennines, Apennines aplication application aplied applied apolegetics apologetics apon upon, apron apparant apparent apparantly apparently appart apart appartment apartment appartments apartments appealling appealing, appalling appeareance appearance appearence appearance appearences appearances appenines apennines, Apennines apperance appearance apperances appearances applicaiton application applicaitons applications appologies apologies appology apology apprearance appearance apprieciate appreciate approachs approaches appropiate appropriate appropraite appropriate appropropiate appropriate approproximate approximate approxamately approximately approxiately approximately approximitely approximately aprehensive apprehensive apropriate appropriate aproximate approximate aproximately approximately aquaintance acquaintance aquainted acquainted aquiantance acquaintance aquire acquire aquired acquired aquiring acquiring aquisition acquisition aquitted acquitted aranged arranged arangement arrangement arbitarily arbitrarily arbitary arbitrary archaelogists archaeologists archaelogy archaeology archaoelogy archeology, archaeology archaology archeology, archaeology archeaologist archeologist, archaeologist archeaologists archeologists, archaeologists archetect architect archetects architects archetectural architectural archetecturally architecturally archetecture architecture archiac archaic archictect architect archimedian archimedean architechturally architecturally architechture architecture architechtures architectures architectual architectural archtype archetype archtypes archetypes aready already areodynamics aerodynamics argubly arguably arguement argument arguements arguments arised arose arival arrival armamant armament armistace armistice aroud around arrangment arrangement arrangments arrangements arround around artical article artice article articel article artifical artificial artifically artificially artillary artillery arund around asetic ascetic asign assign aslo also asociated associated asorbed absorbed asphyxation asphyxiation assasin assassin assasinate assassinate assasinated assassinated assasinates assassinates assasination assassination assasinations assassinations assasined assassinated assasins assassins assassintation assassination assemple assemble assertation assertion asside aside assisnate assassinate assit assist assitant assistant assocation association assoicate associate assoicated associated assoicates associates assosication assassination asssassans assassins assualt assault assualted assaulted assymetric asymmetric assymetrical asymmetrical asteriod asteroid asthetic aesthetic asthetical aesthetical asthetically aesthetically asume assume aswell as well atain attain atempting attempting atheistical atheistic athenean athenian atheneans athenians athiesm atheism athiest atheist atorney attorney atribute attribute atributed attributed atributes attributes attaindre attainder, attained attemp attempt attemped attempted attemt attempt attemted attempted attemting attempting attemts attempts attendence attendance attendent attendant attendents attendants attened attended attension attention attitide attitude attributred attributed attrocities atrocities audeince audience auromated automated austrailia Australia austrailian Australian auther author authobiographic autobiographic authobiography autobiography authorative authoritative authorites authorities authorithy authority authoritiers authorities authoritive authoritative authrorities authorities autochtonous autochthonous autoctonous autochthonous automaticly automatically automibile automobile automonomous autonomous autor author autority authority auxilary auxiliary auxillaries auxiliaries auxillary auxiliary auxilliaries auxiliaries auxilliary auxiliary availablity availability availaible available availble available availiable available availible available avalable available avalance avalanche avaliable available avation aviation avengence a vengeance averageed averaged avilable available awared awarded awya away baceause because backgorund background backrounds backgrounds bakc back banannas bananas bandwith bandwidth bankrupcy bankruptcy banruptcy bankruptcy baout about, bout basicaly basically basicly basically bcak back beachead beachhead beacuse because beastiality bestiality beatiful beautiful beaurocracy bureaucracy beaurocratic bureaucratic beautyfull beautiful becamae became becasue because beccause because becomeing becoming becomming becoming becouse because becuase because bedore before befoer before beggin begin, begging begginer beginner begginers beginners beggining beginning begginings beginnings beggins begins begining beginning beginnig beginning behavour behavior, behaviour beleagured beleaguered beleif belief beleive believe beleived believed beleives believes beleiving believing beligum belgium belive believe belived believed belives believes, beliefs belligerant belligerent bellweather bellwether bemusemnt bemusement beneficary beneficiary beng being benificial beneficial benifit benefit benifits benefits bergamont bergamot Bernouilli Bernoulli beseige besiege beseiged besieged beseiging besieging betwen between beween between bewteen between bilateraly bilaterally billingualism bilingualism binominal binomial bizzare bizarre blaim blame blaimed blamed blessure blessing Blitzkreig Blitzkrieg boaut bout, boat, about bodydbuilder bodybuilder bombardement bombardment bombarment bombardment bondary boundary Bonnano Bonanno borke broke boundry boundary bouyancy buoyancy bouyant buoyant boyant buoyant Brasillian Brazilian breakthough breakthrough breakthroughts breakthroughs breif brief breifly briefly brethen brethren bretheren brethren briliant brilliant brillant brilliant brimestone brimstone Britian Britain Brittish British broacasted broadcast broadacasting broadcasting broady broadly Buddah Buddha buisness business buisnessman businessman buoancy buoyancy buring burying, burning, burin, during burried buried busineses business, businesses busness business bussiness business cacuses caucuses cahracters characters calaber caliber calander calendar, calender, colander calculs calculus calenders calendars caligraphy calligraphy caluclate calculate caluclated calculated caluculate calculate caluculated calculated calulate calculate calulated calculated Cambrige Cambridge camoflage camouflage campain campaign campains campaigns candadate candidate candiate candidate candidiate candidate cannister canister cannisters canisters cannnot cannot cannonical canonical cannotation connotation cannotations connotations cant cannot, can not, can't caost coast caperbility capability Capetown Cape Town capible capable captial capital captued captured capturd captured carachter character caracterized characterized carcas carcass, Caracas carefull careful careing caring carismatic charismatic Carmalite Carmelite carmel caramel, carmel-by-the-sea carniverous carnivorous carreer career carrers careers Carribbean Caribbean Carribean Caribbean cartdridge cartridge Carthagian Carthaginian carthographer cartographer cartilege cartilage cartilidge cartilage cartrige cartridge casette cassette casion caisson cassawory cassowary cassowarry cassowary casulaties casualties casulaty casualty catagories categories catagorized categorized catagory category catergorize categorize catergorized categorized Cataline Catiline, Catalina cathlic catholic catholocism catholicism catterpilar caterpillar catterpilars caterpillars cattleship battleship causalities casualties Ceasar Caesar Celcius Celsius cellpading cellpadding cementary cemetery cemetarey cemetery cemetaries cemeteries cemetary cemetery cencus census censur censor, censure cententenial centennial centruies centuries centruy century ceratin certain, keratin cerimonial ceremonial cerimonies ceremonies cerimonious ceremonious cerimony ceremony ceromony ceremony certainity certainty certian certain cervial cervical, servile, serval chalenging challenging challange challenge challanged challenged challege challenge Champange Champagne changable changeable charachter character charactor character charachters characters charactersistic characteristic charactors characters charasmatic charismatic charaterized characterized chariman chairman charistics characteristics chasr chaser, chase cheif chief chemcial chemical chemcially chemically chemestry chemistry chemicaly chemically childbird childbirth childen children choosen chosen chracter character chuch church churchs churches Cincinatti Cincinnati Cincinnatti Cincinnati circulaton circulation circumsicion circumcision circut circuit ciricuit circuit ciriculum curriculum civillian civilian claer clear claerer clearer claerly clearly claimes claims clas class clasic classic clasical classical clasically classically cleareance clearance clera clear, sclera clincial clinical clinicaly clinically cmo com cmoputer computer co-incided coincided coctail cocktail coform conform cognizent cognizant coincedentally coincidentally colaborations collaborations colateral collateral colelctive collective collaberative collaborative collecton collection collegue colleague collegues colleagues collonade colonnade collonies colonies collony colony collosal colossal colonizators colonizers comander commander, commandeer comando commando comandos commandos comany company comapany company comback comeback combanations combinations combinatins combinations combusion combustion comdemnation condemnation comemmorates commemorates comemoretion commemoration comision commission comisioned commissioned comisioner commissioner comisioning commissioning comisions commissions comission commission comissioned commissioned comissioner commissioner comissioning commissioning comissions commissions comited committed comiting committing comitted committed comittee committee comitting committing commandoes commandos commedic comedic commemerative commemorative commemmorate commemorate commemmorating commemorating commerical commercial commerically commercially commericial commercial commericially commercially commerorative commemorative comming coming comminication communication commision commission commisioned commissioned commisioner commissioner commisioning commissioning commisions commissions commited committed commitee committee commiting committing committe committee committment commitment committments commitments commmemorated commemorated commongly commonly commonweath commonwealth commuications communications commuinications communications communciation communication communiation communication communites communities compability compatibility comparision comparison comparisions comparisons comparitive comparative comparitively comparatively compatabilities compatibilities compatability compatibility compatable compatible compatablities compatibilities compatablity compatibility compatiable compatible compatiblities compatibilities compatiblity compatibility compeitions competitions compensantion compensation competance competence competant competent competative competitive competion competition, completion competitiion competition competive competitive competiveness competitiveness comphrehensive comprehensive compitent competent completedthe completed the completelyl completely completetion completion complier compiler componant component comprable comparable comprimise compromise compulsary compulsory compulsery compulsory computarized computerized concensus consensus concider consider concidered considered concidering considering conciders considers concieted conceited concieved conceived concious conscious conciously consciously conciousness consciousness condamned condemned condemmed condemned condidtion condition condidtions conditions conditionsof conditions of conected connected conection connection conesencus consensus confidental confidential confidentally confidentially confids confides configureable configurable confortable comfortable congradulations congratulations congresional congressional conived connived conjecutre conjecture conjuction conjunction Conneticut Connecticut conotations connotations conquerd conquered conquerer conqueror conquerers conquerors conqured conquered conscent consent consciouness consciousness consdider consider consdidered considered consdiered considered consectutive consecutive consenquently consequently consentrate concentrate consentrated concentrated consentrates concentrates consept concept consequentually consequently consequeseces consequences consern concern conserned concerned conserning concerning conservitive conservative consiciousness consciousness consicousness consciousness considerd considered consideres considered consious conscious consistant consistent consistantly consistently consituencies constituencies consituency constituency consituted constituted consitution constitution consitutional constitutional consolodate consolidate consolodated consolidated consonent consonant consonents consonants consorcium consortium conspiracys conspiracies conspiriator conspirator constaints constraints constanly constantly constarnation consternation constatn constant constinually continually constituant constituent constituants constituents constituion constitution constituional constitutional consttruction construction constuction construction consulant consultant consumate consummate consumated consummated contaiminate contaminate containes contains contamporaries contemporaries contamporary contemporary contempoary contemporary contemporaneus contemporaneous contempory contemporary contendor contender contined continued continous continuous continously continuously continueing continuing contravercial controversial contraversy controversy contributer contributor contributers contributors contritutions contributions controled controlled controling controlling controll control controlls controls controvercial controversial controvercy controversy controveries controversies controversal controversial controversey controversy controvertial controversial controvery controversy contruction construction conveinent convenient convenant covenant convential conventional convertables convertibles convertion conversion conveyer conveyor conviced convinced convienient convenient coordiantion coordination coorperation cooperation, corporation coorperations corporations copmetitors competitors coputer computer copywrite copyright coridal cordial cornmitted committed corosion corrosion corparate corporate corperations corporations correcters correctors correponding corresponding correposding corresponding correspondant correspondent correspondants correspondents corridoors corridors corrispond correspond corrispondant correspondent corrispondants correspondents corrisponded corresponded corrisponding corresponding corrisponds corresponds costitution constitution coucil council coudl could, cloud councellor councillor, counselor, councilor councellors councillors, counselors, councilors counries countries countains contains countires countries coururier courier, couturier coverted converted, covered, coveted cpoy coy, copy creaeted created creedence credence critereon criterion criterias criteria criticists critics critising criticising, criticizing critisising criticising critisism criticism critisisms criticisms critisize criticise, criticize critisized criticised, criticized critisizes criticises, criticizes critisizing criticising, criticizing critized criticized critizing criticizing crockodiles crocodiles crowm crown crtical critical crticised criticised crucifiction crucifixion crusies cruises crystalisation crystallisation culiminating culminating cumulatative cumulative curch church curcuit circuit currenly currently curriculem curriculum cxan cyan cyclinder cylinder dael deal, dial, dahl dalmation dalmatian damenor demeanor Dardenelles Dardanelles dacquiri daiquiri debateable debatable decendant descendant decendants descendants decendent descendant decendents descendants decideable decidable decidely decidedly decieved deceived decison decision decomissioned decommissioned decomposit decompose decomposited decomposed decompositing decomposing decomposits decomposes decress decrees decribe describe decribed described decribes describes decribing describing dectect detect defendent defendant defendents defendants deffensively defensively deffine define deffined defined definance defiance definate definite definately definitely definatly definitely definetly definitely definining defining definit definite definitly definitely definiton definition defintion definition degrate degrade delagates delegates delapidated dilapidated delerious delirious delevopment development deliberatly deliberately delusionally delusively demenor demeanor demographical demographic demolision demolition demorcracy democracy demostration demonstration denegrating denigrating densly densely deparment department deparments departments deparmental departmental dependance dependence dependancy dependency dependant dependent deram dram, dream deriviated derived derivitive derivative derogitory derogatory descendands descendants descibed described descision decision descisions decisions descriibes describes descripters descriptors descripton description desctruction destruction descuss discuss desgined designed deside decide desigining designing desinations destinations desintegrated disintegrated desintegration disintegration desireable desirable desitned destined desktiop desktop desorder disorder desoriented disoriented desparate desperate, disparate despatched dispatched despict depict despiration desperation dessicated desiccated dessigned designed destablized destabilized destory destroy detailled detailed detatched detached deteoriated deteriorated deteriate deteriorate deterioriating deteriorating determinining determining detremental detrimental devasted devastated develope develop developement development developped developed develpment development devels delves devestated devastated devestating devastating devide divide devided divided devistating devastating devolopement development diablical diabolical diamons diamonds diaster disaster dichtomy dichotomy diconnects disconnects dicover discover dicovered discovered dicovering discovering dicovers discovers dicovery discovery dicussed discussed didnt didn't diea idea, die dieing dying, dyeing dieties deities diety deity diferent different diferrent different differentiatiations differentiations differnt different difficulity difficulty diffrent different dificulties difficulties dificulty difficulty dimenions dimensions dimention dimension dimentional dimensional dimentions dimensions dimesnional dimensional diminuitive diminutive diosese diocese diphtong diphthong diphtongs diphthongs diplomancy diplomacy dipthong diphthong dipthongs diphthongs dirived derived disagreeed disagreed disapeared disappeared disapointing disappointing disappearred disappeared disaproval disapproval disasterous disastrous disatisfaction dissatisfaction disatisfied dissatisfied disatrous disastrous discontentment discontent discribe describe discribed described discribes describes discribing describing disctinction distinction disctinctive distinctive disemination dissemination disenchanged disenchanted disiplined disciplined disobediance disobedience disobediant disobedient disolved dissolved disover discover dispair despair disparingly disparagingly dispence dispense dispenced dispensed dispencing dispensing dispicable despicable dispite despite dispostion disposition disproportiate disproportionate disputandem disputandum disricts districts dissagreement disagreement dissapear disappear dissapearance disappearance dissapeared disappeared dissapearing disappearing dissapears disappears dissappear disappear dissappears disappears dissappointed disappointed dissarray disarray dissobediance disobedience dissobediant disobedient dissobedience disobedience dissobedient disobedient distiction distinction distingish distinguish distingished distinguished distingishes distinguishes distingishing distinguishing distingquished distinguished distrubution distribution distruction destruction distructive destructive ditributed distributed diversed diverse, diverged divice device divison division divisons divisions doccument document doccumented documented doccuments documents docrines doctrines doctines doctrines documenatry documentary doens does doesnt doesn't doign doing dominaton domination dominent dominant dominiant dominant donig doing dosen't doesn't doub doubt, daub doulbe double dowloads downloads dramtic dramatic draughtman draughtsman Dravadian Dravidian dreasm dreams driectly directly drnik drink druming drumming drummless drumless dupicate duplicate durig during durring during duting during dyas dryas eahc each ealier earlier earlies earliest earnt earned ecclectic eclectic eceonomy economy ecidious deciduous eclispe eclipse ecomonic economic ect etc eearly early efel evil effeciency efficiency effecient efficient effeciently efficiently efficency efficiency efficent efficient efficently efficiently efford effort, afford effords efforts, affords effulence effluence eigth eighth, eight eiter either elction election electic eclectic, electric electon election, electron electrial electrical electricly electrically electricty electricity elementay elementary eleminated eliminated eleminating eliminating eles eels eletricity electricity elicided elicited eligable eligible elimentary elementary ellected elected elphant elephant embarass embarrass embarassed embarrassed embarassing embarrassing embarassment embarrassment embargos embargoes embarras embarrass embarrased embarrassed embarrasing embarrassing embarrasment embarrassment embezelled embezzled emblamatic emblematic eminate emanate eminated emanated emision emission emited emitted emiting emitting emition emission, emotion emmediately immediately emmigrated emigrated emminent eminent, imminent emminently eminently emmisaries emissaries emmisarries emissaries emmisarry emissary emmisary emissary emmision emission emmisions emissions emmited emitted emmiting emitting emmitted emitted emmitting emitting emnity enmity emperical empirical emphaised emphasised emphsis emphasis emphysyma emphysema empirial empirical, imperial emprisoned imprisoned enameld enameled enchancement enhancement encouraing encouraging encryptiion encryption encylopedia encyclopedia endevors endeavors endevour endeavour endig ending endolithes endoliths enduce induce ened need enflamed inflamed enforceing enforcing engagment engagement engeneer engineer engeneering engineering engieneer engineer engieneers engineers enlargment enlargement enlargments enlargements Enlish English, enlist enourmous enormous enourmously enormously ensconsed ensconced entaglements entanglements enteratinment entertainment entitity entity entitlied entitled entrepeneur entrepreneur entrepeneurs entrepreneurs enviorment environment enviormental environmental enviormentally environmentally enviorments environments enviornment environment enviornmental environmental enviornmentalist environmentalist enviornmentally environmentally enviornments environments enviroment environment enviromental environmental enviromentalist environmentalist enviromentally environmentally enviroments environments envolutionary evolutionary envrionments environments enxt next epidsodes episodes epsiode episode equialent equivalent equilibium equilibrium equilibrum equilibrium equiped equipped equippment equipment equitorial equatorial equivelant equivalent equivelent equivalent equivilant equivalent equivilent equivalent equivlalent equivalent erally orally, really eratic erratic eratically erratically eraticly erratically erested arrested, erected errupted erupted esential essential esitmated estimated esle else especialy especially essencial essential essense essence essentail essential essentialy essentially essentual essential essesital essential estabishes establishes establising establishing ethnocentricm ethnocentrism ethose those, ethos Europian European Europians Europeans Eurpean European Eurpoean European evenhtually eventually eventally eventually eventially eventually eventualy eventually everthing everything everytime every time everyting everything eveyr every evidentally evidently exagerate exaggerate exagerated exaggerated exagerates exaggerates exagerating exaggerating exagerrate exaggerate exagerrated exaggerated exagerrates exaggerates exagerrating exaggerating examinated examined exampt exempt exapansion expansion excact exact excange exchange excecute execute excecuted executed excecutes executes excecuting executing excecution execution excedded exceeded excelent excellent excell excel excellance excellence excellant excellent excells excels excercise exercise exchanching exchanging excisted existed exculsivly exclusively execising exercising exection execution exectued executed exeedingly exceedingly exelent excellent exellent excellent exemple example exept except exeptional exceptional exerbate exacerbate exerbated exacerbated exerciese exercises exerpt excerpt exerpts excerpts exersize exercise exerternal external exhalted exalted exhibtion exhibition exibition exhibition exibitions exhibitions exicting exciting exinct extinct existance existence existant existent existince existence exliled exiled exludes excludes exmaple example exonorate exonerate exoskelaton exoskeleton expalin explain expeced expected expecially especially expeditonary expeditionary expeiments experiments expell expel expells expels experiance experience experianced experienced expiditions expeditions expierence experience explaination explanation explaning explaining explictly explicitly exploititive exploitative explotation exploitation expropiated expropriated expropiation expropriation exressed expressed extemely extremely extention extension extentions extensions extered exerted extermist extremist extint extinct, extant extradiction extradition extraterrestial extraterrestrial extraterrestials extraterrestrials extravagent extravagant extrememly extremely extremeophile extremophile extremly extremely extrordinarily extraordinarily extrordinary extraordinary eyar year, eyas eyars years, eyas eyasr years, eyas faciliate facilitate faciliated facilitated faciliates facilitates facilites facilities facillitate facilitate facinated fascinated facist fascist familes families familliar familiar famoust famous fanatism fanaticism Farenheit Fahrenheit fatc fact faught fought favoutrable favourable feasable feasible Febuary February fedreally federally feromone pheromone fertily fertility fianite finite fianlly finally ficticious fictitious fictious fictitious fidn find fiel feel, field, file, phial fiels feels, fields, files, phials fiercly fiercely fightings fighting filiament filament fimilies families finacial financial finaly finally financialy financially firends friends firts flirts, first fisionable fissionable flamable flammable flawess flawless fleed fled, freed Flemmish Flemish florescent fluorescent flourescent fluorescent fluorish flourish follwoing following folowing following fomed formed fomr from, form fonetic phonetic fontrier fontier foootball football forbad forbade forbiden forbidden foreward foreword forfiet forfeit forhead forehead foriegn foreign Formalhaut Fomalhaut formallize formalize formallized formalized formaly formally formelly formerly formidible formidable formost foremost forsaw foresaw forseeable foreseeable fortelling foretelling forunner forerunner foucs focus foudn found fougth fought foundaries foundries foundary foundry Foundland Newfoundland fourties forties fourty forty fouth fourth foward forward fucntion function fucntioning functioning Fransiscan Franciscan Fransiscans Franciscans freind friend freindly friendly frequentily frequently frome from fromed formed froniter frontier fufill fulfill fufilled fulfilled fulfiled fulfilled fundametal fundamental fundametals fundamentals funguses fungi funtion function furuther further futher further futhermore furthermore futhroc futhark, futhorc gae game, Gael, gale galatic galactic Galations Galatians gallaxies galaxies galvinized galvanized Gameboy Game Boy ganerate generate ganes games ganster gangster garantee guarantee garanteed guaranteed garantees guarantees garnison garrison gauarana guaraná gaurantee guarantee gauranteed guaranteed gaurantees guarantees gaurd guard, gourd gaurentee guarantee gaurenteed guaranteed gaurentees guarantees geneological genealogical geneologies genealogies geneology genealogy generaly generally generatting generating genialia genitalia geographicial geographical geometrician geometer geometricians geometers gerat great Ghandi Gandhi glight flight gnawwed gnawed godess goddess godesses goddesses Godounov Godunov gogin going, Gauguin goign going gonig going Gothenberg Gothenburg Gottleib Gottlieb gouvener governor govement government govenment government govenrment government goverance governance goverment government govermental governmental governer governor governmnet government govorment government govormental governmental govornment government gracefull graceful graet great grafitti graffiti gramatically grammatically grammaticaly grammatically grammer grammar grat great gratuitious gratuitous greatful grateful greatfully gratefully greif grief gridles griddles gropu group grwo grow Guaduloupe Guadalupe, Guadeloupe Guadulupe Guadalupe, Guadeloupe guage gauge guarentee guarantee guarenteed guaranteed guarentees guarantees Guatamala Guatemala Guatamalan Guatemalan guerilla guerrilla guerillas guerrillas guerrila guerrilla guerrilas guerrillas guidence guidance Guilia Giulia Guilio Giulio Guiness Guinness Guiseppe Giuseppe gunanine guanine gurantee guarantee guranteed guaranteed gurantees guarantees guttaral guttural gutteral guttural habaeus habeas habeus habeas Habsbourg Habsburg haemorrage haemorrhage haev have, heave Hallowean Hallowe'en, Halloween halp help hapen happen hapened happened hapening happening happend happened happended happened happenned happened harased harassed harases harasses harasment harassment harasments harassments harassement harassment harras harass harrased harassed harrases harasses harrasing harassing harrasment harassment harrasments harassments harrassed harassed harrasses harassed harrassing harassing harrassment harassment harrassments harassments hasnt hasn't haviest heaviest headquater headquarter headquarer headquarter headquatered headquartered headquaters headquarters healthercare healthcare heared heard heathy healthy Heidelburg Heidelberg heigher higher heirarchy hierarchy heiroglyphics hieroglyphics helment helmet helpfull helpful helpped helped hemmorhage hemorrhage herad heard, Hera heridity heredity heroe hero heros heroes hertzs hertz hesistant hesitant heterogenous heterogeneous hieght height hierachical hierarchical hierachies hierarchies hierachy hierarchy hierarcical hierarchical hierarcy hierarchy hieroglph hieroglyph hieroglphs hieroglyphs higer higher higest highest higway highway hillarious hilarious himselv himself hinderance hindrance hinderence hindrance hindrence hindrance hipopotamus hippopotamus hismelf himself histocompatability histocompatibility historicians historians hitsingles hit singles holliday holiday homestate home state homogeneize homogenize homogeneized homogenized honory honorary horrifing horrifying hosited hoisted hospitible hospitable hounour honour housr hours, house howver however hsitorians historians hstory history hten then, hen, the htere there, here htey they htikn think hting thing htink think htis this humer humor, humour humerous humorous, humerus huminoid humanoid humoural humoral humurous humorous husban husband hvae have hvaing having hvea have, heave hwihc which hwile while hwole whole hydogen hydrogen hydropile hydrophile hydropilic hydrophilic hydropobe hydrophobe hydropobic hydrophobic hygeine hygiene hypocracy hypocrisy hypocrasy hypocrisy hypocricy hypocrisy hypocrit hypocrite hypocrits hypocrites iconclastic iconoclastic idaeidae idea idaes ideas idealogies ideologies idealogy ideology identicial identical identifers identifiers ideosyncratic idiosyncratic idesa ideas, ides idiosyncracy idiosyncrasy Ihaca Ithaca illegimacy illegitimacy illegitmate illegitimate illess illness illiegal illegal illution illusion ilness illness ilogical illogical imagenary imaginary imagin imagine imaginery imaginary, imagery imanent eminent, imminent imcomplete incomplete imediately immediately imense immense imigrant emigrant, immigrant imigrated emigrated, immigrated imigration emigration, immigration iminent eminent, imminent, immanent immediatley immediately immediatly immediately immidately immediately immidiately immediately immitate imitate immitated imitated immitating imitating immitator imitator immunosupressant immunosuppressant impecabbly impeccably impedence impedance implamenting implementing impliment implement implimented implemented imploys employs importamt important imprioned imprisoned imprisonned imprisoned improvision improvisation improvments improvements inablility inability inaccessable inaccessible inadiquate inadequate inadquate inadequate inadvertant inadvertent inadvertantly inadvertently inagurated inaugurated inaguration inauguration inappropiate inappropriate inaugures inaugurates inbalance imbalance inbalanced imbalanced inbetween between incarcirated incarcerated incidentially incidentally incidently incidentally inclreased increased includ include includng including incompatabilities incompatibilities incompatability incompatibility incompatable incompatible incompatablities incompatibilities incompatablity incompatibility incompatiblities incompatibilities incompatiblity incompatibility incompetance incompetence incompetant incompetent incomptable incompatible incomptetent incompetent inconsistant inconsistent incorperation incorporation incorportaed incorporated incorprates incorporates incorruptable incorruptible incramentally incrementally increadible incredible incredable incredible inctroduce introduce inctroduced introduced incuding including incunabla incunabula indefinately indefinitely indefineable undefinable indefinitly indefinitely indentical identical indepedantly independently indepedence independence independance independence independant independent independantly independently independece independence independendet independent indictement indictment indigineous indigenous indipendence independence indipendent independent indipendently independently indespensible indispensable indespensable indispensable indispensible indispensable indisputible indisputable indisputibly indisputably indite indict individualy individually indpendent independent indpendently independently indulgue indulge indutrial industrial indviduals individuals inefficienty inefficiently inevatible inevitable inevitible inevitable inevititably inevitably infalability infallibility infallable infallible infectuous infectious infered inferred infilitrate infiltrate infilitrated infiltrated infilitration infiltration infinit infinite inflamation inflammation influencial influential influented influenced infomation information informtion information infrantryman infantryman infrigement infringement ingenius ingenious ingreediants ingredients inhabitans inhabitants inherantly inherently inheritage heritage, inheritance inheritence inheritance inital initial initally initially initation initiation initiaitive initiative inlcuding including inmigrant immigrant inmigrants immigrants innoculated inoculated inocence innocence inofficial unofficial inot into inpeach impeach inpolite impolite inprisonment imprisonment inproving improving insectiverous insectivorous insensative insensitive inseperable inseparable insistance insistence insitution institution insitutions institutions inspite in spite, inspire instade instead instatance instance institue institute instuction instruction instuments instruments instutionalized institutionalized instutions intuitions insurence insurance intelectual intellectual inteligence intelligence inteligent intelligent intenational international intepretation interpretation intepretator interpretor interational international interbread interbreed, interbred interchangable interchangeable interchangably interchangeably intercontinetal intercontinental intered interred, interned interelated interrelated interferance interference interfereing interfering intergrated integrated intergration integration interm interim internation international interpet interpret interrim interim interrugum interregnum intertaining entertaining interupt interrupt intervines intervenes intevene intervene intial initial intially initially intrduced introduced intrest interest introdued introduced intruduced introduced intrusted entrusted intutive intuitive intutively intuitively inudstry industry inumerable enumerable, innumerable inventer inventor invertibrates invertebrates investingate investigate involvment involvement irelevent irrelevant iresistable irresistible iresistably irresistibly iresistible irresistible iresistibly irresistibly iritable irritable iritated irritated ironicly ironically irregardless regardless irrelevent irrelevant irreplacable irreplaceable irresistable irresistible irresistably irresistibly isnt isn't Israelies Israelis issueing issuing itnroduced introduced iunior junior iwll will iwth with Japanes Japanese jaques jacques jeapardy jeopardy jewllery jewellery Johanine Johannine Jospeh Joseph jouney journey journied journeyed journies journeys jstu just jsut just Juadaism Judaism Juadism Judaism judical judicial judisuary judiciary juducial judicial juristiction jurisdiction juristictions jurisdictions kindergarden kindergarten klenex kleenex knifes knives knive knife knowlege knowledge knowlegeable knowledgeable knwo know knwos knows konw know konws knows kwno know labatory lavatory, laboratory labled labelled, labeled labratory laboratory laguage language laguages languages larg large largst largest larrry larry lastr last lattitude latitude launchs launch launhed launched lavae larvae layed laid lazyness laziness leaded led leage league leanr lean, learn, leaner leathal lethal lefted left legitamate legitimate legitmate legitimate leibnitz leibniz lenght length leran learn lerans learns lieuenant lieutenant leutenant lieutenant levetate levitate levetated levitated levetates levitates levetating levitating levle level liasion liaison liason liaison liasons liaisons libary library libell libel libguistic linguistic libguistics linguistics libitarianisn libertarianism lible libel, liable lieing lying liek like liekd liked liesure leisure lieved lived liftime lifetime lightyear light year lightyears light years likelyhood likelihood linnaena linnaean lippizaner lipizzaner liquify liquefy liscense license, licence lisence license, licence lisense license, licence listners listeners litature literature literture literature littel little litterally literally liuke like livley lively lmits limits loev love lonelyness loneliness longitudonal longitudinal lonley lonely lonly lonely, only loosing losing lotharingen lothringen lsat last lukid likud lveo love lvoe love Lybia Libya mackeral mackerel magasine magazine magincian magician magnificient magnificent magolia magnolia mailny mainly maintainance maintenance maintainence maintenance maintance maintenance maintenence maintenance maintinaing maintaining maintioned mentioned majoroty majority maked marked, made makse makes Malcom Malcolm maltesian Maltese mamal mammal mamalian mammalian managable manageable, manageably managment management manisfestations manifestations manoeuverability maneuverability manouver maneuver, manoeuvre manouverability maneuverability, manoeuvrability, manoeuverability manouverable maneuverable, manoeuvrable manouvers maneuvers, manoeuvres mantained maintained manuever maneuver, manoeuvre manuevers maneuvers, manoeuvres manufacturedd manufactured manufature manufacture manufatured manufactured manufaturing manufacturing manuver maneuver mariage marriage marjority majority markes marks marketting marketing marmelade marmalade marrage marriage marraige marriage marrtyred martyred marryied married Massachussets Massachusetts Massachussetts Massachusetts massmedia mass media masterbation masturbation mataphysical metaphysical materalists materialist mathamatics mathematics mathematican mathematician mathematicas mathematics matheticians mathematicians mathmatically mathematically mathmatician mathematician mathmaticians mathematicians mccarthyst mccarthyist mchanics mechanics meaninng meaning mear wear, mere, mare mechandise merchandise medacine medicine medeival medieval medevial medieval mediciney mediciny medievel medieval mediterainnean mediterranean Mediteranean Mediterranean meerkrat meerkat melieux milieux membranaphone membranophone memeber member menally mentally meranda veranda, Miranda mercentile mercantile messanger messenger messenging messaging metalic metallic metalurgic metallurgic metalurgical metallurgical metalurgy metallurgy metamorphysis metamorphosis metaphoricial metaphorical meterologist meteorologist meterology meteorology methaphor metaphor methaphors metaphors Michagan Michigan micoscopy microscopy midwifes midwives mileau milieu milennia millennia milennium millennium mileu milieu miliary military milion million miliraty military millenia millennia millenial millennial millenialism millennialism millenium millennium millepede millipede millioniare millionaire millitary military millon million miltary military minature miniature minerial mineral miniscule minuscule ministery ministry minstries ministries minstry ministry minumum minimum mirrorred mirrored miscelaneous miscellaneous miscellanious miscellaneous miscellanous miscellaneous mischeivous mischievous mischevious mischievous mischievious mischievous misdameanor misdemeanor misdameanors misdemeanors misdemenor misdemeanor misdemenors misdemeanors misfourtunes misfortunes misile missile Misouri Missouri mispell misspell mispelled misspelled mispelling misspelling missen mizzen Missisipi Mississippi Missisippi Mississippi missle missile missonary missionary misterious mysterious mistery mystery misteryous mysterious mkae make mkaes makes mkaing making mkea make moderm modem modle model moent moment moeny money mohammedans muslims moil mohel moleclues molecules momento memento monestaries monasteries monestary monastery, monetary monickers monikers monolite monolithic Monserrat Montserrat montains mountains montanous mountainous monts months montypic monotypic moreso more, more so morgage mortgage Morisette Morissette Morrisette Morissette morroccan moroccan morrocco morocco morroco morocco mosture moisture motiviated motivated mounth month movei movie movment movement mroe more mucuous mucous muder murder mudering murdering muhammadan muslim multicultralism multiculturalism multipled multiplied multiplers multipliers munbers numbers muncipalities municipalities muncipality municipality munnicipality municipality muscels mussels, muscles muscial musical muscician musician muscicians musicians mutiliated mutilated myraid myriad mysef myself mysogynist misogynist mysogyny misogyny mysterous mysterious Mythraic Mithraic naieve naive Napoleonian Napoleonic naturaly naturally naturely naturally naturual natural naturually naturally Nazereth Nazareth neccesarily necessarily neccesary necessary neccessarily necessarily neccessary necessary neccessities necessities necesarily necessarily necesary necessary necessiate necessitate neglible negligible negligable negligible negociate negotiate negociation negotiation negociations negotiations negotation negotiation neice niece, nice neigborhood neighborhood neigbour neighbour, neighbor neigbourhood neighbourhood neigbouring neighbouring, neighboring neigbours neighbours, neighbors neolitic neolithic nessasarily necessarily nessecary necessary nestin nesting neverthless nevertheless newletters newsletters Newyorker New Yorker nickle nickel nightfa;; nightfall nightime nighttime nineth ninth ninteenth nineteenth ninties 1990s ninty ninety nkow know nkwo know nmae name noncombatents noncombatants nonsence nonsense nontheless nonetheless noone no one norhern northern northen northern northereastern northeastern notabley notably noteable notable noteably notably noteriety notoriety noth north nothern northern noticable noticeable noticably noticeably noticeing noticing noticible noticeable notwhithstanding notwithstanding noveau nouveau nowdays nowadays nowe now nto not nucular nuclear nuculear nuclear nuisanse nuisance Nullabour Nullarbor numberous numerous Nuremburg Nuremberg nusance nuisance nutritent nutrient nutritents nutrients nuturing nurturing obediance obedience obediant obedient obession obsession obssessed obsessed obstacal obstacle obstancles obstacles obstruced obstructed ocasion occasion ocasional occasional ocasionally occasionally ocasionaly occasionally ocasioned occasioned ocasions occasions ocassion occasion ocassional occasional ocassionally occasionally ocassionaly occasionally ocassioned occasioned ocassions occasions occaison occasion occassion occasion occassional occasional occassionally occasionally occassionaly occasionally occassioned occasioned occassions occasions occationally occasionally occour occur occurance occurrence occurances occurrences occured occurred occurence occurrence occurences occurrences occuring occurring occurr occur occurrance occurrence occurrances occurrences octohedra octahedra octohedral octahedral octohedron octahedron ocuntries countries ocuntry country ocurr occur ocurrance occurrence ocurred occurred ocurrence occurrence offcers officers offcially officially offereings offerings offical official officals officials offically officially officaly officially officialy officially offred offered oftenly often oging going, ogling omision omission omited omitted omiting omitting omlette omelette ommision omission ommited omitted ommiting omitting ommitted omitted ommitting omitting omniverous omnivorous omniverously omnivorously omre more onot note, not onyl only openess openness oponent opponent oportunity opportunity opose oppose oposite opposite oposition opposition oppenly openly oppinion opinion opponant opponent oppononent opponent oppositition opposition oppossed opposed opprotunity opportunity opression oppression opressive oppressive opthalmic ophthalmic opthalmologist ophthalmologist opthalmology ophthalmology opthamologist ophthalmologist optmizations optimizations optomism optimism orded ordered organim organism organiztion organization orgin origin, organ orginal original orginally originally orginize organise oridinarily ordinarily origanaly originally originall original, originally originaly originally originially originally originnally originally origional original orignally originally orignially originally otehr other ouevre oeuvre overshaddowed overshadowed overthere over there overwelming overwhelming overwheliming overwhelming owrk work owudl would oxigen oxygen oximoron oxymoron paide paid paitience patience palce place, palace paleolitic paleolithic paliamentarian parliamentarian Palistian Palestinian Palistinian Palestinian Palistinians Palestinians pallete palette pamflet pamphlet pamplet pamphlet pantomine pantomime Papanicalou Papanicolaou paralel parallel paralell parallel paralelly parallelly paralely parallelly parallely parallelly paranthesis parenthesis paraphenalia paraphernalia parellels parallels parituclar particular parliment parliament parrakeets parakeets parralel parallel parrallel parallel parrallell parallel parrallelly parallelly parrallely parallelly partialy partially particually particularly particualr particular particuarly particularly particularily particularly particulary particularly pary party pased passed pasengers passengers passerbys passersby pasttime pastime pastural pastoral paticular particular pattented patented pavillion pavilion payed paid peacefuland peaceful and peageant pageant peculure peculiar pedestrain pedestrian peice piece Peloponnes Peloponnesus penatly penalty penerator penetrator penisula peninsula penisular peninsular penninsula peninsula penninsular peninsular pennisula peninsula pensinula peninsula peom poem peoms poems peopel people peotry poetry perade parade percepted perceived percieve perceive percieved perceived perenially perennially perfomers performers performence performance performes performed, performs perhasp perhaps perheaps perhaps perhpas perhaps peripathetic peripatetic peristent persistent perjery perjury perjorative pejorative permanant permanent permenant permanent permenantly permanently permissable permissible perogative prerogative peronal personal perosnality personality perphas perhaps perpindicular perpendicular perseverence perseverance persistance persistence persistant persistent personel personnel, personal personell personnel personnell personnel persuded persuaded persue pursue persued pursued persuing pursuing persuit pursuit persuits pursuits pertubation perturbation pertubations perturbations pessiary pessary petetion petition Pharoah Pharaoh phenomenom phenomenon phenomenonal phenomenal phenomenonly phenomenally phenomonenon phenomenon phenomonon phenomenon phenonmena phenomena Philipines Philippines philisopher philosopher philisophical philosophical philisophy philosophy Phillipine Philippine Phillipines Philippines Phillippines Philippines phillosophically philosophically philospher philosopher philosphies philosophies philosphy philosophy Phonecian Phoenecian phongraph phonograph phylosophical philosophical physicaly physically pich pitch pilgrimmage pilgrimage pilgrimmages pilgrimages pinapple pineapple pinnaple pineapple pinoneered pioneered plagarism plagiarism planation plantation planed planned plantiff plaintiff plateu plateau plausable plausible playright playwright playwrite playwright playwrites playwrights pleasent pleasant plebicite plebiscite plesant pleasant poeoples peoples poety poetry poisin poison polical political polinator pollinator polinators pollinators politican politician politicans politicians poltical political polute pollute poluted polluted polutes pollutes poluting polluting polution pollution polyphonyic polyphonic polysaccaride polysaccharide polysaccharid polysaccharide pomegranite pomegranate pomotion promotion poportional proportional popoulation population popularaty popularity populare popular populer popular portayed portrayed portraing portraying Portugese Portuguese portuguease portuguese posess possess posessed possessed posesses possesses posessing possessing posession possession posessions possessions posion poison positon position, positron possable possible possably possibly posseses possesses possesing possessing possesion possession possessess possesses possibile possible possibilty possibility possiblility possibility possiblilty possibility possiblities possibilities possiblity possibility possition position Postdam Potsdam posthomous posthumous postion position postive positive potatos potatoes portait portrait potrait portrait potrayed portrayed poulations populations poverful powerful poweful powerful powerfull powerful practial practical practially practically practicaly practically practicioner practitioner practicioners practitioners practicly practically practioner practitioner practioners practitioners prairy prairie prarie prairie praries prairies pratice practice preample preamble precedessor predecessor preceed precede preceeded preceded preceeding preceding preceeds precedes precentage percentage precice precise precisly precisely precurser precursor predecesors predecessors predicatble predictable predicitons predictions predomiantly predominately prefered preferred prefering preferring preferrably preferably pregancies pregnancies preiod period preliferation proliferation premeire premiere premeired premiered premillenial premillennial preminence preeminence premission permission Premonasterians Premonstratensians preocupation preoccupation prepair prepare prepartion preparation prepatory preparatory preperation preparation preperations preparations preriod period presedential presidential presense presence presidenital presidential presidental presidential presitgious prestigious prespective perspective prestigeous prestigious prestigous prestigious presumabely presumably presumibly presumably pretection protection prevelant prevalent preverse perverse previvous previous pricipal principal priciple principle priestood priesthood primarly primarily primative primitive primatively primitively primatives primitives primordal primordial priveledges privileges privelege privilege priveleged privileged priveleges privileges privelige privilege priveliged privileged priveliges privileges privelleges privileges privilage privilege priviledge privilege priviledges privileges privledge privilege privte private probabilaty probability probablistic probabilistic probablly probably probalibity probability probaly probably probelm problem proccess process proccessing processing procede proceed, precede proceded proceeded, preceded procedes proceeds, precedes procedger procedure proceding proceeding, preceding procedings proceedings proceedure procedure proces process processer processor proclaimation proclamation proclamed proclaimed proclaming proclaiming proclomation proclamation profesion profusion, profession profesor professor professer professor proffesed professed proffesion profession proffesional professional proffesor professor profilic prolific progessed progressed programable programmable progrom pogrom, program progroms pogroms, programs prohabition prohibition prologomena prolegomena prominance prominence prominant prominent prominantly prominently prominately prominently, predominately promiscous promiscuous promotted promoted pronomial pronominal pronouced pronounced pronounched pronounced pronounciation pronunciation proove prove prooved proved prophacy prophecy propietary proprietary propmted prompted propoganda propaganda propogate propagate propogates propagates propogation propagation propostion proposition propotions proportions propper proper propperly properly proprietory proprietary proseletyzing proselytizing protaganist protagonist protaganists protagonists protocal protocol protoganist protagonist protrayed portrayed protruberance protuberance protruberances protuberances prouncements pronouncements provacative provocative provded provided provicial provincial provinicial provincial provisonal provisional provisiosn provision proximty proximity pseudononymous pseudonymous pseudonyn pseudonym psuedo pseudo psycology psychology psyhic psychic publicaly publicly puchasing purchasing Pucini Puccini Puertorrican Puerto Rican Puertorricans Puerto Ricans pumkin pumpkin puritannical puritanical purposedly purposely purpotedly purportedly pursuade persuade pursuaded persuaded pursuades persuades pususading persuading puting putting pwoer power pyscic psychic qtuie quite, quiet quantaty quantity quantitiy quantity quarantaine quarantine Queenland Queensland questonable questionable quicklyu quickly quinessential quintessential quitted quit quizes quizzes qutie quite, quiet rabinnical rabbinical racaus raucous radiactive radioactive radify ratify raelly really rarified rarefied reaccurring recurring reacing reaching reacll recall readmition readmission realitvely relatively realsitic realistic realtions relations realy really realyl really reasearch research rebiulding rebuilding rebllions rebellions rebounce rebound reccomend recommend reccomendations recommendations reccomended recommended reccomending recommending reccommend recommend reccommended recommended reccommending recommending reccuring recurring receeded receded receeding receding receivedfrom received from recepient recipient recepients recipients receving receiving rechargable rechargeable reched reached recide reside recided resided recident resident recidents residents reciding residing reciepents recipients reciept receipt recieve receive recieved received reciever receiver recievers receivers recieves receives recieving receiving recipiant recipient recipiants recipients recived received recivership receivership recogise recognise recogize recognize recomend recommend recomended recommended recomending recommending recomends recommends recommedations recommendations reconaissance reconnaissance reconcilation reconciliation reconized recognized reconnaissence reconnaissance recontructed reconstructed recordproducer record producer recquired required recrational recreational recrod record recuiting recruiting recuring recurring recurrance recurrence rediculous ridiculous reedeming redeeming reenforced reinforced refect reflect refedendum referendum referal referral refered referred referiang referring refering referring refernces references referrence reference referrs refers reffered referred refference reference refrence reference refrences references refrers refers refridgeration refrigeration refridgerator refrigerator refromist reformist refusla refusal regardes regards regluar regular reguarly regularly regulaion regulation regulaotrs regulators regularily regularly rehersal rehearsal reicarnation reincarnation reigining reigning reknown renown reknowned renowned rela real relaly really relatiopnship relationship relativly relatively relected reelected releive relieve releived relieved releiver reliever releses releases relevence relevance relevent relevant reliablity reliability relient reliant religeous religious religous religious religously religiously relinqushment relinquishment relitavely relatively relized realised, realized relpacement replacement remaing remaining remeber remember rememberable memorable rememberance remembrance remembrence remembrance remenant remnant remenicent reminiscent reminent remnant reminescent reminiscent reminscent reminiscent reminsicent reminiscent rendevous rendezvous rendezous rendezvous renedered rende renewl renewal rentors renters reoccurrence recurrence reorganision reorganisation repatition repetition, repartition repentence repentance repentent repentant repeteadly repeatedly repetion repetition repid rapid reponse response reponsible responsible reportadly reportedly represantative representative representive representative representives representatives reproducable reproducible reprtoire repertoire repsectively respectively reptition repetition requirment requirement requred required resaurant restaurant resembelance resemblance resembes resembles resemblence resemblance resevoir reservoir resignement resignment resistable resistible resistence resistance resistent resistant respectivly respectively responce response responibilities responsibilities responisble responsible responnsibilty responsibility responsability responsibility responsibile responsible responsibilites responsibilities responsiblity responsibility ressemblance resemblance ressemble resemble ressembled resembled ressemblence resemblance ressembling resembling resssurecting resurrecting ressurect resurrect ressurected resurrected ressurection resurrection ressurrection resurrection restaraunt restaurant restaraunteur restaurateur restaraunteurs restaurateurs restaraunts restaurants restauranteurs restaurateurs restauration restoration restauraunt restaurant resteraunt restaurant resteraunts restaurants resticted restricted restraunt restraint, restaurant resturant restaurant resturaunt restaurant resurecting resurrecting retalitated retaliated retalitation retaliation retreive retrieve returnd returned revaluated reevaluated reveral reversal reversable reversible revolutionar revolutionary rewitten rewritten rewriet rewrite rhymme rhyme rhythem rhythm rhythim rhythm rhytmic rhythmic rigeur rigueur, rigour, rigor rigourous rigorous rininging ringing rised rose Rockerfeller Rockefeller rococco rococo rocord record roomate roommate rougly roughly rucuperate recuperate rudimentatry rudimentary rulle rule runing running runnung running russina Russian Russion Russian rwite write rythem rhythm rythim rhythm rythm rhythm rythmic rhythmic rythyms rhythms sacrafice sacrifice sacreligious sacrilegious sacrifical sacrificial saftey safety safty safety salery salary sanctionning sanctioning sandwhich sandwich Sanhedrim Sanhedrin santioned sanctioned sargant sergeant sargeant sergeant sasy says, sassy satelite satellite satelites satellites Saterday Saturday Saterdays Saturdays satisfactority satisfactorily satric satiric satrical satirical satrically satirically sattelite satellite sattelites satellites saught sought saveing saving saxaphone saxophone scaleable scalable scandanavia Scandinavia scaricity scarcity scavanged scavenged schedual schedule scholarhip scholarship scholarstic scholastic, scholarly scientfic scientific scientifc scientific scientis scientist scince science scinece science scirpt script scoll scroll screenwrighter screenwriter scrutinity scrutiny scuptures sculptures seach search seached searched seaches searches secceeded seceded, succeeded seceed succeed, secede seceeded succeeded, seceded secratary secretary secretery secretary sedereal sidereal seeked sought segementation segmentation seguoys segues seige siege seing seeing seinor senior seldomly seldom senarios scenarios sence sense senstive sensitive sensure censure seperate separate seperated separated seperately separately seperates separates seperating separating seperation separation seperatism separatism seperatist separatist sepina subpoena sepulchure sepulchre, sepulcher sepulcre sepulchre, sepulcher sergent sergeant settelement settlement settlment settlement severeal several severley severely severly severely sevice service shaddow shadow shamen shaman, shamans sheat sheath, sheet, cheat sheild shield sherif sheriff shineing shining shiped shipped shiping shipping shopkeeepers shopkeepers shorly shortly shortwhile short while shoudl should shoudln should, shouldn't shouldnt shouldn't shreak shriek shrinked shrunk sicne since sideral sidereal sieze seize, size siezed seized, sized siezing seizing, sizing siezure seizure siezures seizures siginificant significant signficant significant signficiant significant signfies signifies signifantly significantly significently significantly signifigant significant signifigantly significantly signitories signatories signitory signatory similarily similarly similiar similar similiarity similarity similiarly similarly simmilar similar simpley simply simplier simpler simultanous simultaneous simultanously simultaneously sincerley sincerely singsog singsong sinse sines, since Sionist Zionist Sionists Zionists Sixtin Sistine Skagerak Skagerrak skateing skating slaugterhouses slaughterhouses slowy slowly smae same smealting smelting smoe some sneeks sneaks snese sneeze socalism socialism socities societies soem some sofware software sohw show soilders soldiers solatary solitary soley solely soliders soldiers soliliquy soliloquy soluable soluble somene someone somtimes sometimes somwhere somewhere sophicated sophisticated sorceror sorcerer sorrounding surrounding sotry story sotyr satyr, story soudn sound soudns sounds sould could, should, sold sountrack soundtrack sourth south sourthern southern souvenier souvenir souveniers souvenirs soveits soviets sovereignity sovereignty soverign sovereign soverignity sovereignty soverignty sovereignty spainish Spanish speach speech specfic specific speciallized specialised, specialized specif specific, specify specifiying specifying speciman specimen spectauclar spectacular spectaulars spectaculars spects aspects, expects spectum spectrum speices species spendour splendour spermatozoan spermatozoon spoace space sponser sponsor sponsered sponsored spontanous spontaneous sponzored sponsored spoonfulls spoonfuls sppeches speeches spreaded spread sprech speech spred spread spriritual spiritual spritual spiritual sqaure square stablility stability stainlees stainless staion station standars standards stange strange startegic strategic startegies strategies startegy strategy stateman statesman statememts statements statment statement steriods steroids sterotypes stereotypes stilus stylus stingent stringent stiring stirring stirrs stirs stlye style stong strong stopry story storeis stories storise stories stornegst strongest stoyr story stpo stop stradegies strategies stradegy strategy strat start, strata stratagically strategically streemlining streamlining stregth strength strenghen strengthen strenghened strengthened strenghening strengthening strenght strength strenghten strengthen strenghtened strengthened strenghtening strengthening strengtened strengthened strenous strenuous strictist strictest strikely strikingly strnad strand stroy story, destroy structual structural stubborness stubbornness stucture structure stuctured structured studdy study studing studying stuggling struggling sturcture structure subcatagories subcategories subcatagory subcategory subconsiously subconsciously subjudgation subjugation submachne submachine subpecies subspecies subsidary subsidiary subsiduary subsidiary subsquent subsequent subsquently subsequently substace substance substancial substantial substatial substantial substituded substituted substract subtract substracted subtracted substracting subtracting substraction subtraction substracts subtracts subtances substances subterranian subterranean suburburban suburban succceeded succeeded succcesses successes succedded succeeded succeded succeeded succeds succeeds succesful successful succesfully successfully succesfuly successfully succesion succession succesive successive successfull successful successully successfully succsess success succsessfull successful suceed succeed suceeded succeeded suceeding succeeding suceeds succeeds sucesful successful sucesfully successfully sucesfuly successfully sucesion succession sucess success sucesses successes sucessful successful sucessfull successful sucessfully successfully sucessfuly successfully sucession succession sucessive successive sucessor successor sucessot successor sucide suicide sucidial suicidal sufferage suffrage sufferred suffered sufferring suffering sufficent sufficient sufficently sufficiently sumary summary sunglases sunglasses suop soup superceeded superseded superintendant superintendent suphisticated sophisticated suplimented supplemented supose suppose suposed supposed suposedly supposedly suposes supposes suposing supposing supplamented supplemented suppliementing supplementing suppoed supposed supposingly supposedly suppy supply supress suppress supressed suppressed supresses suppresses supressing suppressing suprise surprise suprised surprised suprising surprising suprisingly surprisingly suprize surprise suprized surprised suprizing surprising suprizingly surprisingly surfce surface surley surly, surely suround surround surounded surrounded surounding surrounding suroundings surroundings surounds surrounds surplanted supplanted surpress suppress surpressed suppressed surprize surprise surprized surprised surprizing surprising surprizingly surprisingly surrended surrounded, surrendered surrepetitious surreptitious surrepetitiously surreptitiously surreptious surreptitious surreptiously surreptitiously surronded surrounded surrouded surrounded surrouding surrounding surrundering surrendering surveilence surveillance surveill surveil surveyer surveyor surviver survivor survivers survivors survivied survived suseptable susceptible suseptible susceptible suspention suspension swaer swear swaers swears swepth swept swiming swimming syas says symetrical symmetrical symetrically symmetrically symetry symmetry symettric symmetric symmetral symmetric symmetricaly symmetrically synagouge synagogue syncronization synchronization synonomous synonymous synonymns synonyms synphony symphony syphyllis syphilis sypmtoms symptoms syrap syrup sysmatically systematically sytem system sytle style tabacco tobacco tahn than taht that talekd talked targetted targeted targetting targeting tast taste tath that tattooes tattoos taxanomic taxonomic taxanomy taxonomy teached taught techician technician techicians technicians techiniques techniques technitian technician technnology technology technolgy technology teh the tehy they telelevision television televsion television telphony telephony temerature temperature temparate temperate temperarily temporarily temperment temperament tempertaure temperature temperture temperature temprary temporary tenacle tentacle tenacles tentacles tendacy tendency tendancies tendencies tendancy tendency tennisplayer tennis player tepmorarily temporarily terrestial terrestrial terriories territories terriory territory territorist terrorist territoy territory terroist terrorist testiclular testicular tghe the thast that, that's theather theater, theatre theese these theif thief theives thieves themselfs themselves themslves themselves ther there, their, the therafter thereafter therby thereby theri their thgat that thge the thier their thign thing thigns things thigsn things thikn think thikning thinking, thickening thikns thinks thiunk think thn then thna than thne then thnig thing thnigs things thoughout throughout threatend threatened threatning threatening threee three threshhold threshold thrid third throrough thorough throughly thoroughly throught thought, through, throughout througout throughout thru through thsi this thsoe those thta that thyat that tiem time, Tim tihkn think tihs this timne time tiome time, tome tje the tjhe the tjpanishad upanishad tkae take tkaes takes tkaing taking tlaking talking tobbaco tobacco todays today's todya today toghether together tolerence tolerance Tolkein Tolkien tomatos tomatoes tommorow tomorrow tommorrow tomorrow tongiht tonight toriodal toroidal tormenters tormentors torpeados torpedoes torpedos torpedoes tothe to the toubles troubles tounge tongue tourch torch, touch towords towards towrad toward tradionally traditionally traditionaly traditionally traditionnal traditional traditition tradition tradtionally traditionally trafficed trafficked trafficing trafficking trafic traffic trancendent transcendent trancending transcending tranform transform tranformed transformed transcendance transcendence transcendant transcendent transcendentational transcendental transcripting transcribing, transcription transending transcending transesxuals transsexuals transfered transferred transfering transferring transformaton transformation transistion transition translater translator translaters translators transmissable transmissible transporation transportation tremelo tremolo tremelos tremolos triguered triggered triology trilogy troling trolling troup troupe troups troupes, troops truely truly trustworthyness trustworthiness turnk turnkey, trunk Tuscon Tucson tust trust twelth twelfth twon town twpo two tyhat that tyhe they typcial typical typicaly typically tyranies tyrannies tyrany tyranny tyrranies tyrannies tyrrany tyranny ubiquitious ubiquitous uise use Ukranian Ukrainian ultimely ultimately unacompanied unaccompanied unahppy unhappy unanymous unanimous unathorised unauthorised unavailible unavailable unballance unbalance unbeleivable unbelievable uncertainity uncertainty unchallengable unchallengeable unchangable unchangeable uncompetive uncompetitive unconcious unconscious unconciousness unconsciousness unconfortability discomfort uncontitutional unconstitutional unconvential unconventional undecideable undecidable understoon understood undesireable undesirable undetecable undetectable undoubtely undoubtedly undreground underground uneccesary unnecessary unecessary unnecessary unequalities inequalities unforetunately unfortunately unforgetable unforgettable unforgiveable unforgivable unfortunatley unfortunately unfortunatly unfortunately unfourtunately unfortunately unihabited uninhabited unilateraly unilaterally unilatreal unilateral unilatreally unilaterally uninterruped uninterrupted uninterupted uninterrupted UnitesStates UnitedStates univeral universal univeristies universities univeristy university universtiy university univesities universities univesity university unkown unknown unlikey unlikely unmanouverable unmaneuverable, unmanoeuvrable unmistakeably unmistakably unneccesarily unnecessarily unneccesary unnecessary unneccessarily unnecessarily unneccessary unnecessary unnecesarily unnecessarily unnecesary unnecessary unoffical unofficial unoperational nonoperational unoticeable unnoticeable unplease displease unplesant unpleasant unprecendented unprecedented unprecidented unprecedented unrepentent unrepentant unrepetant unrepentant unrepetent unrepentant unsed used, unused, unsaid unsubstanciated unsubstantiated unsuccesful unsuccessful unsuccesfully unsuccessfully unsuccessfull unsuccessful unsucesful unsuccessful unsucesfuly unsuccessfully unsucessful unsuccessful unsucessfull unsuccessful unsucessfully unsuccessfully unsuprised unsurprised unsuprising unsurprising unsuprisingly unsurprisingly unsuprized unsurprised unsuprizing unsurprising unsuprizingly unsurprisingly unsurprized unsurprised unsurprizing unsurprising unsurprizingly unsurprisingly untill until untranslateable untranslatable unuseable unusable unusuable unusable unviersity university unwarrented unwarranted unweildly unwieldy unwieldly unwieldy upcomming upcoming upgradded upgraded usally usually useage usage usefull useful usefuly usefully useing using usualy usually ususally usually vaccum vacuum vaccume vacuum vacinity vicinity vaguaries vagaries vaieties varieties vailidty validity valetta valletta valuble valuable valueable valuable varations variations varient variant variey variety varing varying varities varieties varity variety vasall vassal vasalls vassals vegatarian vegetarian vegitable vegetable vegitables vegetables vegtable vegetable vehicule vehicle vell well venemous venomous vengance vengeance vengence vengeance verfication verification verison version verisons versions vermillion vermilion versitilaty versatility versitlity versatility vetween between veyr very vigeur vigueur, vigour, vigor vigilence vigilance vigourous vigorous villian villain villification vilification villify vilify villin villi, villain, villein vincinity vicinity violentce violence virutal virtual virtualy virtually virutally virtually visable visible visably visibly visting visiting vistors visitors vitories victories volcanoe volcano voleyball volleyball volontary voluntary volonteer volunteer volonteered volunteered volonteering volunteering volonteers volunteers volounteer volunteer volounteered volunteered volounteering volunteering volounteers volunteers vreity variety vrey very vriety variety vulnerablility vulnerability vyer very vyre very waht what wanna want to warantee warranty wardobe wardrobe warrent warrant warrriors warriors wasnt wasn't wass was watn want wayword wayward weaponary weaponry weas was wehn when weild wield, wild weilded wielded wendsay Wednesday wensday Wednesday wereabouts whereabouts whant want whants wants whcih which wheras whereas wherease whereas whereever wherever whic which whihc which whith with whlch which whn when wholey wholly wholy wholly, holy whta what whther whether wich which, witch widesread widespread wief wife wierd weird wiew view wih with wiht with wille will willingless willingness wirting writing withdrawl withdrawal, withdraw witheld withheld withing within withold withhold witht with witn with wiull will wnat want wnated wanted wnats wants wohle whole wokr work wokring working wonderfull wonderful workststion workstation worls world wordlwide worldwide worshipper worshiper worshipping worshiping worstened worsened woudl would wresters wrestlers wriet write writen written wroet wrote wrok work wroking working ws was wtih with wupport support xenophoby xenophobia yaching yachting yatch yacht yeasr years yeild yield yeilding yielding Yementite Yemenite, Yemeni yearm year yera year yeras years yersa years youseff yousef youself yourself ytou you yuo you joo you zeebra zebra [[Category:Wikipedia tools]] nuspell-5.1.7/tests/legacy_test.cxx000066400000000000000000000065161511132717100174060ustar00rootroot00000000000000/* Copyright 2018-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include #include #include using namespace std; int main(int argc, char* argv[]) { if (argc < 2) return 3; auto test = string(argv[1]); if (test.size() < 4) { cerr << "Invalid test type\n"; return 3; } auto type = test.substr(test.size() - 4); auto file = ifstream(test); if (!file.is_open()) { cerr << "Can not open test file " << test << " \n"; return 2; } file.close(); test.replace(test.size() - 4, 4, ".aff"); auto d = nuspell::Dictionary(); try { d.load_aff_dic(test); } catch (const nuspell::Dictionary_Loading_Error& err) { cerr << err.what() << '\n'; return 2; } test.erase(test.size() - 4); auto word = string(); if (type == ".dic") { auto error = vector(); file.open(test + ".good"); while (file >> word) { if (d.spell(word) == false) error.push_back(word); } if (!error.empty()) { cout << "Good words recognised as bad:\n"; for (auto& w : error) { cout << w << '\n'; } return 1; } file.close(); error.clear(); file.open(test + ".wrong"); while (file >> word) { if (d.spell(word)) error.push_back(word); } if (!error.empty()) { cout << "Bad words recognised as good:\n"; for (auto& w : error) { cout << w << '\n'; } return 1; } } else if (type == ".sug") { file.open(test + ".wrong"); if (!file.is_open()) { cerr << "Can not open test file " << test + ".wrong" << " \n"; return 2; } auto list_sugs = vector>(); auto sug = vector(); while (file >> word) { if (d.spell(word)) continue; d.suggest(word, sug); if (!sug.empty()) list_sugs.push_back(sug); } file.close(); file.open(test + ".sug"); if (!file.is_open()) return 2; auto expected_list_sugs = vector>(); auto line = string(); while (getline(file, line)) { if (line.empty()) continue; sug.clear(); for (size_t i = 0;;) { auto j = line.find(',', i); word.assign(line, i, j - i); sug.push_back(word); if (j == line.npos) break; i = line.find_first_not_of(' ', j + 1); if (i == line.npos) break; } if (!sug.empty()) expected_list_sugs.push_back(sug); } if (list_sugs != expected_list_sugs) { cout << "Bad suggestions.\nExpected output:\n"; for (auto& x : expected_list_sugs) { for (auto& w : x) { cout << w << ", "; } cout << '\n'; } cout << "\nActual output:\n"; for (auto& x : list_sugs) { for (auto& w : x) { cout << w << ", "; } cout << '\n'; } return 1; } } else { cerr << "Invalid test type\n"; return 3; } } nuspell-5.1.7/tests/unit_test.cxx000066400000000000000000000353301511132717100171150ustar00rootroot00000000000000/* Copyright 2021-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include #include #include #include using namespace std; using namespace nuspell; TEST_CASE("Subrange") { auto str = "abc"s; auto s = Subrange(str); STATIC_REQUIRE(is_same_v>); REQUIRE(s.begin() == begin(str)); REQUIRE(s.end() == end(str)); } TEST_CASE("String_Set") { auto ss = String_Set(u"zaZAa"); STATIC_REQUIRE(is_same_v>); REQUIRE(ss == String_Set(u"AZaz")); REQUIRE(ss.str() == u"AZaz"); REQUIRE(ss.size() == 4); REQUIRE_FALSE(ss.empty()); REQUIRE(ss.contains(u'a')); REQUIRE(ss.contains(u'A')); REQUIRE(ss.contains(u'z')); REQUIRE(ss.contains(u'Z')); REQUIRE_FALSE(ss.contains(u'\0')); REQUIRE_FALSE(ss.contains(u'b')); REQUIRE_FALSE(ss.contains(u'B')); REQUIRE(ss.lower_bound(u'a') == ss.begin() + 2); REQUIRE(ss.upper_bound(u'a') == ss.begin() + 3); REQUIRE(ss.equal_range(u'a') == pair(ss.begin() + 2, ss.begin() + 3)); REQUIRE(ss.lower_bound(u'b') == ss.begin() + 3); REQUIRE(ss.upper_bound(u'b') == ss.begin() + 3); REQUIRE(ss.equal_range(u'b') == pair(ss.begin() + 3, ss.begin() + 3)); ss.insert(u'b'); REQUIRE(ss == String_Set(u"AZabz")); REQUIRE(ss.str() == u"AZabz"); REQUIRE(ss.size() == 5); REQUIRE_FALSE(ss.empty()); REQUIRE(ss.contains(u'a')); REQUIRE(ss.contains(u'A')); REQUIRE(ss.contains(u'z')); REQUIRE(ss.contains(u'Z')); REQUIRE(ss.contains(u'b')); REQUIRE_FALSE(ss.contains(u'\0')); REQUIRE_FALSE(ss.contains(u'B')); ss.erase(u'A'); ss.erase(u'b'); REQUIRE(ss == String_Set(u"Zaz")); REQUIRE(ss.str() == u"Zaz"); REQUIRE(ss.size() == 3); REQUIRE_FALSE(ss.empty()); REQUIRE(ss.contains(u'a')); REQUIRE(ss.contains(u'z')); REQUIRE(ss.contains(u'Z')); REQUIRE_FALSE(ss.contains(u'\0')); REQUIRE_FALSE(ss.contains(u'A')); REQUIRE_FALSE(ss.contains(u'b')); REQUIRE_FALSE(ss.contains(u'B')); } TEST_CASE("Substr_Replacer") { auto rep = Substr_Replacer({{"asd", "zxc"}, {"as", "rtt"}, {"a", "A"}, {"abbb", "ABBB"}, {"asd ", ""}, {"asd ZXC", "YES"}, {"sd ZXC as", "NO"}, {"", "123"}, {" TT", ""}}); REQUIRE(rep.replace_copy("QWE asd ZXC as TT") == "QWE YES rtt"); } TEST_CASE("Break_Table") { auto b = Break_Table({ "bsd", "zxc", "asd", "^bar", "^zoo", "^abc", "car$", "yoyo$", "air$", }); auto swb = b.start_word_breaks(); auto swb_v = vector(begin(swb), end(swb)); sort(begin(swb_v), end(swb_v)); REQUIRE(swb_v == vector{"abc"s, "bar"s, "zoo"s}); auto mwb = b.middle_word_breaks(); auto mwb_v = vector(begin(mwb), end(mwb)); sort(begin(mwb_v), end(mwb_v)); REQUIRE(mwb_v == vector{"asd"s, "bsd"s, "zxc"s}); auto ewb = b.end_word_breaks(); auto ewb_v = vector(begin(ewb), end(ewb)); sort(begin(ewb_v), end(ewb_v)); REQUIRE(ewb_v == vector{"air"s, "car"s, "yoyo"s}); } TEST_CASE("Hash_Multimap") { auto h = Hash_Multimap(); REQUIRE(h.empty()); REQUIRE(h.size() == 0); auto res = h.equal_range("hello"); #if !defined(_GLIBCXX_DEBUG) || _GLIBCXX_RELEASE >= 11 // ifdef because of // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70303 REQUIRE(res.first == res.second); #endif h.emplace("hello", 5); res = h.equal_range("hello"); REQUIRE_FALSE(h.empty()); REQUIRE(h.size() == 1); REQUIRE(res.first != res.second); REQUIRE(next(res.first) == res.second); REQUIRE(*res.first == pair("hello"s, 5)); res = h.equal_range("Hi"); REQUIRE(res.first == res.second); res = h.equal_range(""); REQUIRE(res.first == res.second); h.emplace("hello", 4); res = h.equal_range("hello"); REQUIRE_FALSE(h.empty()); REQUIRE(h.size() == 2); REQUIRE(res.first != res.second); REQUIRE(next(res.first, 2) == res.second); REQUIRE(*res.first == pair("hello"s, 5)); REQUIRE(*next(res.first) == pair("hello"s, 4)); res = h.equal_range("Hi"); REQUIRE(res.first == res.second); res = h.equal_range(""); REQUIRE(res.first == res.second); } TEST_CASE("Condition") { auto c = Condition(); REQUIRE(c.match_prefix("")); REQUIRE(c.match_prefix("a")); REQUIRE(c.match_suffix("")); REQUIRE(c.match_suffix("b")); c = "abcd"; REQUIRE(c.match_prefix("abcd")); REQUIRE(c.match_prefix("abcdXYZ")); REQUIRE(c.match_prefix("abcdБВГДШ\uABCD\U0010ABCD")); REQUIRE_FALSE(c.match_prefix("")); REQUIRE_FALSE(c.match_prefix("abc")); REQUIRE_FALSE(c.match_prefix("abcX")); REQUIRE_FALSE(c.match_prefix("XYZ")); REQUIRE_FALSE(c.match_prefix("АаБбВвГгШш\uABCD\U0010ABCD")); REQUIRE(c.match_suffix("abcd")); REQUIRE(c.match_suffix("XYZabcd")); REQUIRE(c.match_suffix("БВГДШ\uABCD\U0010ABCDabcd")); REQUIRE_FALSE(c.match_suffix("")); REQUIRE_FALSE(c.match_suffix("bcd")); REQUIRE_FALSE(c.match_suffix("Xbcd")); REQUIRE_FALSE(c.match_suffix("XYZ")); REQUIRE_FALSE(c.match_suffix("АаБбВвГгШш\uABCD\U0010ABCD")); c = "."; REQUIRE(c.match_prefix("Y")); REQUIRE(c.match_prefix("abc")); REQUIRE(c.match_prefix("БВГДШ\uABCD\U0010ABCD")); REQUIRE_FALSE(c.match_prefix("")); REQUIRE(c.match_suffix("Y")); REQUIRE(c.match_suffix("qwe")); REQUIRE(c.match_suffix("БВГДШ\uABCD\U0010ABCD")); REQUIRE_FALSE(c.match_suffix("")); c = "[vbn]"; REQUIRE(c.match_prefix("v")); REQUIRE(c.match_prefix("vAAш")); REQUIRE(c.match_prefix("b")); REQUIRE(c.match_prefix("bBBш")); REQUIRE(c.match_prefix("n")); REQUIRE(c.match_prefix("nCCш")); REQUIRE_FALSE(c.match_prefix("")); REQUIRE_FALSE(c.match_prefix("Q")); REQUIRE_FALSE(c.match_prefix("Qqqq")); REQUIRE_FALSE(c.match_prefix("1342234")); REQUIRE_FALSE(c.match_prefix("V")); REQUIRE_FALSE(c.match_prefix("бвгдш")); REQUIRE(c.match_suffix("v")); REQUIRE(c.match_suffix("шVVv")); REQUIRE(c.match_suffix("b")); REQUIRE(c.match_suffix("шBBb")); REQUIRE(c.match_suffix("n")); REQUIRE(c.match_suffix("шNNn")); REQUIRE_FALSE(c.match_suffix("")); REQUIRE_FALSE(c.match_suffix("Q")); REQUIRE_FALSE(c.match_suffix("Qqqq")); REQUIRE_FALSE(c.match_suffix("123123")); REQUIRE_FALSE(c.match_suffix("V")); REQUIRE_FALSE(c.match_suffix("бвгдш")); c = "[бш\u1234]"; REQUIRE(c.match_prefix("б")); REQUIRE(c.match_prefix("беТ")); REQUIRE(c.match_prefix("ш")); REQUIRE(c.match_prefix("шок")); REQUIRE(c.match_prefix("\u1234кош")); REQUIRE_FALSE(c.match_prefix("")); REQUIRE_FALSE(c.match_prefix("Q")); REQUIRE_FALSE(c.match_prefix("Qqqq")); REQUIRE_FALSE(c.match_prefix("пан")); REQUIRE_FALSE(c.match_prefix("\uABCD\u1234")); REQUIRE_FALSE(c.match_prefix("вбгдш")); REQUIRE(c.match_suffix("б")); REQUIRE(c.match_suffix("еТб")); REQUIRE(c.match_suffix("ш")); REQUIRE(c.match_suffix("кош")); REQUIRE(c.match_suffix("кош\u1234")); REQUIRE_FALSE(c.match_suffix("")); REQUIRE_FALSE(c.match_suffix("Q")); REQUIRE_FALSE(c.match_suffix("Qqqq")); REQUIRE_FALSE(c.match_suffix("пан")); REQUIRE_FALSE(c.match_suffix("\u1234\uABCD")); REQUIRE_FALSE(c.match_suffix("вбгдз")); c = "[^zш\u1234\U0010ABCD]"; REQUIRE_FALSE(c.match_prefix("z")); REQUIRE_FALSE(c.match_prefix("ш")); REQUIRE_FALSE(c.match_prefix("\u1234")); REQUIRE_FALSE(c.match_prefix("\U0010ABCD")); REQUIRE_FALSE(c.match_prefix("zљње")); REQUIRE_FALSE(c.match_prefix("шabc")); REQUIRE_FALSE(c.match_prefix("\u1234 ytyty")); REQUIRE_FALSE(c.match_prefix("\U0010ABCD tytyty")); REQUIRE(c.match_prefix("q")); REQUIRE(c.match_prefix("r")); REQUIRE(c.match_prefix("\uFFFD")); REQUIRE(c.match_prefix("\U0010FFFF")); REQUIRE(c.match_prefix("qљње")); REQUIRE(c.match_prefix("фabc")); REQUIRE(c.match_prefix("\uFFFD ytyty")); REQUIRE(c.match_prefix("\U0010FFFF tytyty")); REQUIRE_FALSE(c.match_suffix("z")); REQUIRE_FALSE(c.match_suffix("ш")); REQUIRE_FALSE(c.match_suffix("\u1234")); REQUIRE_FALSE(c.match_suffix("\U0010ABCD")); REQUIRE_FALSE(c.match_suffix("љњеz")); REQUIRE_FALSE(c.match_suffix("abcш")); REQUIRE_FALSE(c.match_suffix("ytyty \u1234")); REQUIRE_FALSE(c.match_suffix("tytyty \U0010ABCD")); REQUIRE(c.match_suffix("q")); REQUIRE(c.match_suffix("r")); REQUIRE(c.match_suffix("\uFFFD")); REQUIRE(c.match_suffix("\U0010FFFF")); REQUIRE(c.match_suffix("љњеq")); REQUIRE(c.match_suffix("abcф")); REQUIRE(c.match_suffix("ytyty \uFFFD")); REQUIRE(c.match_suffix("tytyty \U0010FFFF")); c = "abc АБВ..[zбш\u1234][^zш\u1234\U0010ABCD]X"; REQUIRE(c.match_prefix("abc АБВ \u2345z\U00011111X")); REQUIRE(c.match_prefix("abc АБВ\u2345 ш\U00011112Xопop")); REQUIRE_FALSE(c.match_prefix("abc ШШШ \u2345z\U00011111X")); REQUIRE_FALSE(c.match_prefix("abc АБВ\u2345 t\U00011112Xопop")); REQUIRE_FALSE(c.match_prefix("abc АБВ \u2345z\u1234X")); } TEST_CASE("Prefix") { auto pfx = Prefix{'F', false, "qw", "Qwe", {}, {}}; REQUIRE(pfx.to_derived_copy("qwrty") == "Qwerty"); REQUIRE(pfx.to_root_copy("Qwerty") == "qwrty"); } TEST_CASE("Suffix") { auto sfx = Suffix{'F', false, "ie", "ying", {}, {}}; REQUIRE(sfx.to_derived_copy("pie") == "pying"); REQUIRE(sfx.to_root_copy("pying") == "pie"); } TEST_CASE("Prefix_Multiset") { auto set = Prefix_Multiset{"", "a", "", "ab", "abx", "as", "asdf", "axx", "as", "bqwe", "ba", "rqwe"}; auto expected = vector{"", "", "a", "as", "as", "asdf"}; auto out = vector(); set.copy_all_prefixes_of("asdfg", back_inserter(out)); CHECK(out == expected); auto word = string("asdfg"); auto it = set.iterate_prefixes_of(word); out.assign(begin(it), end(it)); REQUIRE(out == expected); } TEST_CASE("Suffix_Multiset") { auto set = Suffix_Multiset{"", "", "a", "b", "b", "ab", "ub", "zb", "aub", "uub", "xub", "huub"}; auto expected = vector{"", "", "b", "b", "ub", "uub", "huub"}; auto out = vector(); auto word = string("ahahuub"); set.copy_all_prefixes_of(word, back_inserter(out)); CHECK(out == expected); auto it = set.iterate_prefixes_of(word); out.assign(begin(it), end(it)); REQUIRE(out == expected); } TEST_CASE("String_Pair") { auto x = String_Pair(); REQUIRE(x.str() == ""); REQUIRE(x.idx() == 0); REQUIRE(x.first() == ""); REQUIRE(x.second() == ""); x.first("123qwe"); REQUIRE(x.str() == "123qwe"); REQUIRE(x.idx() == 6); REQUIRE(x.first() == "123qwe"); REQUIRE(x.second() == ""); x.second("456z"); REQUIRE(x.str() == "123qwe456z"); REQUIRE(x.idx() == 6); REQUIRE(x.first() == "123qwe"); REQUIRE(x.second() == "456z"); x = String_Pair("6789"s, "zxcvbnm"s); REQUIRE(x.str() == "6789zxcvbnm"); REQUIRE(x.idx() == 4); REQUIRE(x.first() == "6789"); REQUIRE(x.second() == "zxcvbnm"); x = String_Pair("6789zxcvbnm", 4); REQUIRE(x.str() == "6789zxcvbnm"); REQUIRE(x.idx() == 4); REQUIRE(x.first() == "6789"); REQUIRE(x.second() == "zxcvbnm"); REQUIRE_NOTHROW(String_Pair("6789", 4)); REQUIRE_THROWS_AS(String_Pair("6789", 5), std::out_of_range); REQUIRE_THROWS_WITH(String_Pair("6789", 5), "word split is too long"); } TEST_CASE("match_simple_regex()") { REQUIRE(match_simple_regex("abdff"s, "abc?de*ff"s)); REQUIRE(match_simple_regex("abcdff"s, "abc?de*ff"s)); REQUIRE(match_simple_regex("abdeeff"s, "abc?de*ff"s)); REQUIRE(match_simple_regex("abcdeff"s, "abc?de*ff"s)); REQUIRE_FALSE(match_simple_regex("abcdeeeefff"s, "abc?de*ff"s)); REQUIRE_FALSE(match_simple_regex("abccdeeeeff"s, "abc?de*ff"s)); REQUIRE_FALSE(match_simple_regex("qwerty"s, "abc?de*ff"s)); } TEST_CASE("Similarity_Group") { auto sg = Similarity_Group("abc(AB)БШП(ghgh)"); REQUIRE(sg.chars == "abcБШП"); REQUIRE(sg.strings == vector{"AB"s, "ghgh"s}); } TEST_CASE("utf32_to_utf8()") { REQUIRE(utf32_to_utf8(U"") == ""); REQUIRE(utf32_to_utf8(U"abcАбвг\uABCD\u1234\U0010ABCD") == "abcАбвг\uABCD\u1234\U0010ABCD"); } TEST_CASE("is_all_ascii()") { REQUIRE(is_all_ascii("")); REQUIRE(is_all_ascii("abcd\x7f")); REQUIRE_FALSE(is_all_ascii("abcd\x80")); REQUIRE_FALSE(is_all_ascii("abcd\xFF")); } TEST_CASE("latin1_to_ucs2()") { REQUIRE(latin1_to_ucs2("abcd\x7F\x80\xFF") == u"abcd\u007F\u0080\u00FF"); } TEST_CASE("is_all_bmp()") { REQUIRE(is_all_bmp(u"abc\u00FF\uFFFF")); REQUIRE_FALSE(is_all_bmp(u"abc\u00FF\uFFFF\U00010000")); REQUIRE_FALSE(is_all_bmp(u"abc\U0010FFFF\u00FF\uFFFF")); } TEST_CASE("case conversion") { // These are simple tests that only test if we wrap properly. // There is no need for extensive testing, ICU is well tested. auto in = "grüßEN"; auto l = icu::Locale(); CHECK(to_lower(in, l) == "grüßen"); CHECK(to_upper(in, l) == "GRÜSSEN"); CHECK(to_title(in, l) == "Grüßen"); in = "isTAnbulI"; CHECK(to_lower(in, l) == "istanbuli"); CHECK(to_upper(in, l) == "ISTANBULI"); CHECK(to_title(in, l) == "Istanbuli"); l = {"tr_TR"}; CHECK(to_lower(in, l) == "istanbulı"); CHECK(to_upper(in, l) == "İSTANBULI"); CHECK(to_title(in, l) == "İstanbulı"); } TEST_CASE("classify_casing()") { REQUIRE(classify_casing("") == Casing::SMALL); REQUIRE(classify_casing("здраво") == Casing::SMALL); REQUIRE(classify_casing("Здраво") == Casing::INIT_CAPITAL); REQUIRE(classify_casing("ЗДРАВО") == Casing::ALL_CAPITAL); REQUIRE(classify_casing("здРаВо") == Casing::CAMEL); REQUIRE(classify_casing("ЗдрАво") == Casing::PASCAL); } TEST_CASE("is_number()") { REQUIRE_FALSE(is_number("")); REQUIRE(is_number("1234567890")); REQUIRE(is_number("-1234567890")); REQUIRE(is_number("123.456.78-9,0")); REQUIRE(is_number("-123.456.78-9,0")); REQUIRE_FALSE(is_number("123..456.78-9,0")); REQUIRE_FALSE(is_number("123.456.-78-9,0")); REQUIRE_FALSE(is_number("123..456.78-9-,0")); } TEST_CASE("Dict_Base::forgotten_char_suggest()") { auto d = nuspell::Suggester(); d.words.emplace("Забвгд", u""); d.words.emplace("абвШгд", u""); d.words.emplace("абвгдИ", u""); d.words.emplace("абвгдК", u""); d.try_chars = "шизШИЗ"; auto in = "абвгд"s; auto sugs = vector(); d.forgotten_char_suggest(in, sugs); REQUIRE(sugs == vector{"абвШгд"s, "абвгдИ"s, "Забвгд"s}); } nuspell-5.1.7/tests/v1cmdline/000077500000000000000000000000001511132717100162315ustar00rootroot00000000000000nuspell-5.1.7/tests/v1cmdline/1463589.aff000066400000000000000000000001621511132717100175510ustar00rootroot00000000000000# capitalized ngram suggestion test data for # Sf.net Bug ID 1463589, reported by Frederik Fouvry. MAXNGRAMSUGS 1 nuspell-5.1.7/tests/v1cmdline/1463589.dic000066400000000000000000000000161511132717100175520ustar00rootroot000000000000001 Khlschrank nuspell-5.1.7/tests/v1cmdline/1463589.sug000066400000000000000000000001011511132717100176040ustar00rootroot00000000000000Kühlschrank Kühlschrank Kühlschrank Kühlschrank Kühlschrank nuspell-5.1.7/tests/v1cmdline/1463589.wrong000066400000000000000000000000771511132717100201560ustar00rootroot00000000000000kuhlschrank kuehlschrank kühlschrank Kuhlschrank Kuehlschrank nuspell-5.1.7/tests/v1cmdline/1463589_utf.aff000066400000000000000000000002161511132717100204270ustar00rootroot00000000000000# capitalized ngram suggestion test data (Unicode version) for # Sf.net Bug ID 1463589, reported by Frederik Fouvry. SET UTF-8 MAXNGRAMSUGS 1 nuspell-5.1.7/tests/v1cmdline/1463589_utf.dic000066400000000000000000000000171511132717100204310ustar00rootroot000000000000001 Kühlschrank nuspell-5.1.7/tests/v1cmdline/1463589_utf.sug000066400000000000000000000001011511132717100204620ustar00rootroot00000000000000Kühlschrank Kühlschrank Kühlschrank Kühlschrank Kühlschrank nuspell-5.1.7/tests/v1cmdline/1463589_utf.wrong000066400000000000000000000000771511132717100210340ustar00rootroot00000000000000kuhlschrank kuehlschrank kühlschrank Kuhlschrank Kuehlschrank nuspell-5.1.7/tests/v1cmdline/1592880.aff000066400000000000000000000004271511132717100175520ustar00rootroot00000000000000# fix homonym handling for German dictionary project, # reported by Björn Jacke (sf.net Bug ID 1592880). SET ISO8859-1 SFX N Y 1 SFX N 0 n . SFX S Y 1 SFX S 0 s . SFX P Y 1 SFX P 0 en . SFX Q Y 2 SFX Q 0 e . SFX Q 0 en . COMPOUNDEND z COMPOUNDPERMITFLAG c ONLYINCOMPOUND o nuspell-5.1.7/tests/v1cmdline/1592880.dic000066400000000000000000000000251511132717100175470ustar00rootroot000000000000003 weg/Qoz weg/P wege nuspell-5.1.7/tests/v1cmdline/1592880.good000066400000000000000000000000171511132717100177410ustar00rootroot00000000000000weg wege wegen nuspell-5.1.7/tests/v1cmdline/1695964.aff000066400000000000000000000003201511132717100175510ustar00rootroot00000000000000# fix NEEDAFFIX homonym suggestion. # Sf.net Bug ID 1695964, reported by Björn Jacke. TRY esianrtolcdugmphbyfvkwESIANRTOLCDUGMPHBYFVKW MAXNGRAMSUGS 0 NEEDAFFIX h SFX S Y 1 SFX S 0 s . SFX e Y 1 SFX e 0 e . nuspell-5.1.7/tests/v1cmdline/1695964.dic000066400000000000000000000000211511132717100175520ustar00rootroot000000000000002 Mull/he Mull/S nuspell-5.1.7/tests/v1cmdline/1695964.sug000066400000000000000000000000211511132717100176110ustar00rootroot00000000000000Mull Mulle Mulls nuspell-5.1.7/tests/v1cmdline/1695964.wrong000066400000000000000000000000211511132717100201470ustar00rootroot00000000000000Mall Malle Malls nuspell-5.1.7/tests/v1cmdline/1706659.aff000066400000000000000000000003111511132717100175430ustar00rootroot00000000000000# test COMPOUNDRULE bug reported by Björn Jacke SET ISO8859-1 TRY esijanrtolcdugmphbyfvkwqxz SFX A Y 5 SFX A 0 e . SFX A 0 er . SFX A 0 en . SFX A 0 em . SFX A 0 es . COMPOUNDRULE 1 COMPOUNDRULE vw nuspell-5.1.7/tests/v1cmdline/1706659.dic000066400000000000000000000000361511132717100175520ustar00rootroot000000000000003 arbeits/v scheu/Aw farbig/A nuspell-5.1.7/tests/v1cmdline/1706659.wrong000066400000000000000000000000551511132717100201500ustar00rootroot00000000000000arbeitsfarbig arbeitsfarbige arbeitsfarbiger nuspell-5.1.7/tests/v1cmdline/1975530.aff000066400000000000000000000001021511132717100175350ustar00rootroot00000000000000SET UTF-8 IGNORE ٌٍَُِّْـ PFX x N 1 PFX x أ ت أ[^ي] nuspell-5.1.7/tests/v1cmdline/1975530.dic000066400000000000000000000000261511132717100175450ustar00rootroot000000000000002 أرى/x أيار/x nuspell-5.1.7/tests/v1cmdline/1975530.good000066400000000000000000000000271511132717100177370ustar00rootroot00000000000000أرى أيار ترى nuspell-5.1.7/tests/v1cmdline/1975530.wrong000066400000000000000000000000111511132717100201340ustar00rootroot00000000000000تيار nuspell-5.1.7/tests/v1cmdline/2970240.aff000066400000000000000000000001401511132717100175310ustar00rootroot00000000000000# test words with three parts CHECKCOMPOUNDPATTERN 1 CHECKCOMPOUNDPATTERN le fi COMPOUNDFLAG c nuspell-5.1.7/tests/v1cmdline/2970240.dic000066400000000000000000000000321511132717100175340ustar00rootroot000000000000003 first/c middle/c last/c nuspell-5.1.7/tests/v1cmdline/2970240.good000066400000000000000000000000201511132717100177220ustar00rootroot00000000000000firstmiddlelast nuspell-5.1.7/tests/v1cmdline/2970240.wrong000066400000000000000000000000201511132717100201260ustar00rootroot00000000000000lastmiddlefirst nuspell-5.1.7/tests/v1cmdline/2970242.aff000066400000000000000000000001021511132717100175310ustar00rootroot00000000000000CHECKCOMPOUNDPATTERN 1 CHECKCOMPOUNDPATTERN /a /b COMPOUNDFLAG c nuspell-5.1.7/tests/v1cmdline/2970242.dic000066400000000000000000000000261511132717100175410ustar00rootroot000000000000003 foo/ac bar/c baz/bc nuspell-5.1.7/tests/v1cmdline/2970242.good000066400000000000000000000000431511132717100177310ustar00rootroot00000000000000foobar barfoo bazfoo barbaz bazbar nuspell-5.1.7/tests/v1cmdline/2970242.wrong000066400000000000000000000000071511132717100201350ustar00rootroot00000000000000foobaz nuspell-5.1.7/tests/v1cmdline/2999225.aff000066400000000000000000000000771511132717100175600ustar00rootroot00000000000000COMPOUNDRULE 1 COMPOUNDRULE ab COMPOUNDBEGIN A COMPOUNDEND B nuspell-5.1.7/tests/v1cmdline/2999225.dic000066400000000000000000000000251511132717100175540ustar00rootroot000000000000003 foo/aA bar/b baz/B nuspell-5.1.7/tests/v1cmdline/2999225.good000066400000000000000000000000161511132717100177450ustar00rootroot00000000000000foobar foobaz nuspell-5.1.7/tests/v1cmdline/IJ.aff000066400000000000000000000001571511132717100172140ustar00rootroot00000000000000# check bad capitalisation of Dutch letter IJ. TRY i FORBIDDENWORD * PFX i N 1 PFX i ij IJ ij REP 1 REP ij IJ nuspell-5.1.7/tests/v1cmdline/IJ.dic000066400000000000000000000000161511132717100172110ustar00rootroot000000000000001 ijs/i Ijs/* nuspell-5.1.7/tests/v1cmdline/IJ.good000066400000000000000000000000101511132717100173740ustar00rootroot00000000000000ijs IJs nuspell-5.1.7/tests/v1cmdline/IJ.sug000066400000000000000000000000111511132717100172430ustar00rootroot00000000000000IJs, ijs nuspell-5.1.7/tests/v1cmdline/IJ.wrong000066400000000000000000000000041511132717100176030ustar00rootroot00000000000000Ijs nuspell-5.1.7/tests/v1cmdline/affixes.aff000066400000000000000000000001711511132717100203330ustar00rootroot00000000000000# simple example for affix compression (see Hunspell(4)) PFX A Y 1 PFX A 0 re . SFX B Y 2 SFX B 0 ed [^y] SFX B y ied y nuspell-5.1.7/tests/v1cmdline/affixes.dic000066400000000000000000000000261511132717100203350ustar00rootroot000000000000003 hello try/B work/AB nuspell-5.1.7/tests/v1cmdline/affixes.good000066400000000000000000000000541511132717100205270ustar00rootroot00000000000000hello try tried work worked rework reworked nuspell-5.1.7/tests/v1cmdline/alias.aff000066400000000000000000000001631511132717100200000ustar00rootroot00000000000000# aliases for flag vectors (AF) # AB -> 1 # A -> 2 AF 2 AF AB AF A SFX A Y 1 SFX A 0 x . SFX B Y 1 SFX B 0 y/2 . nuspell-5.1.7/tests/v1cmdline/alias.dic000066400000000000000000000000101511132717100177720ustar00rootroot000000000000001 foo/1 nuspell-5.1.7/tests/v1cmdline/alias.good000066400000000000000000000000241511132717100201700ustar00rootroot00000000000000foo foox fooy fooyx nuspell-5.1.7/tests/v1cmdline/alias2.aff000066400000000000000000000003261511132717100200630ustar00rootroot00000000000000# aliases for flag vectors (AF) and morphological descriptions (AM) # AB -> 1 # A -> 2 AF 2 AF AB AF A AM 3 AM is:affix_x AM ds:affix_y AM po:noun xx:other_data SFX A Y 1 SFX A 0 x . 1 SFX B Y 1 SFX B 0 y/2 . 2 nuspell-5.1.7/tests/v1cmdline/alias2.dic000066400000000000000000000000121511132717100200560ustar00rootroot000000000000001 foo/1 3 nuspell-5.1.7/tests/v1cmdline/alias2.good000066400000000000000000000000241511132717100202520ustar00rootroot00000000000000foo foox fooy fooyx nuspell-5.1.7/tests/v1cmdline/alias2.morph000066400000000000000000000005061511132717100204540ustar00rootroot00000000000000> foo analyze(foo) = st:foo po:noun xx:other_data stem(foo) = foo > foox analyze(foox) = st:foo po:noun xx:other_data is:affix_x stem(foox) = foo > fooy analyze(fooy) = st:foo po:noun xx:other_data ds:affix_y stem(fooy) = fooy > fooyx analyze(fooyx) = st:foo po:noun xx:other_data ds:affix_y is:affix_x stem(fooyx) = fooy nuspell-5.1.7/tests/v1cmdline/alias3.aff000066400000000000000000000003201511132717100200560ustar00rootroot00000000000000# morph. aliases with complex prefixes COMPLEXPREFIXES WORDCHARS _ AM 4 AM affix_1/ AM affix_2/ AM /suffix_1 AM [stem_1] PFX A Y 1 PFX A 0 tek . 1 PFX B Y 1 PFX B 0 met/A . 2 SFX C Y 1 SFX C 0 _test_ . 3 nuspell-5.1.7/tests/v1cmdline/alias3.dic000066400000000000000000000000141511132717100200610ustar00rootroot000000000000001 ouro/BC 4 nuspell-5.1.7/tests/v1cmdline/alias3.good000066400000000000000000000000431511132717100202540ustar00rootroot00000000000000ouro metouro tekmetouro ouro_test_ nuspell-5.1.7/tests/v1cmdline/alias3.morph000066400000000000000000000003451511132717100204560ustar00rootroot00000000000000> ouro analyze(ouro) = [stem_1] ouro:ts > metouro analyze(metouro) = affix_2/ ouro:ts [stem_1] > tekmetouro analyze(tekmetouro) = affix_1/ affix_2/ ouro:ts [stem_1] > ouro_test_ analyze(ouro_test_) = [stem_1] ouro:ts /suffix_1 nuspell-5.1.7/tests/v1cmdline/allcaps.aff000066400000000000000000000001741511132717100203300ustar00rootroot00000000000000# check uppercase forms of allcaps word + affix and words with mixed casing WORDCHARS '. SFX S N 1 SFX S 0 's . nuspell-5.1.7/tests/v1cmdline/allcaps.dic000066400000000000000000000000321511132717100203240ustar00rootroot000000000000002 OpenOffice.org UNICEF/S nuspell-5.1.7/tests/v1cmdline/allcaps.good000066400000000000000000000000601511132717100205160ustar00rootroot00000000000000OpenOffice.org OPENOFFICE.ORG UNICEF's UNICEF'S nuspell-5.1.7/tests/v1cmdline/allcaps.sug000066400000000000000000000000371511132717100203700ustar00rootroot00000000000000OpenOffice.org UNICEF UNICEF's nuspell-5.1.7/tests/v1cmdline/allcaps.wrong000066400000000000000000000000371511132717100207260ustar00rootroot00000000000000Openoffice.org Unicef Unicef's nuspell-5.1.7/tests/v1cmdline/allcaps2.aff000066400000000000000000000001771511132717100204150ustar00rootroot00000000000000# forbidden all caps words are case sensitive # iPod -> ipodos ("iPodic" in Hungarian) FORBIDDENWORD * SFX s N 1 SFX s 0 os . nuspell-5.1.7/tests/v1cmdline/allcaps2.dic000066400000000000000000000000311511132717100204050ustar00rootroot000000000000003 iPod/s iPodos/* ipodos nuspell-5.1.7/tests/v1cmdline/allcaps2.good000066400000000000000000000000301511132717100205750ustar00rootroot00000000000000iPod IPOD ipodos IPODOS nuspell-5.1.7/tests/v1cmdline/allcaps2.sug000066400000000000000000000000141511132717100204450ustar00rootroot00000000000000iPod ipodos nuspell-5.1.7/tests/v1cmdline/allcaps2.wrong000066400000000000000000000000141511132717100210030ustar00rootroot00000000000000ipod iPodos nuspell-5.1.7/tests/v1cmdline/allcaps3.aff000066400000000000000000000001171511132717100204100ustar00rootroot00000000000000# homonym support WORDCHARS ' SFX s N 1 SFX s 0 s . SFX S N 1 SFX S 0 's . nuspell-5.1.7/tests/v1cmdline/allcaps3.dic000066400000000000000000000000551511132717100204140ustar00rootroot000000000000004 UNESCO/S Unesco/S Nasa/S NASA/S ACTS act/s nuspell-5.1.7/tests/v1cmdline/allcaps3.good000066400000000000000000000001271511132717100206050ustar00rootroot00000000000000UNESCO Unesco UNESCO's Unesco's UNESCO'S NASA Nasa NASA's Nasa's NASA'S ACTS acts Acts nuspell-5.1.7/tests/v1cmdline/allcaps3.wrong000066400000000000000000000000341511132717100210060ustar00rootroot00000000000000unesco unesco's nasa nasa's nuspell-5.1.7/tests/v1cmdline/allcaps_utf.aff000066400000000000000000000000601511132717100212000ustar00rootroot00000000000000SET UTF-8 WORDCHARS '. SFX S N 1 SFX S 0 's . nuspell-5.1.7/tests/v1cmdline/allcaps_utf.dic000066400000000000000000000000321511132717100212020ustar00rootroot000000000000002 OpenOffice.org UNICEF/S nuspell-5.1.7/tests/v1cmdline/allcaps_utf.good000066400000000000000000000000601511132717100213740ustar00rootroot00000000000000OpenOffice.org OPENOFFICE.ORG UNICEF's UNICEF'S nuspell-5.1.7/tests/v1cmdline/allcaps_utf.sug000066400000000000000000000000371511132717100212460ustar00rootroot00000000000000OpenOffice.org UNICEF UNICEF's nuspell-5.1.7/tests/v1cmdline/allcaps_utf.wrong000066400000000000000000000000371511132717100216040ustar00rootroot00000000000000Openoffice.org Unicef Unicef's nuspell-5.1.7/tests/v1cmdline/arabic.aff000066400000000000000000000001111511132717100201210ustar00rootroot00000000000000SET UTF-8 TRY أ IGNORE ٌٍَُِّْ PFX Aa Y 1 PFX Aa 0 0/X0 أ[^ي] nuspell-5.1.7/tests/v1cmdline/arabic.dic000066400000000000000000000000051511132717100201260ustar00rootroot000000000000001 ب nuspell-5.1.7/tests/v1cmdline/arabic.wrong000066400000000000000000000000031511132717100205210ustar00rootroot00000000000000ـ nuspell-5.1.7/tests/v1cmdline/base.aff000066400000000000000000000053051511132717100176240ustar00rootroot00000000000000# OpenOffice.org's en_US.aff file SET ISO8859-1 TRY esianrtolcdugmphbyfvkwz' WORDCHARS .' PFX A Y 1 PFX A 0 re . PFX I Y 1 PFX I 0 in . PFX U Y 1 PFX U 0 un . PFX C Y 1 PFX C 0 de . PFX E Y 1 PFX E 0 dis . PFX F Y 1 PFX F 0 con . PFX K Y 1 PFX K 0 pro . SFX V N 2 SFX V e ive e SFX V 0 ive [^e] SFX N Y 3 SFX N e ion e SFX N y ication y SFX N 0 en [^ey] SFX X Y 3 SFX X e ions e SFX X y ications y SFX X 0 ens [^ey] SFX H N 2 SFX H y ieth y SFX H 0 th [^y] SFX Y Y 1 SFX Y 0 ly . SFX G Y 2 SFX G e ing e SFX G 0 ing [^e] SFX J Y 2 SFX J e ings e SFX J 0 ings [^e] SFX D Y 4 SFX D 0 d e SFX D y ied [^aeiou]y SFX D 0 ed [^ey] SFX D 0 ed [aeiou]y SFX T N 4 SFX T 0 st e SFX T y iest [^aeiou]y SFX T 0 est [aeiou]y SFX T 0 est [^ey] SFX R Y 4 SFX R 0 r e SFX R y ier [^aeiou]y SFX R 0 er [aeiou]y SFX R 0 er [^ey] SFX Z Y 4 SFX Z 0 rs e SFX Z y iers [^aeiou]y SFX Z 0 ers [aeiou]y SFX Z 0 ers [^ey] SFX S Y 4 SFX S y ies [^aeiou]y SFX S 0 s [aeiou]y SFX S 0 es [sxzh] SFX S 0 s [^sxzhy] SFX P Y 3 SFX P y iness [^aeiou]y SFX P 0 ness [aeiou]y SFX P 0 ness [^y] SFX M Y 1 SFX M 0 's . SFX B Y 3 SFX B 0 able [^aeiou] SFX B 0 able ee SFX B e able [^aeiou]e SFX L Y 1 SFX L 0 ment . REP 88 REP a ei REP ei a REP a ey REP ey a REP ai ie REP ie ai REP are air REP are ear REP are eir REP air are REP air ere REP ere air REP ere ear REP ere eir REP ear are REP ear air REP ear ere REP eir are REP eir ere REP ch te REP te ch REP ch ti REP ti ch REP ch tu REP tu ch REP ch s REP s ch REP ch k REP k ch REP f ph REP ph f REP gh f REP f gh REP i igh REP igh i REP i uy REP uy i REP i ee REP ee i REP j di REP di j REP j gg REP gg j REP j ge REP ge j REP s ti REP ti s REP s ci REP ci s REP k cc REP cc k REP k qu REP qu k REP kw qu REP o eau REP eau o REP o ew REP ew o REP oo ew REP ew oo REP ew ui REP ui ew REP oo ui REP ui oo REP ew u REP u ew REP oo u REP u oo REP u oe REP oe u REP u ieu REP ieu u REP ue ew REP ew ue REP uff ough REP oo ieu REP ieu oo REP ier ear REP ear ier REP ear air REP air ear REP w qu REP qu w REP z ss REP ss z REP shun tion REP shun sion REP shun cion nuspell-5.1.7/tests/v1cmdline/base.dic000066400000000000000000000003421511132717100176230ustar00rootroot0000000000000028 created/U create/XKVNGADS imply/GNSDX natural/PUY like/USPBY convey/BDGS look/GZRDS text hello said sawyer NASA rotten day tomorrow seven FAQ/SM can't doesn't etc won't lip text horrifying speech suggest uncreate/V Nuspell nuspell-5.1.7/tests/v1cmdline/base.good000066400000000000000000000002701511132717100200140ustar00rootroot00000000000000created uncreate uncreated imply implied unnatural conveyed sawyer NASA FAQs can't doesn't won't Created Hello HELLO NASA etc. etc HELLO lip. text. NASA. Text. TEXT. Nuspell. NUSPELL. nuspell-5.1.7/tests/v1cmdline/base.sug000066400000000000000000000001521511132717100176610ustar00rootroot00000000000000looked, look text hello said rotten day, rotten-day, rotten tomorrow seven NASA horrifying speech suggest nuspell-5.1.7/tests/v1cmdline/base.wrong000066400000000000000000000001221511132717100202140ustar00rootroot00000000000000loooked texxt hlelo seid rottenday tomorow seeeven Nasa horrorfying peech sugesst nuspell-5.1.7/tests/v1cmdline/base_utf.aff000066400000000000000000000056511511132717100205060ustar00rootroot00000000000000# OpenOffice.org’s en_US.aff file # with Unicode apostrophe: ’ SET UTF-8 TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' MAXNGRAMSUGS 1 WORDCHARS .'’ PFX A Y 1 PFX A 0 re . PFX I Y 1 PFX I 0 in . PFX U Y 1 PFX U 0 un . PFX C Y 1 PFX C 0 de . PFX E Y 1 PFX E 0 dis . PFX F Y 1 PFX F 0 con . PFX K Y 1 PFX K 0 pro . SFX V N 2 SFX V e ive e SFX V 0 ive [^e] SFX N Y 3 SFX N e ion e SFX N y ication y SFX N 0 en [^ey] SFX X Y 3 SFX X e ions e SFX X y ications y SFX X 0 ens [^ey] SFX H N 2 SFX H y ieth y SFX H 0 th [^y] SFX Y Y 1 SFX Y 0 ly . SFX G Y 2 SFX G e ing e SFX G 0 ing [^e] SFX J Y 2 SFX J e ings e SFX J 0 ings [^e] SFX D Y 4 SFX D 0 d e SFX D y ied [^aeiou]y SFX D 0 ed [^ey] SFX D 0 ed [aeiou]y SFX T N 4 SFX T 0 st e SFX T y iest [^aeiou]y SFX T 0 est [aeiou]y SFX T 0 est [^ey] SFX R Y 4 SFX R 0 r e SFX R y ier [^aeiou]y SFX R 0 er [aeiou]y SFX R 0 er [^ey] SFX Z Y 4 SFX Z 0 rs e SFX Z y iers [^aeiou]y SFX Z 0 ers [aeiou]y SFX Z 0 ers [^ey] SFX S Y 4 SFX S y ies [^aeiou]y SFX S 0 s [aeiou]y SFX S 0 es [sxzh] SFX S 0 s [^sxzhy] SFX P Y 3 SFX P y iness [^aeiou]y SFX P 0 ness [aeiou]y SFX P 0 ness [^y] SFX M Y 1 SFX M 0 's . SFX B Y 3 SFX B 0 able [^aeiou] SFX B 0 able ee SFX B e able [^aeiou]e SFX L Y 1 SFX L 0 ment . REP 88 REP a ei REP ei a REP a ey REP ey a REP ai ie REP ie ai REP are air REP are ear REP are eir REP air are REP air ere REP ere air REP ere ear REP ere eir REP ear are REP ear air REP ear ere REP eir are REP eir ere REP ch te REP te ch REP ch ti REP ti ch REP ch tu REP tu ch REP ch s REP s ch REP ch k REP k ch REP f ph REP ph f REP gh f REP f gh REP i igh REP igh i REP i uy REP uy i REP i ee REP ee i REP j di REP di j REP j gg REP gg j REP j ge REP ge j REP s ti REP ti s REP s ci REP ci s REP k cc REP cc k REP k qu REP qu k REP kw qu REP o eau REP eau o REP o ew REP ew o REP oo ew REP ew oo REP ew ui REP ui ew REP oo ui REP ui oo REP ew u REP u ew REP oo u REP u oo REP u oe REP oe u REP u ieu REP ieu u REP ue ew REP ew ue REP uff ough REP oo ieu REP ieu oo REP ier ear REP ear ier REP ear air REP air ear REP w qu REP qu w REP z ss REP ss z REP shun tion REP shun sion REP shun cion McDonalds’sá/w McDonald’sszá/g3) st:McDonald’s po:noun_prs is:TRANS McDonald’sszal/g4) st:McDonald’s po:noun_prs is:INSTR McDonald’ssal/w nuspell-5.1.7/tests/v1cmdline/base_utf.dic000066400000000000000000000003571511132717100205070ustar00rootroot0000000000000028 created/U create/XKVNGADS imply/GNSDX natural/PUY like/USPBY convey/BDGS look/GZRDS text hello said sawyer NASA rotten day tomorrow seven FAQ/SM can’t doesn’t etc won’t lip text horrifying speech suggest uncreate/V Nuspell İzmir nuspell-5.1.7/tests/v1cmdline/base_utf.good000066400000000000000000000003521511132717100206730ustar00rootroot00000000000000created uncreate uncreated imply implied unnatural conveyed sawyer NASA FAQs can’t doesn’t won’t Created Hello HELLO NASA etc. etc HELLO lip. text. NASA. Text. TEXT. Nuspell. NUSPELL. İzmir İZMİR İzmir. İZMİR. Imply IMPLY nuspell-5.1.7/tests/v1cmdline/base_utf.sug000066400000000000000000000001661511132717100205440ustar00rootroot00000000000000looked, look text hello said rotten day, rotten-day, rotten tomorrow seven NASA horrifying speech suggest Imply IMPLY nuspell-5.1.7/tests/v1cmdline/base_utf.wrong000066400000000000000000000001401511132717100210720ustar00rootroot00000000000000loooked texxt hlelo seid rottenday tomorow seeeven Nasa horrorfying peech sugesst İmply İMPLY nuspell-5.1.7/tests/v1cmdline/break.aff000066400000000000000000000003121511132717100177670ustar00rootroot00000000000000# word break points test, recursive break at dash and n-dash # note: spelling is incorrect when word has ten or more break patterns SET UTF-8 BREAK 2 BREAK - BREAK – WORDCHARS -– FORBIDDENWORD ! nuspell-5.1.7/tests/v1cmdline/break.dic000066400000000000000000000000401511132717100177700ustar00rootroot000000000000003 foo bar baz fox-bax foo-baz/! nuspell-5.1.7/tests/v1cmdline/break.good000066400000000000000000000001741511132717100201710ustar00rootroot00000000000000foo bar fox-bax foo-bar foo–bar foo-bar-foo-bar foo-bar–foo-bar bar-baz baz-foo foo-bar-foo-bar-foo-bar-foo-bar-foo-bar nuspell-5.1.7/tests/v1cmdline/break.wrong000066400000000000000000000002561511132717100203760ustar00rootroot00000000000000fox bax -foo bar- fox-bar foo-bax foo–bax fox–bar foo-bar-fox-bar foo-bax-foo-bar foo-bar–fox-bar foo-bax–foo-bar foo-baz foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo nuspell-5.1.7/tests/v1cmdline/breakdefault.aff000066400000000000000000000001321511132717100213340ustar00rootroot00000000000000# default word break at hyphens and n-dashes SET UTF-8 MAXNGRAMSUGS 0 WORDCHARS - TRY ot nuspell-5.1.7/tests/v1cmdline/breakdefault.dic000066400000000000000000000000371511132717100213430ustar00rootroot000000000000003 foo bar free scott scot-free nuspell-5.1.7/tests/v1cmdline/breakdefault.good000066400000000000000000000000641511132717100215340ustar00rootroot00000000000000foo bar foo- -foo scot-free foo-bar foo-bar-foo-bar nuspell-5.1.7/tests/v1cmdline/breakdefault.sug000066400000000000000000000000601511132717100213760ustar00rootroot00000000000000scott scot-free foo-bar foo-foo-bar foo-foo-foo nuspell-5.1.7/tests/v1cmdline/breakdefault.wrong000066400000000000000000000000531511132717100217360ustar00rootroot00000000000000scot sco-free fo-bar foo-fo-bar foo-foo-fo nuspell-5.1.7/tests/v1cmdline/breakoff.aff000066400000000000000000000001701511132717100204640ustar00rootroot00000000000000# switch off default word break at hyphens and n-dashes by BREAK 0 SET UTF-8 MAXNGRAMSUGS 0 WORDCHARS - TRY ot BREAK 0 nuspell-5.1.7/tests/v1cmdline/breakoff.dic000066400000000000000000000000371511132717100204710ustar00rootroot000000000000003 foo bar free scott scot-free nuspell-5.1.7/tests/v1cmdline/breakoff.good000066400000000000000000000000221511132717100206540ustar00rootroot00000000000000foo bar scot-free nuspell-5.1.7/tests/v1cmdline/breakoff.wrong000066400000000000000000000000471511132717100210670ustar00rootroot00000000000000foo- -foo foo-bar foo-bar-foo-bar scot nuspell-5.1.7/tests/v1cmdline/checkcompoundcase.aff000066400000000000000000000001331511132717100223620ustar00rootroot00000000000000# forbid upper case letters at word bounds in compounding CHECKCOMPOUNDCASE COMPOUNDFLAG A nuspell-5.1.7/tests/v1cmdline/checkcompoundcase.dic000066400000000000000000000000301511132717100223610ustar00rootroot000000000000004 foo/A Bar/A BAZ/A -/A nuspell-5.1.7/tests/v1cmdline/checkcompoundcase.good000066400000000000000000000000471511132717100225620ustar00rootroot00000000000000Barfoo foo-Bar foo-BAZ BAZ-foo BAZ-Bar nuspell-5.1.7/tests/v1cmdline/checkcompoundcase.wrong000066400000000000000000000000251511132717100227620ustar00rootroot00000000000000fooBar BAZBar BAZfoo nuspell-5.1.7/tests/v1cmdline/checkcompoundcase2.aff000066400000000000000000000000701511132717100224440ustar00rootroot00000000000000# check extended ascii CHECKCOMPOUNDCASE COMPOUNDFLAG A nuspell-5.1.7/tests/v1cmdline/checkcompoundcase2.dic000066400000000000000000000000161511132717100224470ustar00rootroot000000000000002 o/A o/A nuspell-5.1.7/tests/v1cmdline/checkcompoundcase2.good000066400000000000000000000000261511132717100226410ustar00rootroot00000000000000áoóáoó Óoááoó nuspell-5.1.7/tests/v1cmdline/checkcompoundcase2.wrong000066400000000000000000000000131511132717100230410ustar00rootroot00000000000000áoóÓoá nuspell-5.1.7/tests/v1cmdline/checkcompoundcaseutf.aff000066400000000000000000000000531511132717100231020ustar00rootroot00000000000000SET UTF-8 CHECKCOMPOUNDCASE COMPOUNDFLAG A nuspell-5.1.7/tests/v1cmdline/checkcompoundcaseutf.dic000066400000000000000000000000221511132717100231010ustar00rootroot000000000000002 áoó/A Óoá/A nuspell-5.1.7/tests/v1cmdline/checkcompoundcaseutf.good000066400000000000000000000000261511132717100232760ustar00rootroot00000000000000áoóáoó Óoááoó nuspell-5.1.7/tests/v1cmdline/checkcompoundcaseutf.wrong000066400000000000000000000000131511132717100234760ustar00rootroot00000000000000áoóÓoá nuspell-5.1.7/tests/v1cmdline/checkcompounddup.aff000066400000000000000000000001131511132717100222350ustar00rootroot00000000000000# Forbid compound word with triple letters CHECKCOMPOUNDDUP COMPOUNDFLAG A nuspell-5.1.7/tests/v1cmdline/checkcompounddup.dic000066400000000000000000000000161511132717100222420ustar00rootroot000000000000002 foo/A bar/A nuspell-5.1.7/tests/v1cmdline/checkcompounddup.good000066400000000000000000000000571511132717100224400ustar00rootroot00000000000000barfoo foobar foofoobar foobarfoo barfoobarfoo nuspell-5.1.7/tests/v1cmdline/checkcompounddup.wrong000066400000000000000000000000331511132717100226360ustar00rootroot00000000000000foofoo foofoofoo foobarbar nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern.aff000066400000000000000000000002231511132717100231240ustar00rootroot00000000000000# forbid compounds with spec. pattern at word bounds COMPOUNDFLAG A CHECKCOMPOUNDPATTERN 2 CHECKCOMPOUNDPATTERN nny ny CHECKCOMPOUNDPATTERN ssz sz nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern.dic000066400000000000000000000000461511132717100231320ustar00rootroot000000000000004 knny/A nyels/A hossz/A szmts/A nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern.good000066400000000000000000000000371511132717100233230ustar00rootroot00000000000000könnyszámítás hossznyelés nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern.wrong000066400000000000000000000001051511132717100235230ustar00rootroot00000000000000könnynyelés hosszszámítás hosszkönnynyelés könnynyeléshossz nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern2.aff000066400000000000000000000003371511132717100232140ustar00rootroot00000000000000# forbid compounds with spec. pattern at word bound and allow modificated form # (for German and Indian languages) COMPOUNDFLAG A CHECKCOMPOUNDPATTERN 2 CHECKCOMPOUNDPATTERN o b z CHECKCOMPOUNDPATTERN oo ba u COMPOUNDMIN 1 nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern2.dic000066400000000000000000000000161511132717100232110ustar00rootroot000000000000002 foo/A bar/A nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern2.good000066400000000000000000000000211511132717100233760ustar00rootroot00000000000000barfoo fozar fur nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern2.wrong000066400000000000000000000000071511132717100236060ustar00rootroot00000000000000foobar nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern3.aff000066400000000000000000000002731511132717100232140ustar00rootroot00000000000000# forbid compounds with spec. pattern at word bound and allow modificated form # (for Indian languages) COMPOUNDFLAG A CHECKCOMPOUNDPATTERN 1 CHECKCOMPOUNDPATTERN o/X b/Y z COMPOUNDMIN 1 nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern3.dic000066400000000000000000000000341511132717100232120ustar00rootroot000000000000004 foo/A boo/AX bar/A ban/AY nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern3.good000066400000000000000000000001041511132717100234010ustar00rootroot00000000000000bozan barfoo banfoo banbar foobar fooban foobanbar boobar boobarfoo nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern3.wrong000066400000000000000000000000761511132717100236150ustar00rootroot00000000000000booban boobanfoo fozar fozarfoo fozan fozanfoo bozar bozarfoo nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern4.aff000066400000000000000000000002761511132717100232200ustar00rootroot00000000000000# sandhi in Telugu writing system, based on the Kiran Chittella's example COMPOUNDFLAG x COMPOUNDMIN 1 CHECKCOMPOUNDPATTERN 2 CHECKCOMPOUNDPATTERN a/A u/A O CHECKCOMPOUNDPATTERN u/B u/B u nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern4.dic000066400000000000000000000000461511132717100232160ustar00rootroot000000000000004 sUrya/Ax udayaM/Ax pEru/Bx unna/Bx nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern4.good000066400000000000000000000000231511132717100234020ustar00rootroot00000000000000sUryOdayaM pErunna nuspell-5.1.7/tests/v1cmdline/checkcompoundpattern4.wrong000066400000000000000000000000251511132717100236100ustar00rootroot00000000000000sUryaudayaM pEruunna nuspell-5.1.7/tests/v1cmdline/checkcompoundrep.aff000066400000000000000000000004311511132717100222360ustar00rootroot00000000000000// forbid compound word, if it is also a non-compound word with a REP fault // In example: Hungarian `szervz' (szer+vz) compound word is forbidden, because // this word is also a dictionary word (szerviz) with typical fault (i->) CHECKCOMPOUNDREP COMPOUNDFLAG A REP 1 REP i nuspell-5.1.7/tests/v1cmdline/checkcompoundrep.dic000066400000000000000000000000371511132717100222430ustar00rootroot000000000000003 szer/A vz/A szerviz kocsi/A nuspell-5.1.7/tests/v1cmdline/checkcompoundrep.good000066400000000000000000000000231511132717100224270ustar00rootroot00000000000000vízszer szerkocsi nuspell-5.1.7/tests/v1cmdline/checkcompoundrep.wrong000066400000000000000000000000451511132717100226370ustar00rootroot00000000000000szervíz szervízkocsi kocsiszervíz nuspell-5.1.7/tests/v1cmdline/checkcompoundtriple.aff000066400000000000000000000001161511132717100227470ustar00rootroot00000000000000# Forbid compound word with triple letters CHECKCOMPOUNDTRIPLE COMPOUNDFLAG A nuspell-5.1.7/tests/v1cmdline/checkcompoundtriple.dic000066400000000000000000000000351511132717100227520ustar00rootroot000000000000004 foo/A opera/A eel/A bare/A nuspell-5.1.7/tests/v1cmdline/checkcompoundtriple.good000066400000000000000000000000641511132717100231450ustar00rootroot00000000000000operafoo operaeel operabare eelbare eelfoo eelopera nuspell-5.1.7/tests/v1cmdline/checkcompoundtriple.wrong000066400000000000000000000000211511132717100233420ustar00rootroot00000000000000fooopera bareeel nuspell-5.1.7/tests/v1cmdline/checksharps.aff000066400000000000000000000001071511132717100212030ustar00rootroot00000000000000# test - SS special capitalizing CHECKSHARPS WORDCHARS . KEEPCASE k nuspell-5.1.7/tests/v1cmdline/checksharps.dic000066400000000000000000000001051511132717100212040ustar00rootroot000000000000006 mig/k Aussto Absto. Auenabmessung Prozessionsstrae Auenmae nuspell-5.1.7/tests/v1cmdline/checksharps.good000066400000000000000000000002321511132717100213760ustar00rootroot00000000000000müßig Müßig MÜSSIG Ausstoß Abstoß. Außenabmessung Prozessionsstraße Außenmaße AUSSTOSS ABSTOSS. AUSSENABMESSUNG PROZESSIONSSTRASSE AUSSENMASSE nuspell-5.1.7/tests/v1cmdline/checksharps.sug000066400000000000000000000000211511132717100212400ustar00rootroot00000000000000MÜSSIG, müßig nuspell-5.1.7/tests/v1cmdline/checksharps.wrong000066400000000000000000000000101511132717100215740ustar00rootroot00000000000000MÜßIG nuspell-5.1.7/tests/v1cmdline/checksharpsutf.aff000066400000000000000000000001331511132717100217210ustar00rootroot00000000000000# test - SS special capitalizing in UTF-8 SET UTF-8 CHECKSHARPS WORDCHARS ß. KEEPCASE k nuspell-5.1.7/tests/v1cmdline/checksharpsutf.dic000066400000000000000000000001151511132717100217240ustar00rootroot000000000000006 müßig/k Ausstoß Abstoß. Außenabmessung Prozessionsstraße Außenmaße nuspell-5.1.7/tests/v1cmdline/checksharpsutf.good000066400000000000000000000002321511132717100221150ustar00rootroot00000000000000müßig Müßig MÜSSIG Ausstoß Abstoß. Außenabmessung Prozessionsstraße Außenmaße AUSSTOSS ABSTOSS. AUSSENABMESSUNG PROZESSIONSSTRASSE AUSSENMASSE nuspell-5.1.7/tests/v1cmdline/checksharpsutf.sug000066400000000000000000000000211511132717100217570ustar00rootroot00000000000000MÜSSIG, müßig nuspell-5.1.7/tests/v1cmdline/checksharpsutf.wrong000066400000000000000000000000101511132717100223130ustar00rootroot00000000000000MÜßIG nuspell-5.1.7/tests/v1cmdline/circumfix.aff000066400000000000000000000004461511132717100207040ustar00rootroot00000000000000# circumfixes: ~ obligate prefix/suffix combinations # superlative in Hungarian: leg- (prefix) AND -bb (suffix) CIRCUMFIX X PFX A Y 1 PFX A 0 leg/X . PFX B Y 1 PFX B 0 legesleg/X . SFX C Y 3 SFX C 0 obb . is:COMPARATIVE SFX C 0 obb/AX . is:SUPERLATIVE SFX C 0 obb/BX . is:SUPERSUPERLATIVE nuspell-5.1.7/tests/v1cmdline/circumfix.dic000066400000000000000000000000201511132717100206730ustar00rootroot000000000000001 nagy/C po:adj nuspell-5.1.7/tests/v1cmdline/circumfix.good000066400000000000000000000000501511132717100210670ustar00rootroot00000000000000nagy nagyobb legnagyobb legeslegnagyobb nuspell-5.1.7/tests/v1cmdline/circumfix.morph000066400000000000000000000005341511132717100212730ustar00rootroot00000000000000> nagy analyze(nagy) = st:nagy po:adj stem(nagy) = nagy > nagyobb analyze(nagyobb) = st:nagy po:adj is:COMPARATIVE stem(nagyobb) = nagy > legnagyobb analyze(legnagyobb) = fl:A st:nagy po:adj is:SUPERLATIVE stem(legnagyobb) = nagy > legeslegnagyobb analyze(legeslegnagyobb) = fl:B st:nagy po:adj is:SUPERSUPERLATIVE stem(legeslegnagyobb) = nagy nuspell-5.1.7/tests/v1cmdline/circumfix.wrong000066400000000000000000000000251511132717100212750ustar00rootroot00000000000000legnagy legeslegnagy nuspell-5.1.7/tests/v1cmdline/colons_in_words.aff000066400000000000000000000001631511132717100221100ustar00rootroot00000000000000# Colons in Finnish and Swedish words. Problem reported by Lars Aronsson. # Parsing test (src/parsers) WORDCHARS : nuspell-5.1.7/tests/v1cmdline/colons_in_words.dic000066400000000000000000000000161511132717100221100ustar00rootroot000000000000002 c:a S:t foo nuspell-5.1.7/tests/v1cmdline/complexprefixes.aff000066400000000000000000000002061511132717100221220ustar00rootroot00000000000000# set twofold prefix stripping # Coptic example by Moheb Mekhaiel COMPLEXPREFIXES PFX A Y 1 PFX A 0 tek . PFX B Y 1 PFX B 0 met/A . nuspell-5.1.7/tests/v1cmdline/complexprefixes.dic000066400000000000000000000000121511132717100221200ustar00rootroot000000000000001 ouro/B nuspell-5.1.7/tests/v1cmdline/complexprefixes.good000066400000000000000000000000301511132717100223110ustar00rootroot00000000000000ouro metouro tekmetouro nuspell-5.1.7/tests/v1cmdline/complexprefixes.wrong000066400000000000000000000000231511132717100225170ustar00rootroot00000000000000tekouro mettekouro nuspell-5.1.7/tests/v1cmdline/complexprefixes2.aff000066400000000000000000000002671511132717100222130ustar00rootroot00000000000000# complex prefixes with morphological analysis COMPLEXPREFIXES WORDCHARS _ PFX A Y 1 PFX A 0 tek . affix_1/ PFX B Y 1 PFX B 0 met/A . affix_2/ SFX C Y 1 SFX C 0 _test_ . /suffix_1 nuspell-5.1.7/tests/v1cmdline/complexprefixes2.dic000066400000000000000000000000241511132717100222050ustar00rootroot000000000000001 ouro/BC [stem_1] nuspell-5.1.7/tests/v1cmdline/complexprefixes2.good000066400000000000000000000000431511132717100223770ustar00rootroot00000000000000ouro metouro tekmetouro ouro_test_ nuspell-5.1.7/tests/v1cmdline/complexprefixesutf.aff000066400000000000000000000003351511132717100226440ustar00rootroot00000000000000# Coptic example by Moheb Mekhaiel # Encoded with the new Coptic character encoding of Unicode 4.1 SET UTF-8 # set twofold prefix stripping COMPLEXPREFIXES PFX A Y 1 PFX A 0 ⲧⲉⲕ . PFX B Y 1 PFX B 0 ⲙⲉⲧ/A . nuspell-5.1.7/tests/v1cmdline/complexprefixesutf.dic000066400000000000000000000000211511132717100226370ustar00rootroot000000000000001 ⲟⲩⲣⲟ/B nuspell-5.1.7/tests/v1cmdline/complexprefixesutf.good000066400000000000000000000001021511132717100230300ustar00rootroot00000000000000ⲟⲩⲣⲟ ⲙⲉⲧⲟⲩⲣⲟ ⲧⲉⲕⲙⲉⲧⲟⲩⲣⲟ nuspell-5.1.7/tests/v1cmdline/complexprefixesutf.wrong000066400000000000000000000000651511132717100232440ustar00rootroot00000000000000ⲧⲉⲕⲟⲩⲣⲟ ⲙⲉⲧⲧⲉⲕⲟⲩⲣⲟ nuspell-5.1.7/tests/v1cmdline/compoundaffix.aff000066400000000000000000000001351511132717100215500ustar00rootroot00000000000000COMPOUNDFLAG X PFX P Y 1 PFX P 0 pre . SFX S Y 1 SFX S 0 suf . nuspell-5.1.7/tests/v1cmdline/compoundaffix.dic000066400000000000000000000000221511132717100215460ustar00rootroot000000000000002 foo/XPS bar/XPS nuspell-5.1.7/tests/v1cmdline/compoundaffix.good000066400000000000000000000000601511132717100217410ustar00rootroot00000000000000foo foofoo prefoo foosuf prefoosuf prefoobarsuf nuspell-5.1.7/tests/v1cmdline/compoundaffix.wrong000066400000000000000000000000471511132717100221520ustar00rootroot00000000000000foosufbar fooprebarsuf prefooprebarsuf nuspell-5.1.7/tests/v1cmdline/compoundaffix2.aff000066400000000000000000000001661511132717100216360ustar00rootroot00000000000000COMPOUNDFLAG X COMPOUNDPERMITFLAG Y PFX P Y 1 PFX P 0 pre/Y . SFX S Y 1 SFX S 0 suf/Y . nuspell-5.1.7/tests/v1cmdline/compoundaffix2.dic000066400000000000000000000000221511132717100216300ustar00rootroot000000000000002 foo/XPS bar/XPS nuspell-5.1.7/tests/v1cmdline/compoundaffix2.good000066400000000000000000000001201511132717100220200ustar00rootroot00000000000000foo prefoo foosuf prefoosuf prefoobarsuf foosufbar fooprebarsuf prefooprebarsuf nuspell-5.1.7/tests/v1cmdline/compoundaffix3.aff000066400000000000000000000001661511132717100216370ustar00rootroot00000000000000COMPOUNDFLAG X COMPOUNDFORBIDFLAG Z PFX P Y 1 PFX P 0 pre/Z . SFX S Y 1 SFX S 0 suf/Z . nuspell-5.1.7/tests/v1cmdline/compoundaffix3.dic000066400000000000000000000000221511132717100216310ustar00rootroot000000000000002 foo/XPS bar/XPS nuspell-5.1.7/tests/v1cmdline/compoundaffix3.good000066400000000000000000000000431511132717100220250ustar00rootroot00000000000000foo foofoo prefoo foosuf prefoosuf nuspell-5.1.7/tests/v1cmdline/compoundaffix3.wrong000066400000000000000000000001131511132717100222270ustar00rootroot00000000000000prefoobarsuf foosufbar fooprebar foosufprebar fooprebarsuf prefooprebarsuf nuspell-5.1.7/tests/v1cmdline/compoundflag.aff000066400000000000000000000000361511132717100213640ustar00rootroot00000000000000COMPOUNDMIN 3 COMPOUNDFLAG A nuspell-5.1.7/tests/v1cmdline/compoundflag.dic000066400000000000000000000000301511132717100213610ustar00rootroot000000000000004 foo/A bar/A xy/A yz/A nuspell-5.1.7/tests/v1cmdline/compoundflag.good000066400000000000000000000000301511132717100215520ustar00rootroot00000000000000foobar barfoo foobarfoo nuspell-5.1.7/tests/v1cmdline/compoundflag.wrong000066400000000000000000000000321511132717100217600ustar00rootroot00000000000000xyyz fooxy xyfoo fooxybar nuspell-5.1.7/tests/v1cmdline/compoundrule.aff000066400000000000000000000000561511132717100214240ustar00rootroot00000000000000COMPOUNDMIN 1 COMPOUNDRULE 1 COMPOUNDRULE ABC nuspell-5.1.7/tests/v1cmdline/compoundrule.dic000066400000000000000000000000201511132717100214160ustar00rootroot000000000000003 a/A b/B c/BC nuspell-5.1.7/tests/v1cmdline/compoundrule.good000066400000000000000000000000101511132717100216060ustar00rootroot00000000000000abc acc nuspell-5.1.7/tests/v1cmdline/compoundrule.wrong000066400000000000000000000003111511132717100220160ustar00rootroot00000000000000ba aaabaaa bbaaa aaaaba bbbbbaa aa aaa aaaa ab aab aaab aaaab abb aabb aaabbb bb bbb bbbb aaab abcc abbc abbcc aabc aabcc aabbc aabbcc aaabbbccc ac aac aacc aaaccc bc bcc bbc bbcc bbbccc cc ccc cccccc nuspell-5.1.7/tests/v1cmdline/compoundrule2.aff000066400000000000000000000000611511132717100215020ustar00rootroot00000000000000COMPOUNDMIN 1 COMPOUNDRULE 1 COMPOUNDRULE A*B*C* nuspell-5.1.7/tests/v1cmdline/compoundrule2.dic000066400000000000000000000000171511132717100215060ustar00rootroot000000000000003 a/A b/B c/C nuspell-5.1.7/tests/v1cmdline/compoundrule2.good000066400000000000000000000002661511132717100217050ustar00rootroot00000000000000aa aaa aaaa ab aab aaab aaaab abb aabb aaabbb bb bbb bbbb aaab abc abcc abbc abbcc aabc aabcc aabbc aabbcc aaabbbccc ac acc aac aacc aaaccc bc bcc bbc bbcc bbbccc cc ccc cccccc abcc nuspell-5.1.7/tests/v1cmdline/compoundrule2.wrong000066400000000000000000000000541511132717100221040ustar00rootroot00000000000000ba aaabaaa bbaaa aaaaba bbbbbaa cba cab acb nuspell-5.1.7/tests/v1cmdline/compoundrule3.aff000066400000000000000000000000611511132717100215030ustar00rootroot00000000000000COMPOUNDMIN 1 COMPOUNDRULE 1 COMPOUNDRULE A?B?C? nuspell-5.1.7/tests/v1cmdline/compoundrule3.dic000066400000000000000000000000171511132717100215070ustar00rootroot000000000000003 a/A b/B c/C nuspell-5.1.7/tests/v1cmdline/compoundrule3.good000066400000000000000000000000231511132717100216750ustar00rootroot00000000000000a b c ab abc ac bc nuspell-5.1.7/tests/v1cmdline/compoundrule3.wrong000066400000000000000000000003251511132717100221060ustar00rootroot00000000000000aa aaa aaaa aab aaab aaaab abb aabb aaabbb bb bbb bbbb aaab abcc abbc abbcc aabc aabcc aabbc aabbcc aaabbbccc acc aac aacc aaaccc bcc bbc bbcc bbbccc cc ccc cccccc abcc ba aaabaaa bbaaa aaaaba bbbbbaa cba cab acb nuspell-5.1.7/tests/v1cmdline/compoundrule4.aff000066400000000000000000000002011511132717100215000ustar00rootroot00000000000000# English ordinal numbers WORDCHARS 0123456789 COMPOUNDMIN 1 ONLYINCOMPOUND c COMPOUNDRULE 2 COMPOUNDRULE n*1t COMPOUNDRULE n*mp nuspell-5.1.7/tests/v1cmdline/compoundrule4.dic000066400000000000000000000002151511132717100215100ustar00rootroot0000000000000022 0/nm 1/n1 2/nm 3/nm 4/nm 5/nm 6/nm 7/nm 8/nm 9/nm 0th/pt 1st/p 1th/tc 2nd/p 2th/tc 3rd/p 3th/tc 4th/pt 5th/pt 6th/pt 7th/pt 8th/pt 9th/pt nuspell-5.1.7/tests/v1cmdline/compoundrule4.good000066400000000000000000000002211511132717100216760ustar00rootroot000000000000001st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 100th 1000th 10001st 10011th nuspell-5.1.7/tests/v1cmdline/compoundrule4.wrong000066400000000000000000000000341511132717100221040ustar00rootroot000000000000001th 2th 3th 10001th 10011st nuspell-5.1.7/tests/v1cmdline/compoundrule5.aff000066400000000000000000000001741511132717100215120ustar00rootroot00000000000000# number + percent SET UTF-8 COMPOUNDMIN 1 COMPOUNDRULE 2 COMPOUNDRULE N*%? COMPOUNDRULE NN*.NN*%? WORDCHARS 0123456789‰. nuspell-5.1.7/tests/v1cmdline/compoundrule5.dic000066400000000000000000000002551511132717100215150ustar00rootroot0000000000000013 0/N po:num 1/N po:num 2/N po:num 3/N po:num 4/N po:num 5/N po:num 6/N po:num 7/N po:num 8/N po:num 9/N po:num ./. po:sign_dot %/% po:sign_percent ‰/% po:sign_per_mille nuspell-5.1.7/tests/v1cmdline/compoundrule5.good000066400000000000000000000000511511132717100217000ustar00rootroot0000000000000010% 0.2% 0.20% 123.4561‰ 10 0000 10.25 nuspell-5.1.7/tests/v1cmdline/compoundrule5.morph000066400000000000000000000016341511132717100221050ustar00rootroot00000000000000> 10% analyze(10%) = pa:1 st:1 po:num pa:0 st:0 po:num pa:% st:% po:sign_percent stem(10%) = 10% > 0.2% analyze(0.2%) = pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:% st:% po:sign_percent stem(0.2%) = 0.2% > 0.20% analyze(0.20%) = pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:0 st:0 po:num pa:% st:% po:sign_percent stem(0.20%) = 0.20% > 123.4561‰ analyze(123.4561‰) = pa:1 st:1 po:num pa:2 st:2 po:num pa:3 st:3 po:num pa:. st:. po:sign_dot pa:4 st:4 po:num pa:5 st:5 po:num pa:6 st:6 po:num pa:1 st:1 po:num pa:‰ st:‰ po:sign_per_mille stem(123.4561‰) = 123.4561‰ > 10 analyze(10) = pa:1 st:1 po:num pa:0 st:0 po:num stem(10) = 10 > 0000 analyze(0000) = pa:0 st:0 po:num pa:0 st:0 po:num pa:0 st:0 po:num pa:0 st:0 po:num stem(0000) = 0000 > 10.25 analyze(10.25) = pa:1 st:1 po:num pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:5 st:5 po:num stem(10.25) = 10.25 nuspell-5.1.7/tests/v1cmdline/compoundrule5.wrong000066400000000000000000000000041511132717100221020ustar00rootroot00000000000000.25 nuspell-5.1.7/tests/v1cmdline/compoundrule6.aff000066400000000000000000000001101511132717100215010ustar00rootroot00000000000000COMPOUNDMIN 1 COMPOUNDRULE 2 COMPOUNDRULE A*A COMPOUNDRULE A*AAB*BBBC*C nuspell-5.1.7/tests/v1cmdline/compoundrule6.dic000066400000000000000000000000171511132717100215120ustar00rootroot000000000000003 a/A b/B c/C nuspell-5.1.7/tests/v1cmdline/compoundrule6.good000066400000000000000000000000431511132717100217020ustar00rootroot00000000000000aa aaaaaa aabbbc aaaaabbbbbbcccccc nuspell-5.1.7/tests/v1cmdline/compoundrule6.wrong000066400000000000000000000000501511132717100221040ustar00rootroot00000000000000abc abbbbbccccccc aabbccccccc aabbbbbbb nuspell-5.1.7/tests/v1cmdline/compoundrule7.aff000066400000000000000000000002711511132717100215120ustar00rootroot00000000000000# English ordinal numbers (parenthesized long flags) FLAG long WORDCHARS 0123456789 COMPOUNDMIN 1 ONLYINCOMPOUND cc COMPOUNDRULE 2 COMPOUNDRULE (nn)*(11)(tt) COMPOUNDRULE (nn)*(mm)(pp) nuspell-5.1.7/tests/v1cmdline/compoundrule7.dic000066400000000000000000000002701511132717100215140ustar00rootroot0000000000000022 0/nnmm 1/nn11 2/nnmm 3/nnmm 4/nnmm 5/nnmm 6/nnmm 7/nnmm 8/nnmm 9/nnmm 0th/pptt 1st/pp 1th/ttcc 2nd/pp 2th/ttcc 3rd/pp 3th/ttcc 4th/pptt 5th/pptt 6th/pptt 7th/pptt 8th/pptt 9th/pptt nuspell-5.1.7/tests/v1cmdline/compoundrule7.good000066400000000000000000000002211511132717100217010ustar00rootroot000000000000001st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 100th 1000th 10001st 10011th nuspell-5.1.7/tests/v1cmdline/compoundrule7.wrong000066400000000000000000000000341511132717100221070ustar00rootroot000000000000001th 2th 3th 10001th 10011st nuspell-5.1.7/tests/v1cmdline/compoundrule8.aff000066400000000000000000000003131511132717100215100ustar00rootroot00000000000000# English ordinal numbers (parenthesized numerical flags) FLAG num WORDCHARS 0123456789 COMPOUNDMIN 1 ONLYINCOMPOUND 1000 COMPOUNDRULE 2 COMPOUNDRULE (1001)*(1002)(2001) COMPOUNDRULE (1001)*(2002)(2000) nuspell-5.1.7/tests/v1cmdline/compoundrule8.dic000066400000000000000000000004421511132717100215160ustar00rootroot0000000000000022 0/1001,2002 1/1001,1002 2/1001,2002 3/1001,2002 4/1001,2002 5/1001,2002 6/1001,2002 7/1001,2002 8/1001,2002 9/1001,2002 0th/2000,2001 1st/2000 1th/2001,1000 2nd/2000 2th/2001,1000 3rd/2000 3th/2001,1000 4th/2000,2001 5th/2000,2001 6th/2000,2001 7th/2000,2001 8th/2000,2001 9th/2000,2001 nuspell-5.1.7/tests/v1cmdline/compoundrule8.good000066400000000000000000000002211511132717100217020ustar00rootroot000000000000001st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 100th 1000th 10001st 10011th nuspell-5.1.7/tests/v1cmdline/compoundrule8.wrong000066400000000000000000000000341511132717100221100ustar00rootroot000000000000001th 2th 3th 10001th 10011st nuspell-5.1.7/tests/v1cmdline/condition.aff000066400000000000000000000025011511132717100206730ustar00rootroot00000000000000SET ISO8859-2 WORDCHARS 0123456789 SFX S N 18 SFX S 0 suf1 . SFX S 0 suf2 o SFX S 0 suf3 [aeou] SFX S 0 suf4 [^o] SFX S 0 suf5 [^aeou] SFX S 0 suf6 fo SFX S 0 suf7 f[aeou] SFX S 0 suf8 f[^o] SFX S 0 suf9 f[^aeou] SFX S 0 suf10 [aefu]o SFX S 0 suf11 [^f]o SFX S 0 suf12 [^aefu]o SFX S 0 suf13 [aefu][^aefu] SFX S 0 suf14 [^aeou][aeou] SFX S 0 suf15 [aeou][^aefu] SFX S 0 suf16 [^aeou][^aefu] SFX S 0 suf17 [aeou][bcdfgkmnoprstvz] SFX S 0 suf18 [aeou]o SFX Q N 2 SFX Q 0 ning [^aeio][aeiou]n SFX Q 0 ing [aeio][aeiou][bcdfgkmnprstvz] SFX T N 1 SFX T y ies .[^aeiou]y PFX U N 1 PFX U 0 un wr. SFX Z Y 3 SFX Z 0 ch [].a SFX Z 0 m [].a SFX Z a 0 [].a PFX P N 18 PFX P 0 pre1 . PFX P 0 pre2 o PFX P 0 pre3 [aeou] PFX P 0 pre4 [^o] PFX P 0 pre5 [^aeou] PFX P 0 pre6 of PFX P 0 pre7 o[aefou] PFX P 0 pre8 o[^f] PFX P 0 pre9 o[^aefu] PFX P 0 pre10 [aefu]o PFX P 0 pre11 [^f]o PFX P 0 pre12 [^aefou]o PFX P 0 pre13 [aeou][aefu] PFX P 0 pre14 [aeou][^aeou] PFX P 0 pre15 [aeou][^aefu] PFX P 0 pre16 [^aefu][^aeou] PFX P 0 pre17 [bcdfgkmnoprstvz][aeou] PFX P 0 pre18 o[aeou] PFX R N 2 PFX R 0 gnin n[aeiou][^aeio] PFX R 0 gni [bcdfgkmnprstvz][aeiou][aeio] nuspell-5.1.7/tests/v1cmdline/condition.dic000066400000000000000000000000561511132717100207010ustar00rootroot000000000000005 ofo/SP entertain/Q nianretne/R ra/Z wry/TU nuspell-5.1.7/tests/v1cmdline/condition.good000066400000000000000000000003241511132717100210700ustar00rootroot00000000000000ofo ofosuf1 pre1ofo ofosuf2 pre2ofo ofosuf3 pre3ofo ofosuf6 pre6ofo ofosuf7 pre7ofo ofosuf10 ofosuf13 pre13ofo ofosuf14 pre14ofo ofosuf16 pre16ofo entertain entertaining gninianretne ér éram érach wries unwry nuspell-5.1.7/tests/v1cmdline/condition.wrong000066400000000000000000000002771511132717100213030ustar00rootroot00000000000000ofosuf4 pre4ofo ofosuf5 pre5ofo ofosuf8 pre8ofo ofosuf9 pre9ofo ofosuf11 pre10ofo pre11ofo ofosuf12 pre12ofo ofosuf15 pre15ofo ofosuf17 pre17ofo ofosuf18 pre18ofo entertainning gninnianretne nuspell-5.1.7/tests/v1cmdline/condition_utf.aff000066400000000000000000000021221511132717100215500ustar00rootroot00000000000000SET UTF-8 WORDCHARS 0123456789 SFX S N 18 SFX S 0 suf1 . SFX S 0 suf2 ó SFX S 0 suf3 [áéóú] SFX S 0 suf4 [^ó] SFX S 0 suf5 [^áéóú] SFX S 0 suf6 őó SFX S 0 suf7 ő[áéóú] SFX S 0 suf8 ő[^ó] SFX S 0 suf9 ő[^áéóú] SFX S 0 suf10 [áéóőú]ó SFX S 0 suf11 [^ő]ó SFX S 0 suf12 [^áéóőú]ó SFX S 0 suf13 [áéőú][^ú] SFX S 0 suf14 [^ú][áéóú] SFX S 0 suf15 [áéóú][^áéőú] SFX S 0 suf16 [^áéóú][^áéőú] SFX S 0 suf17 [áéóú][bcdfgkmnóprstvz] SFX S 0 suf18 [áéóú]ó PFX P N 18 PFX P 0 pre1 . PFX P 0 pre2 ó PFX P 0 pre3 [áéóú] PFX P 0 pre4 [^ó] PFX P 0 pre5 [^áéóú] PFX P 0 pre6 óő PFX P 0 pre7 ó[áéőú] PFX P 0 pre8 ó[^ő] PFX P 0 pre9 ó[^áéóőú] PFX P 0 pre10 [áéóőú]ő PFX P 0 pre11 [^ó]ő PFX P 0 pre12 [^áéóőú]ő PFX P 0 pre13 [áéóú][áéőú] PFX P 0 pre14 [áéóú][^áéóú] PFX P 0 pre15 [áéóú][^áéőú] PFX P 0 pre16 [^áéőú][^áéóú] PFX P 0 pre17 [bcdfgkmnóprstvz][áéóú] PFX P 0 pre18 ó[áéóú] nuspell-5.1.7/tests/v1cmdline/condition_utf.dic000066400000000000000000000000141511132717100215510ustar00rootroot000000000000001 óőó/SP nuspell-5.1.7/tests/v1cmdline/condition_utf.good000066400000000000000000000003251511132717100217470ustar00rootroot00000000000000óőó óőósuf1 pre1óőó óőósuf2 pre2óőó óőósuf3 pre3óőó óőósuf6 pre6óőó óőósuf7 pre7óőó óőósuf10 pre10óőó óőósuf13 pre13óőó óőósuf14 pre14óőó óőósuf16 pre16óőó nuspell-5.1.7/tests/v1cmdline/condition_utf.wrong000066400000000000000000000003201511132717100221460ustar00rootroot00000000000000óőósuf4 pre4óőó óőósuf5 pre5óőó óőósuf8 pre8óőó óőósuf9 pre9óőó óőósuf11 pre11óőó óőósuf12 pre12óőó óőósuf15 pre15óőó óőósuf17 óőósuf18 pre17óőó pre18óőó nuspell-5.1.7/tests/v1cmdline/conditionalprefix.aff000066400000000000000000000002201511132717100224220ustar00rootroot00000000000000PFX P Y 1 PFX P 0 un . ip:un SFX S Y 1 SFX S 0 s . is:PL SFX Q Y 1 SFX Q 0 s . is:3SGV SFX R Y 1 SFX R 0 able/PS . ds:DER_V_ADJ_ABLE nuspell-5.1.7/tests/v1cmdline/conditionalprefix.dic000066400000000000000000000000431511132717100224300ustar00rootroot000000000000002 drink/RQ po:verb drink/S po:noun nuspell-5.1.7/tests/v1cmdline/conditionalprefix.good000066400000000000000000000000731511132717100226240ustar00rootroot00000000000000drink drinks drinkable drinkables undrinkable undrinkables nuspell-5.1.7/tests/v1cmdline/conditionalprefix.morph000066400000000000000000000012041511132717100230160ustar00rootroot00000000000000> drink analyze(drink) = st:drink po:verb analyze(drink) = st:drink po:noun stem(drink) = drink > drinks analyze(drinks) = st:drink po:verb is:3SGV analyze(drinks) = st:drink po:noun is:PL stem(drinks) = drink > drinkable analyze(drinkable) = st:drink po:verb ds:DER_V_ADJ_ABLE stem(drinkable) = drinkable > drinkables analyze(drinkables) = st:drink po:verb ds:DER_V_ADJ_ABLE is:PL stem(drinkables) = drinkable > undrinkable analyze(undrinkable) = ip:un st:drink po:verb ds:DER_V_ADJ_ABLE stem(undrinkable) = drinkable > undrinkables analyze(undrinkables) = ip:un st:drink po:verb ds:DER_V_ADJ_ABLE is:PL stem(undrinkables) = drinkable nuspell-5.1.7/tests/v1cmdline/conditionalprefix.wrong000066400000000000000000000000211511132717100230210ustar00rootroot00000000000000undrink undrinks nuspell-5.1.7/tests/v1cmdline/digits_in_words.aff000066400000000000000000000004021511132717100220720ustar00rootroot00000000000000# Digits in words, handled by COMPOUNDRULE. # 1-jährig, 2-jährig, 100-jährig etc. SET UTF-8 COMPOUNDMIN 1 # recognize ab, aab, aaab etc. compounds (a=digits, b=-jährig, see dic file) COMPOUNDRULE 1 COMPOUNDRULE a*b ONLYINCOMPOUND c WORDCHARS 0123456789- nuspell-5.1.7/tests/v1cmdline/digits_in_words.dic000066400000000000000000000000671511132717100221040ustar00rootroot0000000000000011 0/a 1/a 2/a 3/a 4/a 5/a 6/a 7/a 8/a 9/a -jährig/bc nuspell-5.1.7/tests/v1cmdline/digits_in_words.wrong000066400000000000000000000000111511132717100224660ustar00rootroot00000000000000-jährig nuspell-5.1.7/tests/v1cmdline/dotless_i.aff000066400000000000000000000000221511132717100206660ustar00rootroot00000000000000SET UTF-8 LANG tr nuspell-5.1.7/tests/v1cmdline/dotless_i.dic000066400000000000000000000000321511132717100206720ustar00rootroot000000000000003 iç ışık Diyarbakır nuspell-5.1.7/tests/v1cmdline/dotless_i.good000066400000000000000000000000731511132717100210700ustar00rootroot00000000000000Diyarbakır DİYARBAKIR iç İç ışık Işık İÇ IŞIK nuspell-5.1.7/tests/v1cmdline/dotless_i.wrong000066400000000000000000000000551511132717100212740ustar00rootroot00000000000000Diyarbakir DIYARBAKIR Iç İşık IÇ İŞIK nuspell-5.1.7/tests/v1cmdline/encoding.aff000066400000000000000000000000201511132717100204650ustar00rootroot00000000000000SET ISO-8859-15 nuspell-5.1.7/tests/v1cmdline/encoding.dic000066400000000000000000000000151511132717100204740ustar00rootroot000000000000002 cur uvre nuspell-5.1.7/tests/v1cmdline/encoding.good000066400000000000000000000000321511132717100206640ustar00rootroot00000000000000cœur œuvre CŒUR ŒUVRE nuspell-5.1.7/tests/v1cmdline/flag.aff000066400000000000000000000001761511132717100176240ustar00rootroot00000000000000# base 1-character flags SFX A Y 1 SFX A 0 s/123 . SFX 1 Y 1 SFX 1 0 bar . SFX 2 Y 1 SFX 2 0 baz . PFX 3 Y 1 PFX 3 0 un . nuspell-5.1.7/tests/v1cmdline/flag.dic000066400000000000000000000000111511132717100176130ustar00rootroot000000000000001 foo/A3 nuspell-5.1.7/tests/v1cmdline/flag.good000066400000000000000000000000721511132717100200130ustar00rootroot00000000000000foo foos foosbar foosbaz unfoo unfoos unfoosbar unfoosbaz nuspell-5.1.7/tests/v1cmdline/flaglong.aff000066400000000000000000000002161511132717100204770ustar00rootroot00000000000000# 2-character flags FLAG long SFX zx Y 1 SFX zx 0 s/g?1G09 . SFX g? Y 1 SFX g? 0 bar . SFX 1G Y 1 SFX 1G 0 baz . PFX 09 Y 1 PFX 09 0 un . nuspell-5.1.7/tests/v1cmdline/flaglong.dic000066400000000000000000000000131511132717100204750ustar00rootroot000000000000001 foo/zx09 nuspell-5.1.7/tests/v1cmdline/flaglong.good000066400000000000000000000000721511132717100206730ustar00rootroot00000000000000foo foos foosbar foosbaz unfoo unfoos unfoosbar unfoosbaz nuspell-5.1.7/tests/v1cmdline/flagnum.aff000066400000000000000000000002361511132717100203410ustar00rootroot00000000000000# numerical flags FLAG num SFX 999 Y 1 SFX 999 0 s/214,216,54321 . SFX 214 Y 1 SFX 214 0 bar . SFX 216 Y 1 SFX 216 0 baz . PFX 54321 Y 1 PFX 54321 0 un . nuspell-5.1.7/tests/v1cmdline/flagnum.dic000066400000000000000000000000201511132717100203330ustar00rootroot000000000000001 foo/999,54321 nuspell-5.1.7/tests/v1cmdline/flagnum.good000066400000000000000000000000721511132717100205330ustar00rootroot00000000000000foo foos foosbar foosbaz unfoo unfoos unfoosbar unfoosbaz nuspell-5.1.7/tests/v1cmdline/flagutf8.aff000066400000000000000000000002351511132717100204270ustar00rootroot00000000000000# UTF-8 flags FLAG UTF-8 SFX A Y 1 SFX A 0 s/ÖüÜ . #SFX A 0 s/ÖüÖÜ . SFX Ö Y 1 SFX Ö 0 bar . SFX ü Y 1 SFX ü 0 baz . PFX Ü Y 1 PFX Ü 0 un . nuspell-5.1.7/tests/v1cmdline/flagutf8.dic000066400000000000000000000000121511132717100204230ustar00rootroot000000000000001 foo/AÜ nuspell-5.1.7/tests/v1cmdline/flagutf8.good000066400000000000000000000000721511132717100206220ustar00rootroot00000000000000foo foos foosbar foosbaz unfoo unfoos unfoosbar unfoosbaz nuspell-5.1.7/tests/v1cmdline/fogemorpheme.aff000066400000000000000000000003071511132717100213640ustar00rootroot00000000000000# fogemorphemes: special morphemes in compounds # # Swedish example: # gata + kontoret = gatukontoret COMPOUNDFLAG X COMPOUNDBEGIN Y ONLYINCOMPOUND Z COMPOUNDPERMITFLAG P SFX A Y 1 SFX A a u/YPZ . nuspell-5.1.7/tests/v1cmdline/fogemorpheme.dic000066400000000000000000000000241511132717100213630ustar00rootroot000000000000002 gata/A kontoret/X nuspell-5.1.7/tests/v1cmdline/fogemorpheme.good000066400000000000000000000000331511132717100215540ustar00rootroot00000000000000gata kontoret gatukontoret nuspell-5.1.7/tests/v1cmdline/fogemorpheme.wrong000066400000000000000000000000371511132717100217640ustar00rootroot00000000000000gatu gatakontoret kontoretgatu nuspell-5.1.7/tests/v1cmdline/forbiddenword.aff000066400000000000000000000003411511132717100215350ustar00rootroot00000000000000# FORBIDDENWORD flag # The signed word, and its suffixed forms are all forbidden, # excepts with root homonyms. # Useful for forbidding bad suffixed forms or compounds. FORBIDDENWORD X COMPOUNDFLAG Y SFX A Y 1 SFX A 0 s . nuspell-5.1.7/tests/v1cmdline/forbiddenword.dic000066400000000000000000000001041511132717100215350ustar00rootroot000000000000005 foo/S [1] foo/YX [2] foo/Y [3] foo/S [4] bar/YS [5] bars/X foos/X nuspell-5.1.7/tests/v1cmdline/forbiddenword.good000066400000000000000000000000111511132717100217230ustar00rootroot00000000000000foo bar nuspell-5.1.7/tests/v1cmdline/forbiddenword.wrong000066400000000000000000000000301511132717100221300ustar00rootroot00000000000000bars foos foobar barfoo nuspell-5.1.7/tests/v1cmdline/forceucase.aff000066400000000000000000000000771511132717100210320ustar00rootroot00000000000000# force capitalized compound TRY F FORCEUCASE A COMPOUNDFLAG C nuspell-5.1.7/tests/v1cmdline/forceucase.dic000066400000000000000000000000251511132717100210260ustar00rootroot000000000000003 foo/C bar/C baz/CA nuspell-5.1.7/tests/v1cmdline/forceucase.good000066400000000000000000000000561511132717100212230ustar00rootroot00000000000000foo bar baz foobar Foobaz foobazbar Foobarbaz nuspell-5.1.7/tests/v1cmdline/forceucase.sug000066400000000000000000000000211511132717100210610ustar00rootroot00000000000000Foobaz Foobarbaz nuspell-5.1.7/tests/v1cmdline/forceucase.wrong000066400000000000000000000000211511132717100214170ustar00rootroot00000000000000foobaz foobarbaz nuspell-5.1.7/tests/v1cmdline/fullstrip.aff000066400000000000000000000006121511132717100207320ustar00rootroot00000000000000# FULLSTRIP option: Hunspell can strip full words by affix rules # see OpenOffice.org Issue #80145 # test data from Davide Prina FULLSTRIP SET ISO8859-15 TRY aioertnsclmdpgubzfvhàq'ACMSkBGPLxEyRTVòIODNwFéùèìjUZKHWJYQX SFX A Y 3 # verbo andare (verb to go) SFX A andare vado andare # io vado (I go) SFX A andare va andare # tu vai (you go) SFX A are iamo andare # noi andiamo (we go) nuspell-5.1.7/tests/v1cmdline/fullstrip.dic000066400000000000000000000000271511132717100207350ustar00rootroot000000000000002 andare/A riandare/A nuspell-5.1.7/tests/v1cmdline/fullstrip.good000066400000000000000000000000671511132717100211320ustar00rootroot00000000000000andare vado va andiamo riandare rivado riva riandiamo nuspell-5.1.7/tests/v1cmdline/germancompounding.aff000066400000000000000000000030531511132717100224240ustar00rootroot00000000000000# German compounding # handle special casing of German sharp s CHECKSHARPS # compound flags COMPOUNDBEGIN U COMPOUNDMIDDLE V COMPOUNDEND W # Prefixes are allowed at the beginning of compounds, # suffixes are allowed at the end of compounds by default: # (prefix)?(root)+(affix)? # Affixes with COMPOUNDPERMITFLAG may be inside of compounds. COMPOUNDPERMITFLAG P # for German fogemorphemes (Fuge-element) # Hint: ONLYINCOMPOUND is not required everywhere, but the # checking will be a little faster with it. ONLYINCOMPOUND X # forbid uppercase characters at compound word bounds CHECKCOMPOUNDCASE # for handling Fuge-elements with dashes (Arbeits-) # dash will be a special word COMPOUNDMIN 1 WORDCHARS - # compound settings and fogemorpheme for `Arbeit' SFX A Y 3 SFX A 0 s/UPX . SFX A 0 s/VPDX . SFX A 0 0/WXD . SFX B Y 2 SFX B 0 0/UPX . SFX B 0 0/VWXDP . # a suffix for `Computer' SFX C Y 1 SFX C 0 n/WD . # for forbid exceptions (*Arbeitsnehmer) FORBIDDENWORD Z # dash prefix for compounds with dash (Arbeits-Computer) PFX - Y 1 PFX - 0 -/P . # decapitalizing prefix # circumfix for positioning in compounds PFX D Y 29 PFX D A a/PX A PFX D /PX PFX D B b/PX B PFX D C c/PX C PFX D D d/PX D PFX D E e/PX E PFX D F f/PX F PFX D G g/PX G PFX D H h/PX H PFX D I i/PX I PFX D J j/PX J PFX D K k/PX K PFX D L l/PX L PFX D M m/PX M PFX D N n/PX N PFX D O o/PX O PFX D /PX PFX D P p/PX P PFX D Q q/PX Q PFX D R r/PX R PFX D S s/PX S PFX D T t/PX T PFX D U u/PX U PFX D /PX PFX D V v/PX V PFX D W w/PX W PFX D X x/PX X PFX D Y y/PX Y PFX D Z z/PX Z nuspell-5.1.7/tests/v1cmdline/germancompounding.dic000066400000000000000000000000551511132717100224260ustar00rootroot000000000000004 Arbeit/A- Computer/BC- -/W Arbeitsnehmer/Z nuspell-5.1.7/tests/v1cmdline/germancompounding.good000066400000000000000000000005531511132717100226220ustar00rootroot00000000000000Computer Computern Arbeit Arbeits- Computerarbeit Computerarbeits- Arbeitscomputer Computercomputer Computercomputern Arbeitscomputern Computerarbeitscomputer Computerarbeitscomputern Arbeitscomputercomputer Computercomputerarbeit Arbeitscomputerarbeit Arbeitsarbeitsarbeit Computerarbeitsarbeit Computerarbeits-Computer Computerarbeits-Computern Computer-Arbeit nuspell-5.1.7/tests/v1cmdline/germancompounding.wrong000066400000000000000000000016011511132717100230210ustar00rootroot00000000000000computer computern arbeit Arbeits arbeits ComputerArbeit ComputernArbeit Computernarbeit ComputerArbeits Arbeitcomputer Arbeitcomputern ArbeitsComputer ArbeitsComputern Computerarbeitcomputer ComputerArbeitcomputer ComputerArbeitscomputer Computerarbeitcomputern ComputerArbeitcomputern ComputerArbeitscomputern Arbeitscomputerarbeits Arbeitscomputernarbeits Computerarbeits-computer Arbeitsnehmer computers computern computernarbeit computernArbeit computerArbeit computerArbeits arbeitcomputer arbeitsComputer computerarbeitcomputer computerArbeitcomputer computerArbeitscomputer arbeitscomputerarbeits computerarbeits-computer arbeitsnehmer computernarbeit computernArbeit arbeits- computerarbeit computerarbeits- arbeitscomputer arbeitscomputern computerarbeitscomputer computerarbeitscomputern computerarbeitscomputers arbeitscomputerarbeit computerarbeits-Computer computerarbeits-Computern nuspell-5.1.7/tests/v1cmdline/germancompoundingold.aff000066400000000000000000000032021511132717100231170ustar00rootroot00000000000000# German compounding # handle special casing of German sharp s CHECKSHARPS # compound flags COMPOUNDBEGIN U COMPOUNDMIDDLE V COMPOUNDEND W # Prefixes are allowed at the beginning of compounds, # suffixes are allowed at the end of compounds by default: # (prefix)?(root)+(affix)? # Affixes with COMPOUNDPERMITFLAG may be inside of compounds. COMPOUNDPERMITFLAG P # for German fogemorphemes (Fuge-element) # Hint: ONLYINCOMPOUND is not required everywhere, but the # checking will be a little faster with it. ONLYINCOMPOUND X # for decapitalizing nouns with fogemorphemes CIRCUMFIX Y # for handling Fuge-elements with dashes (Arbeits-) # dash will be a special word COMPOUNDMIN 1 WORDCHARS - # compound settings and fogemorpheme for `Arbeit' SFX A Y 3 SFX A 0 s/UPX . SFX A 0 s/VPXDY . SFX A 0 0/WXDY . # compound settings for `Computer' SFX B Y 2 SFX B 0 0/UPX . SFX B 0 0/VWPXDY . # a suffix for `Computer' SFX C Y 2 SFX C 0 n . SFX C 0 n/WXDY . # for forbid exceptions (*Arbeitsnehmer) FORBIDDENWORD Z # dash prefix for compounds with dash (Arbeits-Computer) PFX - Y 2 PFX - 0 -/PUVW . PFX - 0 -/PY . # decapitalizing prefix # circumfix for positioning in compounds PFX D Y 29 PFX D A a/PXY A PFX D /PXY PFX D B b/PXY B PFX D C c/PXY C PFX D D d/PXY D PFX D E e/PXY E PFX D F f/PXY F PFX D G g/PXY G PFX D H h/PXY H PFX D I i/PXY I PFX D J j/PXY J PFX D K k/PXY K PFX D L l/PXY L PFX D M m/PXY M PFX D N n/PXY N PFX D O o/PXY O PFX D /PXY PFX D P p/PXY P PFX D Q q/PXY Q PFX D R r/PXY R PFX D S s/PXY S PFX D T t/PXY T PFX D U u/PXY U PFX D /PXY PFX D V v/PXY V PFX D W w/PXY W PFX D X x/PXY X PFX D Y y/PXY Y PFX D Z z/PXY Z nuspell-5.1.7/tests/v1cmdline/germancompoundingold.dic000066400000000000000000000000551511132717100231250ustar00rootroot000000000000004 Arbeit/A- Computer/BC- -/W Arbeitsnehmer/Z nuspell-5.1.7/tests/v1cmdline/germancompoundingold.good000066400000000000000000000003561511132717100233220ustar00rootroot00000000000000Computer Computern Arbeit Arbeits- Computerarbeit Computerarbeits- Arbeitscomputer Arbeitscomputern Computerarbeitscomputer Computerarbeitscomputern Arbeitscomputerarbeit Computerarbeits-Computer Computerarbeits-Computern Computer-Arbeit nuspell-5.1.7/tests/v1cmdline/germancompoundingold.wrong000066400000000000000000000016011511132717100235200ustar00rootroot00000000000000computer computern arbeit Arbeits arbeits ComputerArbeit ComputernArbeit Computernarbeit ComputerArbeits Arbeitcomputer Arbeitcomputern ArbeitsComputer ArbeitsComputern Computerarbeitcomputer ComputerArbeitcomputer ComputerArbeitscomputer Computerarbeitcomputern ComputerArbeitcomputern ComputerArbeitscomputern Arbeitscomputerarbeits Arbeitscomputernarbeits Computerarbeits-computer Arbeitsnehmer computers computern computernarbeit computernArbeit computerArbeit computerArbeits arbeitcomputer arbeitsComputer computerarbeitcomputer computerArbeitcomputer computerArbeitscomputer arbeitscomputerarbeits computerarbeits-computer arbeitsnehmer computernarbeit computernArbeit arbeits- computerarbeit computerarbeits- arbeitscomputer arbeitscomputern computerarbeitscomputer computerarbeitscomputern computerarbeitscomputers arbeitscomputerarbeit computerarbeits-Computer computerarbeits-Computern nuspell-5.1.7/tests/v1cmdline/hu.aff000066400000000000000000000007451511132717100173310ustar00rootroot00000000000000SET UTF-8 LANG hu_HU # words with flag Y can form compound words COMPOUNDFLAG Y # min. word length in compounds: # allow 2-letter words COMPOUNDMIN 2 # max. word count in compounds COMPOUNDWORDMAX 2 # exception for Hungarian: # allow more words in a compound, than COMPOUNDWORDMAX, # if syllable count of the compound is 6 or less COMPOUNDSYLLABLE 6 aáeéiíoóöőuúüű # test case for commit 1fada01 "fix other regression in compounding" REP 1 REP kor _kor CHECKCOMPOUNDREP nuspell-5.1.7/tests/v1cmdline/hu.dic000066400000000000000000000001761511132717100173320ustar00rootroot000000000000005 majom/Y kenyér/Y fa/Y ág/Y virág/Y sárkány/Y fog/Y vetemény/Y iskola/Y tej/Y akció/Y devon/Y kor/Y társ/Y devon kor nuspell-5.1.7/tests/v1cmdline/hu.good000066400000000000000000000001601511132717100175140ustar00rootroot00000000000000majomkenyér majomkenyérfa majomkenyérfaág majomkenyérvirág kenyérfavirág sárkányfogvetemény kortárs nuspell-5.1.7/tests/v1cmdline/hu.wrong000066400000000000000000000000561511132717100177240ustar00rootroot00000000000000majomkenyérfavirág iskolatejakció devonkor nuspell-5.1.7/tests/v1cmdline/i35725.aff000066400000000000000000000060411511132717100175460ustar00rootroot00000000000000# Ngram suggestions # - fix case problem # - detect character swapping (keep only these suggestions) # - lesser suggestions # - weight with common subsequence algorithm # - suggest uppercased words # 2007-02-05: # now not neighbour character replacements and character movings are # detected by not ngram suggestions, too. # OpenOffice.org's en_US.aff file SET ISO8859-1 TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' WORDCHARS ' PFX A Y 1 PFX A 0 re . PFX I Y 1 PFX I 0 in . PFX U Y 1 PFX U 0 un . PFX C Y 1 PFX C 0 de . PFX E Y 1 PFX E 0 dis . PFX F Y 1 PFX F 0 con . PFX K Y 1 PFX K 0 pro . SFX V N 2 SFX V e ive e SFX V 0 ive [^e] SFX N Y 3 SFX N e ion e SFX N y ication y SFX N 0 en [^ey] SFX X Y 3 SFX X e ions e SFX X y ications y SFX X 0 ens [^ey] SFX H N 2 SFX H y ieth y SFX H 0 th [^y] SFX Y Y 1 SFX Y 0 ly . SFX G Y 2 SFX G e ing e SFX G 0 ing [^e] SFX J Y 2 SFX J e ings e SFX J 0 ings [^e] SFX D Y 4 SFX D 0 d e SFX D y ied [^aeiou]y SFX D 0 ed [^ey] SFX D 0 ed [aeiou]y SFX T N 4 SFX T 0 st e SFX T y iest [^aeiou]y SFX T 0 est [aeiou]y SFX T 0 est [^ey] SFX R Y 4 SFX R 0 r e SFX R y ier [^aeiou]y SFX R 0 er [aeiou]y SFX R 0 er [^ey] SFX Z Y 4 SFX Z 0 rs e SFX Z y iers [^aeiou]y SFX Z 0 ers [aeiou]y SFX Z 0 ers [^ey] SFX S Y 4 SFX S y ies [^aeiou]y SFX S 0 s [aeiou]y SFX S 0 es [sxzh] SFX S 0 s [^sxzhy] SFX P Y 3 SFX P y iness [^aeiou]y SFX P 0 ness [aeiou]y SFX P 0 ness [^y] SFX M Y 1 SFX M 0 's . SFX B Y 3 SFX B 0 able [^aeiou] SFX B 0 able ee SFX B e able [^aeiou]e SFX L Y 1 SFX L 0 ment . REP 88 REP a ei REP ei a REP a ey REP ey a REP ai ie REP ie ai REP are air REP are ear REP are eir REP air are REP air ere REP ere air REP ere ear REP ere eir REP ear are REP ear air REP ear ere REP eir are REP eir ere REP ch te REP te ch REP ch ti REP ti ch REP ch tu REP tu ch REP ch s REP s ch REP ch k REP k ch REP f ph REP ph f REP gh f REP f gh REP i igh REP igh i REP i uy REP uy i REP i ee REP ee i REP j di REP di j REP j gg REP gg j REP j ge REP ge j REP s ti REP ti s REP s ci REP ci s REP k cc REP cc k REP k qu REP qu k REP kw qu REP o eau REP eau o REP o ew REP ew o REP oo ew REP ew oo REP ew ui REP ui ew REP oo ui REP ui oo REP ew u REP u ew REP oo u REP u oo REP u oe REP oe u REP u ieu REP ieu u REP ue ew REP ew ue REP uff ough REP oo ieu REP ieu oo REP ier ear REP ear ier REP ear air REP air ear REP w qu REP qu w REP z ss REP ss z REP shun tion REP shun sion REP shun cion nuspell-5.1.7/tests/v1cmdline/i35725.dic000066400000000000000000000002731511132717100175520ustar00rootroot0000000000000015 endangerment/SM ferment/FSCM preferment/SM impermanent/Y permanent/YSP semipermanent/Y empowerment/MS supermen tournament/MS ornamental/SY ornament/GSDM supernatant pimpernel UNESCO/M nuspell-5.1.7/tests/v1cmdline/i35725.good000066400000000000000000000000121511132717100177320ustar00rootroot00000000000000permanent nuspell-5.1.7/tests/v1cmdline/i35725.sug000066400000000000000000000002101511132717100176000ustar00rootroot00000000000000permanent, preferment permanent, ornament permanent Permanent, Preferment Permanent, Ornament Permanent UNESCO UNESCO UNESCO's UNESCO's nuspell-5.1.7/tests/v1cmdline/i35725.wrong000066400000000000000000000001341511132717100201430ustar00rootroot00000000000000permenant pernament pernemant Permenant Pernament Pernemant unesco Unesco unesco's Unesco's nuspell-5.1.7/tests/v1cmdline/i53643.aff000066400000000000000000000000701511132717100175410ustar00rootroot00000000000000# check numbers with separators WORDCHARS 0123456789.-, nuspell-5.1.7/tests/v1cmdline/i53643.dic000066400000000000000000000000061511132717100175430ustar00rootroot000000000000001 foo nuspell-5.1.7/tests/v1cmdline/i53643.good000066400000000000000000000002061511132717100177360ustar00rootroot000000000000001 12 123 1234 12345 123456 1234567 1.1 1.12 1.123 1.1234 1.12345 1.123456 12.1 123.12 1234.123 12345.1234 123456.12345 1234567.123456 nuspell-5.1.7/tests/v1cmdline/i53643.wrong000066400000000000000000000000241511132717100201400ustar00rootroot000000000000001..2 1,,2 1.,2 1,.2 nuspell-5.1.7/tests/v1cmdline/i54633.aff000066400000000000000000000001111511132717100175350ustar00rootroot00000000000000# Missing capitalized suggestion for capitalized bad words SET ISO8859-1 nuspell-5.1.7/tests/v1cmdline/i54633.dic000066400000000000000000000000111511132717100175370ustar00rootroot000000000000001 diter nuspell-5.1.7/tests/v1cmdline/i54633.good000066400000000000000000000000201511132717100177300ustar00rootroot00000000000000éditer Éditer nuspell-5.1.7/tests/v1cmdline/i54633.sug000066400000000000000000000000201511132717100175760ustar00rootroot00000000000000éditer Éditer nuspell-5.1.7/tests/v1cmdline/i54633.wrong000066400000000000000000000000161511132717100201410ustar00rootroot00000000000000editer Editer nuspell-5.1.7/tests/v1cmdline/i54980.aff000066400000000000000000000001341511132717100175470ustar00rootroot00000000000000# ISO-8859-15 (extended latin-1) support for French, Finnish and EURO symbol SET ISO8859-15 nuspell-5.1.7/tests/v1cmdline/i54980.dic000066400000000000000000000000151511132717100175500ustar00rootroot000000000000002 cur uvre nuspell-5.1.7/tests/v1cmdline/i54980.good000066400000000000000000000000321511132717100177400ustar00rootroot00000000000000cœur œuvre CŒUR ŒUVRE nuspell-5.1.7/tests/v1cmdline/i58202.aff000066400000000000000000000000761511132717100175430ustar00rootroot00000000000000# case suggestions MAXNGRAMSUGS 0 # capitalise baz->Baz TRY B nuspell-5.1.7/tests/v1cmdline/i58202.dic000066400000000000000000000000221511132717100175350ustar00rootroot000000000000004 foo bar Baz Boo nuspell-5.1.7/tests/v1cmdline/i58202.good000066400000000000000000000000501511132717100177270ustar00rootroot00000000000000foo bar Foo Bar Baz Boo FOO BAR BAZ BOO nuspell-5.1.7/tests/v1cmdline/i58202.sug000066400000000000000000000001351511132717100176010ustar00rootroot00000000000000foo, Boo Bar Baz Boo foo bar foo Bar Foo bar Foo Bar foo Baz Foo Baz Baz foo Baz Foo Baz Boo nuspell-5.1.7/tests/v1cmdline/i58202.wrong000066400000000000000000000001171511132717100201370ustar00rootroot00000000000000fOO BAr baz BOo foobar fooBar Foobar FooBar fooBaz FooBaz Bazfoo BazFoo BazBoo nuspell-5.1.7/tests/v1cmdline/i68568.aff000066400000000000000000000001501511132717100175540ustar00rootroot00000000000000# Sant'Elia -> SANT'ELIA (Italian) # OpenOffice.org Issue 68658 PFX a Y 1 PFX a 0 Sant' E WORDCHARS ' nuspell-5.1.7/tests/v1cmdline/i68568.dic000066400000000000000000000000111511132717100175530ustar00rootroot000000000000001 Elia/a nuspell-5.1.7/tests/v1cmdline/i68568.wrong000066400000000000000000000000521511132717100201550ustar00rootroot00000000000000sant'elia sant'Elia Sant'elia Sant' SANT' nuspell-5.1.7/tests/v1cmdline/i68568utf.aff000066400000000000000000000001621511132717100202760ustar00rootroot00000000000000# Sant'Elia -> SANT'ELIA (Italian) # OpenOffice.org Issue 68658 SET UTF-8 PFX a Y 1 PFX a 0 Foó' B WORDCHARS ' nuspell-5.1.7/tests/v1cmdline/i68568utf.dic000066400000000000000000000000111511132717100202720ustar00rootroot000000000000001 Bár/a nuspell-5.1.7/tests/v1cmdline/i68568utf.wrong000066400000000000000000000000521511132717100206740ustar00rootroot00000000000000foó'bár foó'Bár Foó'bár foó' FOÓ' nuspell-5.1.7/tests/v1cmdline/iconv.aff000066400000000000000000000002731511132717100200270ustar00rootroot00000000000000# input conversion (accept comma acuted letters also with cedilla, # as de facto replacement of the Romanian standard) SET UTF-8 ICONV 4 ICONV ş ș ICONV ţ ț ICONV Ş Ș ICONV Ţ Ț nuspell-5.1.7/tests/v1cmdline/iconv.dic000066400000000000000000000000321511132717100200230ustar00rootroot000000000000004 Chișinău Țepes ț Ș nuspell-5.1.7/tests/v1cmdline/iconv.good000066400000000000000000000000521511132717100202160ustar00rootroot00000000000000Chișinău Chişinău Țepes Ţepes Ş ţ nuspell-5.1.7/tests/v1cmdline/iconv2.aff000066400000000000000000000002151511132717100201050ustar00rootroot00000000000000# The longer input pattern should be used if matched ICONV 6 ICONV Da DA ICONV Ga GA ICONV Gag GAG ICONV Gagg GAGG ICONV Na NA ICONV Nan NAN nuspell-5.1.7/tests/v1cmdline/iconv2.dic000066400000000000000000000000301511132717100201030ustar00rootroot000000000000004 GAG GAGGNA GANA NANDA nuspell-5.1.7/tests/v1cmdline/iconv2.good000066400000000000000000000000261511132717100203010ustar00rootroot00000000000000GaNa Gag GaggNa NanDa nuspell-5.1.7/tests/v1cmdline/ignore.aff000066400000000000000000000001501511132717100201660ustar00rootroot00000000000000# ignore characters in words (for Arabic Harakat or Hebrew niqqud) IGNORE aeiou PFX A Y 1 PFX A 0 re . nuspell-5.1.7/tests/v1cmdline/ignore.dic000066400000000000000000000000241511132717100201710ustar00rootroot000000000000002 xmpl expression/A nuspell-5.1.7/tests/v1cmdline/ignore.good000066400000000000000000000000641511132717100203660ustar00rootroot00000000000000example expression xmpl xprssn reexpression rxprssn nuspell-5.1.7/tests/v1cmdline/ignoreutf.aff000066400000000000000000000003361511132717100207130ustar00rootroot00000000000000# Arabic test for feature ignoring diacritics SET UTF-8 # Arabic diacritics (harakat): # sukun, shadda, kasra, damma, fatha, kasratan, dammantan, fathatan (left to right) IGNORE ًٌٍَُِّْ WORDCHARS ًٌٍَُِّْ nuspell-5.1.7/tests/v1cmdline/ignoreutf.dic000066400000000000000000000001511511132717100207110ustar00rootroot000000000000009 طِير فَتحة ضُمة كِسرة فتحًتان ضمتانٌ كسرتاٍن شدّة سكوْن nuspell-5.1.7/tests/v1cmdline/ignoreutf.good000066400000000000000000000001361511132717100211050ustar00rootroot00000000000000طير فتحة ضمة كسرة فتحتان ضمتان كسرتان شدة سكون nuspell-5.1.7/tests/v1cmdline/keepcase.aff000066400000000000000000000000631511132717100204660ustar00rootroot00000000000000# keep case in signed words KEEPCASE A WORDCHARS . nuspell-5.1.7/tests/v1cmdline/keepcase.dic000066400000000000000000000000351511132717100204700ustar00rootroot000000000000004 foo/A Bar/A baz./A Quux./A nuspell-5.1.7/tests/v1cmdline/keepcase.good000066400000000000000000000000231511132717100206560ustar00rootroot00000000000000foo Bar baz. Quux. nuspell-5.1.7/tests/v1cmdline/keepcase.sug000066400000000000000000000000461511132717100205310ustar00rootroot00000000000000foo foo Bar Bar baz. baz. Quux. Quux. nuspell-5.1.7/tests/v1cmdline/keepcase.wrong000066400000000000000000000000461511132717100210670ustar00rootroot00000000000000Foo FOO BAR bar Baz. BAZ. quux. QUUX. nuspell-5.1.7/tests/v1cmdline/korean.aff000066400000000000000000000000121511132717100201570ustar00rootroot00000000000000SET UTF-8 nuspell-5.1.7/tests/v1cmdline/korean.dic000066400000000000000000000000421511132717100201650ustar00rootroot000000000000002 들어오세요 안녕하세요 nuspell-5.1.7/tests/v1cmdline/korean.good000066400000000000000000000000401511132717100203540ustar00rootroot00000000000000들어오세요 안녕하세요 nuspell-5.1.7/tests/v1cmdline/korean.wrong000066400000000000000000000000151511132717100205620ustar00rootroot00000000000000들어오세 nuspell-5.1.7/tests/v1cmdline/map.aff000066400000000000000000000002361511132717100174650ustar00rootroot00000000000000# With MAP suggestion, Hunspell can add missing accents to a word. # switch off ngram suggestion for testing MAXNGRAMSUGS 0 MAP 3 MAP u MAP o MAP (ss) nuspell-5.1.7/tests/v1cmdline/map.dic000066400000000000000000000000331511132717100174630ustar00rootroot000000000000003 Frhstck tkrfr gro nuspell-5.1.7/tests/v1cmdline/map.sug000066400000000000000000000000401511132717100175200ustar00rootroot00000000000000Frühstück tükörfúró groß nuspell-5.1.7/tests/v1cmdline/map.wrong000066400000000000000000000000321511132717100200570ustar00rootroot00000000000000Fruhstuck tukorfuro gross nuspell-5.1.7/tests/v1cmdline/maputf.aff000066400000000000000000000002561511132717100202060ustar00rootroot00000000000000# With MAP suggestion, Hunspell can add missing accents to a word. SET UTF-8 # switch off ngram suggestion for testing MAXNGRAMSUGS 0 MAP 3 MAP uúü MAP öóo MAP ß(ss) nuspell-5.1.7/tests/v1cmdline/maputf.dic000066400000000000000000000000421511132717100202020ustar00rootroot000000000000003 Frühstück tükörfúró groß nuspell-5.1.7/tests/v1cmdline/maputf.sug000066400000000000000000000000401511132717100202370ustar00rootroot00000000000000Frühstück tükörfúró groß nuspell-5.1.7/tests/v1cmdline/maputf.wrong000066400000000000000000000000321511132717100205760ustar00rootroot00000000000000Fruhstuck tukorfuro gross nuspell-5.1.7/tests/v1cmdline/morph.aff000066400000000000000000000003241511132717100200330ustar00rootroot00000000000000# example for morphological analysis, stemming and generation PFX P Y 1 PFX P 0 un . dp:pfx_un sp:un SFX S Y 1 SFX S 0 s . is:plur SFX Q Y 1 SFX Q 0 s . is:sg_3 SFX R Y 1 SFX R 0 able/PS . ds:der_able nuspell-5.1.7/tests/v1cmdline/morph.dic000066400000000000000000000004601511132717100200370ustar00rootroot000000000000009 drink/S po:noun drink/RQ po:verb al:drank al:drunk ts:present drank po:verb st:drink is:past_1 drunk po:verb st:drink is:past_2 eat/RQ po:verb al:ate al:eaten ts:present ate po:verb st:eat is:past_1 eaten po:verb st:eat is:past_2 phenomenon po:noun al:phenomena phenomena po:noun st:phenomenon is:plur nuspell-5.1.7/tests/v1cmdline/morph.good000066400000000000000000000004731511132717100202340ustar00rootroot00000000000000drink drinks drinkable drinkables undrinkable undrinkables drank drunk phenomenon phenomena drink eat drink eats drink ate drink eaten drink eatable drink eatables drink phenomena drinks eat drinks eats drinks ate drinks eaten drinks eatable drinks eatables drinks phenomena undrinkable phenomena phenomenon drinks nuspell-5.1.7/tests/v1cmdline/morph.morph000066400000000000000000000032741511132717100204330ustar00rootroot00000000000000> drink analyze(drink) = st:drink po:noun analyze(drink) = st:drink po:verb al:drank al:drunk ts:present stem(drink) = drink > drinks analyze(drinks) = st:drink po:verb al:drank al:drunk ts:present is:sg_3 analyze(drinks) = st:drink po:noun is:plur stem(drinks) = drink > drinkable analyze(drinkable) = st:drink po:verb al:drank al:drunk ts:present ds:der_able stem(drinkable) = drinkable > drinkables analyze(drinkables) = st:drink po:verb al:drank al:drunk ts:present ds:der_able is:plur stem(drinkables) = drinkable > undrinkable analyze(undrinkable) = dp:pfx_un sp:un st:drink po:verb al:drank al:drunk ts:present ds:der_able stem(undrinkable) = undrinkable > undrinkables analyze(undrinkables) = dp:pfx_un sp:un st:drink po:verb al:drank al:drunk ts:present ds:der_able is:plur stem(undrinkables) = undrinkable > drank analyze(drank) = po:verb st:drink is:past_1 stem(drank) = drink > drunk analyze(drunk) = po:verb st:drink is:past_2 stem(drunk) = drink > phenomenon analyze(phenomenon) = st:phenomenon po:noun al:phenomena stem(phenomenon) = phenomenon > phenomena analyze(phenomena) = po:noun st:phenomenon is:plur stem(phenomena) = phenomenon generate(drink, eat) = drink generate(drink, eats) = drinks generate(drink, ate) = drank generate(drink, eaten) = drunk generate(drink, eatable) = drinkable generate(drink, eatables) = drinkables generate(drink, phenomena) = drinks generate(drinks, eat) = drink generate(drinks, eats) = drinks generate(drinks, ate) = drank generate(drinks, eaten) = drunk generate(drinks, eatable) = drinkable generate(drinks, eatables) = drinkables generate(drinks, phenomena) = drinks generate(undrinkable, phenomena) = undrinkables generate(phenomenon, drinks) = phenomena nuspell-5.1.7/tests/v1cmdline/needaffix.aff000066400000000000000000000000641511132717100206400ustar00rootroot00000000000000NEEDAFFIX X COMPOUNDFLAG Y SFX A Y 1 SFX A 0 s/Y . nuspell-5.1.7/tests/v1cmdline/needaffix.dic000066400000000000000000000000201511132717100206330ustar00rootroot000000000000002 foo/YXA bar/Y nuspell-5.1.7/tests/v1cmdline/needaffix.good000066400000000000000000000000211511132717100210250ustar00rootroot00000000000000bar foos barfoos nuspell-5.1.7/tests/v1cmdline/needaffix.wrong000066400000000000000000000000041511132717100212320ustar00rootroot00000000000000foo nuspell-5.1.7/tests/v1cmdline/needaffix2.aff000066400000000000000000000000331511132717100207160ustar00rootroot00000000000000NEEDAFFIX X COMPOUNDFLAG Y nuspell-5.1.7/tests/v1cmdline/needaffix2.dic000066400000000000000000000000751511132717100207270ustar00rootroot000000000000004 foo st:foo id:1 foo/YX st:foo id:2 foo/Y st:foo id:3 bar/Y nuspell-5.1.7/tests/v1cmdline/needaffix2.good000066400000000000000000000000271511132717100211150ustar00rootroot00000000000000foo bar foobar barfoo nuspell-5.1.7/tests/v1cmdline/needaffix2.morph000066400000000000000000000004271511132717100213160ustar00rootroot00000000000000> foo analyze(foo) = st:foo id:1 analyze(foo) = st:foo id:3 stem(foo) = foo > bar analyze(bar) = st:bar stem(bar) = bar > foobar analyze(foobar) = pa:foo st:foo id:3 pa:bar stem(foobar) = foo > barfoo analyze(barfoo) = pa:bar st:bar pa:foo st:foo id:3 stem(barfoo) = barfoo nuspell-5.1.7/tests/v1cmdline/needaffix3.aff000066400000000000000000000001271511132717100207230ustar00rootroot00000000000000# neeadaffix on affixes NEEDAFFIX X SFX A Y 1 SFX A 0 s/XB . SFX B Y 1 SFX B 0 baz . nuspell-5.1.7/tests/v1cmdline/needaffix3.dic000066400000000000000000000000101511132717100207150ustar00rootroot000000000000002 foo/A nuspell-5.1.7/tests/v1cmdline/needaffix3.good000066400000000000000000000000141511132717100211120ustar00rootroot00000000000000foo foosbaz nuspell-5.1.7/tests/v1cmdline/needaffix3.wrong000066400000000000000000000000051511132717100213160ustar00rootroot00000000000000foos nuspell-5.1.7/tests/v1cmdline/needaffix4.aff000066400000000000000000000000331511132717100207200ustar00rootroot00000000000000NEEDAFFIX X COMPOUNDFLAG Y nuspell-5.1.7/tests/v1cmdline/needaffix4.dic000066400000000000000000000000531511132717100207250ustar00rootroot000000000000004 foo/X [1] foo/Y [2] foo/YX [3] bar/Y [4] nuspell-5.1.7/tests/v1cmdline/needaffix4.good000066400000000000000000000000271511132717100211170ustar00rootroot00000000000000foo bar foobar barfoo nuspell-5.1.7/tests/v1cmdline/needaffix5.aff000066400000000000000000000002231511132717100207220ustar00rootroot00000000000000# on affixes NEEDAFFIX X SFX A Y 2 SFX A 0 suf/B . SFX A 0 pseudosuf/XB . SFX B Y 1 SFX B 0 bar . PFX C Y 2 PFX C 0 pre . PFX C 0 pseudopre/X . nuspell-5.1.7/tests/v1cmdline/needaffix5.dic000066400000000000000000000000111511132717100207200ustar00rootroot000000000000001 foo/AC nuspell-5.1.7/tests/v1cmdline/needaffix5.good000066400000000000000000000002221511132717100211150ustar00rootroot00000000000000foo prefoo foosuf prefoosuf foosufbar prefoosufbar pseudoprefoosuf pseudoprefoosufbar pseudoprefoopseudosufbar prefoopseudosuf prefoopseudosufbar nuspell-5.1.7/tests/v1cmdline/needaffix5.wrong000066400000000000000000000000601511132717100213210ustar00rootroot00000000000000pseudoprefoo foopseudosuf pseudoprefoopseudosuf nuspell-5.1.7/tests/v1cmdline/nepali.aff000066400000000000000000000003051511132717100201550ustar00rootroot00000000000000SET UTF-8 IGNORE ￰ WORDCHARS ःािीॉॊोौॎॏॕॖॗ‌‍ ICONV 5 ICONV ‌_ ‌ ICONV र्‌य र्‌य ICONV र्‌व र्‌व ICONV ‌ ￰ ICONV ‍_ ￰ nuspell-5.1.7/tests/v1cmdline/nepali.dic000066400000000000000000000000661511132717100201640ustar00rootroot000000000000004 अलम् क्यार न्न र्‌य nuspell-5.1.7/tests/v1cmdline/nepali.good000066400000000000000000000000641511132717100203530ustar00rootroot00000000000000न्न न्‌न अलम्‍ र्‌य nuspell-5.1.7/tests/v1cmdline/nepali.wrong000066400000000000000000000000551511132717100205570ustar00rootroot00000000000000र्य क्‍यार अलम्‌ nuspell-5.1.7/tests/v1cmdline/ngram_utf_fix.aff000066400000000000000000000005561511132717100215450ustar00rootroot00000000000000# Test fix of suffixed ngram suggestions with UTF-8 encoding and long flags. # Based on Vitaly Piryatinsky's bug report and example. SET UTF-8 FLAG num PFX 101 Y 1 PFX 101 0 пред . SFX 1381 Y 1 SFX 1381 0 о . SFX 2000 Y 3 SFX 2000 0 ам . SFX 2000 0 ами . SFX 2000 0 ах . SFX 2022 Y 4 SFX 2022 0 а . SFX 2022 0 у . SFX 2022 0 ом . SFX 2022 0 е . nuspell-5.1.7/tests/v1cmdline/ngram_utf_fix.dic000066400000000000000000000000371511132717100215420ustar00rootroot000000000000001 человек/2022,2000,101 nuspell-5.1.7/tests/v1cmdline/ngram_utf_fix.good000066400000000000000000000000171511132717100217310ustar00rootroot00000000000000человек nuspell-5.1.7/tests/v1cmdline/ngram_utf_fix.sug000066400000000000000000000000171511132717100215770ustar00rootroot00000000000000человек nuspell-5.1.7/tests/v1cmdline/ngram_utf_fix.wrong000066400000000000000000000000421511132717100221330ustar00rootroot00000000000000времячко человеко nuspell-5.1.7/tests/v1cmdline/nosuggest.aff000066400000000000000000000002571511132717100207310ustar00rootroot00000000000000# don't suggest word with NOSUGGEST flag (for example vulgar or obscene words) # See OpenOffice.org Issue #55498 # (nosuggest.sug is an empty file) NOSUGGEST A COMPOUNDFLAG B nuspell-5.1.7/tests/v1cmdline/nosuggest.dic000066400000000000000000000000171511132717100207260ustar00rootroot000000000000001 foo/AB bar/B nuspell-5.1.7/tests/v1cmdline/nosuggest.good000066400000000000000000000000221511132717100211130ustar00rootroot00000000000000foo foobar barfoo nuspell-5.1.7/tests/v1cmdline/nosuggest.sug000066400000000000000000000000001511132717100207550ustar00rootroot00000000000000nuspell-5.1.7/tests/v1cmdline/nosuggest.wrong000066400000000000000000000000251511132717100213220ustar00rootroot00000000000000foox foobarx barfoox nuspell-5.1.7/tests/v1cmdline/oconv.aff000066400000000000000000000001631511132717100200330ustar00rootroot00000000000000# output conversion SET UTF-8 OCONV 7 OCONV a A OCONV á Á OCONV b B OCONV c C OCONV d D OCONV e E OCONV é É nuspell-5.1.7/tests/v1cmdline/oconv.dic000066400000000000000000000000321511132717100200310ustar00rootroot000000000000003 bébé dádá aábcdeé nuspell-5.1.7/tests/v1cmdline/oconv.good000066400000000000000000000000161511132717100202240ustar00rootroot00000000000000bébé dádá nuspell-5.1.7/tests/v1cmdline/oconv.sug000066400000000000000000000000301511132717100200660ustar00rootroot00000000000000BÉBÉ DÁDÁ AÁBCDEÉ nuspell-5.1.7/tests/v1cmdline/oconv.wrong000066400000000000000000000000221511132717100204250ustar00rootroot00000000000000béb dád aábcde nuspell-5.1.7/tests/v1cmdline/onlyincompound.aff000066400000000000000000000001601511132717100217610ustar00rootroot00000000000000# words only in compounds (see also fogemorpheme example) ONLYINCOMPOUND O COMPOUNDFLAG A SFX B Y 1 SFX B 0 s . nuspell-5.1.7/tests/v1cmdline/onlyincompound.dic000066400000000000000000000000231511132717100217620ustar00rootroot000000000000002 foo/A pseudo/OAB nuspell-5.1.7/tests/v1cmdline/onlyincompound.good000066400000000000000000000000431511132717100221550ustar00rootroot00000000000000foo pseudofoo foopseudo foopseudos nuspell-5.1.7/tests/v1cmdline/onlyincompound.sug000066400000000000000000000000001511132717100220140ustar00rootroot00000000000000nuspell-5.1.7/tests/v1cmdline/onlyincompound.wrong000066400000000000000000000000171511132717100223620ustar00rootroot00000000000000pseudo pseudos nuspell-5.1.7/tests/v1cmdline/onlyincompound2.aff000066400000000000000000000004001511132717100220400ustar00rootroot00000000000000# affixes only in compounds (see also fogemorpheme example) ONLYINCOMPOUND O COMPOUNDFLAG A COMPOUNDPERMITFLAG P SFX B Y 1 SFX B 0 s/OP . # obligate fogemorpheme by forbidding the stem (0) in compounds CHECKCOMPOUNDPATTERN 1 CHECKCOMPOUNDPATTERN 0/B /A nuspell-5.1.7/tests/v1cmdline/onlyincompound2.dic000066400000000000000000000000221511132717100220430ustar00rootroot000000000000002 foo/A pseudo/AB nuspell-5.1.7/tests/v1cmdline/onlyincompound2.good000066400000000000000000000000311511132717100222340ustar00rootroot00000000000000foo foopseudo pseudosfoo nuspell-5.1.7/tests/v1cmdline/onlyincompound2.wrong000066400000000000000000000000351511132717100224440ustar00rootroot00000000000000pseudos foopseudos pseudofoo nuspell-5.1.7/tests/v1cmdline/opentaal_cpdpat.aff000066400000000000000000000003221511132717100220420ustar00rootroot00000000000000FLAG long COMPOUNDBEGIN Ca COMPOUNDMIDDLE Cb COMPOUNDEND Cc COMPOUNDPERMITFLAG Cp ONLYINCOMPOUND Cx CHECKCOMPOUNDPATTERN 1 CHECKCOMPOUNDPATTERN /Ch /Xs SFX Ch Y 2 SFX Ch 0 s/CaCbCxCp . SFX Ch 0 s-/CaCbCcCp . nuspell-5.1.7/tests/v1cmdline/opentaal_cpdpat.dic000066400000000000000000000000431511132717100220450ustar00rootroot000000000000003 schoonheid/Ch port/CcXs sport/Cc nuspell-5.1.7/tests/v1cmdline/opentaal_cpdpat.good000066400000000000000000000000211511132717100222320ustar00rootroot00000000000000schoonheidssport nuspell-5.1.7/tests/v1cmdline/opentaal_cpdpat.wrong000066400000000000000000000000201511132717100224350ustar00rootroot00000000000000schoonheidsport nuspell-5.1.7/tests/v1cmdline/opentaal_cpdpat2.aff000066400000000000000000000006571511132717100221370ustar00rootroot00000000000000# Test file based on OpenTaal's Dutch dictionary, coded by Ruud Baars WORDCHARS - NOSPLITSUGS FLAG long COMPOUNDBEGIN Ca COMPOUNDMIDDLE Cb COMPOUNDEND Cc COMPOUNDPERMITFLAG Cp ONLYINCOMPOUND Cx CHECKCOMPOUNDPATTERN 2 CHECKCOMPOUNDPATTERN 0/Ch /Xs CHECKCOMPOUNDPATTERN 0/Xm /Xm SFX CA Y 2 SFX CA 0 /CaCp . SFX CA 0 -/CaCp . SFX CB Y 2 SFX CB 0 /CbCp . SFX CB 0 -/CbCp . SFX Ch Y 2 SFX Ch 0 s/CaCbCxCp . SFX Ch 0 s-/CaCbCcCp . nuspell-5.1.7/tests/v1cmdline/opentaal_cpdpat2.dic000066400000000000000000000000511511132717100221260ustar00rootroot00000000000000100 test/CACBCc zout/CACBXm suiker/CACBXmnuspell-5.1.7/tests/v1cmdline/opentaal_cpdpat2.good000066400000000000000000000000201511132717100223130ustar00rootroot00000000000000zout-suikertest nuspell-5.1.7/tests/v1cmdline/opentaal_cpdpat2.wrong000066400000000000000000000000171511132717100225250ustar00rootroot00000000000000zoutsuikertest nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword1.aff000066400000000000000000000001361511132717100235030ustar00rootroot00000000000000TRY r FORBIDDENWORD F COMPOUNDRULE 2 COMPOUNDRULE WW COMPOUNDRULE WWW SFX S Y 1 SFX S 0 s . nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword1.dic000066400000000000000000000000441511132717100235040ustar00rootroot000000000000004 foo/W word/W bar/WS foowordbar/FS nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword1.good000066400000000000000000000000331511132717100236730ustar00rootroot00000000000000fooword wordbar barwordfoo nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword1.sug000066400000000000000000000000131511132717100235370ustar00rootroot00000000000000barwordfoo nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword1.wrong000066400000000000000000000000661511132717100241050ustar00rootroot00000000000000foowordbar foowordbars foowordba foowordbas barwodfoo nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword2.aff000066400000000000000000000000751511132717100235060ustar00rootroot00000000000000TRY r FORBIDDENWORD F COMPOUNDFLAG W SFX S Y 1 SFX S 0 s . nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword2.dic000066400000000000000000000000441511132717100235050ustar00rootroot000000000000003 foo/WS word/W bar/WS foowordbar/FSnuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword2.good000066400000000000000000000000471511132717100237010ustar00rootroot00000000000000fooword wordbar barwordfoo barwordfoos nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword2.sug000066400000000000000000000000131511132717100235400ustar00rootroot00000000000000barwordfoo nuspell-5.1.7/tests/v1cmdline/opentaal_forbiddenword2.wrong000066400000000000000000000000661511132717100241060ustar00rootroot00000000000000foowordbar foowordbars foowordba foowordbas barwodfoo nuspell-5.1.7/tests/v1cmdline/opentaal_keepcase.aff000066400000000000000000000001421511132717100223470ustar00rootroot00000000000000KEEPCASE K COMPOUNDBEGIN B COMPOUNDEND E COMPOUNDFLAG C COMPOUNDMIN 1 WORDCHARS - BREAK 1 BREAK # nuspell-5.1.7/tests/v1cmdline/opentaal_keepcase.dic000066400000000000000000000000501511132717100223500ustar00rootroot000000000000005 tv-/KB -tv/KE word/C NATO-/B -NATO/E nuspell-5.1.7/tests/v1cmdline/opentaal_keepcase.good000066400000000000000000000000441511132717100225440ustar00rootroot00000000000000tv-word word-tv NATO-word word-NATO nuspell-5.1.7/tests/v1cmdline/opentaal_keepcase.sug000066400000000000000000000002001511132717100224040ustar00rootroot00000000000000Tv-word, Tv- word, Word Tv- word, Word word -tv, word-tv, word word -tv, word-tv, word wordword-tv, word Tv-word-tv NATO- -NATO nuspell-5.1.7/tests/v1cmdline/opentaal_keepcase.wrong000066400000000000000000000001131511132717100227450ustar00rootroot00000000000000TV-word Tv-word word-TV word-Tv wordword-TV TV-word-TV Nato-word word-nato nuspell-5.1.7/tests/v1cmdline/phone.aff000066400000000000000000000177451511132717100200360ustar00rootroot00000000000000# phonetic suggestions by PHONE and optional ph field of dictionary words # Documentationo of PHONE: http://aspell.net/man-html/Phonetic-Code.html # phonetic_english.h - phonetic transformation rules for use with phonetic.c # Copyright (C) 2000 Björn Jacke # # This rule set is based on Lawrence Phillips original metaphone # algorithm with modifications made by Michael Kuhn in his # C implantation, more modifications by Björn Jacke when # converting the algorithm to a rule set and minor # touch ups by Kevin Atkinson # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License version 2.1 as published by the Free Software Foundation; # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Björn Jacke may be reached by email at bjoern.jacke@gmx.de # # Changelog: # # 2000-01-05 Björn Jacke # - first version with translation rules derived from # metaphone.cc distributed with aspell 0.28.3 # - "TH" is now representated as "@" because "0" is a # meta character # - removed TH(!vowel) --> T; always use TH --> # instead # - dropped "^AE" -> "E" (redundant) # - "ing" is transformed to "N", not "NK" # - "SCH(EO)" transforms to "SK" now # - added R --> SILENT if (after a vowel) and no (vowel or # "y" follows) like in "Marcy" or "abort" # - H is SILENT in RH at beginning of words # - H is SILENT if vowel leads and "Y" follows # - some ".OUGH.." --> ...F exceptions added # - "^V" transforms to "W" # 2000-01-07 Kevin Atkinson # Converted from header to data file. # # 2007-08-23 László Németh # Add PHONE header and PHONE keywords # # version 1.1 PHONE 105 PHONE AH(AEIOUY)-^ *H PHONE AR(AEIOUY)-^ *R PHONE A(HR)^ * PHONE A^ * PHONE AH(AEIOUY)- H PHONE AR(AEIOUY)- R PHONE A(HR) _ PHONE BB- _ PHONE B B PHONE CQ- _ PHONE CIA X PHONE CH X PHONE C(EIY)- S PHONE CK K PHONE COUGH^ KF PHONE CC< C PHONE C K PHONE DG(EIY) K PHONE DD- _ PHONE D T PHONE < E PHONE EH(AEIOUY)-^ *H PHONE ER(AEIOUY)-^ *R PHONE E(HR)^ * PHONE ENOUGH^$ *NF PHONE E^ * PHONE EH(AEIOUY)- H PHONE ER(AEIOUY)- R PHONE E(HR) _ PHONE FF- _ PHONE F F PHONE GN^ N PHONE GN$ N PHONE GNS$ NS PHONE GNED$ N PHONE GH(AEIOUY)- K PHONE GH _ PHONE GG9 K PHONE G K PHONE H H PHONE IH(AEIOUY)-^ *H PHONE IR(AEIOUY)-^ *R PHONE I(HR)^ * PHONE I^ * PHONE ING6 N PHONE IH(AEIOUY)- H PHONE IR(AEIOUY)- R PHONE I(HR) _ PHONE J K PHONE KN^ N PHONE KK- _ PHONE K K PHONE LAUGH^ LF PHONE LL- _ PHONE L L PHONE MB$ M PHONE MM M PHONE M M PHONE NN- _ PHONE N N PHONE OH(AEIOUY)-^ *H PHONE OR(AEIOUY)-^ *R PHONE O(HR)^ * PHONE O^ * PHONE OH(AEIOUY)- H PHONE OR(AEIOUY)- R PHONE O(HR) _ PHONE PH F PHONE PN^ N PHONE PP- _ PHONE P P PHONE Q K PHONE RH^ R PHONE ROUGH^ RF PHONE RR- _ PHONE R R PHONE SCH(EOU)- SK PHONE SC(IEY)- S PHONE SH X PHONE SI(AO)- X PHONE SS- _ PHONE S S PHONE TI(AO)- X PHONE TH @ PHONE TCH-- _ PHONE TOUGH^ TF PHONE TT- _ PHONE T T PHONE UH(AEIOUY)-^ *H PHONE UR(AEIOUY)-^ *R PHONE U(HR)^ * PHONE U^ * PHONE UH(AEIOUY)- H PHONE UR(AEIOUY)- R PHONE U(HR) _ PHONE V^ W PHONE V F PHONE WR^ R PHONE WH^ W PHONE W(AEIOU)- W PHONE X^ S PHONE X KS PHONE Y(AEIOU)- Y PHONE ZZ- _ PHONE Z S #The rules in a different view: # # Exceptions: # # Beginning of word: "gn", "kn-", "pn-", "wr-" ----> drop first letter # "Aebersold", "Gnagy", "Knuth", "Pniewski", "Wright" # # Beginning of word: "x" ----> change to "s" # as in "Deng Xiaopeng" # # Beginning of word: "wh-" ----> change to "w" # as in "Whalen" # Beginning of word: leading vowels are transformed to "*" # # "[crt]ough" and "enough" are handled separately because of "F" sound # # # A --> A at beginning # _ otherwise # # B --> B unless at the end of word after "m", as in "dumb", "McComb" # # C --> X (sh) if "-cia-" or "-ch-" # S if "-ci-", "-ce-", or "-cy-" # SILENT if "-sci-", "-sce-", or "-scy-", or "-cq-" # K otherwise, including in "-sch-" # # D --> K if in "-dge-", "-dgy-", or "-dgi-" # T otherwise # # E --> A at beginnig # _ SILENT otherwise # # F --> F # # G --> SILENT if in "-gh-" and not at end or before a vowel # in "-gn" or "-gned" or "-gns" # in "-dge-" etc., as in above rule # K if before "i", or "e", or "y" if not double "gg" # # K otherwise (incl. "GG"!) # # H --> SILENT if after vowel and no vowel or "Y" follows # or after "-ch-", "-sh-", "-ph-", "-th-", "-gh-" # or after "rh-" at beginning # H otherwise # # I --> A at beginning # _ SILENT otherwise # # J --> K # # K --> SILENT if after "c" # K otherwise # # L --> L # # M --> M # # N --> N # # O --> A at beginning # _ SILENT otherwise # # P --> F if before "h" # P otherwise # # Q --> K # # R --> SILENT if after vowel and no vowel or "Y" follows # R otherwise # # S --> X (sh) if before "h" or in "-sio-" or "-sia-" # SK if followed by "ch(eo)" (SCH(EO)) # S otherwise # # T --> X (sh) if "-tia-" or "-tio-" # 0 (th) if before "h" # silent if in "-tch-" # T otherwise # # U --> A at beginning # _ SILENT otherwise # # V --> V if first letter of word # F otherwise # # W --> SILENT if not followed by a vowel # W if followed by a vowel # # X --> KS # # Y --> SILENT if not followed by a vowel # Y if followed by a vowel # # Z --> S nuspell-5.1.7/tests/v1cmdline/phone.dic000066400000000000000000000001571511132717100200260ustar00rootroot0000000000000010 Brasilia brassily Brazilian brilliance brilliancy brilliant brain brass Churchillian xxxxxxxxxx ph:Brasilia nuspell-5.1.7/tests/v1cmdline/phone.sug000066400000000000000000000001011511132717100200520ustar00rootroot00000000000000Brasilia, Xxxxxxxxxx, Brilliant, Brazilian, Brassily, Brilliance nuspell-5.1.7/tests/v1cmdline/phone.wrong000066400000000000000000000000131511132717100204120ustar00rootroot00000000000000Brasillian nuspell-5.1.7/tests/v1cmdline/rep.aff000066400000000000000000000005721511132717100175010ustar00rootroot00000000000000# With REP suggestions, we can fix typical language specific misspellings. # switch off ngram suggestion for testing MAXNGRAMSUGS 0 REP 8 REP f ph REP ph f REP shun$ tion REP ^alot$ a_lot # add the highest priority for "a lot" suggestion to "alot" REP ^foo$ bar REP ' _ # "un'alunno" -> "un alunno" REP ^vinten$ vinte_e_un REP s 's SFX A Y 1 SFX A 0 's . WORDCHARS ' nuspell-5.1.7/tests/v1cmdline/rep.dic000066400000000000000000000001211511132717100174720ustar00rootroot0000000000000010 form phantom vacation vacations a lot un alunno bar barbars vinte e un auto/A nuspell-5.1.7/tests/v1cmdline/rep.sug000066400000000000000000000001071511132717100175350ustar00rootroot00000000000000form phantom vacation a lot, lot un alunno bar vinte e un auto's, auto nuspell-5.1.7/tests/v1cmdline/rep.wrong000066400000000000000000000001221511132717100200700ustar00rootroot00000000000000phorm fantom vacashun vacashuns alot un'alunno foo foobars barfoos vinteún autos nuspell-5.1.7/tests/v1cmdline/reputf.aff000066400000000000000000000002431511132717100202130ustar00rootroot00000000000000# With REP suggestions, we can fix typical language specific misspellings. SET UTF-8 # switch off ngram suggestion for testing MAXNGRAMSUGS 0 REP 1 REP oo őő nuspell-5.1.7/tests/v1cmdline/reputf.dic000066400000000000000000000000101511132717100202060ustar00rootroot000000000000001 főő nuspell-5.1.7/tests/v1cmdline/reputf.sug000066400000000000000000000000061511132717100202520ustar00rootroot00000000000000főő nuspell-5.1.7/tests/v1cmdline/reputf.wrong000066400000000000000000000000041511132717100206060ustar00rootroot00000000000000foo nuspell-5.1.7/tests/v1cmdline/simplifiedtriple.aff000066400000000000000000000002101511132717100222450ustar00rootroot00000000000000# Forbid compound word with triple letters CHECKCOMPOUNDTRIPLE # Allow simplified forms SIMPLIFIEDTRIPLE COMPOUNDMIN 2 COMPOUNDFLAG A nuspell-5.1.7/tests/v1cmdline/simplifiedtriple.dic000066400000000000000000000000201511132717100222470ustar00rootroot000000000000002 glass/A sko/A nuspell-5.1.7/tests/v1cmdline/simplifiedtriple.good000066400000000000000000000000221511132717100224420ustar00rootroot00000000000000glass sko glassko nuspell-5.1.7/tests/v1cmdline/simplifiedtriple.wrong000066400000000000000000000000111511132717100226440ustar00rootroot00000000000000glasssko nuspell-5.1.7/tests/v1cmdline/slash.aff000066400000000000000000000001001511132717100200100ustar00rootroot00000000000000# slashes in words (\/) # (only for tokenization) WORDCHARS /: nuspell-5.1.7/tests/v1cmdline/slash.dic000066400000000000000000000000531511132717100200220ustar00rootroot000000000000004 / 1\/2 http:\/\/ \/usr\/share\/nuspell\/ nuspell-5.1.7/tests/v1cmdline/slash.good000066400000000000000000000000421511132717100202110ustar00rootroot00000000000000/ 1/2 http:// /usr/share/nuspell/ nuspell-5.1.7/tests/v1cmdline/slash.wrong000066400000000000000000000000301511132717100204120ustar00rootroot00000000000000\/usr\/share\/nuspell\/ nuspell-5.1.7/tests/v1cmdline/sug.aff000066400000000000000000000006251511132717100175100ustar00rootroot00000000000000# new suggestion methods of Hunspell 1.5: # capitalization: nasa -> NASA # long swap: permenant -> permanent # long mov: Ghandi -> Gandhi # double two characters: vacacation -> vacation # space with REP: "alot" -> "a lot" ("a lot" need to be in the dic file.) # switch off ngram suggestion for testing MAXNGRAMSUGS 0 REP 1 REP alot a_lot KEY qwertzuiop|asdfghjkl|yxcvbnm|aq WORDCHARS .- FORBIDDENWORD ? nuspell-5.1.7/tests/v1cmdline/sug.dic000066400000000000000000000001311511132717100175030ustar00rootroot000000000000001 NASA Gandhi grateful permanent vacation a lot have which McDonald permanent-vacation/? nuspell-5.1.7/tests/v1cmdline/sug.sug000066400000000000000000000001561511132717100175510ustar00rootroot00000000000000NASA Gandhi grateful permanent vacation a lot, lot permanent. Vacation have which Gandhi McDonald permanent nuspell-5.1.7/tests/v1cmdline/sug.wrong000066400000000000000000000002151511132717100201030ustar00rootroot00000000000000nasa Ghandi greatful permenant vacacation alot permanent.Vacation ahev hwihc GAndhi Mcdonald permqnent permanent-vacation permqnent-vacation nuspell-5.1.7/tests/v1cmdline/sugutf.aff000066400000000000000000000006351511132717100202300ustar00rootroot00000000000000# new suggestion methods of Hunspell 1.5: # capitalization: nasa -> NASA # long swap: permenant -> permanent # long mov: Ghandi -> Gandhi # double two characters: vacacation -> vacation # space with REP: "alot" -> "a lot" ("a lot" need to be in the dic file.) SET UTF-8 # switch off ngram suggestion for testing MAXNGRAMSUGS 0 REP 1 REP alot a_lot KEY qwertzuiop|asdfghjkl|yxcvbnm|aq WORDCHARS . FORBIDDENWORD ? nuspell-5.1.7/tests/v1cmdline/sugutf.dic000066400000000000000000000001051511132717100202230ustar00rootroot0000000000000010 NASA Gandhi grateful permanent vacation a lot have which McDonald nuspell-5.1.7/tests/v1cmdline/sugutf.sug000066400000000000000000000001541511132717100202660ustar00rootroot00000000000000NASA Gandhi grateful permanent vacation a lot, lot permanent. Vacation have which Gandhi McDonald permanent nuspell-5.1.7/tests/v1cmdline/sugutf.wrong000066400000000000000000000001471511132717100206260ustar00rootroot00000000000000nasa Ghandi greatful permenant vacacation alot permanent.Vacation ahev hwihc GAndhi Mcdonald permqnent nuspell-5.1.7/tests/v1cmdline/utf8.aff000066400000000000000000000002011511132717100175660ustar00rootroot00000000000000SET UTF-8 SFX A Y 7 SFX A 0 őő . SFX A 0 ő o SFX A 0 ő ó SFX A ó ő ó SFX A ó őoo ó SFX A o őo o SFX A 0 ó [abcdó] nuspell-5.1.7/tests/v1cmdline/utf8.dic000066400000000000000000000000171511132717100175760ustar00rootroot000000000000002 foo/A foó/A nuspell-5.1.7/tests/v1cmdline/utf8.good000066400000000000000000000000671511132717100177740ustar00rootroot00000000000000foo foó fooőő fooő foóő foő foőo foőoo foóó nuspell-5.1.7/tests/v1cmdline/utf8_bom.aff000066400000000000000000000000711511132717100204300ustar00rootroot00000000000000SET UTF-8 # removing byte order mark from affix file nuspell-5.1.7/tests/v1cmdline/utf8_bom.dic000066400000000000000000000000141511132717100204300ustar00rootroot000000000000001 apéritif nuspell-5.1.7/tests/v1cmdline/utf8_bom.good000066400000000000000000000000261511132717100206240ustar00rootroot00000000000000apéritif APÉRITIF nuspell-5.1.7/tests/v1cmdline/utf8_bom2.aff000066400000000000000000000000641511132717100205140ustar00rootroot00000000000000SET UTF-8 # removing byte order mark from dic file nuspell-5.1.7/tests/v1cmdline/utf8_bom2.dic000066400000000000000000000000171511132717100205150ustar00rootroot000000000000001 apéritif nuspell-5.1.7/tests/v1cmdline/utf8_bom2.good000066400000000000000000000000261511132717100207060ustar00rootroot00000000000000apéritif APÉRITIF nuspell-5.1.7/tests/v1cmdline/utf8_nonbmp.aff000066400000000000000000000000121511132717100211370ustar00rootroot00000000000000SET UTF-8 nuspell-5.1.7/tests/v1cmdline/utf8_nonbmp.dic000066400000000000000000000001151511132717100211460ustar00rootroot000000000000004 # Old Persian numbers (1-4), source: Wikipedia 𐏑 𐏒 𐏒𐏑 𐏒𐏒 nuspell-5.1.7/tests/v1cmdline/utf8_nonbmp.good000066400000000000000000000000411511132717100213350ustar00rootroot00000000000000𐏑 𐏒 𐏒𐏑 𐏒𐏒 nuspell-5.1.7/tests/v1cmdline/utf8_nonbmp.sug000066400000000000000000000000461511132717100212100ustar00rootroot00000000000000𐏒𐏑, 𐏒𐏒 𐏒𐏑, 𐏒𐏒 nuspell-5.1.7/tests/v1cmdline/utf8_nonbmp.wrong000066400000000000000000000000341511132717100215430ustar00rootroot00000000000000𐏑𐏒𐏒 𐏑𐏒𐏒 nuspell-5.1.7/tests/v1cmdline/utfcompound.aff000066400000000000000000000000471511132717100212530ustar00rootroot00000000000000SET UTF-8 COMPOUNDMIN 3 COMPOUNDFLAG A nuspell-5.1.7/tests/v1cmdline/utfcompound.dic000066400000000000000000000000661511132717100212570ustar00rootroot000000000000008 foo/A bar/A fóó/A áár/A xy/A yz/A éé/A őő/A nuspell-5.1.7/tests/v1cmdline/utfcompound.good000066400000000000000000000000561511132717100214470ustar00rootroot00000000000000foobar barfoo foobarfoo fóóáár áárfóó nuspell-5.1.7/tests/v1cmdline/utfcompound.wrong000066400000000000000000000000671511132717100216550ustar00rootroot00000000000000xyyz fooxy xyfoo fooxybar ééőő fóóéé őőáár nuspell-5.1.7/tests/v1cmdline/warn.aff000066400000000000000000000003051511132717100176540ustar00rootroot00000000000000# WARN flag # The signed word, and its suffixed forms result warning message in command-line #Use to forbid the words with flag WARN #FORBIDWARN WARN W SFX A Y 1 SFX A 0 s . REP 1 REP foo bar nuspell-5.1.7/tests/v1cmdline/warn.dic000066400000000000000000000000151511132717100176550ustar00rootroot000000000000001 foo/WA bar nuspell-5.1.7/tests/v1cmdline/warn.good000066400000000000000000000000111511132717100200420ustar00rootroot00000000000000foo foos nuspell-5.1.7/tests/v1cmdline/zeroaffix.aff000066400000000000000000000002251511132717100207030ustar00rootroot00000000000000PSEUDOROOT X COMPOUNDFLAG Y SFX A Y 1 SFX A 0 0 . > SFX B Y 1 SFX B 0 0 . > SFX C Y 2 SFX C 0 0/XAB . SFX C 0 baz/XAB . nuspell-5.1.7/tests/v1cmdline/zeroaffix.dic000066400000000000000000000000341511132717100207040ustar00rootroot000000000000002 foo/XA bar analyze(bar) = st:bar > analyze(bar) = st:bar analyze(bar) = st:bar > analyze(bar) = st:bar > stem(bar) = bar > foo analyze(foo) = st:foo stem(foo) = foo > barbaz analyze(barbaz) = st:bar > analyze(barbaz) = st:bar > stem(barbaz) = bar nuspell-5.1.7/tests/verify.cxx000066400000000000000000000375701511132717100164130ustar00rootroot00000000000000/* Copyright 2016-2024 Dimitrij Mijoski * * This file is part of Nuspell. * * Nuspell is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Nuspell 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Nuspell. If not, see . */ #include #include #include #include #include #include #include #include #include #if __has_include() #include // defines _POSIX_VERSION #endif #ifdef _POSIX_VERSION #include #include #include #endif #ifdef _WIN32 #include #ifndef NOMINMAX #define NOMINMAX #endif #define WIN32_LEAN_AND_MEAN #include #include #endif // manually define if not supplied by the build system #ifndef PROJECT_VERSION #define PROJECT_VERSION "unknown.version" #endif using namespace std; using nuspell::Dictionary, nuspell::Dictionary_Loading_Error, nuspell::Dict_Finder_For_CLI_Tool_2; namespace { enum Mode { NORMAL, HELP, VERSION }; auto print_help(const char* program_name) -> void { auto p = string_view(program_name); auto& o = cout; o << "Usage:\n" << p << " [-d dict_NAME] [OPTION]... [FILE...]\n" << p << " --help|--version\n" << R"( Check spelling of each FILE, and measure speed and correctness in regard to other spellchecking libraries. If no FILE is specified, check standard input. The input text should be a simple wordlist with one word per line. -d, --dictionary=di_CT use di_CT dictionary (only one is supported) -m, --print-mismatches print mismatches (false positives and negatives) -s, --test-suggestions call suggest function (useful only for debugging) -w, --wikipedia-list input is Wikipedia's list of common misspellings --encoding=enc set both input and output encoding --input-encoding=enc input encoding, default is active locale --output-encoding=enc (UNUSED, always UTF-8) output encoding, default is active locale --help print this help --version print version number The following environment variables can have effect: DICTIONARY - same as -d, DICPATH - additional directory path to search for dictionaries. Example: )" << " " << p << " -d en_US file.txt\n" << " " << p << " -d ../../subdir/di_CT.aff\n"; } auto ver_str = "nuspell " PROJECT_VERSION R"( Copyright 2016-2024 Dimitrij Mijoski License LGPLv3+: GNU LGPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Dimitrij Mijoski. )"; auto print_version() -> void { cout << ver_str; } auto get_peak_ram_usage() -> long { #ifdef _POSIX_VERSION rusage r; auto err = getrusage(RUSAGE_SELF, &r); if (!err) return r.ru_maxrss; #elif _WIN32 PROCESS_MEMORY_COUNTERS pmc; auto suc = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); if (suc) return pmc.PeakWorkingSetSize >> 10; #endif return 0; } auto to_utf8(string_view source, string& dest, UConverter* ucnv, UErrorCode& uerr) { dest.resize(dest.capacity()); auto len = ucnv_toAlgorithmic(UCNV_UTF8, ucnv, dest.data(), dest.size(), source.data(), source.size(), &uerr); dest.resize(len); if (uerr == U_BUFFER_OVERFLOW_ERROR) { uerr = U_ZERO_ERROR; ucnv_toAlgorithmic(UCNV_UTF8, ucnv, dest.data(), dest.size(), source.data(), source.size(), &uerr); } } auto from_utf8(string_view source, string& dest, UConverter* ucnv, UErrorCode& uerr) { dest.resize(dest.capacity()); auto len = ucnv_fromAlgorithmic(ucnv, UCNV_UTF8, dest.data(), dest.size(), source.data(), source.size(), &uerr); dest.resize(len); if (uerr == U_BUFFER_OVERFLOW_ERROR) { uerr = U_ZERO_ERROR; ucnv_fromAlgorithmic(ucnv, UCNV_UTF8, dest.data(), dest.size(), source.data(), source.size(), &uerr); } } struct Options { bool print_mismatches = false; bool test_suggestions = false; bool wikipedia_list = false; }; auto process_text(Options opt, const Dictionary& dic, Hunspell& hun, UConverter* hun_cnv, istream& in, UConverter* in_cnv, ostream& out, UErrorCode& uerr) { using Duration = chrono::high_resolution_clock::duration; string word, line, u8_tmp_buf, hun_word; size_t total = 0; size_t true_pos = 0, true_neg = 0, false_pos = 0, false_neg = 0; Duration time_nu_true = {}, time_nu_false = {}; Duration time_hun_true = {}, time_hun_false = {}; auto nus_sugs = vector(); Duration time_nu_sugs = {}, time_hun_sugs = {}; size_t nus_hits = 0, nus_misses = 0, nus_sum_orders = 0; size_t hun_hits = 0, hun_misses = 0, hun_sum_orders = 0; auto hun_enc = nuspell::Encoding(hun.get_dict_encoding()).value_or_default(); auto in_is_utf8 = ucnv_getType(in_cnv) == UCNV_UTF8; // auto out_is_utf8 = ucnv_getType(out_cnv) == UCNV_UTF8; auto hun_is_utf8 = ucnv_getType(hun_cnv) == UCNV_UTF8; for (;;) { size_t i = 0; if (opt.wikipedia_list) { if (!getline(in, line)) break; if (line.empty() || line.front() == '#') continue; auto rtrim_idx = line.find_last_not_of(" \t\r"); if (rtrim_idx != line.npos) line.erase(++rtrim_idx); if (!in_is_utf8) { to_utf8(line, u8_tmp_buf, in_cnv, uerr); line = u8_tmp_buf; } if ((i = line.find("->")) != line.npos) { word.assign(line, 0, i); i += 2; } else if ((i = line.find('\t')) != line.npos) { word.assign(line, 0, i); i += 1; } else continue; } else if (in >> word) { if (!in_is_utf8) { to_utf8(word, u8_tmp_buf, in_cnv, uerr); word = u8_tmp_buf; } } else break; auto time_a = chrono::high_resolution_clock::now(); auto res_nu = dic.spell(word); auto time_b = chrono::high_resolution_clock::now(); if (hun_is_utf8) hun_word = word; else from_utf8(word, hun_word, hun_cnv, uerr); auto res_hun = hun.spell(hun_word); auto time_c = chrono::high_resolution_clock::now(); auto time_nu = time_b - time_a; auto time_hun = time_c - time_b; if (res_nu) time_nu_true += time_nu; else time_nu_false += time_nu; if (res_hun) time_hun_true += time_hun; else time_hun_false += time_hun; if (res_hun) { if (res_nu) { ++true_pos; } else { ++false_neg; if (opt.print_mismatches) out << "FN: " << word << '\n'; } } else { if (res_nu) { ++false_pos; if (opt.print_mismatches) out << "FP: " << word << '\n'; } else { ++true_neg; } } ++total; if (!opt.test_suggestions && !opt.wikipedia_list) continue; time_a = chrono::high_resolution_clock::now(); dic.suggest(word, nus_sugs); time_b = chrono::high_resolution_clock::now(); auto hun_sugs = hun.suggest(hun_word); time_c = chrono::high_resolution_clock::now(); time_nu_sugs += time_b - time_a; time_hun_sugs += time_c - time_b; if (!opt.wikipedia_list) continue; if (opt.print_mismatches && (res_nu || res_hun)) { out << "Word " << word << " detected as correct.\n" << "Suggestions from list: " << line.substr(i) << '\n'; } if (opt.print_mismatches && res_nu && !empty(nus_sugs)) { out << "Nuspell sugs : "; for (auto it = begin(nus_sugs);;) { out << *it; if (++it == end(nus_sugs)) break; out << ", "; } out << '\n'; } for (auto& hs : hun_sugs) { to_utf8(hs, u8_tmp_buf, hun_cnv, uerr); hs = u8_tmp_buf; } // hun_sugs is now utf8 if (opt.print_mismatches && res_hun && !empty(hun_sugs)) { out << "Hunspell sugs: "; for (auto it = begin(hun_sugs);;) { out << *it; if (++it == end(hun_sugs)) break; out << ", "; } out << '\n'; } for (auto needle = ", "sv;;) { auto j = line.find(needle, i); auto wiki_sug = line.substr(i, j - i); // process wiki_sug auto it = find(begin(nus_sugs), end(nus_sugs), wiki_sug); if (it != end(nus_sugs)) { ++nus_hits; auto order = distance(begin(nus_sugs), it) + 1; nus_sum_orders += order; } else { ++nus_misses; } it = find(begin(hun_sugs), end(hun_sugs), wiki_sug); if (it != end(hun_sugs)) { ++hun_hits; auto order = distance(begin(hun_sugs), it) + 1; hun_sum_orders += order; } else { ++hun_misses; } // stop condition if (j == line.npos) break; // increment i = j + size(needle); } if (total % 100 == 0) out << total << " words processed." << endl; } out << "Total Words = " << total << '\n'; if (total == 0) return; auto accuracy = (true_pos + true_neg) * 1.0 / total; auto precision = true_pos * 1.0 / (true_pos + false_pos); auto total_hun_time = time_hun_true + time_hun_false; auto total_nu_time = time_nu_true + time_nu_false; auto speedup = total_hun_time.count() * 1.0 / total_nu_time.count(); out << "TP = " << true_pos << '\n'; out << "TN = " << true_neg << '\n'; out << "FP = " << false_pos << '\n'; out << "FN = " << false_neg << '\n'; out << "Accuracy = " << accuracy << '\n'; out << "Precision = " << precision << '\n'; out << "Time Nuspell True = " << time_nu_true.count() << '\n'; out << "Time Nuspell False = " << time_nu_false.count() << '\n'; out << "Time Hunspell True = " << time_hun_true.count() << '\n'; out << "Time Hunspell False = " << time_hun_false.count() << '\n'; out << "Speedup = " << speedup << '\n'; if (!opt.test_suggestions && !opt.wikipedia_list) return; out << '\n'; out << "Nus hits = " << nus_hits << '\n'; out << "Nus misses = " << nus_misses << '\n'; out << "Nus avg order = " << nus_sum_orders * 1.0 / nus_hits << '\n'; out << "Hun hits = " << hun_hits << '\n'; out << "Hun misses = " << hun_misses << '\n'; out << "Hun avg order = " << hun_sum_orders * 1.0 / hun_hits << '\n'; out << "Time Nuspell sugs = " << time_nu_sugs.count() << '\n'; out << "Time Hunspell sugs = " << time_hun_sugs.count() << '\n'; } } // namespace int main(int argc, char* argv[]) { auto mode_int = int(Mode::NORMAL); auto program_name = "nuspell"; auto dictionary = string(); auto input_enc = string(); auto output_enc = string(); auto options = Options(); if (argc > 0 && argv[0]) program_name = argv[0]; ios_base::sync_with_stdio(false); auto optstring = "d:msw"; option longopts[] = { {"help", no_argument, &mode_int, Mode::HELP}, {"version", no_argument, &mode_int, Mode::VERSION}, {"dictionary", required_argument, nullptr, 'd'}, {"print-mismatches", no_argument, nullptr, 'm'}, {"test-suggestions", no_argument, nullptr, 's'}, {"wikipedia-list", no_argument, nullptr, 'w'}, {"encoding", required_argument, nullptr, 'e'}, {"input-encoding", required_argument, nullptr, 'i'}, {"output-encoding", required_argument, nullptr, 'o'}, {}}; int longindex; int c; while ((c = getopt_long(argc, argv, optstring, longopts, &longindex)) != -1) { switch (c) { case 0: // check longopts[longindex] if needed break; case 'd': dictionary = optarg; break; case 'm': options.print_mismatches = true; break; case 's': options.test_suggestions = true; break; case 'w': options.wikipedia_list = true; break; case 'e': input_enc = optarg; output_enc = optarg; break; case 'i': input_enc = optarg; break; case 'o': output_enc = optarg; break; case '?': return EXIT_FAILURE; } } auto mode = static_cast(mode_int); if (mode == Mode::VERSION) { print_version(); return 0; } else if (mode == Mode::HELP) { print_help(program_name); return 0; } auto f = Dict_Finder_For_CLI_Tool_2(); char* loc_str = nullptr; #if _WIN32 loc_str = setlocale(LC_CTYPE, nullptr); // will return "C" #else loc_str = setlocale(LC_CTYPE, ""); if (!loc_str) { clog << "WARNING: Can not set to system locale, fall back to " "\"C\".\n"; loc_str = setlocale(LC_CTYPE, nullptr); // will return "C" } #endif #if _POSIX_VERSION auto enc_str = nl_langinfo(CODESET); if (input_enc.empty()) input_enc = enc_str; if (output_enc.empty()) output_enc = enc_str; #elif _WIN32 if (optind == argc && _isatty(_fileno(stdin))) input_enc = "cp" + to_string(GetConsoleCP()); else if (input_enc.empty()) input_enc = "UTF-8"; if (_isatty(_fileno(stdout))) output_enc = "cp" + to_string(GetConsoleOutputCP()); else if (output_enc.empty()) output_enc = "UTF-8"; #endif auto loc_str_sv = string_view(loc_str); clog << "INFO: Locale LC_CTYPE=" << loc_str_sv << ", Input encoding=" << input_enc << ", Output encoding=" << output_enc << endl; if (dictionary.empty()) { auto denv = getenv("DICTIONARY"); if (denv) dictionary = denv; } if (dictionary.empty()) { // infer dictionary from locale auto idx = min(loc_str_sv.find('.'), loc_str_sv.find('@')); dictionary = loc_str_sv.substr(0, idx); } if (dictionary.empty()) { clog << "ERROR: No dictionary provided and can not infer from " "OS locale\n"; return EXIT_FAILURE; } auto filename = f.get_dictionary_path(dictionary); if (filename.empty()) { clog << "ERROR: Dictionary " << dictionary << " not found\n"; return EXIT_FAILURE; } clog << "INFO: Pointed dictionary " << filename.string() << endl; auto peak_ram_a = get_peak_ram_usage(); auto dic = Dictionary(); try { dic.load_aff_dic_internal(filename, clog); } catch (const Dictionary_Loading_Error& e) { clog << "ERROR: " << e.what() << '\n'; return EXIT_FAILURE; } auto nuspell_ram = get_peak_ram_usage() - peak_ram_a; auto aff_name = filename.string(); auto dic_name = filename.replace_extension(".dic").string(); peak_ram_a = get_peak_ram_usage(); auto hun = Hunspell(aff_name.c_str(), dic_name.c_str()); auto hunspell_ram = get_peak_ram_usage() - peak_ram_a; cout << "Nuspell peak RAM usage: " << nuspell_ram << "KB\n" << "Hunspell peak RAM usage: " << hunspell_ram << "KB\n"; // ICU reports all types of errors, logic errors and runtime errors // using this enum. We should not check for logic errors, they should // not happened. Optionally, only assert that they are not there can be // used. We should check for runtime errors. // The encoding conversion is a common case where runtime error can // happen, but by default ICU uses Unicode replacement character on // errors and reports success. This can be changed, but there is no need // for that. auto uerr = U_ZERO_ERROR; auto inp_enc_cstr = input_enc.c_str(); if (input_enc.empty()) { inp_enc_cstr = nullptr; clog << "WARNING: using default ICU encoding converter for IO" << endl; } auto in_ucnv = icu::LocalUConverterPointer(ucnv_open(inp_enc_cstr, &uerr)); if (U_FAILURE(uerr)) { clog << "ERROR: Invalid encoding " << input_enc << ".\n"; return EXIT_FAILURE; } auto hun_enc = nuspell::Encoding(hun.get_dict_encoding()).value_or_default(); auto hun_cnv = icu::LocalUConverterPointer(ucnv_open(hun_enc.c_str(), &uerr)); if (U_FAILURE(uerr)) { clog << "ERROR: Invalid Hun encoding " << hun_enc << ".\n"; return EXIT_FAILURE; } if (optind == argc) { process_text(options, dic, hun, hun_cnv.getAlias(), cin, in_ucnv.getAlias(), cout, uerr); } else { for (; optind != argc; ++optind) { auto file_name = argv[optind]; ifstream in(file_name); if (!in.is_open()) { clog << "ERROR: Can't open " << file_name << '\n'; return EXIT_FAILURE; } process_text(options, dic, hun, hun_cnv.getAlias(), in, in_ucnv.getAlias(), cout, uerr); } } } nuspell-5.1.7/vcpkg.json000066400000000000000000000004321511132717100152110ustar00rootroot00000000000000{ "builtin-baseline": "2f9972005f61f02fa3cda7fc062d1b834b534b8d", "dependencies": [ { "name": "catch2", "version>=": "3.3.2" }, { "name": "getopt", "version>=": "0#2" }, { "name": "icu", "version>=": "69.1#18" } ] }